diff --git a/discordDark.css b/discordDark.css
deleted file mode 100644
index 90b97e2b0c5a4b2abf214af7b65bf5181a48964a..0000000000000000000000000000000000000000
--- a/discordDark.css
+++ /dev/null
@@ -1,481 +0,0 @@
-@-moz-document regexp("(https:\/\/.*):(8006)\/?(.*)")
-{
-.x-box-inner {
-overflow:hidden;
-position:relative;
-left:0;
-top:0;
-background:#23272a
-}
-
-.x-body {
-color:#fff;
-font-size:13px;
-line-height:17px;
-font-weight:300;
-font-family:helvetica, arial, verdana, sans-serif;
-background:#fff
-}
-
-.x-viewport,.x-viewport > .x-body {
-background:#23272a
-}
-
-.x-form-text-default {
-color:#818082;
-background-color:#4a4d53;
-font:300 13px/17px helvetica, arial, verdana, sans-serif;
-min-height:22px;
-padding:0 6px 2px
-}
-
-.x-form-trigger-wrap-default {
-border-color:#cfcfcf;
-border-style:solid;
-border-width:0
-}
-
-.x-form-trigger-default {
-width:22px;
-background:0 center #72767d url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_trigger.png) no-repeat
-}
-
-.x-panel-body-default {
-background:#2c2f33;
-color:#fff;
-font-size:13px;
-font-weight:300;
-font-family:helvetica, arial, verdana, sans-serif;
-border-color:#fff;
-border-style:solid;
-border-width:0
-}
-
-.x-grid-cell-inner,.x-grid-cell-rowbody {
-background:#2c2f33;
-color:#fff
-}
-
-.x-toolbar-default {
-background-color:#2c2f33;
-border-width:0
-}
-
-.x-toolbar {
-background:#2c2f33
-}
-
-#toolbar-1069-innerCt {
-background:#2c2f33
-}
-
-.x-autocontainer-innerCt {
-background:#2c2f33
-}
-
-[id^="toolbar"] {
-background:#2c2f33
-}
-
-[id^="legend"] {
-background:#23272a;
-border-color:red
-}
-
-.x-legend-item {
-background:#2c2f33;
-color:#fff;
-border-width:0
-}
-
-.x-legend-container {
-background:#2c2f33;
-border-radius:0;
-box-shadow:rgba(0,0,0,0) 0 0 0;
-border-width:0
-}
-
-.x-legend.x-docked-top .x-legend-item,.x-legend.x-docked-bottom .x-legend-item,.x-legend-panel.x-docked-top .x-legend-item,.x-legend-panel.x-docked-bottom .x-legend-item {
-border-left:0;
-border-bottom:0
-}
-
-.x-treelist-item-leaf,.x-treelist-container,.x-treelist-row,.x-treelist-row-with-icon,.x-treelist-item-expandable,.x-treelist-item-wrap,.x-treelist-item-text,.x-treelist-item-icon {
-background:#2c2f33;
-color:#fff
-}
-
-.x-treelist-item-selected > .x-treelist-row {
-background-color:#23272a
-}
-
-.x-treelist-row-over {
-color:#FF0
-}
-
-.x-treelist-row-over > * > .x-treelist-item-text {
-color:#7289da;
-transition:color .5s
-}
-
-.x-treelist-row-over > * > .x-treelist-item-icon {
-color:#7289da;
-transition:color .5s
-}
-
-.fa-ceph:before {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_cephwhite.png)
-}
-
-.x-treelist-row-over > * > .fa-ceph:before {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_cephblurp.png);
-background-size:14px 14px;
-transition:background-image .5s
-}
-
-.x-progress {
-background:#2c2f33
-}
-
-.x-progress-bar {
-background-color:#7289da!important
-}
-
-.x-progress-text.x-progress-text-back,.x-progress-text {
-color:#fff!important
-}
-
-.x-component.x-box-item.x-component-default {
-background:#23272a
-}
-
-.x-panel-header {
-background:#23272a;
-border:0
-}
-
-.x-title-text {
-color:#7289da
-}
-
-.x-btn {
-background:#7289da;
-border-width:0
-}
-
-.x-btn-inner,.x-btn-inner.x-btn-inner-default-small {
-color:#fff
-}
-
-#button-1030 {
-background:#23272a;
-border-color:#d23d3f;
-border-width:1px
-}
-
-.x-btn.x-unselectable.x-box-item.x-toolbar-item.x-btn-default-toolbar-small.x-btn-over,.x-btn.x-unselectable.x-box-item.x-btn-default-small.x-btn-over,.x-menu-item-focus {
-background-color:#677bc4
-}
-
-.x-btn.x-unselectable.x-box-item.x-toolbar-item.x-btn-default-toolbar-small.x-btn-menu-active {
-background-color:#677bc4
-}
-
-.x-btn-disabled {
-background-image:none;
-background-color:#737fab!important
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-small.fa.fa-book.x-btn-icon-el-default-toolbar-small,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-undo,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-terminal,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-fw.fa-ellipsis-v,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.x-btn-icon-el-default-toolbar-small.fa.fa-question-circle,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-send-o,.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-play,.x-btn-inner.x-btn-inner-default-toolbar-small,.x-btn-icon-el.x-btn-icon-el-default-small.fa.black.fa-gear,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-send-o,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-clone,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-file-o,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-heartbeat,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-trash-o,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-desktop,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-cube,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-terminal {
-color:#fff
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-play,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-play {
-color:#43b581
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-power-off,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-stop,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-stop,.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-power-off {
-color:#d23d3f
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-pause {
-color:#faa61a
-}
-
-.x-menu-item,.x-menu-default {
-background:#7289da;
-border-style:none;
-border-width:0
-}
-
-.x-menu-item-text {
-color:#fff
-}
-
-.x-menu-item-default.x-menu-item-separator {
-height:0;
-border-top-width:0;
-margin:0;
-padding:0
-}
-
-.x-menu-header {
-border-radius:1px;
-background:#23272a;
-border-width:0
-}
-
-[id^="tooltip"] {
-background:#7289da;
-color:#fff;
-border-width:0
-}
-
-[id^="ext-quicktips-tip-body"],[id^="ext-quicktips-tip-innerCt"],[id^="ext-quicktips-tip-ext-quicktips-tip-outerCt"],[id^="ext-form-error"],.x-tip-default {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0
-}
-
-.x-tool-img {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_tool-sprites.png)
-}
-
-.x-window-header.x-header.x-header-draggable.x-docked.x-unselectable.x-window-header-default.x-horizontal.x-window-header-horizontal.x-window-header-default-horizontal.x-top.x-window-header-top.x-window-header-default-top.x-box-layout-ct,.x-window-body {
-background:#23272a;
-border-bottom-width:0;
-border-right-width:0
-}
-
-.x-window-default {
-border-radius:0;
-background-color:#23272a;
-box-shadow:none;
-border-color:#23272a;
-border-style:none;
-border-width:0;
-padding:0
-}
-
-.x-window-default-mc {
-background-color:#23272a
-}
-
-.x-window-body-default {
-color: white;
-border-width:0!important
-}
-
-.x-window-header-default-top {
-border-top-left-radius:0!important;
-border-top-right-radius:0!important;
-border-bottom-right-radius:0!important;
-border-bottom-left-radius:0!important;
-background-color:#23272a;
-border-width:0!important;
-padding:9px
-}
-
-.x-form-text,.x-form-item-label-inner-default,.x-window-text,.x-form-display-field,.x-component {
-color:#fff
-}
-
-.x-mask {
-background-color:rgba(26,26,29,0.27)
-}
-
-.x-splitter-collapsed .x-layout-split-bottom {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_mini-top.png)
-}
-
-.x-layout-split-bottom {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_mini-bottom.png)
-}
-
-.x-tab {
-background:#737fab;
-color:#fff;
-border-width:0
-}
-
-.x-tab-inner {
-color:#fff
-}
-
-.x-tab-active,.x-tab-over,.x-tab-default-focus,.x-tab-focus {
-background:#7289da!important;
-border-width:0!important
-}
-
-.x-tab-bar-body {
-background:#23272a
-}
-
-.x-tab-disabled {
-background:#737fab!important
-}
-
-.x-column-header-inner,.x-column-header-default,.x-grid-item,.x-grid-header-ct {
-background:#2c2f33;
-border-width:0!important
-}
-
-.x-column-header-text-inner {
-color:#fff
-}
-
-.x-column-header-trigger {
-border-color:#23272a
-}
-
-.x-toolbar-text.x-box-item.x-toolbar-item.x-toolbar-text-default,.x-grid-group-title {
-color:#fff
-}
-
-[id^="pveNodeStatus"] {
-background:#23272a
-}
-
-div[id^="pveNotesView-"][id$="-innerCt"] {
-background:#23272a
-}
-
-img[src^="/pve2/images/proxmox_logo"] {
-background:#23272a;
-content:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_logo.png)
-}
-
-[id^="versioninfo"] {
-background:#23272a
-}
-
-[id^="proxmoxGauge"] {
-background:#23272a
-}
-
-div[id^="panel-"][id$="-body"] {
-background:#23272a
-}
-
-.x-surface-canvas {
-border-radius:3px
-}
-
-.x-component.x-fieldset-header-text.x-component-default {
-color:#fff
-}
-
-.x-fieldset-default {
-border:1px solid #7289da
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-server,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-server,.fa-building.online,.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-cube.running.ha-unmanaged,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-building,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-building,.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-cube,.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-desktop,.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-database,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-cube,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-desktop,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-database,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-database,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-desktop,.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-cube {
-color:#7289da!important
-}
-
-.x-grid-group-hd.x-grid-group-hd-collapsible {
-background:#23272a;
-color:#fff;
-border-width:0
-}
-
-.x-splitter {
-background:#23272a
-}
-
-.x-box-scroller,.x-box-scroller-body-vertical,.x-vertical-scroller,.x-toolbar-vertical-scroller,.x-toolbar-default-vertical-scroller {
-background:#2c2f33!important
-}
-
-.pve-itype-icon-processor {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cpu.png)
-}
-
-.pve-itype-icon-memory {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-ram.png)
-}
-
-.pve-itype-icon-storage {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-hdd.png)
-}
-
-.pve-itype-icon-swap {
-background-image:url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-swap.png)
-}
-
-.pve-itype-icon-display, .x-grid-row-console {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-display.png);
-}
-    
-.pve-itype-icon-cdrom  {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cd.png);
-}
-    
-.pve-itype-icon-network {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-network.png);
-}
-    
-.pve-itype-icon-pci {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-pci.png);
-}
-    
-.pve-itype-icon-usb {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-usb.png);
-}
-    
-.pve-itype-icon-serial {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-serial.png);
-}
-    
-.pve-itype-icon-cloud {
-background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cloud.png);
-}
-
-.fa-fw.x-grid-icon-custom.fa.fa-database,.fa-fw.x-grid-icon-custom.fa.fa-desktop,.fa-fw.x-grid-icon-custom.fa.fa-cube {
-color:#7289da
-}
-
-html {
-overflow:scroll;
-overflow-x:hidden
-}
-
-::-webkit-scrollbar {
-width:0;
-background:transparent
-}
-
-.lxc:after,.qemu:after {
-background:transparent!important;
-color:#7289da;
-text-shadow:0 0 0 #2c2f33!important
-}
-
-.x-tree-icon-custom:after,.x-grid-icon-custom:after {
-text-shadow:0 0 0 #2c2f33
-}
-
-* {
-        font-weight: 350;
-}
-
-.x-surface-canvas {
-    filter: invert(100%);
-}
-
-.x-legend-item-marker {
-    filter: invert(100%);
-}
-
-.x-grid-row-loading {
-    background-image: url(https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_loading.svg);
-    background-size: 32px;
-}
-
-.x-grid-item-alt {
-background:#23272a;
-border-width:0!important;
-}
-
-}
\ No newline at end of file
diff --git a/serverside/ddInstall.sh b/serverside/ddInstall.sh
deleted file mode 100644
index a82d1a04f12e5f8f6f415899576c9a1719108bc8..0000000000000000000000000000000000000000
--- a/serverside/ddInstall.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-Say () {
-    printf "\e[1;34m $1  \e[0m \n";
-}
-
-DotSay () {
-    printf "[\e[1;34m*\e[0m] \e[1;34m $1  \e[0m \n"; 
-}
-
-
-Say '[PVE Discord Dark UI Theme Installer]'
-Say 'Internet connection required to download files'
-Say '>Press any key to begin installation'
-read -p ""
-Say ' '
-DotSay 'Backing up index template file'
-cp /usr/share/pve-manager/index.html.tpl /usr/share/pve-manager/index.html.tpl.bak 
-DotSay 'Applying stylesheet..'
-echo "<link rel='stylesheet' type='text/css' href='/pve2/css/dd_style.css'>" >> /usr/share/pve-manager/index.html.tpl
-cd /usr/share/pve-manager/css
-wget -O dd_style.css https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/style.css &> /dev/null 
-DotSay 'Applied stylesheet!'
-DotSay 'Downloading images..'
-cd /usr/share/pve-manager/images
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_cephblurp.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_cephwhite.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cpu.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-hdd.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-ram.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-swap.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cd.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-display.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-network.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-cloud.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-serial.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-usb.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_icon-pci.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_logo.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_mini-bottom.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_mini-top.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_readme &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_tool-sprites.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_trigger.png &> /dev/null 
-wget https://github.com/Weilbyte/PVEDiscordDark/raw/master/images/dd_loading.svg &> /dev/null 
-
-DotSay 'Downloaded images!'
-Say ''
-Say 'Installation finished!'
-Say 'o7'  
diff --git a/serverside/ddRemove.sh b/serverside/ddRemove.sh
deleted file mode 100644
index 5149c2f0d3732e7e26e266bf09ea76179907cfc6..0000000000000000000000000000000000000000
--- a/serverside/ddRemove.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-Say () {
-    printf "\e[1;34m $1  \e[0m \n";
-}
-
-DotSay () {
-    printf "[\e[1;34m*\e[0m] \e[1;34m $1  \e[0m \n"; 
-}
-
-
-Say '[PVE Discord Dark UI Theme Remover]'
-Say '>Press any key to remove theme'
-read -p ""
-Say ' '
-DotSay 'Reverting template change'
-rm /usr/share/pve-manager/index.html.tpl
-cp /usr/share/pve-manager/index.html.tpl.bak /usr/share/pve-manager/index.html.tpl
-DotSay 'Removing stylesheet'
-rm /usr/share/pve-manager/css/dd_style.css
-DotSay 'Removing images'
-cd /usr/share/pve-manager/images
-rm dd_*
-Say ''
-Say 'Theme removed!'
-Say 'o7'  
diff --git a/serverside/jsmod/5.4-3.sh b/serverside/jsmod/5.4-3.sh
deleted file mode 100644
index 98b9a8f8133bf53c3cd550745e6a73654d776ff3..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-Say () {
-    printf "\e[1;34m $1  \e[0m \n";
-}
-
-DotSay () {
-    printf "[\e[1;34m*\e[0m] \e[1;34m $1  \e[0m \n"; 
-}
-
-
-Say '[PVE Discord Dark UI Theme JSMOD Installer]'
-Say 'Internet connection REQUIRED.'
-Say '!!ONLY FOR PVE 5.4-3!!'
-Say '>Press any key to begin installation'
-read -p ""
-Say ' '
-DotSay 'Backing up files'
-cp /usr/share/pve-manager/js/pvemanagerlib.js /usr/share/pve-manager/js/pvemanagerlib.js.bak 
-cp /usr/share/javascript/extjs/charts.js /usr/share/javascript/extjs/charts.js.bak
-cp /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.bak
-DotSay 'Replacing files with modded versions'
-rm /usr/share/pve-manager/js/pvemanagerlib.js
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/5.4-3/pvemanagerlib.js -P /usr/share/pve-manager/js/ &> /dev/null 
-rm /usr/share/javascript/extjs/charts.js
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/5.4-3/charts.js -P /usr/share/javascript/extjs/ &> /dev/null 
-rm /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/5.4-3/proxmoxlib.js -P /usr/share/javascript/proxmox-widget-toolkit/ &> /dev/null 
-DotSay 'Applied successfully.'
-Say ''
-Say 'Installation finished!'
-Say 'o7'  
diff --git a/serverside/jsmod/5.4-3/charts.js b/serverside/jsmod/5.4-3/charts.js
deleted file mode 100644
index bc45966056f905b76949e8bd8f26109d8d8a1468..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/charts.js
+++ /dev/null
@@ -1,22013 +0,0 @@
-Ext.define("Ext.draw.ContainerBase", {
-    extend: "Ext.panel.Panel",
-    requires: ["Ext.window.Window"],
-    previewTitleText: "Chart Preview",
-    previewAltText: "Chart preview",
-    layout: "container",
-    addElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.on.apply(b.el, a)
-        } else {
-            b.on("render", function() {
-                b.el.on.apply(b.el, a)
-            })
-        }
-    },
-    removeElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.un.apply(b.el, a)
-        }
-    },
-    afterRender: function() {
-        this.callParent(arguments);
-        this.initAnimator()
-    },
-    getItems: function() {
-        var b = this,
-            a = b.items;
-        if (!a || !a.isMixedCollection) {
-            b.initItems()
-        }
-        return b.items
-    },
-    onRender: function() {
-        this.callParent(arguments);
-        this.element = this.el;
-        this.innerElement = this.body
-    },
-    setItems: function(a) {
-        this.items = a;
-        return a
-    },
-    setSurfaceSize: function(b, a) {
-        this.resizeHandler({
-            width: b,
-            height: a
-        });
-        this.renderFrame()
-    },
-    onResize: function(c, a, b, e) {
-        var d = this;
-        d.callParent([c, a, b, e]);
-        d.setBodySize({
-            width: c,
-            height: a
-        })
-    },
-    preview: function() {
-        var a = this.getImage();
-        new Ext.window.Window({
-            title: this.previewTitleText,
-            closeable: true,
-            renderTo: Ext.getBody(),
-            autoShow: true,
-            maximizeable: true,
-            maximized: true,
-            border: true,
-            layout: {
-                type: "hbox",
-                pack: "center",
-                align: "middle"
-            },
-            items: {
-                xtype: "container",
-                items: {
-                    xtype: "image",
-                    mode: "img",
-                    cls: Ext.baseCSSPrefix + "chart-image",
-                    alt: this.previewAltText,
-                    src: a.data,
-                    listeners: {
-                        afterrender: function() {
-                            var e = this,
-                                b = e.imgEl.dom,
-                                d = a.type === "svg" ? 1 : (window.devicePixelRatio || 1),
-                                c;
-                            if (!b.naturalWidth || !b.naturalHeight) {
-                                b.onload = function() {
-                                    var g = b.naturalWidth,
-                                        f = b.naturalHeight;
-                                    e.setWidth(Math.floor(g / d));
-                                    e.setHeight(Math.floor(f / d))
-                                }
-                            } else {
-                                c = e.getSize();
-                                e.setWidth(Math.floor(c.width / d));
-                                e.setHeight(Math.floor(c.height / d))
-                            }
-                        }
-                    }
-                }
-            }
-        })
-    },
-    privates: {
-        getTargetEl: function() {
-            return this.innerElement
-        },
-        reattachToBody: function() {
-            var a = this;
-            if (a.pendingDetachSize) {
-                a.onBodyResize()
-            }
-            a.pendingDetachSize = false;
-            a.callParent()
-        }
-    }
-});
-Ext.define("Ext.draw.SurfaceBase", {
-    extend: "Ext.Widget",
-    getOwnerBody: function() {
-        return this.ownerCt.body
-    },
-    destroy: function() {
-        var a = this;
-        if (a.hasListeners.destroy) {
-            a.fireEvent("destroy", a)
-        }
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.Color", {
-    statics: {
-        colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbToHexRe: /\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbaToHexRe: /\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,
-        hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,
-        NONE: "none",
-        RGBA_NONE: "rgba(0, 0, 0, 0)"
-    },
-    isColor: true,
-    lightnessFactor: 0.2,
-    constructor: function(d, b, a, c) {
-        this.setRGB(d, b, a, c)
-    },
-    setRGB: function(e, c, a, d) {
-        var b = this;
-        b.r = Math.min(255, Math.max(0, e));
-        b.g = Math.min(255, Math.max(0, c));
-        b.b = Math.min(255, Math.max(0, a));
-        if (d === undefined) {
-            b.a = 1
-        } else {
-            b.a = Math.min(1, Math.max(0, d))
-        }
-    },
-    getGrayscale: function() {
-        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11
-    },
-    getHSL: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            m = k - d,
-            e, n = 0,
-            c = 0.5 * (k + d);
-        if (d !== k) {
-            n = (c <= 0.5) ? m / (k + d) : m / (2 - k - d);
-            if (a === k) {
-                e = 60 * (f - j) / m
-            } else {
-                if (f === k) {
-                    e = 120 + 60 * (j - a) / m
-                } else {
-                    e = 240 + 60 * (a - f) / m
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, n, c]
-    },
-    getHSV: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            c = k - d,
-            e, m = 0,
-            l = k;
-        if (d != k) {
-            m = l ? c / l : 0;
-            if (a === k) {
-                e = 60 * (f - j) / c
-            } else {
-                if (f === k) {
-                    e = 60 * (j - a) / c + 120
-                } else {
-                    e = 60 * (a - f) / c + 240
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, m, l]
-    },
-    setHSL: function(g, f, e) {
-        var i = this,
-            d = Math.abs,
-            j, b, a;
-        g = (g % 360 + 360) % 360;
-        f = f > 1 ? 1 : f < 0 ? 0 : f;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        if (f === 0 || g === null) {
-            e *= 255;
-            i.setRGB(e, e, e)
-        } else {
-            g /= 60;
-            j = f * (1 - d(2 * e - 1));
-            b = j * (1 - d(g % 2 - 1));
-            a = e - j / 2;
-            a *= 255;
-            j *= 255;
-            b *= 255;
-            switch (Math.floor(g)) {
-                case 0:
-                    i.setRGB(j + a, b + a, a);
-                    break;
-                case 1:
-                    i.setRGB(b + a, j + a, a);
-                    break;
-                case 2:
-                    i.setRGB(a, j + a, b + a);
-                    break;
-                case 3:
-                    i.setRGB(a, b + a, j + a);
-                    break;
-                case 4:
-                    i.setRGB(b + a, a, j + a);
-                    break;
-                case 5:
-                    i.setRGB(j + a, a, b + a);
-                    break
-            }
-        }
-        return i
-    },
-    setHSV: function(f, e, d) {
-        var g = this,
-            i, b, a;
-        f = (f % 360 + 360) % 360;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        d = d > 1 ? 1 : d < 0 ? 0 : d;
-        if (e === 0 || f === null) {
-            d *= 255;
-            g.setRGB(d, d, d)
-        } else {
-            f /= 60;
-            i = d * e;
-            b = i * (1 - Math.abs(f % 2 - 1));
-            a = d - i;
-            a *= 255;
-            i *= 255;
-            b *= 255;
-            switch (Math.floor(f)) {
-                case 0:
-                    g.setRGB(i + a, b + a, a);
-                    break;
-                case 1:
-                    g.setRGB(b + a, i + a, a);
-                    break;
-                case 2:
-                    g.setRGB(a, i + a, b + a);
-                    break;
-                case 3:
-                    g.setRGB(a, b + a, i + a);
-                    break;
-                case 4:
-                    g.setRGB(b + a, a, i + a);
-                    break;
-                case 5:
-                    g.setRGB(i + a, a, b + a);
-                    break
-            }
-        }
-        return g
-    },
-    createLighter: function(b) {
-        if (!b && b !== 0) {
-            b = this.lightnessFactor
-        }
-        var a = this.getHSL();
-        a[2] = Ext.Number.constrain(a[2] + b, 0, 1);
-        return Ext.draw.Color.fromHSL(a[0], a[1], a[2])
-    },
-    createDarker: function(a) {
-        if (!a && a !== 0) {
-            a = this.lightnessFactor
-        }
-        return this.createLighter(-a)
-    },
-    toString: function() {
-        var f = this,
-            c = Math.round;
-        if (f.a === 1) {
-            var e = c(f.r).toString(16),
-                d = c(f.g).toString(16),
-                a = c(f.b).toString(16);
-            e = (e.length === 1) ? "0" + e : e;
-            d = (d.length === 1) ? "0" + d : d;
-            a = (a.length === 1) ? "0" + a : a;
-            return ["#", e, d, a].join("")
-        } else {
-            return "rgba(" + [c(f.r), c(f.g), c(f.b), f.a === 0 ? 0 : f.a.toFixed(15)].join(", ") + ")"
-        }
-    },
-    toHex: function(b) {
-        if (Ext.isArray(b)) {
-            b = b[0]
-        }
-        if (!Ext.isString(b)) {
-            return ""
-        }
-        if (b.substr(0, 1) === "#") {
-            return b
-        }
-        var e = Ext.draw.Color.colorToHexRe.exec(b);
-        if (Ext.isArray(e)) {
-            var f = parseInt(e[2], 10),
-                d = parseInt(e[3], 10),
-                a = parseInt(e[4], 10),
-                c = a | (d << 8) | (f << 16);
-            return e[1] + "#" + ("000000" + c.toString(16)).slice(-6)
-        } else {
-            return ""
-        }
-    },
-    setFromString: function(j) {
-        var e, h, f, c, d = 1,
-            i = parseInt;
-        if (j === Ext.draw.Color.NONE) {
-            this.r = this.g = this.b = this.a = 0;
-            return this
-        }
-        if ((j.length === 4 || j.length === 7) && j.substr(0, 1) === "#") {
-            e = j.match(Ext.draw.Color.hexRe);
-            if (e) {
-                h = i(e[1], 16) >> 0;
-                f = i(e[2], 16) >> 0;
-                c = i(e[3], 16) >> 0;
-                if (j.length === 4) {
-                    h += (h * 16);
-                    f += (f * 16);
-                    c += (c * 16)
-                }
-            }
-        } else {
-            if ((e = j.match(Ext.draw.Color.rgbToHexRe))) {
-                h = +e[1];
-                f = +e[2];
-                c = +e[3]
-            } else {
-                if ((e = j.match(Ext.draw.Color.rgbaToHexRe))) {
-                    h = +e[1];
-                    f = +e[2];
-                    c = +e[3];
-                    d = +e[4]
-                } else {
-                    if (Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())) {
-                        return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])
-                    }
-                }
-            }
-        }
-        if (typeof h === "undefined") {
-            return this
-        }
-        this.r = h;
-        this.g = f;
-        this.b = c;
-        this.a = d;
-        return this
-    }
-}, function() {
-    var a = new this();
-    this.addStatics({
-        fly: function(f, e, c, d) {
-            switch (arguments.length) {
-                case 1:
-                    a.setFromString(f);
-                    break;
-                case 3:
-                case 4:
-                    a.setRGB(f, e, c, d);
-                    break;
-                default:
-                    return null
-            }
-            return a
-        },
-        ColorList: {
-            aliceblue: "#f0f8ff",
-            antiquewhite: "#faebd7",
-            aqua: "#00ffff",
-            aquamarine: "#7fffd4",
-            azure: "#f0ffff",
-            beige: "#f5f5dc",
-            bisque: "#ffe4c4",
-            black: "#000000",
-            blanchedalmond: "#ffebcd",
-            blue: "#0000ff",
-            blueviolet: "#8a2be2",
-            brown: "#a52a2a",
-            burlywood: "#deb887",
-            cadetblue: "#5f9ea0",
-            chartreuse: "#7fff00",
-            chocolate: "#d2691e",
-            coral: "#ff7f50",
-            cornflowerblue: "#6495ed",
-            cornsilk: "#fff8dc",
-            crimson: "#dc143c",
-            cyan: "#00ffff",
-            darkblue: "#00008b",
-            darkcyan: "#008b8b",
-            darkgoldenrod: "#b8860b",
-            darkgray: "#a9a9a9",
-            darkgreen: "#006400",
-            darkkhaki: "#bdb76b",
-            darkmagenta: "#8b008b",
-            darkolivegreen: "#556b2f",
-            darkorange: "#ff8c00",
-            darkorchid: "#9932cc",
-            darkred: "#8b0000",
-            darksalmon: "#e9967a",
-            darkseagreen: "#8fbc8f",
-            darkslateblue: "#483d8b",
-            darkslategray: "#2f4f4f",
-            darkturquoise: "#00ced1",
-            darkviolet: "#9400d3",
-            deeppink: "#ff1493",
-            deepskyblue: "#00bfff",
-            dimgray: "#696969",
-            dodgerblue: "#1e90ff",
-            firebrick: "#b22222",
-            floralwhite: "#fffaf0",
-            forestgreen: "#228b22",
-            fuchsia: "#ff00ff",
-            gainsboro: "#dcdcdc",
-            ghostwhite: "#f8f8ff",
-            gold: "#ffd700",
-            goldenrod: "#daa520",
-            gray: "#808080",
-            green: "#008000",
-            greenyellow: "#adff2f",
-            honeydew: "#f0fff0",
-            hotpink: "#ff69b4",
-            indianred: "#cd5c5c",
-            indigo: "#4b0082",
-            ivory: "#fffff0",
-            khaki: "#f0e68c",
-            lavender: "#e6e6fa",
-            lavenderblush: "#fff0f5",
-            lawngreen: "#7cfc00",
-            lemonchiffon: "#fffacd",
-            lightblue: "#add8e6",
-            lightcoral: "#f08080",
-            lightcyan: "#e0ffff",
-            lightgoldenrodyellow: "#fafad2",
-            lightgray: "#d3d3d3",
-            lightgrey: "#d3d3d3",
-            lightgreen: "#90ee90",
-            lightpink: "#ffb6c1",
-            lightsalmon: "#ffa07a",
-            lightseagreen: "#20b2aa",
-            lightskyblue: "#87cefa",
-            lightslategray: "#778899",
-            lightsteelblue: "#b0c4de",
-            lightyellow: "#ffffe0",
-            lime: "#00ff00",
-            limegreen: "#32cd32",
-            linen: "#faf0e6",
-            magenta: "#ff00ff",
-            maroon: "#800000",
-            mediumaquamarine: "#66cdaa",
-            mediumblue: "#0000cd",
-            mediumorchid: "#ba55d3",
-            mediumpurple: "#9370d8",
-            mediumseagreen: "#3cb371",
-            mediumslateblue: "#7b68ee",
-            mediumspringgreen: "#00fa9a",
-            mediumturquoise: "#48d1cc",
-            mediumvioletred: "#c71585",
-            midnightblue: "#191970",
-            mintcream: "#f5fffa",
-            mistyrose: "#ffe4e1",
-            moccasin: "#ffe4b5",
-            navajowhite: "#ffdead",
-            navy: "#000080",
-            oldlace: "#fdf5e6",
-            olive: "#808000",
-            olivedrab: "#6b8e23",
-            orange: "#ffa500",
-            orangered: "#ff4500",
-            orchid: "#da70d6",
-            palegoldenrod: "#eee8aa",
-            palegreen: "#98fb98",
-            paleturquoise: "#afeeee",
-            palevioletred: "#d87093",
-            papayawhip: "#ffefd5",
-            peachpuff: "#ffdab9",
-            peru: "#cd853f",
-            pink: "#ffc0cb",
-            plum: "#dda0dd",
-            powderblue: "#b0e0e6",
-            purple: "#800080",
-            red: "#ff0000",
-            rosybrown: "#bc8f8f",
-            royalblue: "#4169e1",
-            saddlebrown: "#8b4513",
-            salmon: "#fa8072",
-            sandybrown: "#f4a460",
-            seagreen: "#2e8b57",
-            seashell: "#fff5ee",
-            sienna: "#a0522d",
-            silver: "#c0c0c0",
-            skyblue: "#87ceeb",
-            slateblue: "#6a5acd",
-            slategray: "#708090",
-            snow: "#fffafa",
-            springgreen: "#00ff7f",
-            steelblue: "#4682b4",
-            tan: "#d2b48c",
-            teal: "#008080",
-            thistle: "#d8bfd8",
-            tomato: "#ff6347",
-            turquoise: "#40e0d0",
-            violet: "#ee82ee",
-            wheat: "#f5deb3",
-            white: "#ffffff",
-            whitesmoke: "#f5f5f5",
-            yellow: "#ffff00",
-            yellowgreen: "#9acd32"
-        },
-        fromHSL: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromHSV: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromString: function(b) {
-            return (new this(0, 0, 0, 0)).setFromString(b)
-        },
-        create: function(b) {
-            if (b instanceof this) {
-                return b
-            } else {
-                if (Ext.isArray(b)) {
-                    return new Ext.draw.Color(b[0], b[1], b[2], b[3])
-                } else {
-                    if (Ext.isString(b)) {
-                        return Ext.draw.Color.fromString(b)
-                    } else {
-                        if (arguments.length > 2) {
-                            return new Ext.draw.Color(arguments[0], arguments[1], arguments[2], arguments[3])
-                        } else {
-                            return new Ext.draw.Color(0, 0, 0, 0)
-                        }
-                    }
-                }
-            }
-        }
-    })
-});
-Ext.define("Ext.draw.sprite.AnimationParser", function() {
-    function a(d, c, b) {
-        return d + (c - d) * b
-    }
-    return {
-        singleton: true,
-        attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-        requires: ["Ext.draw.Color"],
-        color: {
-            parseInitial: function(c, b) {
-                if (Ext.isString(c)) {
-                    c = Ext.draw.Color.create(c)
-                }
-                if (Ext.isString(b)) {
-                    b = Ext.draw.Color.create(b)
-                }
-                if ((c instanceof Ext.draw.Color) && (b instanceof Ext.draw.Color)) {
-                    return [
-                        [c.r, c.g, c.b, c.a],
-                        [b.r, b.g, b.b, b.a]
-                    ]
-                } else {
-                    return [c || b, b || c]
-                }
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isArray(d) || !Ext.isArray(c)) {
-                    return c || d
-                } else {
-                    return [a(d[0], c[0], b), a(d[1], c[1], b), a(d[2], c[2], b), a(d[3], c[3], b)]
-                }
-            },
-            serve: function(c) {
-                var b = Ext.draw.Color.fly(c[0], c[1], c[2], c[3]);
-                return b.toString()
-            }
-        },
-        number: {
-            parse: function(b) {
-                return b === null ? null : +b
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        angle: {
-            parseInitial: function(c, b) {
-                if (b - c > Math.PI) {
-                    b -= Math.PI * 2
-                } else {
-                    if (b - c < -Math.PI) {
-                        b += Math.PI * 2
-                    }
-                }
-                return [c, b]
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        path: {
-            parseInitial: function(m, n) {
-                var c = m.toStripes(),
-                    o = n.toStripes(),
-                    e, d, k = c.length,
-                    p = o.length,
-                    h, f, b, g = o[p - 1],
-                    l = [g[g.length - 2], g[g.length - 1]];
-                for (e = k; e < p; e++) {
-                    c.push(c[k - 1].slice(0))
-                }
-                for (e = p; e < k; e++) {
-                    o.push(l.slice(0))
-                }
-                b = c.length;
-                o.path = n;
-                o.temp = new Ext.draw.Path();
-                for (e = 0; e < b; e++) {
-                    h = c[e];
-                    f = o[e];
-                    k = h.length;
-                    p = f.length;
-                    o.temp.commands.push("M");
-                    for (d = p; d < k; d += 6) {
-                        f.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    g = o[o.length - 1];
-                    l = [g[g.length - 2], g[g.length - 1]];
-                    for (d = k; d < p; d += 6) {
-                        h.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    for (e = 0; e < f.length; e++) {
-                        f[e] -= h[e]
-                    }
-                    for (e = 2; e < f.length; e += 6) {
-                        o.temp.commands.push("C")
-                    }
-                }
-                return [c, o]
-            },
-            compute: function(c, l, m) {
-                if (m >= 1) {
-                    return l.path
-                }
-                var e = 0,
-                    f = c.length,
-                    d = 0,
-                    b, k, h, n = l.temp.params,
-                    g = 0;
-                for (; e < f; e++) {
-                    k = c[e];
-                    h = l[e];
-                    b = k.length;
-                    for (d = 0; d < b; d++) {
-                        n[g++] = h[d] * m + k[d]
-                    }
-                }
-                return l.temp
-            }
-        },
-        data: {
-            compute: function(h, j, k, g) {
-                var m = h.length - 1,
-                    b = j.length - 1,
-                    e = Math.max(m, b),
-                    d, l, c;
-                if (!g || g === h) {
-                    g = []
-                }
-                g.length = e + 1;
-                for (c = 0; c <= e; c++) {
-                    d = h[Math.min(c, m)];
-                    l = j[Math.min(c, b)];
-                    if (Ext.isNumber(d)) {
-                        if (!Ext.isNumber(l)) {
-                            l = 0
-                        }
-                        g[c] = (l - d) * k + d
-                    } else {
-                        g[c] = l
-                    }
-                }
-                return g
-            }
-        },
-        text: {
-            compute: function(d, c, b) {
-                return d.substr(0, Math.round(d.length * (1 - b))) + c.substr(Math.round(c.length * (1 - b)))
-            }
-        },
-        limited: "number",
-        limited01: "number"
-    }
-});
-(function() {
-    if (!Ext.global.Float32Array) {
-        var a = function(d) {
-            if (typeof d === "number") {
-                this.length = d
-            } else {
-                if ("length" in d) {
-                    this.length = d.length;
-                    for (var c = 0, b = d.length; c < b; c++) {
-                        this[c] = +d[c]
-                    }
-                }
-            }
-        };
-        a.prototype = [];
-        Ext.global.Float32Array = a
-    }
-})();
-Ext.define("Ext.draw.Draw", {
-    singleton: true,
-    radian: Math.PI / 180,
-    pi2: Math.PI * 2,
-    reflectFn: function(b) {
-        return b
-    },
-    rad: function(a) {
-        return (a % 360) * this.radian
-    },
-    degrees: function(a) {
-        return (a / this.radian) % 360
-    },
-    isBBoxIntersect: function(b, a, c) {
-        c = c || 0;
-        return (Math.max(b.x, a.x) - c > Math.min(b.x + b.width, a.x + a.width)) || (Math.max(b.y, a.y) - c > Math.min(b.y + b.height, a.y + a.height))
-    },
-    isPointInBBox: function(a, c, b) {
-        return !!b && a >= b.x && a <= (b.x + b.width) && c >= b.y && c <= (b.y + b.height)
-    },
-    spline: function(m) {
-        var e, c, k = m.length,
-            b, h, l, f, a = 0,
-            g = new Float32Array(m.length),
-            n = new Float32Array(m.length * 3 - 2);
-        g[0] = 0;
-        g[k - 1] = 0;
-        for (e = 1; e < k - 1; e++) {
-            g[e] = (m[e + 1] + m[e - 1] - 2 * m[e]) - g[e - 1];
-            a = 1 / (4 - a);
-            g[e] *= a
-        }
-        for (e = k - 2; e > 0; e--) {
-            a = 3.732050807568877 + 48.248711305964385 / (-13.928203230275537 + Math.pow(0.07179676972449123, e));
-            g[e] -= g[e + 1] * a
-        }
-        f = m[0];
-        b = f - g[0];
-        for (e = 0, c = 0; e < k - 1; c += 3) {
-            l = f;
-            h = b;
-            e++;
-            f = m[e];
-            b = f - g[e];
-            n[c] = l;
-            n[c + 1] = (b + 2 * h) / 3;
-            n[c + 2] = (b * 2 + h) / 3
-        }
-        n[c] = f;
-        return n
-    },
-    getAnchors: function(e, d, i, h, t, s, o) {
-        o = o || 4;
-        var n = Math.PI,
-            p = n / 2,
-            k = Math.abs,
-            a = Math.sin,
-            b = Math.cos,
-            f = Math.atan,
-            r, q, g, j, m, l, v, u, c;
-        r = (i - e) / o;
-        q = (t - i) / o;
-        if ((h >= d && h >= s) || (h <= d && h <= s)) {
-            g = j = p
-        } else {
-            g = f((i - e) / k(h - d));
-            if (d < h) {
-                g = n - g
-            }
-            j = f((t - i) / k(h - s));
-            if (s < h) {
-                j = n - j
-            }
-        }
-        c = p - ((g + j) % (n * 2)) / 2;
-        if (c > p) {
-            c -= n
-        }
-        g += c;
-        j += c;
-        m = i - r * a(g);
-        l = h + r * b(g);
-        v = i + q * a(j);
-        u = h + q * b(j);
-        if ((h > d && l < d) || (h < d && l > d)) {
-            m += k(d - l) * (m - i) / (l - h);
-            l = d
-        }
-        if ((h > s && u < s) || (h < s && u > s)) {
-            v -= k(s - u) * (v - i) / (u - h);
-            u = s
-        }
-        return {
-            x1: m,
-            y1: l,
-            x2: v,
-            y2: u
-        }
-    },
-    smooth: function(l, j, o) {
-        var k = l.length,
-            h, g, c, b, q, p, n, m, f = [],
-            e = [],
-            d, a;
-        for (d = 0; d < k - 1; d++) {
-            h = l[d];
-            g = j[d];
-            if (d === 0) {
-                n = h;
-                m = g;
-                f.push(n);
-                e.push(m);
-                if (k === 1) {
-                    break
-                }
-            }
-            c = l[d + 1];
-            b = j[d + 1];
-            q = l[d + 2];
-            p = j[d + 2];
-            if (!Ext.isNumber(q + p)) {
-                f.push(n, c, c);
-                e.push(m, b, b);
-                break
-            }
-            a = this.getAnchors(h, g, c, b, q, p, o);
-            f.push(n, a.x1, c);
-            e.push(m, a.y1, b);
-            n = a.x2;
-            m = a.y2
-        }
-        return {
-            smoothX: f,
-            smoothY: e
-        }
-    },
-    beginUpdateIOS: Ext.os.is.iOS ? function() {
-        this.iosUpdateEl = Ext.getBody().createChild({
-            style: "position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"
-        })
-    } : Ext.emptyFn,
-    endUpdateIOS: function() {
-        this.iosUpdateEl = Ext.destroy(this.iosUpdateEl)
-    }
-});
-Ext.define("Ext.draw.gradient.Gradient", {
-    requires: ["Ext.draw.Color"],
-    isGradient: true,
-    config: {
-        stops: []
-    },
-    applyStops: function(f) {
-        var e = [],
-            d = f.length,
-            c, b, a;
-        for (c = 0; c < d; c++) {
-            b = f[c];
-            a = b.color;
-            if (!(a && a.isColor)) {
-                a = Ext.draw.Color.fly(a || Ext.draw.Color.NONE)
-            }
-            e.push({
-                offset: Math.min(1, Math.max(0, "offset" in b ? b.offset : b.position || 0)),
-                color: a.toString()
-            })
-        }
-        e.sort(function(h, g) {
-            return h.offset - g.offset
-        });
-        return e
-    },
-    onClassExtended: function(a, b) {
-        if (!b.alias && b.type) {
-            b.alias = "gradient." + b.type
-        }
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    generateGradient: Ext.emptyFn
-});
-Ext.define("Ext.draw.gradient.GradientDefinition", {
-    singleton: true,
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    gradients: {},
-    add: function(a) {
-        var b = this.gradients,
-            c, e, d;
-        for (c = 0, e = a.length; c < e; c++) {
-            d = a[c];
-            if (Ext.isString(d.id)) {
-                b[d.id] = d
-            }
-        }
-    },
-    get: function(d) {
-        var a = this.gradients,
-            b = d.match(this.urlStringRe),
-            c;
-        if (b && b[1] && (c = a[b[1]])) {
-            return c || d
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeParser", {
-    singleton: true,
-    attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-    requires: ["Ext.draw.Color", "Ext.draw.gradient.GradientDefinition"],
-    "default": Ext.identityFn,
-    string: function(a) {
-        return String(a)
-    },
-    number: function(a) {
-        if (Ext.isNumber(+a)) {
-            return a
-        }
-    },
-    angle: function(a) {
-        if (Ext.isNumber(a)) {
-            a %= Math.PI * 2;
-            if (a < -Math.PI) {
-                a += Math.PI * 2
-            } else {
-                if (a >= Math.PI) {
-                    a -= Math.PI * 2
-                }
-            }
-            return a
-        }
-    },
-    data: function(a) {
-        if (Ext.isArray(a)) {
-            return a.slice()
-        } else {
-            if (a instanceof Float32Array) {
-                return new Float32Array(a)
-            }
-        }
-    },
-    bool: function(a) {
-        return !!a
-    },
-    color: function(a) {
-        if (a instanceof Ext.draw.Color) {
-            return a.toString()
-        } else {
-            if (a instanceof Ext.draw.gradient.Gradient) {
-                return a
-            } else {
-                if (!a) {
-                    return Ext.draw.Color.NONE
-                } else {
-                    if (Ext.isString(a)) {
-                        if (a.substr(0, 3) === "url") {
-                            a = Ext.draw.gradient.GradientDefinition.get(a);
-                            if (Ext.isString(a)) {
-                                return a
-                            }
-                        } else {
-                            return Ext.draw.Color.fly(a).toString()
-                        }
-                    }
-                }
-            }
-        }
-        if (a.type === "linear") {
-            return Ext.create("Ext.draw.gradient.Linear", a)
-        } else {
-            if (a.type === "radial") {
-                return Ext.create("Ext.draw.gradient.Radial", a)
-            } else {
-                if (a.type === "pattern") {
-                    return Ext.create("Ext.draw.gradient.Pattern", a)
-                } else {
-                    return Ext.draw.Color.NONE
-                }
-            }
-        }
-    },
-    limited: function(a, b) {
-        return function(c) {
-            c = +c;
-            return Ext.isNumber(c) ? Math.min(Math.max(c, a), b) : undefined
-        }
-    },
-    limited01: function(a) {
-        a = +a;
-        return Ext.isNumber(a) ? Math.min(Math.max(a, 0), 1) : undefined
-    },
-    enums: function() {
-        var d = {},
-            a = Array.prototype.slice.call(arguments, 0),
-            b, c;
-        for (b = 0, c = a.length; b < c; b++) {
-            d[a[b]] = true
-        }
-        return function(e) {
-            return e in d ? e : undefined
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeDefinition", {
-    requires: ["Ext.draw.sprite.AttributeParser", "Ext.draw.sprite.AnimationParser"],
-    config: {
-        defaults: {
-            $value: {},
-            lazy: true
-        },
-        aliases: {},
-        animationProcessors: {},
-        processors: {
-            $value: {},
-            lazy: true
-        },
-        dirtyTriggers: {},
-        triggers: {},
-        updaters: {}
-    },
-    inheritableStatics: {
-        processorFactoryRe: /^(\w+)\(([\w\-,]*)\)$/
-    },
-    spriteClass: null,
-    constructor: function(a) {
-        var b = this;
-        b.initConfig(a)
-    },
-    applyDefaults: function(b, a) {
-        a = Ext.apply(a || {}, this.normalize(b));
-        return a
-    },
-    applyAliases: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    applyProcessors: function(e, i) {
-        this.getAnimationProcessors();
-        var j = i || {},
-            h = Ext.draw.sprite.AttributeParser,
-            a = this.self.processorFactoryRe,
-            g = {},
-            d, b, c, f;
-        for (b in e) {
-            f = e[b];
-            if (typeof f === "string") {
-                c = f.match(a);
-                if (c) {
-                    f = h[c[1]].apply(h, c[2].split(","))
-                } else {
-                    if (h[f]) {
-                        g[b] = f;
-                        d = true;
-                        f = h[f]
-                    }
-                }
-            }
-            j[b] = f
-        }
-        if (d) {
-            this.setAnimationProcessors(g)
-        }
-        return j
-    },
-    applyAnimationProcessors: function(c, a) {
-        var e = Ext.draw.sprite.AnimationParser,
-            b, d;
-        if (!a) {
-            a = {}
-        }
-        for (b in c) {
-            d = c[b];
-            if (d === "none") {
-                a[b] = null
-            } else {
-                if (Ext.isString(d) && !(b in a)) {
-                    if (d in e) {
-                        while (Ext.isString(e[d])) {
-                            d = e[d]
-                        }
-                        a[b] = e[d]
-                    }
-                } else {
-                    if (Ext.isObject(d)) {
-                        a[b] = d
-                    }
-                }
-            }
-        }
-        return a
-    },
-    updateDirtyTriggers: function(a) {
-        this.setTriggers(a)
-    },
-    applyTriggers: function(b, c) {
-        if (!c) {
-            c = {}
-        }
-        for (var a in b) {
-            c[a] = b[a].split(",")
-        }
-        return c
-    },
-    applyUpdaters: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    batchedNormalize: function(f, n) {
-        if (!f) {
-            return {}
-        }
-        var j = this.getProcessors(),
-            d = this.getAliases(),
-            a = f.translation || f.translate,
-            o = {},
-            g, h, b, e, p, c, m, l, k;
-        if ("rotation" in f) {
-            p = f.rotation
-        } else {
-            p = ("rotate" in f) ? f.rotate : undefined
-        }
-        if ("scaling" in f) {
-            c = f.scaling
-        } else {
-            c = ("scale" in f) ? f.scale : undefined
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                o.scalingX = c;
-                o.scalingY = c
-            } else {
-                if ("x" in c) {
-                    o.scalingX = c.x
-                }
-                if ("y" in c) {
-                    o.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    o.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    o.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof p !== "undefined") {
-            if (Ext.isNumber(p)) {
-                p = Ext.draw.Draw.rad(p);
-                o.rotationRads = p
-            } else {
-                if ("rads" in p) {
-                    o.rotationRads = p.rads
-                } else {
-                    if ("degrees" in p) {
-                        if (Ext.isArray(p.degrees)) {
-                            o.rotationRads = Ext.Array.map(p.degrees, function(i) {
-                                return Ext.draw.Draw.rad(i)
-                            })
-                        } else {
-                            o.rotationRads = Ext.draw.Draw.rad(p.degrees)
-                        }
-                    }
-                }
-                if ("centerX" in p) {
-                    o.rotationCenterX = p.centerX
-                }
-                if ("centerY" in p) {
-                    o.rotationCenterY = p.centerY
-                }
-            }
-        }
-        if (typeof a !== "undefined") {
-            if ("x" in a) {
-                o.translationX = a.x
-            }
-            if ("y" in a) {
-                o.translationY = a.y
-            }
-        }
-        if ("matrix" in f) {
-            m = Ext.draw.Matrix.create(f.matrix);
-            k = m.split();
-            o.matrix = m;
-            o.rotationRads = k.rotation;
-            o.rotationCenterX = 0;
-            o.rotationCenterY = 0;
-            o.scalingX = k.scaleX;
-            o.scalingY = k.scaleY;
-            o.scalingCenterX = 0;
-            o.scalingCenterY = 0;
-            o.translationX = k.translateX;
-            o.translationY = k.translateY
-        }
-        for (b in f) {
-            e = f[b];
-            if (typeof e === "undefined") {
-                continue
-            } else {
-                if (Ext.isArray(e)) {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        o[b] = [];
-                        for (g = 0, h = e.length; g < h; g++) {
-                            l = j[b].call(this, e[g]);
-                            if (typeof l !== "undefined") {
-                                o[b][g] = l
-                            }
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                } else {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        e = j[b].call(this, e);
-                        if (typeof e !== "undefined") {
-                            o[b] = e
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                }
-            }
-        }
-        return o
-    },
-    normalize: function(i, j) {
-        if (!i) {
-            return {}
-        }
-        var f = this.getProcessors(),
-            d = this.getAliases(),
-            a = i.translation || i.translate,
-            k = {},
-            b, e, l, c, h, g;
-        if ("rotation" in i) {
-            l = i.rotation
-        } else {
-            l = ("rotate" in i) ? i.rotate : undefined
-        }
-        if ("scaling" in i) {
-            c = i.scaling
-        } else {
-            c = ("scale" in i) ? i.scale : undefined
-        }
-        if (a) {
-            if ("x" in a) {
-                k.translationX = a.x
-            }
-            if ("y" in a) {
-                k.translationY = a.y
-            }
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                k.scalingX = c;
-                k.scalingY = c
-            } else {
-                if ("x" in c) {
-                    k.scalingX = c.x
-                }
-                if ("y" in c) {
-                    k.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    k.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    k.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof l !== "undefined") {
-            if (Ext.isNumber(l)) {
-                l = Ext.draw.Draw.rad(l);
-                k.rotationRads = l
-            } else {
-                if ("rads" in l) {
-                    k.rotationRads = l.rads
-                } else {
-                    if ("degrees" in l) {
-                        k.rotationRads = Ext.draw.Draw.rad(l.degrees)
-                    }
-                }
-                if ("centerX" in l) {
-                    k.rotationCenterX = l.centerX
-                }
-                if ("centerY" in l) {
-                    k.rotationCenterY = l.centerY
-                }
-            }
-        }
-        if ("matrix" in i) {
-            h = Ext.draw.Matrix.create(i.matrix);
-            g = h.split();
-            k.matrix = h;
-            k.rotationRads = g.rotation;
-            k.rotationCenterX = 0;
-            k.rotationCenterY = 0;
-            k.scalingX = g.scaleX;
-            k.scalingY = g.scaleY;
-            k.scalingCenterX = 0;
-            k.scalingCenterY = 0;
-            k.translationX = g.translateX;
-            k.translationY = g.translateY
-        }
-        for (b in i) {
-            e = i[b];
-            if (typeof e === "undefined") {
-                continue
-            }
-            if (b in d) {
-                b = d[b]
-            }
-            if (b in f) {
-                e = f[b].call(this, e);
-                if (typeof e !== "undefined") {
-                    k[b] = e
-                }
-            } else {
-                if (j) {
-                    k[b] = e
-                }
-            }
-        }
-        return k
-    },
-    setBypassingNormalization: function(a, c, b) {
-        return c.pushDown(a, b)
-    },
-    set: function(a, c, b) {
-        b = this.normalize(b);
-        return this.setBypassingNormalization(a, c, b)
-    }
-});
-Ext.define("Ext.draw.Matrix", {
-    isMatrix: true,
-    statics: {
-        createAffineMatrixFromTwoPair: function(h, t, g, s, k, o, i, j) {
-            var v = g - h,
-                u = s - t,
-                e = i - k,
-                q = j - o,
-                d = 1 / (v * v + u * u),
-                p = v * e + u * q,
-                n = e * u - v * q,
-                m = -p * h - n * t,
-                l = n * h - p * t;
-            return new this(p * d, -n * d, n * d, p * d, m * d + k, l * d + o)
-        },
-        createPanZoomFromTwoPair: function(q, e, p, c, h, s, n, g) {
-            if (arguments.length === 2) {
-                return this.createPanZoomFromTwoPair.apply(this, q.concat(e))
-            }
-            var k = p - q,
-                j = c - e,
-                d = (q + p) * 0.5,
-                b = (e + c) * 0.5,
-                o = n - h,
-                a = g - s,
-                f = (h + n) * 0.5,
-                l = (s + g) * 0.5,
-                m = k * k + j * j,
-                i = o * o + a * a,
-                t = Math.sqrt(i / m);
-            return new this(t, 0, 0, t, f - t * d, l - t * b)
-        },
-        fly: (function() {
-            var a = null,
-                b = function(c) {
-                    a.elements = c;
-                    return a
-                };
-            return function(c) {
-                if (!a) {
-                    a = new Ext.draw.Matrix()
-                }
-                a.elements = c;
-                Ext.draw.Matrix.fly = b;
-                return a
-            }
-        })(),
-        create: function(a) {
-            if (a instanceof this) {
-                return a
-            }
-            return new this(a)
-        }
-    },
-    constructor: function(e, d, a, f, c, b) {
-        if (e && e.length === 6) {
-            this.elements = e.slice()
-        } else {
-            if (e !== undefined) {
-                this.elements = [e, d, a, f, c, b]
-            } else {
-                this.elements = [1, 0, 0, 1, 0, 0]
-            }
-        }
-    },
-    prepend: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + h * j;
-        b[1] = l * d + g * j;
-        b[2] = a * e + h * c;
-        b[3] = l * e + g * c;
-        b[4] = a * i + h * f + m;
-        b[5] = l * i + g * f + k;
-        return this
-    },
-    prependMatrix: function(a) {
-        return this.prepend.apply(this, a.elements)
-    },
-    append: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + l * e;
-        b[1] = a * j + l * c;
-        b[2] = h * d + g * e;
-        b[3] = h * j + g * c;
-        b[4] = m * d + k * e + i;
-        b[5] = m * j + k * c + f;
-        return this
-    },
-    appendMatrix: function(a) {
-        return this.append.apply(this, a.elements)
-    },
-    set: function(f, e, a, g, c, b) {
-        var d = this.elements;
-        d[0] = f;
-        d[1] = e;
-        d[2] = a;
-        d[3] = g;
-        d[4] = c;
-        d[5] = b;
-        return this
-    },
-    inverse: function(i) {
-        var g = this.elements,
-            o = g[0],
-            m = g[1],
-            l = g[2],
-            k = g[3],
-            j = g[4],
-            h = g[5],
-            n = 1 / (o * k - m * l);
-        o *= n;
-        m *= n;
-        l *= n;
-        k *= n;
-        if (i) {
-            i.set(k, -m, -l, o, l * h - k * j, m * j - o * h);
-            return i
-        } else {
-            return new Ext.draw.Matrix(k, -m, -l, o, l * h - k * j, m * j - o * h)
-        }
-    },
-    translate: function(a, c, b) {
-        if (b) {
-            return this.prepend(1, 0, 0, 1, a, c)
-        } else {
-            return this.append(1, 0, 0, 1, a, c)
-        }
-    },
-    scale: function(f, e, c, a, b) {
-        var d = this;
-        if (e == null) {
-            e = f
-        }
-        if (c === undefined) {
-            c = 0
-        }
-        if (a === undefined) {
-            a = 0
-        }
-        if (b) {
-            return d.prepend(f, 0, 0, e, c - c * f, a - a * e)
-        } else {
-            return d.append(f, 0, 0, e, c - c * f, a - a * e)
-        }
-    },
-    rotate: function(g, e, c, b) {
-        var d = this,
-            f = Math.cos(g),
-            a = Math.sin(g);
-        e = e || 0;
-        c = c || 0;
-        if (b) {
-            return d.prepend(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        } else {
-            return d.append(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        }
-    },
-    rotateFromVector: function(a, h, c) {
-        var e = this,
-            g = Math.sqrt(a * a + h * h),
-            f = a / g,
-            b = h / g;
-        if (c) {
-            return e.prepend(f, b, -b, f, 0, 0)
-        } else {
-            return e.append(f, b, -b, f, 0, 0)
-        }
-    },
-    clone: function() {
-        return new Ext.draw.Matrix(this.elements)
-    },
-    flipX: function() {
-        return this.append(-1, 0, 0, 1, 0, 0)
-    },
-    flipY: function() {
-        return this.append(1, 0, 0, -1, 0, 0)
-    },
-    skewX: function(a) {
-        return this.append(1, 0, Math.tan(a), 1, 0, 0)
-    },
-    skewY: function(a) {
-        return this.append(1, Math.tan(a), 0, 1, 0, 0)
-    },
-    shearX: function(a) {
-        return this.append(1, 0, a, 1, 0, 0)
-    },
-    shearY: function(a) {
-        return this.append(1, a, 0, 1, 0, 0)
-    },
-    reset: function() {
-        return this.set(1, 0, 0, 1, 0, 0)
-    },
-    precisionCompensate: function(j, g) {
-        var c = this.elements,
-            f = c[0],
-            e = c[1],
-            i = c[2],
-            h = c[3],
-            d = c[4],
-            b = c[5],
-            a = e * i - f * h;
-        g.b = j * e / f;
-        g.c = j * i / h;
-        g.d = j;
-        g.xx = f / j;
-        g.yy = h / j;
-        g.dx = (b * f * i - d * f * h) / a / j;
-        g.dy = (d * e * h - b * f * h) / a / j
-    },
-    precisionCompensateRect: function(j, g) {
-        var b = this.elements,
-            f = b[0],
-            e = b[1],
-            i = b[2],
-            h = b[3],
-            c = b[4],
-            a = b[5],
-            d = i / f;
-        g.b = j * e / f;
-        g.c = j * d;
-        g.d = j * h / f;
-        g.xx = f / j;
-        g.yy = f / j;
-        g.dx = (a * i - c * h) / (e * d - h) / j;
-        g.dy = -(a * f - c * e) / (e * d - h) / j
-    },
-    x: function(a, c) {
-        var b = this.elements;
-        return a * b[0] + c * b[2] + b[4]
-    },
-    y: function(a, c) {
-        var b = this.elements;
-        return a * b[1] + c * b[3] + b[5]
-    },
-    get: function(b, a) {
-        return +this.elements[b + a * 2].toFixed(4)
-    },
-    transformPoint: function(b) {
-        var c = this.elements,
-            a, d;
-        if (b.isPoint) {
-            a = b.x;
-            d = b.y
-        } else {
-            a = b[0];
-            d = b[1]
-        }
-        return [a * c[0] + d * c[2] + c[4], a * c[1] + d * c[3] + c[5]]
-    },
-    transformBBox: function(q, i, j) {
-        var b = this.elements,
-            d = q.x,
-            r = q.y,
-            g = q.width * 0.5,
-            o = q.height * 0.5,
-            a = b[0],
-            s = b[1],
-            n = b[2],
-            k = b[3],
-            e = d + g,
-            c = r + o,
-            p, f, m;
-        if (i) {
-            g -= i;
-            o -= i;
-            m = [Math.sqrt(b[0] * b[0] + b[2] * b[2]), Math.sqrt(b[1] * b[1] + b[3] * b[3])];
-            p = Math.abs(g * a) + Math.abs(o * n) + Math.abs(m[0] * i);
-            f = Math.abs(g * s) + Math.abs(o * k) + Math.abs(m[1] * i)
-        } else {
-            p = Math.abs(g * a) + Math.abs(o * n);
-            f = Math.abs(g * s) + Math.abs(o * k)
-        }
-        if (!j) {
-            j = {}
-        }
-        j.x = e * a + c * n + b[4] - p;
-        j.y = e * s + c * k + b[5] - f;
-        j.width = p + p;
-        j.height = f + f;
-        return j
-    },
-    transformList: function(e) {
-        var b = this.elements,
-            a = b[0],
-            h = b[2],
-            l = b[4],
-            k = b[1],
-            g = b[3],
-            j = b[5],
-            f = e.length,
-            c, d;
-        for (d = 0; d < f; d++) {
-            c = e[d];
-            e[d] = [c[0] * a + c[1] * h + l, c[0] * k + c[1] * g + j]
-        }
-        return e
-    },
-    isIdentity: function() {
-        var a = this.elements;
-        return a[0] === 1 && a[1] === 0 && a[2] === 0 && a[3] === 1 && a[4] === 0 && a[5] === 0
-    },
-    isEqual: function(a) {
-        var c = a && a.isMatrix ? a.elements : a,
-            b = this.elements;
-        return b[0] === c[0] && b[1] === c[1] && b[2] === c[2] && b[3] === c[3] && b[4] === c[4] && b[5] === c[5]
-    },
-    equals: function(a) {
-        return this.isEqual(a)
-    },
-    toArray: function() {
-        var a = this.elements;
-        return [a[0], a[2], a[4], a[1], a[3], a[5]]
-    },
-    toVerticalArray: function() {
-        return this.elements.slice()
-    },
-    toString: function() {
-        var a = this;
-        return [a.get(0, 0), a.get(0, 1), a.get(1, 0), a.get(1, 1), a.get(2, 0), a.get(2, 1)].join(",")
-    },
-    toContext: function(a) {
-        a.transform.apply(a, this.elements);
-        return this
-    },
-    toSvg: function() {
-        var a = this.elements;
-        return "matrix(" + a[0].toFixed(9) + "," + a[1].toFixed(9) + "," + a[2].toFixed(9) + "," + a[3].toFixed(9) + "," + a[4].toFixed(9) + "," + a[5].toFixed(9) + ")"
-    },
-    getScaleX: function() {
-        var a = this.elements;
-        return Math.sqrt(a[0] * a[0] + a[2] * a[2])
-    },
-    getScaleY: function() {
-        var a = this.elements;
-        return Math.sqrt(a[1] * a[1] + a[3] * a[3])
-    },
-    getXX: function() {
-        return this.elements[0]
-    },
-    getXY: function() {
-        return this.elements[1]
-    },
-    getYX: function() {
-        return this.elements[2]
-    },
-    getYY: function() {
-        return this.elements[3]
-    },
-    getDX: function() {
-        return this.elements[4]
-    },
-    getDY: function() {
-        return this.elements[5]
-    },
-    split: function() {
-        var b = this.elements,
-            d = b[0],
-            c = b[1],
-            e = b[3],
-            a = {
-                translateX: b[4],
-                translateY: b[5]
-            };
-        a.rotate = a.rotation = Math.atan2(c, d);
-        a.scaleX = d / Math.cos(a.rotate);
-        a.scaleY = e / d * a.scaleX;
-        return a
-    }
-}, function() {
-    function b(e, c, d) {
-        e[c] = {
-            get: function() {
-                return this.elements[d]
-            },
-            set: function(f) {
-                this.elements[d] = f
-            }
-        }
-    }
-    if (Object.defineProperties) {
-        var a = {};
-        b(a, "a", 0);
-        b(a, "b", 1);
-        b(a, "c", 2);
-        b(a, "d", 3);
-        b(a, "e", 4);
-        b(a, "f", 5);
-        Object.defineProperties(this.prototype, a)
-    }
-    this.prototype.multiply = this.prototype.appendMatrix
-});
-Ext.define("Ext.draw.modifier.Modifier", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        previous: null,
-        next: null,
-        sprite: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    updateNext: function(a) {
-        if (a) {
-            a.setPrevious(this)
-        }
-    },
-    updatePrevious: function(a) {
-        if (a) {
-            a.setNext(this)
-        }
-    },
-    prepareAttributes: function(a) {
-        if (this._previous) {
-            this._previous.prepareAttributes(a)
-        }
-    },
-    popUp: function(a, b) {
-        if (this._next) {
-            this._next.popUp(a, b)
-        } else {
-            Ext.apply(a, b)
-        }
-    },
-    pushDown: function(a, c) {
-        if (this._previous) {
-            return this._previous.pushDown(a, c)
-        } else {
-            for (var b in c) {
-                if (c[b] === a[b]) {
-                    delete c[b]
-                }
-            }
-            return c
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Target", {
-    requires: ["Ext.draw.Matrix"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.target",
-    statics: {
-        uniqueId: 0
-    },
-    prepareAttributes: function(a) {
-        var b = this.getPrevious();
-        if (b) {
-            b.prepareAttributes(a)
-        }
-        a.attributeId = "attribute-" + Ext.draw.modifier.Target.uniqueId++;
-        if (!a.hasOwnProperty("canvasAttributes")) {
-            a.bbox = {
-                plain: {
-                    dirty: true
-                },
-                transform: {
-                    dirty: true
-                }
-            };
-            a.dirty = true;
-            a.pendingUpdaters = {};
-            a.canvasAttributes = {};
-            a.matrix = new Ext.draw.Matrix();
-            a.inverseMatrix = new Ext.draw.Matrix()
-        }
-    },
-    applyChanges: function(f, k) {
-        Ext.apply(f, k);
-        var l = this.getSprite(),
-            o = f.pendingUpdaters,
-            h = l.self.def.getTriggers(),
-            p, a, m, b, e, n, d, c, g;
-        for (b in k) {
-            e = true;
-            if ((p = h[b])) {
-                l.scheduleUpdaters(f, p, [b])
-            }
-            if (f.template && k.removeFromInstance && k.removeFromInstance[b]) {
-                delete f[b]
-            }
-        }
-        if (!e) {
-            return
-        }
-        if (o.canvas) {
-            n = o.canvas;
-            delete o.canvas;
-            for (d = 0, g = n.length; d < g; d++) {
-                b = n[d];
-                f.canvasAttributes[b] = f[b]
-            }
-        }
-        if (f.hasOwnProperty("children")) {
-            a = f.children;
-            for (d = 0, g = a.length; d < g; d++) {
-                m = a[d];
-                Ext.apply(m.pendingUpdaters, o);
-                if (n) {
-                    for (c = 0; c < n.length; c++) {
-                        b = n[c];
-                        m.canvasAttributes[b] = m[b]
-                    }
-                }
-                l.callUpdaters(m)
-            }
-        }
-        l.setDirty(true);
-        l.callUpdaters(f)
-    },
-    popUp: function(a, b) {
-        this.applyChanges(a, b)
-    },
-    pushDown: function(a, b) {
-        var c = this.getPrevious();
-        if (c) {
-            b = c.pushDown(a, b)
-        }
-        this.applyChanges(a, b);
-        return b
-    }
-});
-Ext.define("Ext.draw.TimingFunctions", function() {
-    var g = Math.pow,
-        j = Math.sin,
-        m = Math.cos,
-        l = Math.sqrt,
-        e = Math.PI,
-        b = ["quad", "cube", "quart", "quint"],
-        c = {
-            pow: function(o, i) {
-                return g(o, i || 6)
-            },
-            expo: function(i) {
-                return g(2, 8 * (i - 1))
-            },
-            circ: function(i) {
-                return 1 - l(1 - i * i)
-            },
-            sine: function(i) {
-                return 1 - j((1 - i) * e / 2)
-            },
-            back: function(i, o) {
-                o = o || 1.616;
-                return i * i * ((o + 1) * i - o)
-            },
-            bounce: function(q) {
-                for (var o = 0, i = 1; 1; o += i, i /= 2) {
-                    if (q >= (7 - 4 * o) / 11) {
-                        return i * i - g((11 - 6 * o - 11 * q) / 4, 2)
-                    }
-                }
-            },
-            elastic: function(o, i) {
-                return g(2, 10 * --o) * m(20 * o * e * (i || 1) / 3)
-            }
-        },
-        k = {},
-        a, f, d;
-
-    function h(i) {
-        return function(o) {
-            return g(o, i)
-        }
-    }
-
-    function n(i, o) {
-        k[i + "In"] = function(p) {
-            return o(p)
-        };
-        k[i + "Out"] = function(p) {
-            return 1 - o(1 - p)
-        };
-        k[i + "InOut"] = function(p) {
-            return (p <= 0.5) ? o(2 * p) / 2 : (2 - o(2 * (1 - p))) / 2
-        }
-    }
-    for (d = 0, f = b.length; d < f; ++d) {
-        c[b[d]] = h(d + 2)
-    }
-    for (a in c) {
-        n(a, c[a])
-    }
-    k.linear = Ext.identityFn;
-    k.easeIn = k.quadIn;
-    k.easeOut = k.quadOut;
-    k.easeInOut = k.quadInOut;
-    return {
-        singleton: true,
-        easingMap: k
-    }
-}, function(a) {
-    Ext.apply(a, a.easingMap)
-});
-Ext.define("Ext.draw.Animator", {
-    uses: ["Ext.draw.Draw"],
-    singleton: true,
-    frameCallbacks: {},
-    frameCallbackId: 0,
-    scheduled: 0,
-    frameStartTimeOffset: Ext.now(),
-    animations: [],
-    running: false,
-    animationTime: function() {
-        return Ext.AnimationQueue.frameStartTime - this.frameStartTimeOffset
-    },
-    add: function(b) {
-        var a = this;
-        if (!a.contains(b)) {
-            a.animations.push(b);
-            a.ignite();
-            if ("fireEvent" in b) {
-                b.fireEvent("animationstart", b)
-            }
-        }
-    },
-    remove: function(d) {
-        var c = this,
-            e = c.animations,
-            b = 0,
-            a = e.length;
-        for (; b < a; ++b) {
-            if (e[b] === d) {
-                e.splice(b, 1);
-                if ("fireEvent" in d) {
-                    d.fireEvent("animationend", d)
-                }
-                return
-            }
-        }
-    },
-    contains: function(a) {
-        return Ext.Array.indexOf(this.animations, a) > -1
-    },
-    empty: function() {
-        return this.animations.length === 0
-    },
-    step: function(d) {
-        var c = this,
-            f = c.animations,
-            e, a = 0,
-            b = f.length;
-        for (; a < b; a++) {
-            e = f[a];
-            e.step(d);
-            if (!e.animating) {
-                f.splice(a, 1);
-                a--;
-                b--;
-                if (e.fireEvent) {
-                    e.fireEvent("animationend", e)
-                }
-            }
-        }
-    },
-    schedule: function(c, a) {
-        a = a || this;
-        var b = "frameCallback" + (this.frameCallbackId++);
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a,
-            once: true
-        };
-        this.scheduled++;
-        Ext.draw.Animator.ignite();
-        return b
-    },
-    scheduleIf: function(e, b) {
-        b = b || this;
-        var c = Ext.draw.Animator.frameCallbacks,
-            a, d;
-        if (Ext.isString(e)) {
-            e = b[e]
-        }
-        for (d in c) {
-            a = c[d];
-            if (a.once && a.fn === e && a.scope === b) {
-                return null
-            }
-        }
-        return this.schedule(e, b)
-    },
-    cancel: function(a) {
-        if (Ext.draw.Animator.frameCallbacks[a] && Ext.draw.Animator.frameCallbacks[a].once) {
-            this.scheduled--;
-            delete Ext.draw.Animator.frameCallbacks[a]
-        }
-    },
-    addFrameCallback: function(c, a) {
-        a = a || this;
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        var b = "frameCallback" + (this.frameCallbackId++);
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a
-        };
-        return b
-    },
-    removeFrameCallback: function(a) {
-        delete Ext.draw.Animator.frameCallbacks[a]
-    },
-    fireFrameCallbacks: function() {
-        var c = this.frameCallbacks,
-            d, b, a;
-        for (d in c) {
-            a = c[d];
-            b = a.fn;
-            if (Ext.isString(b)) {
-                b = a.scope[b]
-            }
-            b.call(a.scope);
-            if (c[d] && a.once) {
-                this.scheduled--;
-                delete c[d]
-            }
-        }
-    },
-    handleFrame: function() {
-        this.step(this.animationTime());
-        this.fireFrameCallbacks();
-        if (!this.scheduled && this.empty()) {
-            Ext.AnimationQueue.stop(this.handleFrame, this);
-            this.running = false;
-            Ext.draw.Draw.endUpdateIOS()
-        }
-    },
-    ignite: function() {
-        if (!this.running) {
-            this.running = true;
-            Ext.AnimationQueue.start(this.handleFrame, this);
-            Ext.draw.Draw.beginUpdateIOS()
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Animation", {
-    requires: ["Ext.draw.TimingFunctions", "Ext.draw.Animator"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.animation",
-    config: {
-        easing: Ext.identityFn,
-        duration: 0,
-        customEasings: {},
-        customDurations: {},
-        customDuration: null
-    },
-    constructor: function(a) {
-        var b = this;
-        b.anyAnimation = b.anySpecialAnimations = false;
-        b.animating = 0;
-        b.animatingPool = [];
-        b.callParent([a])
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("timers")) {
-            a.animating = false;
-            a.timers = {};
-            a.animationOriginal = Ext.Object.chain(a);
-            a.animationOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.animationOriginal)
-        }
-    },
-    updateSprite: function(a) {
-        this.setConfig(a.config.fx)
-    },
-    updateDuration: function(a) {
-        this.anyAnimation = a > 0
-    },
-    applyEasing: function(a) {
-        if (typeof a === "string") {
-            a = Ext.draw.TimingFunctions.easingMap[a]
-        }
-        return a
-    },
-    applyCustomEasings: function(a, e) {
-        e = e || {};
-        var g, d, b, h, c, f;
-        for (d in a) {
-            g = true;
-            h = a[d];
-            b = d.split(",");
-            if (typeof h === "string") {
-                h = Ext.draw.TimingFunctions.easingMap[h]
-            }
-            for (c = 0, f = b.length; c < f; c++) {
-                e[b[c]] = h
-            }
-        }
-        if (g) {
-            this.anySpecialAnimations = g
-        }
-        return e
-    },
-    setEasingOn: function(a, e) {
-        a = Ext.Array.from(a).slice();
-        var c = {},
-            d = a.length,
-            b = 0;
-        for (; b < d; b++) {
-            c[a[b]] = e
-        }
-        this.setCustomEasings(c)
-    },
-    clearEasingOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customEasings[a[b]]
-        }
-    },
-    applyCustomDurations: function(g, h) {
-        h = h || {};
-        var e, c, f, a, b, d;
-        for (c in g) {
-            e = true;
-            f = g[c];
-            a = c.split(",");
-            for (b = 0, d = a.length; b < d; b++) {
-                h[a[b]] = f
-            }
-        }
-        if (e) {
-            this.anySpecialAnimations = e
-        }
-        return h
-    },
-    applyCustomDuration: function(a, b) {
-        if (a) {
-            this.getCustomDurations();
-            this.setCustomDurations(a)
-        }
-    },
-    setDurationOn: function(b, e) {
-        b = Ext.Array.from(b).slice();
-        var a = {},
-            c = 0,
-            d = b.length;
-        for (; c < d; c++) {
-            a[b[c]] = e
-        }
-        this.setCustomDurations(a)
-    },
-    clearDurationOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customDurations[a[b]]
-        }
-    },
-    setAnimating: function(a, b) {
-        var e = this,
-            d = e.animatingPool;
-        if (a.animating !== b) {
-            a.animating = b;
-            if (b) {
-                d.push(a);
-                if (e.animating === 0) {
-                    Ext.draw.Animator.add(e)
-                }
-                e.animating++
-            } else {
-                for (var c = d.length; c--;) {
-                    if (d[c] === a) {
-                        d.splice(c, 1)
-                    }
-                }
-                e.animating = d.length
-            }
-        }
-    },
-    setAttrs: function(r, t) {
-        var s = this,
-            m = r.timers,
-            h = s._sprite.self.def._animationProcessors,
-            f = s._easing,
-            e = s._duration,
-            j = s._customDurations,
-            i = s._customEasings,
-            g = s.anySpecialAnimations,
-            n = s.anyAnimation || g,
-            o = r.animationOriginal,
-            d = false,
-            k, u, l, p, c, q, a;
-        if (!n) {
-            for (u in t) {
-                if (r[u] === t[u]) {
-                    delete t[u]
-                } else {
-                    r[u] = t[u]
-                }
-                delete o[u];
-                delete m[u]
-            }
-            return t
-        } else {
-            for (u in t) {
-                l = t[u];
-                p = r[u];
-                if (l !== p && p !== undefined && p !== null && (c = h[u])) {
-                    q = f;
-                    a = e;
-                    if (g) {
-                        if (u in i) {
-                            q = i[u]
-                        }
-                        if (u in j) {
-                            a = j[u]
-                        }
-                    }
-                    if (p && p.isGradient || l && l.isGradient) {
-                        a = 0
-                    }
-                    if (a) {
-                        if (!m[u]) {
-                            m[u] = {}
-                        }
-                        k = m[u];
-                        k.start = 0;
-                        k.easing = q;
-                        k.duration = a;
-                        k.compute = c.compute;
-                        k.serve = c.serve || Ext.identityFn;
-                        k.remove = t.removeFromInstance && t.removeFromInstance[u];
-                        if (c.parseInitial) {
-                            var b = c.parseInitial(p, l);
-                            k.source = b[0];
-                            k.target = b[1]
-                        } else {
-                            if (c.parse) {
-                                k.source = c.parse(p);
-                                k.target = c.parse(l)
-                            } else {
-                                k.source = p;
-                                k.target = l
-                            }
-                        }
-                        o[u] = l;
-                        delete t[u];
-                        d = true;
-                        continue
-                    } else {
-                        delete o[u]
-                    }
-                } else {
-                    delete o[u]
-                }
-                delete m[u]
-            }
-        }
-        if (d && !r.animating) {
-            s.setAnimating(r, true)
-        }
-        return t
-    },
-    updateAttributes: function(g) {
-        if (!g.animating) {
-            return {}
-        }
-        var h = {},
-            e = false,
-            d = g.timers,
-            f = g.animationOriginal,
-            c = Ext.draw.Animator.animationTime(),
-            a, b, i;
-        if (g.lastUpdate === c) {
-            return null
-        }
-        for (a in d) {
-            b = d[a];
-            if (!b.start) {
-                b.start = c;
-                i = 0
-            } else {
-                i = (c - b.start) / b.duration
-            }
-            if (i >= 1) {
-                h[a] = f[a];
-                delete f[a];
-                if (d[a].remove) {
-                    h.removeFromInstance = h.removeFromInstance || {};
-                    h.removeFromInstance[a] = true
-                }
-                delete d[a]
-            } else {
-                h[a] = b.serve(b.compute(b.source, b.target, b.easing(i), g[a]));
-                e = true
-            }
-        }
-        g.lastUpdate = c;
-        this.setAnimating(g, e);
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.animationOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    },
-    step: function(g) {
-        var f = this,
-            c = f.animatingPool.slice(),
-            e = c.length,
-            b = 0,
-            a, d;
-        for (; b < e; b++) {
-            a = c[b];
-            d = f.updateAttributes(a);
-            if (d && f._next) {
-                f._next.popUp(a, d)
-            }
-        }
-    },
-    stop: function() {
-        this.step();
-        var d = this,
-            b = d.animatingPool,
-            a, c;
-        for (a = 0, c = b.length; a < c; a++) {
-            b[a].animating = false
-        }
-        d.animatingPool.length = 0;
-        d.animating = 0;
-        Ext.draw.Animator.remove(d)
-    },
-    destroy: function() {
-        this.animatingPool.length = 0;
-        this.animating = 0;
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.modifier.Highlight", {
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.highlight",
-    config: {
-        enabled: false,
-        highlightStyle: null
-    },
-    preFx: true,
-    applyHighlightStyle: function(b, a) {
-        a = a || {};
-        if (this.getSprite()) {
-            Ext.apply(a, this.getSprite().self.def.normalize(b))
-        } else {
-            Ext.apply(a, b)
-        }
-        return a
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("highlightOriginal")) {
-            a.highlighted = false;
-            a.highlightOriginal = Ext.Object.chain(a);
-            a.highlightOriginal.prototype = a;
-            a.highlightOriginal.removeFromInstance = {}
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.highlightOriginal)
-        }
-    },
-    updateSprite: function(b, a) {
-        if (b) {
-            if (this.getHighlightStyle()) {
-                this._highlightStyle = b.self.def.normalize(this.getHighlightStyle())
-            }
-            this.setHighlightStyle(b.config.highlight)
-        }
-        b.self.def.setConfig({
-            defaults: {
-                highlighted: false
-            },
-            processors: {
-                highlighted: "bool"
-            }
-        });
-        this.setSprite(b)
-    },
-    filterChanges: function(a, d) {
-        var e = this,
-            f = a.highlightOriginal,
-            c = e.getHighlightStyle(),
-            b;
-        if (a.highlighted) {
-            for (b in d) {
-                if (c.hasOwnProperty(b)) {
-                    f[b] = d[b];
-                    delete d[b]
-                }
-            }
-        }
-        for (b in d) {
-            if (b !== "highlighted" && f[b] === d[b]) {
-                delete d[b]
-            }
-        }
-        return d
-    },
-    pushDown: function(e, g) {
-        var f = this.getHighlightStyle(),
-            c = e.highlightOriginal,
-            i = c.removeFromInstance,
-            d, a, h, b;
-        if (g.hasOwnProperty("highlighted")) {
-            d = g.highlighted;
-            delete g.highlighted;
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g);
-            if (d !== e.highlighted) {
-                if (d) {
-                    for (a in f) {
-                        if (a in g) {
-                            c[a] = g[a]
-                        } else {
-                            h = e.template && e.template.ownAttr;
-                            if (h && !e.prototype.hasOwnProperty(a)) {
-                                i[a] = true;
-                                c[a] = h.animationOriginal[a]
-                            } else {
-                                b = c.timers[a];
-                                if (b && b.remove) {
-                                    i[a] = true
-                                }
-                                c[a] = e[a]
-                            }
-                        }
-                        if (c[a] !== f[a]) {
-                            g[a] = f[a]
-                        }
-                    }
-                } else {
-                    for (a in f) {
-                        if (!(a in g)) {
-                            g[a] = c[a]
-                        }
-                        delete c[a]
-                    }
-                    g.removeFromInstance = g.removeFromInstance || {};
-                    Ext.apply(g.removeFromInstance, i);
-                    c.removeFromInstance = {}
-                }
-                g.highlighted = d
-            }
-        } else {
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g)
-        }
-        return g
-    },
-    popUp: function(a, b) {
-        b = this.filterChanges(a, b);
-        Ext.draw.modifier.Modifier.prototype.popUp.call(this, a, b)
-    }
-});
-Ext.define("Ext.draw.sprite.Sprite", {
-    alias: "sprite.sprite",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.draw.Draw", "Ext.draw.gradient.Gradient", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.modifier.Target", "Ext.draw.modifier.Animation", "Ext.draw.modifier.Highlight"],
-    isSprite: true,
-    statics: {
-        defaultHitTestOptions: {
-            fill: true,
-            stroke: true
-        }
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                strokeStyle: "color",
-                fillStyle: "color",
-                strokeOpacity: "limited01",
-                fillOpacity: "limited01",
-                lineWidth: "number",
-                lineCap: "enums(butt,round,square)",
-                lineJoin: "enums(round,bevel,miter)",
-                lineDash: "data",
-                lineDashOffset: "number",
-                miterLimit: "number",
-                shadowColor: "color",
-                shadowOffsetX: "number",
-                shadowOffsetY: "number",
-                shadowBlur: "number",
-                globalAlpha: "limited01",
-                globalCompositeOperation: "enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",
-                hidden: "bool",
-                transformFillStroke: "bool",
-                zIndex: "number",
-                translationX: "number",
-                translationY: "number",
-                rotationRads: "number",
-                rotationCenterX: "number",
-                rotationCenterY: "number",
-                scalingX: "number",
-                scalingY: "number",
-                scalingCenterX: "number",
-                scalingCenterY: "number",
-                constrainGradients: "bool"
-            },
-            aliases: {
-                stroke: "strokeStyle",
-                fill: "fillStyle",
-                color: "fillStyle",
-                "stroke-width": "lineWidth",
-                "stroke-linecap": "lineCap",
-                "stroke-linejoin": "lineJoin",
-                "stroke-miterlimit": "miterLimit",
-                "text-anchor": "textAlign",
-                opacity: "globalAlpha",
-                translateX: "translationX",
-                translateY: "translationY",
-                rotateRads: "rotationRads",
-                rotateCenterX: "rotationCenterX",
-                rotateCenterY: "rotationCenterY",
-                scaleX: "scalingX",
-                scaleY: "scalingY",
-                scaleCenterX: "scalingCenterX",
-                scaleCenterY: "scalingCenterY"
-            },
-            defaults: {
-                hidden: false,
-                zIndex: 0,
-                strokeStyle: "none",
-                fillStyle: "none",
-                lineWidth: 1,
-                lineDash: [],
-                lineDashOffset: 0,
-                lineCap: "butt",
-                lineJoin: "miter",
-                miterLimit: 10,
-                shadowColor: "none",
-                shadowOffsetX: 0,
-                shadowOffsetY: 0,
-                shadowBlur: 0,
-                globalAlpha: 1,
-                strokeOpacity: 1,
-                fillOpacity: 1,
-                transformFillStroke: false,
-                translationX: 0,
-                translationY: 0,
-                rotationRads: 0,
-                rotationCenterX: null,
-                rotationCenterY: null,
-                scalingX: 1,
-                scalingY: 1,
-                scalingCenterX: null,
-                scalingCenterY: null,
-                constrainGradients: false
-            },
-            triggers: {
-                zIndex: "zIndex",
-                globalAlpha: "canvas",
-                globalCompositeOperation: "canvas",
-                transformFillStroke: "canvas",
-                strokeStyle: "canvas",
-                fillStyle: "canvas",
-                strokeOpacity: "canvas",
-                fillOpacity: "canvas",
-                lineWidth: "canvas",
-                lineCap: "canvas",
-                lineJoin: "canvas",
-                lineDash: "canvas",
-                lineDashOffset: "canvas",
-                miterLimit: "canvas",
-                shadowColor: "canvas",
-                shadowOffsetX: "canvas",
-                shadowOffsetY: "canvas",
-                shadowBlur: "canvas",
-                translationX: "transform",
-                translationY: "transform",
-                rotationRads: "transform",
-                rotationCenterX: "transform",
-                rotationCenterY: "transform",
-                scalingX: "transform",
-                scalingY: "transform",
-                scalingCenterX: "transform",
-                scalingCenterY: "transform",
-                constrainGradients: "canvas"
-            },
-            updaters: {
-                bbox: "bboxUpdater",
-                zIndex: function(a) {
-                    a.dirtyZIndex = true
-                },
-                transform: function(a) {
-                    a.dirtyTransform = true;
-                    a.bbox.transform.dirty = true
-                }
-            }
-        }
-    },
-    config: {
-        parent: null,
-        surface: null
-    },
-    onClassExtended: function(d, c) {
-        var b = d.superclass.self.def.initialConfig,
-            e = c.inheritableStatics && c.inheritableStatics.def,
-            a;
-        if (e) {
-            a = Ext.Object.merge({}, b, e);
-            d.def = new Ext.draw.sprite.AttributeDefinition(a);
-            delete c.inheritableStatics.def
-        } else {
-            d.def = new Ext.draw.sprite.AttributeDefinition(b)
-        }
-        d.def.spriteClass = d
-    },
-    constructor: function(b) {
-        var d = this,
-            c = d.self.def,
-            e = c.getDefaults(),
-            a;
-        b = Ext.isObject(b) ? b : {};
-        d.id = b.id || Ext.id(null, "ext-sprite-");
-        d.attr = {};
-        d.mixins.observable.constructor.apply(d, arguments);
-        a = Ext.Array.from(b.modifiers, true);
-        d.prepareModifiers(a);
-        d.initializeAttributes();
-        d.setAttributes(e, true);
-        d.setAttributes(b)
-    },
-    getDirty: function() {
-        return this.attr.dirty
-    },
-    setDirty: function(b) {
-        this.attr.dirty = b;
-        if (b) {
-            var a = this.getParent();
-            if (a) {
-                a.setDirty(true)
-            }
-        }
-    },
-    addModifier: function(a, b) {
-        var c = this;
-        if (!(a instanceof Ext.draw.modifier.Modifier)) {
-            a = Ext.factory(a, null, null, "modifier")
-        }
-        a.setSprite(c);
-        if (a.preFx || a.config && a.config.preFx) {
-            if (c.fx.getPrevious()) {
-                c.fx.getPrevious().setNext(a)
-            }
-            a.setNext(c.fx)
-        } else {
-            c.topModifier.getPrevious().setNext(a);
-            a.setNext(c.topModifier)
-        }
-        if (b) {
-            c.initializeAttributes()
-        }
-        return a
-    },
-    prepareModifiers: function(d) {
-        var c = this,
-            a, b;
-        c.topModifier = new Ext.draw.modifier.Target({
-            sprite: c
-        });
-        c.fx = new Ext.draw.modifier.Animation({
-            sprite: c
-        });
-        c.fx.setNext(c.topModifier);
-        for (a = 0, b = d.length; a < b; a++) {
-            c.addModifier(d[a], false)
-        }
-    },
-    getAnimation: function() {
-        return this.fx
-    },
-    setAnimation: function(a) {
-        this.fx.setConfig(a)
-    },
-    initializeAttributes: function() {
-        this.topModifier.prepareAttributes(this.attr)
-    },
-    callUpdaters: function(d) {
-        var e = this,
-            h = d.pendingUpdaters,
-            i = e.self.def.getUpdaters(),
-            c = false,
-            a = false,
-            b, g, f;
-        e.callUpdaters = Ext.emptyFn;
-        do {
-            c = false;
-            for (g in h) {
-                c = true;
-                b = h[g];
-                delete h[g];
-                f = i[g];
-                if (typeof f === "string") {
-                    f = e[f]
-                }
-                if (f) {
-                    f.call(e, d, b)
-                }
-            }
-            a = a || c
-        } while (c);
-        delete e.callUpdaters;
-        if (a) {
-            e.setDirty(true)
-        }
-    },
-    scheduleUpdaters: function(a, e, c) {
-        var f;
-        if (c) {
-            for (var b = 0, d = e.length; b < d; b++) {
-                f = e[b];
-                this.scheduleUpdater(a, f, c)
-            }
-        } else {
-            for (f in e) {
-                c = e[f];
-                this.scheduleUpdater(a, f, c)
-            }
-        }
-    },
-    scheduleUpdater: function(a, c, b) {
-        b = b || [];
-        var d = a.pendingUpdaters;
-        if (c in d) {
-            if (b.length) {
-                d[c] = Ext.Array.merge(d[c], b)
-            }
-        } else {
-            d[c] = b
-        }
-    },
-    setAttributes: function(d, g, c) {
-        var a = this.attr,
-            b, e, f;
-        if (g) {
-            if (c) {
-                this.topModifier.pushDown(a, d)
-            } else {
-                f = {};
-                for (b in d) {
-                    e = d[b];
-                    if (e !== a[b]) {
-                        f[b] = e
-                    }
-                }
-                this.topModifier.pushDown(a, f)
-            }
-        } else {
-            this.topModifier.pushDown(a, this.self.def.normalize(d))
-        }
-    },
-    setAttributesBypassingNormalization: function(b, a) {
-        return this.setAttributes(b, true, a)
-    },
-    bboxUpdater: function(b) {
-        var c = b.rotationRads !== 0,
-            a = b.scalingX !== 1 || b.scalingY !== 1,
-            d = b.rotationCenterX === null || b.rotationCenterY === null,
-            e = b.scalingCenterX === null || b.scalingCenterY === null;
-        b.bbox.plain.dirty = true;
-        b.bbox.transform.dirty = true;
-        if (c && d || a && e) {
-            this.scheduleUpdater(b, "transform")
-        }
-    },
-    getBBox: function(d) {
-        var e = this,
-            a = e.attr,
-            f = a.bbox,
-            c = f.plain,
-            b = f.transform;
-        if (c.dirty) {
-            e.updatePlainBBox(c);
-            c.dirty = false
-        }
-        if (!d) {
-            e.applyTransformations();
-            if (b.dirty) {
-                e.updateTransformedBBox(b, c);
-                b.dirty = false
-            }
-            return b
-        }
-        return c
-    },
-    updatePlainBBox: Ext.emptyFn,
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, 0, a)
-    },
-    getBBoxCenter: function(a) {
-        var b = this.getBBox(a);
-        if (b) {
-            return [b.x + b.width * 0.5, b.y + b.height * 0.5]
-        } else {
-            return [0, 0]
-        }
-    },
-    hide: function() {
-        this.attr.hidden = true;
-        this.setDirty(true);
-        return this
-    },
-    show: function() {
-        this.attr.hidden = false;
-        this.setDirty(true);
-        return this
-    },
-    useAttributes: function(i, f) {
-        this.applyTransformations();
-        var d = this.attr,
-            h = d.canvasAttributes,
-            e = h.strokeStyle,
-            g = h.fillStyle,
-            b = h.lineDash,
-            c = h.lineDashOffset,
-            a;
-        if (e) {
-            if (e.isGradient) {
-                i.strokeStyle = "black";
-                i.strokeGradient = e
-            } else {
-                i.strokeGradient = false
-            }
-        }
-        if (g) {
-            if (g.isGradient) {
-                i.fillStyle = "black";
-                i.fillGradient = g
-            } else {
-                i.fillGradient = false
-            }
-        }
-        if (b) {
-            i.setLineDash(b)
-        }
-        if (Ext.isNumber(c + i.lineDashOffset)) {
-            i.lineDashOffset = c
-        }
-        for (a in h) {
-            if (h[a] !== undefined && h[a] !== i[a]) {
-                i[a] = h[a]
-            }
-        }
-        this.setGradientBBox(i, f)
-    },
-    setGradientBBox: function(b, c) {
-        var a = this.attr;
-        if (a.constrainGradients) {
-            b.setGradientBBox({
-                x: c[0],
-                y: c[1],
-                width: c[2],
-                height: c[3]
-            })
-        } else {
-            b.setGradientBBox(this.getBBox(a.transformFillStroke))
-        }
-    },
-    applyTransformations: function(b) {
-        if (!b && !this.attr.dirtyTransform) {
-            return
-        }
-        var r = this,
-            k = r.attr,
-            p = r.getBBoxCenter(true),
-            g = p[0],
-            f = p[1],
-            q = k.translationX,
-            o = k.translationY,
-            j = k.scalingX,
-            i = k.scalingY === null ? k.scalingX : k.scalingY,
-            m = k.scalingCenterX === null ? g : k.scalingCenterX,
-            l = k.scalingCenterY === null ? f : k.scalingCenterY,
-            s = k.rotationRads,
-            e = k.rotationCenterX === null ? g : k.rotationCenterX,
-            d = k.rotationCenterY === null ? f : k.rotationCenterY,
-            c = Math.cos(s),
-            a = Math.sin(s),
-            n, h;
-        if (j === 1 && i === 1) {
-            m = 0;
-            l = 0
-        }
-        if (s === 0) {
-            e = 0;
-            d = 0
-        }
-        n = m * (1 - j) - e;
-        h = l * (1 - i) - d;
-        k.matrix.elements = [c * j, a * j, -a * i, c * i, c * n - a * h + e + q, a * n + c * h + d + o];
-        k.matrix.inverse(k.inverseMatrix);
-        k.dirtyTransform = false;
-        k.bbox.transform.dirty = true
-    },
-    transform: function(b, c) {
-        var a = this.attr,
-            e = a.matrix,
-            d;
-        if (b && b.isMatrix) {
-            d = b.elements
-        } else {
-            d = b
-        }
-        e.prepend.apply(e, d.slice());
-        e.inverse(a.inverseMatrix);
-        if (c) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    updateTransformAttributes: function() {
-        var a = this.attr,
-            b = a.matrix.split();
-        a.rotationRads = b.rotate;
-        a.rotationCenterX = 0;
-        a.rotationCenterY = 0;
-        a.scalingX = b.scaleX;
-        a.scalingY = b.scaleY;
-        a.scalingCenterX = 0;
-        a.scalingCenterY = 0;
-        a.translationX = b.translateX;
-        a.translationY = b.translateY
-    },
-    resetTransform: function(b) {
-        var a = this.attr;
-        a.matrix.reset();
-        a.inverseMatrix.reset();
-        if (!b) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    setTransform: function(a, b) {
-        this.resetTransform(true);
-        this.transform.call(this, a, b);
-        return this
-    },
-    preRender: Ext.emptyFn,
-    render: Ext.emptyFn,
-    hitTest: function(b, c) {
-        if (this.isVisible()) {
-            var a = b[0],
-                f = b[1],
-                e = this.getBBox(),
-                d = e && a >= e.x && a <= (e.x + e.width) && f >= e.y && f <= (e.y + e.height);
-            if (d) {
-                return {
-                    sprite: this
-                }
-            }
-        }
-        return null
-    },
-    isVisible: function() {
-        var e = this.attr,
-            f = this.getParent(),
-            g = f && (f.isSurface || f.isVisible()),
-            d = g && !e.hidden && e.globalAlpha,
-            b = Ext.draw.Color.NONE,
-            a = Ext.draw.Color.RGBA_NONE,
-            c = e.fillOpacity && e.fillStyle !== b && e.fillStyle !== a,
-            i = e.strokeOpacity && e.strokeStyle !== b && e.strokeStyle !== a,
-            h = d && (c || i);
-        return !!h
-    },
-    repaint: function() {
-        var a = this.getSurface();
-        if (a) {
-            a.renderFrame()
-        }
-    },
-    remove: function() {
-        var a = this.getSurface();
-        if (a && a.isSurface) {
-            return a.remove(this)
-        }
-        return null
-    },
-    destroy: function() {
-        var b = this,
-            a = b.topModifier,
-            c;
-        while (a) {
-            c = a;
-            a = a.getPrevious();
-            c.destroy()
-        }
-        delete b.attr;
-        b.remove();
-        if (b.fireEvent("beforedestroy", b) !== false) {
-            b.fireEvent("destroy", b)
-        }
-        b.callParent()
-    }
-}, function() {
-    this.def = new Ext.draw.sprite.AttributeDefinition(this.def);
-    this.def.spriteClass = this
-});
-Ext.define("Ext.draw.Path", {
-    requires: ["Ext.draw.Draw"],
-    statics: {
-        pathRe: /,?([achlmqrstvxz]),?/gi,
-        pathRe2: /-/gi,
-        pathSplitRe: /\s|,/g
-    },
-    svgString: "",
-    constructor: function(a) {
-        var b = this;
-        b.commands = [];
-        b.params = [];
-        b.cursor = null;
-        b.startX = 0;
-        b.startY = 0;
-        if (a) {
-            b.fromSvgString(a)
-        }
-    },
-    clear: function() {
-        var a = this;
-        a.params.length = 0;
-        a.commands.length = 0;
-        a.cursor = null;
-        a.startX = 0;
-        a.startY = 0;
-        a.dirt()
-    },
-    dirt: function() {
-        this.svgString = ""
-    },
-    moveTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c]
-        }
-        b.params.push(a, c);
-        b.commands.push("M");
-        b.startX = a;
-        b.startY = c;
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    lineTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c];
-            b.params.push(a, c);
-            b.commands.push("M")
-        } else {
-            b.params.push(a, c);
-            b.commands.push("L")
-        }
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    bezierCurveTo: function(c, e, b, d, a, g) {
-        var f = this;
-        if (!f.cursor) {
-            f.moveTo(c, e)
-        }
-        f.params.push(c, e, b, d, a, g);
-        f.commands.push("C");
-        f.cursor[0] = a;
-        f.cursor[1] = g;
-        f.dirt()
-    },
-    quadraticCurveTo: function(b, e, a, d) {
-        var c = this;
-        if (!c.cursor) {
-            c.moveTo(b, e)
-        }
-        c.bezierCurveTo((2 * b + c.cursor[0]) / 3, (2 * e + c.cursor[1]) / 3, (2 * b + a) / 3, (2 * e + d) / 3, a, d)
-    },
-    closePath: function() {
-        var a = this;
-        if (a.cursor) {
-            a.cursor = null;
-            a.commands.push("Z");
-            a.dirt()
-        }
-    },
-    arcTo: function(A, f, z, d, j, i, v) {
-        var E = this;
-        if (i === undefined) {
-            i = j
-        }
-        if (v === undefined) {
-            v = 0
-        }
-        if (!E.cursor) {
-            E.moveTo(A, f);
-            return
-        }
-        if (j === 0 || i === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        z -= A;
-        d -= f;
-        var B = E.cursor[0] - A,
-            g = E.cursor[1] - f,
-            C = z * g - d * B,
-            b, a, l, r, k, q, x = Math.sqrt(B * B + g * g),
-            u = Math.sqrt(z * z + d * d),
-            t, e, c;
-        if (C === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        if (i !== j) {
-            b = Math.cos(v);
-            a = Math.sin(v);
-            l = b / j;
-            r = a / i;
-            k = -a / j;
-            q = b / i;
-            var D = l * B + r * g;
-            g = k * B + q * g;
-            B = D;
-            D = l * z + r * d;
-            d = k * z + q * d;
-            z = D
-        } else {
-            B /= j;
-            g /= i;
-            z /= j;
-            d /= i
-        }
-        e = B * u + z * x;
-        c = g * u + d * x;
-        t = 1 / (Math.sin(Math.asin(Math.abs(C) / (x * u)) * 0.5) * Math.sqrt(e * e + c * c));
-        e *= t;
-        c *= t;
-        var o = (e * B + c * g) / (B * B + g * g),
-            m = (e * z + c * d) / (z * z + d * d);
-        var n = B * o - e,
-            p = g * o - c,
-            h = z * m - e,
-            y = d * m - c,
-            w = Math.atan2(p, n),
-            s = Math.atan2(y, h);
-        if (C > 0) {
-            if (s < w) {
-                s += Math.PI * 2
-            }
-        } else {
-            if (w < s) {
-                w += Math.PI * 2
-            }
-        }
-        if (i !== j) {
-            e = b * e * j - a * c * i + A;
-            c = a * c * i + b * c * i + f;
-            E.lineTo(b * j * n - a * i * p + e, a * j * n + b * i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        } else {
-            e = e * j + A;
-            c = c * i + f;
-            E.lineTo(j * n + e, i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        }
-    },
-    ellipse: function(h, f, c, a, q, n, d, e) {
-        var o = this,
-            g = o.params,
-            b = g.length,
-            m, l, k;
-        if (d - n >= Math.PI * 2) {
-            o.ellipse(h, f, c, a, q, n, n + Math.PI, e);
-            o.ellipse(h, f, c, a, q, n + Math.PI, d, e);
-            return
-        }
-        if (!e) {
-            if (d < n) {
-                d += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, n, d)
-        } else {
-            if (n < d) {
-                n += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, d, n);
-            for (l = b, k = g.length - 2; l < k; l += 2, k -= 2) {
-                var p = g[l];
-                g[l] = g[k];
-                g[k] = p;
-                p = g[l + 1];
-                g[l + 1] = g[k + 1];
-                g[k + 1] = p
-            }
-        }
-        if (!o.cursor) {
-            o.cursor = [g[g.length - 2], g[g.length - 1]];
-            o.commands.push("M")
-        } else {
-            o.cursor[0] = g[g.length - 2];
-            o.cursor[1] = g[g.length - 1];
-            o.commands.push("L")
-        }
-        for (l = 2; l < m; l += 6) {
-            o.commands.push("C")
-        }
-        o.dirt()
-    },
-    arc: function(b, f, a, d, c, e) {
-        this.ellipse(b, f, a, a, 0, d, c, e)
-    },
-    rect: function(b, e, c, a) {
-        if (c == 0 || a == 0) {
-            return
-        }
-        var d = this;
-        d.moveTo(b, e);
-        d.lineTo(b + c, e);
-        d.lineTo(b + c, e + a);
-        d.lineTo(b, e + a);
-        d.closePath()
-    },
-    approximateArc: function(s, i, f, o, n, d, x, v) {
-        var e = Math.cos(d),
-            z = Math.sin(d),
-            k = Math.cos(x),
-            l = Math.sin(x),
-            q = e * k * o - z * l * n,
-            y = -e * l * o - z * k * n,
-            p = z * k * o + e * l * n,
-            w = -z * l * o + e * k * n,
-            m = Math.PI / 2,
-            r = 2,
-            j = q,
-            u = y,
-            h = p,
-            t = w,
-            b = 0.547443256150549,
-            C, g, A, a, B, c;
-        v -= x;
-        if (v < 0) {
-            v += Math.PI * 2
-        }
-        s.push(q + i, p + f);
-        while (v >= m) {
-            s.push(j + u * b + i, h + t * b + f, j * b + u + i, h * b + t + f, u + i, t + f);
-            r += 6;
-            v -= m;
-            C = j;
-            j = u;
-            u = -C;
-            C = h;
-            h = t;
-            t = -C
-        }
-        if (v) {
-            g = (0.3294738052815987 + 0.012120855841304373 * v) * v;
-            A = Math.cos(v);
-            a = Math.sin(v);
-            B = A + g * a;
-            c = a - g * A;
-            s.push(j + u * g + i, h + t * g + f, j * B + u * c + i, h * B + t * c + f, j * A + u * a + i, h * A + t * a + f);
-            r += 6
-        }
-        return r
-    },
-    arcSvg: function(j, h, r, m, w, t, c) {
-        if (j < 0) {
-            j = -j
-        }
-        if (h < 0) {
-            h = -h
-        }
-        var x = this,
-            u = x.cursor[0],
-            f = x.cursor[1],
-            a = (u - t) / 2,
-            y = (f - c) / 2,
-            d = Math.cos(r),
-            s = Math.sin(r),
-            o = a * d + y * s,
-            v = -a * s + y * d,
-            i = o / j,
-            g = v / h,
-            p = i * i + g * g,
-            e = (u + t) * 0.5,
-            b = (f + c) * 0.5,
-            l = 0,
-            k = 0;
-        if (p >= 1) {
-            p = Math.sqrt(p);
-            j *= p;
-            h *= p
-        } else {
-            p = Math.sqrt(1 / p - 1);
-            if (m === w) {
-                p = -p
-            }
-            l = p * j * g;
-            k = -p * h * i;
-            e += d * l - s * k;
-            b += s * l + d * k
-        }
-        var q = Math.atan2((v - k) / h, (o - l) / j),
-            n = Math.atan2((-v - k) / h, (-o - l) / j) - q;
-        if (w) {
-            if (n <= 0) {
-                n += Math.PI * 2
-            }
-        } else {
-            if (n >= 0) {
-                n -= Math.PI * 2
-            }
-        }
-        x.ellipse(e, b, j, h, r, q, q + n, 1 - w)
-    },
-    fromSvgString: function(e) {
-        if (!e) {
-            return
-        }
-        var m = this,
-            h, l = {
-                a: 7,
-                c: 6,
-                h: 1,
-                l: 2,
-                m: 2,
-                q: 4,
-                s: 4,
-                t: 2,
-                v: 1,
-                z: 0,
-                A: 7,
-                C: 6,
-                H: 1,
-                L: 2,
-                M: 2,
-                Q: 4,
-                S: 4,
-                T: 2,
-                V: 1,
-                Z: 0
-            },
-            k = "",
-            g, f, c = 0,
-            b = 0,
-            d = false,
-            j, n, a;
-        if (Ext.isString(e)) {
-            h = e.replace(Ext.draw.Path.pathRe, " $1 ").replace(Ext.draw.Path.pathRe2, " -").split(Ext.draw.Path.pathSplitRe)
-        } else {
-            if (Ext.isArray(e)) {
-                h = e.join(",").split(Ext.draw.Path.pathSplitRe)
-            }
-        }
-        for (j = 0, n = 0; j < h.length; j++) {
-            if (h[j] !== "") {
-                h[n++] = h[j]
-            }
-        }
-        h.length = n;
-        m.clear();
-        for (j = 0; j < h.length;) {
-            k = d;
-            d = h[j];
-            a = (d.toUpperCase() !== d);
-            j++;
-            switch (d) {
-                case "M":
-                    m.moveTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "L":
-                    m.lineTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "A":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c = +h[j + 5], b = +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "C":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(+h[j], +h[j + 1], g = +h[j + 2], f = +h[j + 3], c = +h[j + 4], b = +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "Z":
-                    m.closePath();
-                    break;
-                case "m":
-                    m.moveTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "l":
-                    m.lineTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "a":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c += +h[j + 5], b += +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "c":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + (+h[j]), b + (+h[j + 1]), g = c + (+h[j + 2]), f = b + (+h[j + 3]), c += +h[j + 4], b += +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "z":
-                    m.closePath();
-                    break;
-                case "s":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "S":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = +h[j], f = +h[j + 1], c = (+h[j + 2]), b = (+h[j + 3]));
-                        j += 4
-                    }
-                    break;
-                case "q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "Q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = +h[j], f = +h[j + 1], c = +h[j + 2], b = +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "t":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c += +h[j + 1], b += +h[j + 2]);
-                        j += 2
-                    }
-                    break;
-                case "T":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c = (+h[j + 1]), b = (+h[j + 2]));
-                        j += 2
-                    }
-                    break;
-                case "h":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b);
-                        j++
-                    }
-                    break;
-                case "H":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b);
-                        j++
-                    }
-                    break;
-                case "v":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b += +h[j]);
-                        j++
-                    }
-                    break;
-                case "V":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b = +h[j]);
-                        j++
-                    }
-                    break
-            }
-        }
-    },
-    clone: function() {
-        var a = this,
-            b = new Ext.draw.Path();
-        b.params = a.params.slice(0);
-        b.commands = a.commands.slice(0);
-        b.cursor = a.cursor ? a.cursor.slice(0) : null;
-        b.startX = a.startX;
-        b.startY = a.startY;
-        b.svgString = a.svgString;
-        return b
-    },
-    transform: function(j) {
-        if (j.isIdentity()) {
-            return
-        }
-        var a = j.getXX(),
-            f = j.getYX(),
-            m = j.getDX(),
-            l = j.getXY(),
-            e = j.getYY(),
-            k = j.getDY(),
-            b = this.params,
-            c = 0,
-            d = b.length,
-            h, g;
-        for (; c < d; c += 2) {
-            h = b[c];
-            g = b[c + 1];
-            b[c] = h * a + g * f + m;
-            b[c + 1] = h * l + g * e + k
-        }
-        this.dirt()
-    },
-    getDimension: function(f) {
-        if (!f) {
-            f = {}
-        }
-        if (!this.commands || !this.commands.length) {
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var d = 0,
-            c = 0,
-            b = this.commands,
-            g = this.params,
-            e = b.length,
-            a, h;
-        for (; d < e; d++) {
-            switch (b[d]) {
-                case "M":
-                case "L":
-                    a = g[c];
-                    h = g[c + 1];
-                    f.left = Math.min(a, f.left);
-                    f.top = Math.min(h, f.top);
-                    f.right = Math.max(a, f.right);
-                    f.bottom = Math.max(h, f.bottom);
-                    c += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, a, h, g[c], g[c + 1], g[c + 2], g[c + 3], a = g[c + 4], h = g[c + 5]);
-                    c += 6;
-                    break
-            }
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    getDimensionWithTransform: function(n, f) {
-        if (!this.commands || !this.commands.length) {
-            if (!f) {
-                f = {}
-            }
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var a = n.getXX(),
-            k = n.getYX(),
-            q = n.getDX(),
-            p = n.getXY(),
-            h = n.getYY(),
-            o = n.getDY(),
-            e = 0,
-            d = 0,
-            b = this.commands,
-            c = this.params,
-            g = b.length,
-            m, l;
-        for (; e < g; e++) {
-            switch (b[e]) {
-                case "M":
-                case "L":
-                    m = c[d] * a + c[d + 1] * k + q;
-                    l = c[d] * p + c[d + 1] * h + o;
-                    f.left = Math.min(m, f.left);
-                    f.top = Math.min(l, f.top);
-                    f.right = Math.max(m, f.right);
-                    f.bottom = Math.max(l, f.bottom);
-                    d += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, m, l, c[d] * a + c[d + 1] * k + q, c[d] * p + c[d + 1] * h + o, c[d + 2] * a + c[d + 3] * k + q, c[d + 2] * p + c[d + 3] * h + o, m = c[d + 4] * a + c[d + 5] * k + q, l = c[d + 4] * p + c[d + 5] * h + o);
-                    d += 6;
-                    break
-            }
-        }
-        if (!f) {
-            f = {}
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    expandDimension: function(i, d, p, k, g, j, e, c, o) {
-        var m = this,
-            f = i.left,
-            a = i.right,
-            q = i.top,
-            n = i.bottom,
-            h = m.dim || (m.dim = []);
-        m.curveDimension(d, k, j, c, h);
-        f = Math.min(f, h[0]);
-        a = Math.max(a, h[1]);
-        m.curveDimension(p, g, e, o, h);
-        q = Math.min(q, h[0]);
-        n = Math.max(n, h[1]);
-        i.left = f;
-        i.right = a;
-        i.top = q;
-        i.bottom = n
-    },
-    curveDimension: function(p, n, k, j, h) {
-        var i = 3 * (-p + 3 * (n - k) + j),
-            g = 6 * (p - 2 * n + k),
-            f = -3 * (p - n),
-            o, m, e = Math.min(p, j),
-            l = Math.max(p, j),
-            q;
-        if (i === 0) {
-            if (g === 0) {
-                h[0] = e;
-                h[1] = l;
-                return
-            } else {
-                o = -f / g;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-            }
-        } else {
-            q = g * g - 4 * i * f;
-            if (q >= 0) {
-                q = Math.sqrt(q);
-                o = (q - g) / 2 / i;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-                if (q > 0) {
-                    o -= q / i;
-                    if (0 < o && o < 1) {
-                        m = this.interpolate(p, n, k, j, o);
-                        e = Math.min(e, m);
-                        l = Math.max(l, m)
-                    }
-                }
-            }
-        }
-        h[0] = e;
-        h[1] = l
-    },
-    interpolate: function(f, e, j, i, g) {
-        if (g === 0) {
-            return f
-        }
-        if (g === 1) {
-            return i
-        }
-        var h = (1 - g) / g;
-        return g * g * g * (i + h * (3 * j + h * (3 * e + h * f)))
-    },
-    fromStripes: function(g) {
-        var e = this,
-            c = 0,
-            d = g.length,
-            b, a, f;
-        e.clear();
-        for (; c < d; c++) {
-            f = g[c];
-            e.params.push.apply(e.params, f);
-            e.commands.push("M");
-            for (b = 2, a = f.length; b < a; b += 6) {
-                e.commands.push("C")
-            }
-        }
-        if (!e.cursor) {
-            e.cursor = []
-        }
-        e.cursor[0] = e.params[e.params.length - 2];
-        e.cursor[1] = e.params[e.params.length - 1];
-        e.dirt()
-    },
-    toStripes: function(k) {
-        var o = k || [],
-            p, n, m, b, a, h, g, f, e, c = this.commands,
-            d = this.params,
-            l = c.length;
-        for (f = 0, e = 0; f < l; f++) {
-            switch (c[f]) {
-                case "M":
-                    p = [h = b = d[e++], g = a = d[e++]];
-                    o.push(p);
-                    break;
-                case "L":
-                    n = d[e++];
-                    m = d[e++];
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break;
-                case "C":
-                    p.push(d[e++], d[e++], d[e++], d[e++], b = d[e++], a = d[e++]);
-                    break;
-                case "Z":
-                    n = h;
-                    m = g;
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break
-            }
-        }
-        return o
-    },
-    updateSvgString: function() {
-        var b = [],
-            a = this.commands,
-            f = this.params,
-            e = a.length,
-            d = 0,
-            c = 0;
-        for (; d < e; d++) {
-            switch (a[d]) {
-                case "M":
-                    b.push("M" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "L":
-                    b.push("L" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "C":
-                    b.push("C" + f[c] + "," + f[c + 1] + " " + f[c + 2] + "," + f[c + 3] + " " + f[c + 4] + "," + f[c + 5]);
-                    c += 6;
-                    break;
-                case "Z":
-                    b.push("Z");
-                    break
-            }
-        }
-        this.svgString = b.join("")
-    },
-    toString: function() {
-        if (!this.svgString) {
-            this.updateSvgString()
-        }
-        return this.svgString
-    }
-});
-Ext.define("Ext.draw.overrides.Path", {
-    override: "Ext.draw.Path",
-    rayOrigin: {
-        x: -10000,
-        y: -10000
-    },
-    isPointInPath: function(o, n) {
-        var m = this,
-            c = m.commands,
-            q = Ext.draw.PathUtil,
-            p = m.rayOrigin,
-            f = m.params,
-            l = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            k = 0,
-            h, g;
-        for (h = 0, g = 0; h < l; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (q.linesIntersection(b, a, f[g], f[g + 1], p.x, p.y, o, n)) {
-                        k += 1
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    k += q.cubicLineIntersections(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], p.x, p.y, o, n).length;
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    break
-            }
-        }
-        return k % 2 === 1
-    },
-    isPointOnPath: function(n, m) {
-        var l = this,
-            c = l.commands,
-            o = Ext.draw.PathUtil,
-            f = l.params,
-            k = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            h, g;
-        for (h = 0, g = 0; h < k; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (o.pointOnLine(b, a, f[g], f[g + 1], n, m)) {
-                        return true
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    if (o.pointOnCubic(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], n, m)) {
-                        return true
-                    }
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    break
-            }
-        }
-        return false
-    },
-    getSegmentIntersections: function(t, d, s, c, r, b, o, a) {
-        var w = this,
-            g = arguments.length,
-            v = Ext.draw.PathUtil,
-            f = w.commands,
-            u = w.params,
-            k = f.length,
-            m = null,
-            l = null,
-            h = 0,
-            e = 0,
-            x = [],
-            q, n, p;
-        for (q = 0, n = 0; q < k; q++) {
-            switch (f[q]) {
-                case "M":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    m = h = u[n];
-                    l = e = u[n + 1];
-                    n += 2;
-                    break;
-                case "L":
-                    switch (g) {
-                        case 4:
-                            p = v.linesIntersection(h, e, u[n], u[n + 1], t, d, s, c);
-                            if (p) {
-                                x.push(p)
-                            }
-                            break;
-                        case 8:
-                            p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, h, e, u[n], u[n + 1]);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n];
-                    e = u[n + 1];
-                    n += 2;
-                    break;
-                case "C":
-                    switch (g) {
-                        case 4:
-                            p = v.cubicLineIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, d, s, c);
-                            x.push.apply(x, p);
-                            break;
-                        case 8:
-                            p = v.cubicsIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, s, r, o, d, c, b, a);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n + 4];
-                    e = u[n + 5];
-                    n += 6;
-                    break;
-                case "Z":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    break
-            }
-        }
-        return x
-    },
-    getIntersections: function(o) {
-        var m = this,
-            c = m.commands,
-            g = m.params,
-            l = c.length,
-            f = null,
-            e = null,
-            b = 0,
-            a = 0,
-            d = [],
-            k, h, n;
-        for (k = 0, h = 0; k < l; k++) {
-            switch (c[k]) {
-                case "M":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    f = b = g[h];
-                    e = a = g[h + 1];
-                    h += 2;
-                    break;
-                case "L":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1]);
-                    d.push.apply(d, n);
-                    b = g[h];
-                    a = g[h + 1];
-                    h += 2;
-                    break;
-                case "C":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1], g[h + 2], g[h + 3], g[h + 4], g[h + 5]);
-                    d.push.apply(d, n);
-                    b = g[h + 4];
-                    a = g[h + 5];
-                    h += 6;
-                    break;
-                case "Z":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    break
-            }
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.Path", {
-    extend: "Ext.draw.sprite.Sprite",
-    requires: ["Ext.draw.Draw", "Ext.draw.Path"],
-    alias: ["sprite.path", "Ext.draw.Sprite"],
-    type: "path",
-    isPath: true,
-    inheritableStatics: {
-        def: {
-            processors: {
-                path: function(b, a) {
-                    if (!(b instanceof Ext.draw.Path)) {
-                        b = new Ext.draw.Path(b)
-                    }
-                    return b
-                }
-            },
-            aliases: {
-                d: "path"
-            },
-            triggers: {
-                path: "bbox"
-            },
-            updaters: {
-                path: function(a) {
-                    var b = a.path;
-                    if (!b || b.bindAttr !== a) {
-                        b = new Ext.draw.Path();
-                        b.bindAttr = a;
-                        a.path = b
-                    }
-                    b.clear();
-                    this.updatePath(b, a);
-                    this.scheduleUpdater(a, "bbox", ["path"])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimension(a)
-        }
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimensionWithTransform(this.attr.matrix, a)
-        }
-    },
-    render: function(b, c) {
-        var d = this.attr.matrix,
-            a = this.attr;
-        if (!a.path || a.path.params.length === 0) {
-            return
-        }
-        d.toContext(c);
-        c.appendPath(a.path);
-        c.fillStroke(a)
-    },
-    updatePath: function(b, a) {}
-});
-Ext.define("Ext.draw.overrides.sprite.Path", {
-    override: "Ext.draw.sprite.Path",
-    requires: ["Ext.draw.Color"],
-    isPointInPath: function(c, g) {
-        var b = this.attr;
-        if (b.fillStyle === Ext.draw.Color.RGBA_NONE) {
-            return this.isPointOnPath(c, g)
-        }
-        var e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointInPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    isPointOnPath: function(c, g) {
-        var b = this.attr,
-            e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointOnPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    hitTest: function(i, l) {
-        var e = this,
-            c = e.attr,
-            k = c.path,
-            g = c.matrix,
-            h = i[0],
-            f = i[1],
-            d = e.callParent([i, l]),
-            j = null,
-            a, b;
-        if (!d) {
-            return j
-        }
-        l = l || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        if (!g.isIdentity()) {
-            a = k.params.slice(0);
-            k.transform(c.matrix)
-        }
-        if (l.fill && l.stroke) {
-            b = c.fillStyle !== Ext.draw.Color.NONE && c.fillStyle !== Ext.draw.Color.RGBA_NONE;
-            if (b) {
-                if (k.isPointInPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (k.isPointInPath(h, f) || k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            }
-        } else {
-            if (l.stroke && !l.fill) {
-                if (k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (l.fill && !l.stroke) {
-                    if (k.isPointInPath(h, f)) {
-                        j = {
-                            sprite: e
-                        }
-                    }
-                }
-            }
-        }
-        if (a) {
-            k.params = a
-        }
-        return j
-    },
-    getIntersections: function(j) {
-        if (!(j.isSprite && j.isPath)) {
-            return []
-        }
-        var e = this.attr,
-            d = j.attr,
-            i = e.path,
-            h = d.path,
-            g = e.matrix,
-            a = d.matrix,
-            c, f, b;
-        if (!g.isIdentity()) {
-            c = i.params.slice(0);
-            i.transform(e.matrix)
-        }
-        if (!a.isIdentity()) {
-            f = h.params.slice(0);
-            h.transform(d.matrix)
-        }
-        b = i.getIntersections(h);
-        if (c) {
-            i.params = c
-        }
-        if (f) {
-            h.params = f
-        }
-        return b
-    }
-});
-Ext.define("Ext.draw.sprite.Circle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.circle",
-    type: "circle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                r: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                r: 4
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                r: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            e = b.cy,
-            d = b.r;
-        c.x = a - d;
-        c.y = e - d;
-        c.width = d + d;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var g = this.attr,
-            f = g.cx,
-            e = g.cy,
-            a = g.r,
-            h = g.matrix,
-            j = h.getScaleX(),
-            i = h.getScaleY(),
-            c, b;
-        c = j * a;
-        b = i * a;
-        d.x = h.x(f, e) - c;
-        d.y = h.y(f, e) - b;
-        d.width = c + c;
-        d.height = b + b
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.Arc", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "sprite.arc",
-    type: "arc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Arrow", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.arrow",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.5,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c * 0.7, ",", e - c * 0.4, "l", [c * 0.6, 0, 0, -c * 0.4, c, c * 0.8, -c, c * 0.8, 0, -c * 0.4, -c * 0.6, 0], "z"))
-    }
-});
-Ext.define("Ext.draw.sprite.Composite", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.composite",
-    type: "composite",
-    isComposite: true,
-    config: {
-        sprites: []
-    },
-    constructor: function() {
-        this.sprites = [];
-        this.sprites.map = {};
-        this.callParent(arguments)
-    },
-    add: function(c) {
-        if (!c) {
-            return null
-        }
-        if (!c.isSprite) {
-            c = Ext.create("sprite." + c.type, c);
-            c.setParent(this);
-            c.setSurface(this.getSurface())
-        }
-        var d = this,
-            a = d.attr,
-            b = c.applyTransformations;
-        c.applyTransformations = function() {
-            if (c.attr.dirtyTransform) {
-                a.dirtyTransform = true;
-                a.bbox.plain.dirty = true;
-                a.bbox.transform.dirty = true
-            }
-            b.call(c)
-        };
-        d.sprites.push(c);
-        d.sprites.map[c.id] = c.getId();
-        a.bbox.plain.dirty = true;
-        a.bbox.transform.dirty = true;
-        return c
-    },
-    updateSurface: function(a) {
-        for (var b = 0, c = this.sprites.length; b < c; b++) {
-            this.sprites[b].setSurface(a)
-        }
-    },
-    addAll: function(b) {
-        if (b.isSprite || b.type) {
-            this.add(b)
-        } else {
-            if (Ext.isArray(b)) {
-                var a = 0;
-                while (a < b.length) {
-                    this.add(b[a++])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(g) {
-        var e = this,
-            b = Infinity,
-            h = -Infinity,
-            f = Infinity,
-            a = -Infinity,
-            j, k, c, d;
-        for (c = 0, d = e.sprites.length; c < d; c++) {
-            j = e.sprites[c];
-            j.applyTransformations();
-            k = j.getBBox();
-            if (b > k.x) {
-                b = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (f > k.y) {
-                f = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        g.x = b;
-        g.y = f;
-        g.width = h - b;
-        g.height = a - f
-    },
-    render: function(a, b, f) {
-        var d = this.attr.matrix,
-            c, e;
-        d.toContext(b);
-        for (c = 0, e = this.sprites.length; c < e; c++) {
-            a.renderSprite(this.sprites[c], f)
-        }
-    },
-    destroy: function() {
-        var c = this,
-            d = c.sprites,
-            b = d.length,
-            a;
-        c.callParent();
-        for (a = 0; a < b; a++) {
-            d[a].destroy()
-        }
-        d.length = 0
-    }
-});
-Ext.define("Ext.draw.sprite.Cross", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.cross",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.7,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c, ",", e, "l", [-c, -c, c, -c, c, c, c, -c, c, c, -c, c, c, c, -c, c, -c, -c, -c, c, -c, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Diamond", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.diamond",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.25,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString(["M", a, e - c, "l", c, c, -c, c, -c, -c, c, -c, "z"])
-    }
-});
-Ext.define("Ext.draw.sprite.Ellipse", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.ellipse",
-    type: "ellipse",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                rx: "number",
-                ry: "number",
-                axisRotation: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy",
-                radiusX: "rx",
-                radiusY: "ry"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                rx: 1,
-                ry: 1,
-                axisRotation: 0
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                rx: "path",
-                ry: "path",
-                axisRotation: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            f = b.cy,
-            e = b.rx,
-            d = b.ry;
-        c.x = a - e;
-        c.y = f - d;
-        c.width = e + e;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var i = this.attr,
-            f = i.cx,
-            e = i.cy,
-            c = i.rx,
-            b = i.ry,
-            l = b / c,
-            m = i.matrix.clone(),
-            a, q, k, j, p, o, n, g;
-        m.append(1, 0, 0, l, 0, e * (1 - l));
-        a = m.getXX();
-        k = m.getYX();
-        p = m.getDX();
-        q = m.getXY();
-        j = m.getYY();
-        o = m.getDY();
-        n = Math.sqrt(a * a + k * k) * c;
-        g = Math.sqrt(q * q + j * j) * c;
-        d.x = f * a + e * k + p - n;
-        d.y = f * q + e * j + o - g;
-        d.width = n + n;
-        d.height = g + g
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.EllipticalArc", {
-    extend: "Ext.draw.sprite.Ellipse",
-    alias: "sprite.ellipticalArc",
-    type: "ellipticalArc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Rect", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.rect",
-    type: "rect",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                radius: "number"
-            },
-            aliases: {},
-            triggers: {
-                x: "path",
-                y: "path",
-                width: "path",
-                height: "path",
-                radius: "path"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                radius: 0
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.x;
-        b.y = a.y;
-        b.width = a.width;
-        b.height = a.height
-    },
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, this.attr.radius, a)
-    },
-    updatePath: function(f, d) {
-        var c = d.x,
-            g = d.y,
-            e = d.width,
-            b = d.height,
-            a = Math.min(d.radius, Math.abs(d.height) * 0.5, Math.abs(d.width) * 0.5);
-        if (a === 0) {
-            f.rect(c, g, e, b)
-        } else {
-            f.moveTo(c + a, g);
-            f.arcTo(c + e, g, c + e, g + b, a);
-            f.arcTo(c + e, g + b, c, g + b, a);
-            f.arcTo(c, g + b, c, g, a);
-            f.arcTo(c, g, c + a, g, a)
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Image", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.image",
-    type: "image",
-    statics: {
-        imageLoaders: {}
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                src: "string"
-            },
-            defaults: {
-                src: "",
-                width: null,
-                height: null
-            }
-        }
-    },
-    render: function(c, o) {
-        var j = this,
-            h = j.attr,
-            n = h.matrix,
-            a = h.src,
-            l = h.x,
-            k = h.y,
-            b = h.width,
-            m = h.height,
-            g = Ext.draw.sprite.Image.imageLoaders[a],
-            f, d, e;
-        if (g && g.done) {
-            n.toContext(o);
-            d = g.image;
-            o.drawImage(d, l, k, b || (d.naturalWidth || d.width) / c.devicePixelRatio, m || (d.naturalHeight || d.height) / c.devicePixelRatio)
-        } else {
-            if (!g) {
-                f = new Image();
-                g = Ext.draw.sprite.Image.imageLoaders[a] = {
-                    image: f,
-                    done: false,
-                    pendingSprites: [j],
-                    pendingSurfaces: [c]
-                };
-                f.width = b;
-                f.height = m;
-                f.onload = function() {
-                    if (!g.done) {
-                        g.done = true;
-                        for (e = 0; e < g.pendingSprites.length; e++) {
-                            g.pendingSprites[e].setDirty(true)
-                        }
-                        for (e in g.pendingSurfaces) {
-                            g.pendingSurfaces[e].renderFrame()
-                        }
-                    }
-                };
-                f.src = a
-            } else {
-                Ext.Array.include(g.pendingSprites, j);
-                Ext.Array.include(g.pendingSurfaces, c)
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Instancing", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.instancing",
-    type: "instancing",
-    isInstancing: true,
-    config: {
-        template: null
-    },
-    instances: null,
-    applyTemplate: function(a) {
-        if (!a.isSprite) {
-            if (!a.xclass && !a.type) {
-                a.type = "circle"
-            }
-            a = Ext.create(a.xclass || "sprite." + a.type, a)
-        }
-        a.setParent(this);
-        return a
-    },
-    updateTemplate: function(a, b) {
-        if (b) {
-            delete b.ownAttr
-        }
-        a.setSurface(this.getSurface());
-        a.ownAttr = a.attr;
-        this.clearAll()
-    },
-    updateSurface: function(a) {
-        var b = this.getTemplate();
-        if (b) {
-            b.setSurface(a)
-        }
-    },
-    get: function(a) {
-        return this.instances[a]
-    },
-    getCount: function() {
-        return this.instances.length
-    },
-    clearAll: function() {
-        var a = this.getTemplate();
-        a.attr.children = this.instances = [];
-        this.position = 0
-    },
-    createInstance: function(d, f, c) {
-        var e = this.getTemplate(),
-            b = e.attr,
-            a = Ext.Object.chain(b);
-        e.topModifier.prepareAttributes(a);
-        e.attr = a;
-        e.setAttributes(d, f, c);
-        a.template = e;
-        this.instances.push(a);
-        e.attr = b;
-        this.position++;
-        return a
-    },
-    getBBox: function() {
-        return null
-    },
-    getBBoxFor: function(b, d) {
-        var c = this.getTemplate(),
-            a = c.attr,
-            e;
-        c.attr = this.instances[b];
-        e = c.getBBox(d);
-        c.attr = a;
-        return e
-    },
-    isVisible: function() {
-        var b = this.attr,
-            c = this.getParent(),
-            a;
-        a = c && c.isSurface && !b.hidden && b.globalAlpha;
-        return !!a
-    },
-    isInstanceVisible: function(c) {
-        var e = this,
-            d = e.getTemplate(),
-            b = d.attr,
-            f = e.instances,
-            a = false;
-        if (!Ext.isNumber(c) || c < 0 || c >= f.length || !e.isVisible()) {
-            return a
-        }
-        d.attr = f[c];
-        a = d.isVisible(point, options);
-        d.attr = b;
-        return a
-    },
-    render: function(b, l, d, h) {
-        var g = this,
-            j = g.getTemplate(),
-            k = g.attr.matrix,
-            c = j.attr,
-            a = g.instances,
-            e, f = g.position;
-        k.toContext(l);
-        j.preRender(b, l, d, h);
-        j.useAttributes(l, h);
-        for (e = 0; e < f; e++) {
-            if (a[e].dirtyZIndex) {
-                break
-            }
-        }
-        for (e = 0; e < f; e++) {
-            if (a[e].hidden) {
-                continue
-            }
-            l.save();
-            j.attr = a[e];
-            j.useAttributes(l, h);
-            j.render(b, l, d, h);
-            l.restore()
-        }
-        j.attr = c
-    },
-    setAttributesFor: function(c, e, f) {
-        var d = this.getTemplate(),
-            b = d.attr,
-            a = this.instances[c];
-        if (!a) {
-            return
-        }
-        d.attr = a;
-        if (f) {
-            e = Ext.apply({}, e)
-        } else {
-            e = d.self.def.normalize(e)
-        }
-        d.topModifier.pushDown(a, e);
-        d.attr = b
-    },
-    destroy: function() {
-        var b = this,
-            a = b.getTemplate();
-        b.instances = null;
-        if (a) {
-            a.destroy()
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.sprite.Instancing", {
-    override: "Ext.draw.sprite.Instancing",
-    hitTest: function(f, j) {
-        var e = this,
-            g = e.getTemplate(),
-            b = g.attr,
-            a = e.instances,
-            d = a.length,
-            c = 0,
-            h = null;
-        if (!e.isVisible()) {
-            return h
-        }
-        for (; c < d; c++) {
-            g.attr = a[c];
-            h = g.hitTest(f, j);
-            if (h) {
-                h.isInstance = true;
-                h.template = h.sprite;
-                h.sprite = this;
-                h.instance = a[c];
-                h.index = c;
-                return h
-            }
-        }
-        g.attr = b;
-        return h
-    }
-});
-Ext.define("Ext.draw.sprite.Line", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.line",
-    type: "line",
-    inheritableStatics: {
-        def: {
-            processors: {
-                fromX: "number",
-                fromY: "number",
-                toX: "number",
-                toY: "number"
-            },
-            defaults: {
-                fromX: 0,
-                fromY: 0,
-                toX: 1,
-                toY: 1,
-                strokeStyle: "black"
-            },
-            aliases: {
-                x1: "fromX",
-                y1: "fromY",
-                x2: "toX",
-                y2: "toY"
-            }
-        }
-    },
-    updateLineBBox: function(b, i, s, g, r, f) {
-        var o = this.attr,
-            q = o.matrix,
-            h = o.lineWidth / 2,
-            m, l, d, c, k, j, n;
-        if (i) {
-            n = q.transformPoint([s, g]);
-            s = n[0];
-            g = n[1];
-            n = q.transformPoint([r, f]);
-            r = n[0];
-            f = n[1]
-        }
-        m = Math.min(s, r);
-        d = Math.max(s, r);
-        l = Math.min(g, f);
-        c = Math.max(g, f);
-        var t = Math.atan2(d - m, c - l),
-            a = Math.sin(t),
-            e = Math.cos(t),
-            k = h * e,
-            j = h * a;
-        m -= k;
-        l -= j;
-        d += k;
-        c += j;
-        b.x = m;
-        b.y = l;
-        b.width = d - m;
-        b.height = c - l
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        this.updateLineBBox(b, false, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    updateTransformedBBox: function(b, c) {
-        var a = this.attr;
-        this.updateLineBBox(b, true, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    render: function(b, c) {
-        var a = this.attr,
-            d = this.attr.matrix;
-        d.toContext(c);
-        c.beginPath();
-        c.moveTo(a.fromX, a.fromY);
-        c.lineTo(a.toX, a.toY);
-        c.stroke()
-    }
-});
-Ext.define("Ext.draw.sprite.Plus", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.plus",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.3,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c / 2, ",", e - c / 2, "l", [0, -c, c, 0, 0, c, c, 0, 0, c, -c, 0, 0, c, -c, 0, 0, -c, -c, 0, 0, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Sector", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.sector",
-    type: "sector",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,bbox",
-                endAngle: "path,bbox",
-                startRho: "path,bbox",
-                endRho: "path,bbox",
-                margin: "path,bbox"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: 0,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                path: "M 0,0"
-            }
-        }
-    },
-    getMidAngle: function() {
-        return this.midAngle || 0
-    },
-    updatePath: function(j, h) {
-        var g = Math.min(h.startAngle, h.endAngle),
-            c = Math.max(h.startAngle, h.endAngle),
-            b = this.midAngle = (g + c) * 0.5,
-            d = h.margin,
-            f = h.centerX,
-            e = h.centerY,
-            i = Math.min(h.startRho, h.endRho),
-            a = Math.max(h.startRho, h.endRho);
-        if (d) {
-            f += d * Math.cos(b);
-            e += d * Math.sin(b)
-        }
-        j.moveTo(f + i * Math.cos(g), e + i * Math.sin(g));
-        j.lineTo(f + a * Math.cos(g), e + a * Math.sin(g));
-        j.arc(f, e, a, g, c, false);
-        j.lineTo(f + i * Math.cos(c), e + i * Math.sin(c));
-        j.arc(f, e, i, c, g, true)
-    }
-});
-Ext.define("Ext.draw.sprite.Square", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.square",
-    inheritableStatics: {
-        def: {
-            processors: {
-                size: "number"
-            },
-            defaults: {
-                size: 4
-            },
-            triggers: {
-                size: "size"
-            },
-            updaters: {
-                size: function(a) {
-                    var c = a.size,
-                        b = a.lineWidth / 2;
-                    this.setAttributes({
-                        x: a.x - c - b,
-                        y: a.y - c,
-                        height: 2 * c,
-                        width: 2 * c
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.TextMeasurer", {
-    singleton: true,
-    requires: ["Ext.util.TextMetrics"],
-    measureDiv: null,
-    measureCache: {},
-    precise: Ext.isIE8,
-    measureDivTpl: {
-        tag: "div",
-        style: {
-            overflow: "hidden",
-            position: "relative",
-            "float": "left",
-            width: 0,
-            height: 0
-        },
-        children: {
-            tag: "div",
-            style: {
-                display: "block",
-                position: "absolute",
-                x: -100000,
-                y: -100000,
-                padding: 0,
-                margin: 0,
-                "z-index": -100000,
-                "white-space": "nowrap"
-            }
-        }
-    },
-    actualMeasureText: function(g, b) {
-        var e = Ext.draw.TextMeasurer,
-            f = e.measureDiv,
-            a = 100000,
-            c;
-        if (!f) {
-            var d = Ext.Element.create({
-                style: {
-                    overflow: "hidden",
-                    position: "relative",
-                    "float": "left",
-                    width: 0,
-                    height: 0
-                }
-            });
-            e.measureDiv = f = Ext.Element.create({
-                style: {
-                    position: "absolute",
-                    x: a,
-                    y: a,
-                    "z-index": -a,
-                    "white-space": "nowrap",
-                    display: "block",
-                    padding: 0,
-                    margin: 0
-                }
-            });
-            Ext.getBody().appendChild(d);
-            d.appendChild(f)
-        }
-        if (b) {
-            f.setStyle({
-                font: b,
-                lineHeight: "normal"
-            })
-        }
-        f.setText("(" + g + ")");
-        c = f.getSize();
-        f.setText("()");
-        c.width -= f.getSize().width;
-        return c
-    },
-    measureTextSingleLine: function(h, d) {
-        if (this.precise) {
-            return this.preciseMeasureTextSingleLine(h, d)
-        }
-        h = h.toString();
-        var a = this.measureCache,
-            g = h.split(""),
-            c = 0,
-            j = 0,
-            l, b, e, f, k;
-        if (!a[d]) {
-            a[d] = {}
-        }
-        a = a[d];
-        if (a[h]) {
-            return a[h]
-        }
-        for (e = 0, f = g.length; e < f; e++) {
-            b = g[e];
-            if (!(l = a[b])) {
-                k = this.actualMeasureText(b, d);
-                l = a[b] = k
-            }
-            c += l.width;
-            j = Math.max(j, l.height)
-        }
-        return a[h] = {
-            width: c,
-            height: j
-        }
-    },
-    preciseMeasureTextSingleLine: function(c, a) {
-        c = c.toString();
-        var b = this.measureDiv || (this.measureDiv = Ext.getBody().createChild(this.measureDivTpl).down("div"));
-        b.setStyle({
-            font: a || ""
-        });
-        return Ext.util.TextMetrics.measure(b, c)
-    },
-    measureText: function(e, b) {
-        var h = e.split("\n"),
-            d = h.length,
-            f = 0,
-            a = 0,
-            j, c, g;
-        if (d === 1) {
-            return this.measureTextSingleLine(e, b)
-        }
-        g = [];
-        for (c = 0; c < d; c++) {
-            j = this.measureTextSingleLine(h[c], b);
-            g.push(j);
-            f += j.height;
-            a = Math.max(a, j.width)
-        }
-        return {
-            width: a,
-            height: f,
-            sizes: g
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Text", function() {
-    var d = {
-        "xx-small": true,
-        "x-small": true,
-        small: true,
-        medium: true,
-        large: true,
-        "x-large": true,
-        "xx-large": true
-    };
-    var b = {
-        normal: true,
-        bold: true,
-        bolder: true,
-        lighter: true,
-        100: true,
-        200: true,
-        300: true,
-        400: true,
-        500: true,
-        600: true,
-        700: true,
-        800: true,
-        900: true
-    };
-    var a = {
-        start: "start",
-        left: "start",
-        center: "center",
-        middle: "center",
-        end: "end",
-        right: "end"
-    };
-    var c = {
-        top: "top",
-        hanging: "hanging",
-        middle: "middle",
-        center: "middle",
-        alphabetic: "alphabetic",
-        ideographic: "ideographic",
-        bottom: "bottom"
-    };
-    return {
-        extend: "Ext.draw.sprite.Sprite",
-        requires: ["Ext.draw.TextMeasurer", "Ext.draw.Color"],
-        alias: "sprite.text",
-        type: "text",
-        lineBreakRe: /\r?\n/g,
-        inheritableStatics: {
-            def: {
-                animationProcessors: {
-                    text: "text"
-                },
-                processors: {
-                    x: "number",
-                    y: "number",
-                    text: "string",
-                    fontSize: function(e) {
-                        if (Ext.isNumber(+e)) {
-                            return e + "px"
-                        } else {
-                            if (e.match(Ext.dom.Element.unitRe)) {
-                                return e
-                            } else {
-                                if (e in d) {
-                                    return e
-                                }
-                            }
-                        }
-                    },
-                    fontStyle: "enums(,italic,oblique)",
-                    fontVariant: "enums(,small-caps)",
-                    fontWeight: function(e) {
-                        if (e in b) {
-                            return String(e)
-                        } else {
-                            return ""
-                        }
-                    },
-                    fontFamily: "string",
-                    textAlign: function(e) {
-                        return a[e] || "center"
-                    },
-                    textBaseline: function(e) {
-                        return c[e] || "alphabetic"
-                    },
-                    font: "string"
-                },
-                aliases: {
-                    "font-size": "fontSize",
-                    "font-family": "fontFamily",
-                    "font-weight": "fontWeight",
-                    "font-variant": "fontVariant",
-                    "text-anchor": "textAlign"
-                },
-                defaults: {
-                    fontStyle: "",
-                    fontVariant: "",
-                    fontWeight: "",
-                    fontSize: "10px",
-                    fontFamily: "sans-serif",
-                    font: "10px sans-serif",
-                    textBaseline: "alphabetic",
-                    textAlign: "start",
-                    strokeStyle: "rgba(0, 0, 0, 0)",
-                    fillStyle: "#000",
-                    x: 0,
-                    y: 0,
-                    text: ""
-                },
-                triggers: {
-                    fontStyle: "fontX,bbox",
-                    fontVariant: "fontX,bbox",
-                    fontWeight: "fontX,bbox",
-                    fontSize: "fontX,bbox",
-                    fontFamily: "fontX,bbox",
-                    font: "font,bbox,canvas",
-                    textBaseline: "bbox",
-                    textAlign: "bbox",
-                    x: "bbox",
-                    y: "bbox",
-                    text: "bbox"
-                },
-                updaters: {
-                    fontX: "makeFontShorthand",
-                    font: "parseFontShorthand"
-                }
-            }
-        },
-        constructor: function(e) {
-            if (e && e.font) {
-                e = Ext.clone(e);
-                for (var f in e) {
-                    if (f !== "font" && f.indexOf("font") === 0) {
-                        delete e[f]
-                    }
-                }
-            }
-            Ext.draw.sprite.Sprite.prototype.constructor.call(this, e)
-        },
-        fontValuesMap: {
-            italic: "fontStyle",
-            oblique: "fontStyle",
-            "small-caps": "fontVariant",
-            bold: "fontWeight",
-            bolder: "fontWeight",
-            lighter: "fontWeight",
-            "100": "fontWeight",
-            "200": "fontWeight",
-            "300": "fontWeight",
-            "400": "fontWeight",
-            "500": "fontWeight",
-            "600": "fontWeight",
-            "700": "fontWeight",
-            "800": "fontWeight",
-            "900": "fontWeight",
-            "xx-small": "fontSize",
-            "x-small": "fontSize",
-            small: "fontSize",
-            medium: "fontSize",
-            large: "fontSize",
-            "x-large": "fontSize",
-            "xx-large": "fontSize"
-        },
-        makeFontShorthand: function(e) {
-            var f = [];
-            if (e.fontStyle) {
-                f.push(e.fontStyle)
-            }
-            if (e.fontVariant) {
-                f.push(e.fontVariant)
-            }
-            if (e.fontWeight) {
-                f.push(e.fontWeight)
-            }
-            if (e.fontSize) {
-                f.push(e.fontSize)
-            }
-            if (e.fontFamily) {
-                f.push(e.fontFamily)
-            }
-            this.setAttributes({
-                font: f.join(" ")
-            }, true)
-        },
-        parseFontShorthand: function(j) {
-            var m = j.font,
-                k = m.length,
-                l = {},
-                n = this.fontValuesMap,
-                e = 0,
-                i, g, f, h;
-            while (e < k && i !== -1) {
-                i = m.indexOf(" ", e);
-                if (i < 0) {
-                    f = m.substr(e)
-                } else {
-                    if (i > e) {
-                        f = m.substr(e, i - e)
-                    } else {
-                        continue
-                    }
-                }
-                g = f.indexOf("/");
-                if (g > 0) {
-                    f = f.substr(0, g)
-                } else {
-                    if (g === 0) {
-                        continue
-                    }
-                }
-                if (f !== "normal" && f !== "inherit") {
-                    h = n[f];
-                    if (h) {
-                        l[h] = f
-                    } else {
-                        if (f.match(Ext.dom.Element.unitRe)) {
-                            l.fontSize = f
-                        } else {
-                            l.fontFamily = m.substr(e);
-                            break
-                        }
-                    }
-                }
-                e = i + 1
-            }
-            if (!l.fontStyle) {
-                l.fontStyle = ""
-            }
-            if (!l.fontVariant) {
-                l.fontVariant = ""
-            }
-            if (!l.fontWeight) {
-                l.fontWeight = ""
-            }
-            this.setAttributes(l, true)
-        },
-        fontProperties: {
-            fontStyle: true,
-            fontVariant: true,
-            fontWeight: true,
-            fontSize: true,
-            fontFamily: true
-        },
-        setAttributes: function(g, i, e) {
-            var f, h;
-            if (g && g.font) {
-                h = {};
-                for (f in g) {
-                    if (!(f in this.fontProperties)) {
-                        h[f] = g[f]
-                    }
-                }
-                g = h
-            }
-            this.callParent([g, i, e])
-        },
-        getBBox: function(g) {
-            var h = this,
-                f = h.attr.bbox.plain,
-                e = h.getSurface();
-            if (f.dirty) {
-                h.updatePlainBBox(f);
-                f.dirty = false
-            }
-            if (e.getInherited().rtl && e.getFlipRtlText()) {
-                h.updatePlainBBox(f, true)
-            }
-            return h.callParent([g])
-        },
-        rtlAlignments: {
-            start: "end",
-            center: "center",
-            end: "start"
-        },
-        updatePlainBBox: function(k, B) {
-            var C = this,
-                w = C.attr,
-                o = w.x,
-                n = w.y,
-                q = [],
-                t = w.font,
-                r = w.text,
-                s = w.textBaseline,
-                l = w.textAlign,
-                u = (B && C.oldSize) ? C.oldSize : (C.oldSize = Ext.draw.TextMeasurer.measureText(r, t)),
-                z = C.getSurface(),
-                p = z.getInherited().rtl,
-                v = p && z.getFlipRtlText(),
-                h = z.getRect(),
-                f = u.sizes,
-                g = u.height,
-                j = u.width,
-                m = f ? f.length : 0,
-                e, A = 0;
-            switch (s) {
-                case "hanging":
-                case "top":
-                    break;
-                case "ideographic":
-                case "bottom":
-                    n -= g;
-                    break;
-                case "alphabetic":
-                    n -= g * 0.8;
-                    break;
-                case "middle":
-                    n -= g * 0.5;
-                    break
-            }
-            if (v) {
-                o = h[2] - h[0] - o;
-                l = C.rtlAlignments[l]
-            }
-            switch (l) {
-                case "start":
-                    if (p) {
-                        for (; A < m; A++) {
-                            e = f[A].width;
-                            q.push(-(j - e))
-                        }
-                    }
-                    break;
-                case "end":
-                    o -= j;
-                    if (p) {
-                        break
-                    }
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push(j - e)
-                    }
-                    break;
-                case "center":
-                    o -= j * 0.5;
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push((p ? -1 : 1) * (j - e) * 0.5)
-                    }
-                    break
-            }
-            w.textAlignOffsets = q;
-            k.x = o;
-            k.y = n;
-            k.width = j;
-            k.height = g
-        },
-        setText: function(e) {
-            this.setAttributes({
-                text: e
-            }, true)
-        },
-        render: function(e, q, k) {
-            var h = this,
-                g = h.attr,
-                p = Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),
-                o = h.getBBox(true),
-                s = g.textAlignOffsets,
-                m = Ext.draw.Color.RGBA_NONE,
-                l, j, f, r, n;
-            if (g.text.length === 0) {
-                return
-            }
-            r = g.text.split(h.lineBreakRe);
-            n = o.height / r.length;
-            l = g.bbox.plain.x;
-            j = g.bbox.plain.y + n * 0.78;
-            p.toContext(q);
-            if (e.getInherited().rtl) {
-                l += g.bbox.plain.width
-            }
-            for (f = 0; f < r.length; f++) {
-                if (q.fillStyle !== m) {
-                    q.fillText(r[f], l + (s[f] || 0), j + n * f)
-                }
-                if (q.strokeStyle !== m) {
-                    q.strokeText(r[f], l + (s[f] || 0), j + n * f)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Tick", {
-    extend: "Ext.draw.sprite.Line",
-    alias: "sprite.tick",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "tick",
-                y: "tick",
-                size: "tick"
-            },
-            updaters: {
-                tick: function(b) {
-                    var d = b.size * 1.5,
-                        c = b.lineWidth / 2,
-                        a = b.x,
-                        e = b.y;
-                    this.setAttributes({
-                        fromX: a - c,
-                        fromY: e - d,
-                        toX: a - c,
-                        toY: e + d
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Triangle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.triangle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 2.2,
-            a = b.x,
-            e = b.y;
-        d.fromSvgString("M".concat(a, ",", e, "m0-", c * 0.58, "l", c * 0.5, ",", c * 0.87, "-", c, ",0z"))
-    }
-});
-Ext.define("Ext.draw.gradient.Linear", {
-    extend: "Ext.draw.gradient.Gradient",
-    requires: ["Ext.draw.Color"],
-    type: "linear",
-    config: {
-        degrees: 0,
-        radians: 0
-    },
-    applyRadians: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    applyDegrees: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    updateRadians: function(a) {
-        this.setDegrees(Ext.draw.Draw.degrees(a))
-    },
-    updateDegrees: function(a) {
-        this.setRadians(Ext.draw.Draw.rad(a))
-    },
-    generateGradient: function(q, o) {
-        var c = this.getRadians(),
-            p = Math.cos(c),
-            j = Math.sin(c),
-            m = o.width,
-            f = o.height,
-            d = o.x + m * 0.5,
-            b = o.y + f * 0.5,
-            n = this.getStops(),
-            g = n.length,
-            k, a, e;
-        if (Ext.isNumber(d + b) && f > 0 && m > 0) {
-            a = (Math.sqrt(f * f + m * m) * Math.abs(Math.cos(c - Math.atan(f / m)))) / 2;
-            k = q.createLinearGradient(d + p * a, b + j * a, d - p * a, b - j * a);
-            for (e = 0; e < g; e++) {
-                k.addColorStop(n[e].offset, n[e].color)
-            }
-            return k
-        }
-        return Ext.draw.Color.NONE
-    }
-});
-Ext.define("Ext.draw.gradient.Radial", {
-    extend: "Ext.draw.gradient.Gradient",
-    type: "radial",
-    config: {
-        start: {
-            x: 0,
-            y: 0,
-            r: 0
-        },
-        end: {
-            x: 0,
-            y: 0,
-            r: 1
-        }
-    },
-    applyStart: function(a, b) {
-        if (!b) {
-            return a
-        }
-        var c = {
-            x: b.x,
-            y: b.y,
-            r: b.r
-        };
-        if ("x" in a) {
-            c.x = a.x
-        } else {
-            if ("centerX" in a) {
-                c.x = a.centerX
-            }
-        }
-        if ("y" in a) {
-            c.y = a.y
-        } else {
-            if ("centerY" in a) {
-                c.y = a.centerY
-            }
-        }
-        if ("r" in a) {
-            c.r = a.r
-        } else {
-            if ("radius" in a) {
-                c.r = a.radius
-            }
-        }
-        return c
-    },
-    applyEnd: function(b, a) {
-        if (!a) {
-            return b
-        }
-        var c = {
-            x: a.x,
-            y: a.y,
-            r: a.r
-        };
-        if ("x" in b) {
-            c.x = b.x
-        } else {
-            if ("centerX" in b) {
-                c.x = b.centerX
-            }
-        }
-        if ("y" in b) {
-            c.y = b.y
-        } else {
-            if ("centerY" in b) {
-                c.y = b.centerY
-            }
-        }
-        if ("r" in b) {
-            c.r = b.r
-        } else {
-            if ("radius" in b) {
-                c.r = b.radius
-            }
-        }
-        return c
-    },
-    generateGradient: function(n, m) {
-        var a = this.getStart(),
-            b = this.getEnd(),
-            k = m.width * 0.5,
-            d = m.height * 0.5,
-            j = m.x + k,
-            f = m.y + d,
-            g = n.createRadialGradient(j + a.x * k, f + a.y * d, a.r * Math.max(k, d), j + b.x * k, f + b.y * d, b.r * Math.max(k, d)),
-            l = this.getStops(),
-            e = l.length,
-            c;
-        for (c = 0; c < e; c++) {
-            g.addColorStop(l[c].offset, l[c].color)
-        }
-        return g
-    }
-});
-Ext.define("Ext.draw.Surface", {
-    extend: "Ext.draw.SurfaceBase",
-    xtype: "surface",
-    requires: ["Ext.draw.sprite.*", "Ext.draw.gradient.*", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.Matrix", "Ext.draw.Draw"],
-    uses: ["Ext.draw.engine.Canvas"],
-    devicePixelRatio: window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI,
-    deprecated: {
-        "5.1.0": {
-            statics: {
-                methods: {
-                    stableSort: function(a) {
-                        return Ext.Array.sort(a, function(d, c) {
-                            return d.attr.zIndex - c.attr.zIndex
-                        })
-                    }
-                }
-            }
-        }
-    },
-    config: {
-        cls: Ext.baseCSSPrefix + "surface",
-        rect: null,
-        background: null,
-        items: [],
-        dirty: false,
-        flipRtlText: false
-    },
-    isSurface: true,
-    isPendingRenderFrame: false,
-    dirtyPredecessorCount: 0,
-    constructor: function(a) {
-        var b = this;
-        b.predecessors = [];
-        b.successors = [];
-        b.map = {};
-        b.callParent([a]);
-        b.matrix = new Ext.draw.Matrix();
-        b.inverseMatrix = b.matrix.inverse()
-    },
-    roundPixel: function(a) {
-        return Math.round(this.devicePixelRatio * a) / this.devicePixelRatio
-    },
-    waitFor: function(a) {
-        var b = this,
-            c = b.predecessors;
-        if (!Ext.Array.contains(c, a)) {
-            c.push(a);
-            a.successors.push(b);
-            if (a.getDirty()) {
-                b.dirtyPredecessorCount++
-            }
-        }
-    },
-    updateDirty: function(d) {
-        var c = this.successors,
-            e = c.length,
-            b = 0,
-            a;
-        for (; b < e; b++) {
-            a = c[b];
-            if (d) {
-                a.dirtyPredecessorCount++;
-                a.setDirty(true)
-            } else {
-                a.dirtyPredecessorCount--;
-                if (a.dirtyPredecessorCount === 0 && a.isPendingRenderFrame) {
-                    a.renderFrame()
-                }
-            }
-        }
-    },
-    applyBackground: function(a, b) {
-        this.setDirty(true);
-        if (Ext.isString(a)) {
-            a = {
-                fillStyle: a
-            }
-        }
-        return Ext.factory(a, Ext.draw.sprite.Rect, b)
-    },
-    applyRect: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return
-        }
-        if (Ext.isArray(a)) {
-            return [a[0], a[1], a[2], a[3]]
-        } else {
-            if (Ext.isObject(a)) {
-                return [a.x || a.left, a.y || a.top, a.width || (a.right - a.left), a.height || (a.bottom - a.top)]
-            }
-        }
-    },
-    updateRect: function(i) {
-        var h = this,
-            c = i[0],
-            f = i[1],
-            g = c + i[2],
-            a = f + i[3],
-            e = h.getBackground(),
-            d = h.element;
-        d.setLocalXY(Math.floor(c), Math.floor(f));
-        d.setSize(Math.ceil(g - Math.floor(c)), Math.ceil(a - Math.floor(f)));
-        if (e) {
-            e.setAttributes({
-                x: 0,
-                y: 0,
-                width: Math.ceil(g - Math.floor(c)),
-                height: Math.ceil(a - Math.floor(f))
-            })
-        }
-        h.setDirty(true)
-    },
-    resetTransform: function() {
-        this.matrix.set(1, 0, 0, 1, 0, 0);
-        this.inverseMatrix.set(1, 0, 0, 1, 0, 0);
-        this.setDirty(true)
-    },
-    get: function(a) {
-        return this.map[a] || this.getItems()[a]
-    },
-    add: function() {
-        var g = this,
-            e = Array.prototype.slice.call(arguments),
-            j = Ext.isArray(e[0]),
-            a = g.map,
-            c = [],
-            f, k, h, b, d;
-        f = Ext.Array.clean(j ? e[0] : e);
-        if (!f.length) {
-            return c
-        }
-        for (b = 0, d = f.length; b < d; b++) {
-            k = f[b];
-            h = null;
-            if (k.isSprite && !a[k.getId()]) {
-                h = k
-            } else {
-                if (!a[k.id]) {
-                    h = this.createItem(k)
-                }
-            }
-            if (h) {
-                a[h.getId()] = h;
-                c.push(h);
-                h.setParent(g);
-                h.setSurface(g);
-                g.onAdd(h)
-            }
-        }
-        f = g.getItems();
-        if (f) {
-            f.push.apply(f, c)
-        }
-        g.dirtyZIndex = true;
-        g.setDirty(true);
-        if (!j && c.length === 1) {
-            return c[0]
-        } else {
-            return c
-        }
-    },
-    onAdd: Ext.emptyFn,
-    remove: function(a, c) {
-        var b = this,
-            e, d;
-        if (a) {
-            if (a.charAt) {
-                a = b.map[a]
-            }
-            if (!a || !a.isSprite) {
-                return null
-            }
-            if (a.isDestroyed || a.isDestroying) {
-                return a
-            }
-            e = a.getId();
-            d = b.map[e];
-            delete b.map[e];
-            if (c) {
-                a.destroy()
-            }
-            if (!d) {
-                return a
-            }
-            a.setParent(null);
-            a.setSurface(null);
-            Ext.Array.remove(b.getItems(), a);
-            b.dirtyZIndex = true;
-            b.setDirty(true)
-        }
-        return a || null
-    },
-    removeAll: function(d) {
-        var a = this.getItems(),
-            b = a.length - 1,
-            c;
-        if (d) {
-            for (; b >= 0; b--) {
-                a[b].destroy()
-            }
-        } else {
-            for (; b >= 0; b--) {
-                c = a[b];
-                c.setParent(null);
-                c.setSurface(null)
-            }
-        }
-        a.length = 0;
-        this.map = {};
-        this.dirtyZIndex = true
-    },
-    applyItems: function(a) {
-        if (this.getItems()) {
-            this.removeAll(true)
-        }
-        return Ext.Array.from(this.add(a))
-    },
-    createItem: function(a) {
-        return Ext.create(a.xclass || "sprite." + a.type, a)
-    },
-    getBBox: function(f, b) {
-        var f = Ext.Array.from(f),
-            c = Infinity,
-            h = -Infinity,
-            g = Infinity,
-            a = -Infinity,
-            j, k, d, e;
-        for (d = 0, e = f.length; d < e; d++) {
-            j = f[d];
-            k = j.getBBox(b);
-            if (c > k.x) {
-                c = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (g > k.y) {
-                g = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        return {
-            x: c,
-            y: g,
-            width: h - c,
-            height: a - g
-        }
-    },
-    emptyRect: [0, 0, 0, 0],
-    getEventXY: function(d) {
-        var g = this,
-            f = g.getInherited().rtl,
-            c = d.getXY(),
-            a = g.getOwnerBody(),
-            i = a.getXY(),
-            h = g.getRect() || g.emptyRect,
-            j = [],
-            b;
-        if (f) {
-            b = a.getWidth();
-            j[0] = i[0] - c[0] - h[0] + b
-        } else {
-            j[0] = c[0] - i[0] - h[0]
-        }
-        j[1] = c[1] - i[1] - h[1];
-        return j
-    },
-    clear: Ext.emptyFn,
-    orderByZIndex: function() {
-        var d = this,
-            a = d.getItems(),
-            e = false,
-            b, c;
-        if (d.getDirty()) {
-            for (b = 0, c = a.length; b < c; b++) {
-                if (a[b].attr.dirtyZIndex) {
-                    e = true;
-                    break
-                }
-            }
-            if (e) {
-                Ext.Array.sort(a, function(g, f) {
-                    return g.attr.zIndex - f.attr.zIndex
-                });
-                this.setDirty(true)
-            }
-            for (b = 0, c = a.length; b < c; b++) {
-                a[b].attr.dirtyZIndex = false
-            }
-        }
-    },
-    repaint: function() {
-        var a = this;
-        a.repaint = Ext.emptyFn;
-        Ext.defer(function() {
-            delete a.repaint;
-            a.element.repaint()
-        }, 1)
-    },
-    renderFrame: function() {
-        var g = this;
-        if (!g.element) {
-            return
-        }
-        if (g.dirtyPredecessorCount > 0) {
-            g.isPendingRenderFrame = true;
-            return
-        }
-        var f = g.getRect(),
-            c = g.getBackground(),
-            a = g.getItems(),
-            e, b, d;
-        if (!f) {
-            return
-        }
-        g.orderByZIndex();
-        if (g.getDirty()) {
-            g.clear();
-            g.clearTransform();
-            if (c) {
-                g.renderSprite(c)
-            }
-            for (b = 0, d = a.length; b < d; b++) {
-                e = a[b];
-                if (g.renderSprite(e) === false) {
-                    return
-                }
-                e.attr.textPositionCount = g.textPosition
-            }
-            g.setDirty(false)
-        }
-    },
-    renderSprite: Ext.emptyFn,
-    clearTransform: Ext.emptyFn,
-    destroy: function() {
-        var a = this;
-        a.removeAll(true);
-        a.predecessors = null;
-        a.successors = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.Surface", {
-    override: "Ext.draw.Surface",
-    hitTest: function(b, c) {
-        var f = this,
-            g = f.getItems(),
-            e, d, a;
-        c = c || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        for (e = g.length - 1; e >= 0; e--) {
-            d = g[e];
-            if (d.hitTest) {
-                a = d.hitTest(b, c);
-                if (a) {
-                    return a
-                }
-            }
-        }
-        return null
-    },
-    hitTestEvent: function(b, a) {
-        var c = this.getEventXY(b);
-        return this.hitTest(c, a)
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext", {
-    requires: ["Ext.draw.Color"],
-    toSave: ["strokeOpacity", "strokeStyle", "fillOpacity", "fillStyle", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "lineDash", "lineDashOffset", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "globalCompositeOperation", "position", "fillGradient", "strokeGradient"],
-    strokeOpacity: 1,
-    strokeStyle: "none",
-    fillOpacity: 1,
-    fillStyle: "none",
-    lineDash: [],
-    lineDashOffset: 0,
-    globalAlpha: 1,
-    lineWidth: 1,
-    lineCap: "butt",
-    lineJoin: "miter",
-    miterLimit: 10,
-    shadowOffsetX: 0,
-    shadowOffsetY: 0,
-    shadowBlur: 0,
-    shadowColor: "none",
-    globalCompositeOperation: "src",
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    constructor: function(a) {
-        this.surface = a;
-        this.state = [];
-        this.matrix = new Ext.draw.Matrix();
-        this.path = null;
-        this.clear()
-    },
-    clear: function() {
-        this.group = this.surface.mainGroup;
-        this.position = 0;
-        this.path = null
-    },
-    getElement: function(a) {
-        return this.surface.getSvgElement(this.group, a, this.position++)
-    },
-    removeElement: function(d) {
-        var d = Ext.fly(d),
-            h, g, b, f, a, e, c;
-        if (!d) {
-            return
-        }
-        if (d.dom.tagName === "g") {
-            a = d.dom.gradients;
-            for (c in a) {
-                a[c].destroy()
-            }
-        } else {
-            h = d.getAttribute("fill");
-            g = d.getAttribute("stroke");
-            b = h && h.match(this.urlStringRe);
-            f = g && g.match(this.urlStringRe);
-            if (b && b[1]) {
-                e = Ext.fly(b[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-            if (f && f[1]) {
-                e = Ext.fly(f[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-        }
-        d.destroy()
-    },
-    save: function() {
-        var c = this.toSave,
-            e = {},
-            d = this.getElement("g"),
-            b, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            if (b in this) {
-                e[b] = this[b]
-            }
-        }
-        this.position = 0;
-        e.matrix = this.matrix.clone();
-        this.state.push(e);
-        this.group = d;
-        return d
-    },
-    restore: function() {
-        var d = this.toSave,
-            e = this.state.pop(),
-            c = this.group.dom.childNodes,
-            b, a;
-        while (c.length > this.position) {
-            this.removeElement(c[c.length - 1])
-        }
-        for (a = 0; a < d.length; a++) {
-            b = d[a];
-            if (b in e) {
-                this[b] = e[b]
-            } else {
-                delete this[b]
-            }
-        }
-        this.setTransform.apply(this, e.matrix.elements);
-        this.group = this.group.getParent()
-    },
-    transform: function(f, b, e, g, d, c) {
-        if (this.path) {
-            var a = Ext.draw.Matrix.fly([f, b, e, g, d, c]).inverse();
-            this.path.transform(a)
-        }
-        this.matrix.append(f, b, e, g, d, c)
-    },
-    setTransform: function(e, a, d, f, c, b) {
-        if (this.path) {
-            this.path.transform(this.matrix)
-        }
-        this.matrix.reset();
-        this.transform(e, a, d, f, c, b)
-    },
-    scale: function(a, b) {
-        this.transform(a, 0, 0, b, 0, 0)
-    },
-    rotate: function(d) {
-        var c = Math.cos(d),
-            a = Math.sin(d),
-            b = -Math.sin(d),
-            e = Math.cos(d);
-        this.transform(c, a, b, e, 0, 0)
-    },
-    translate: function(a, b) {
-        this.transform(1, 0, 0, 1, a, b)
-    },
-    setGradientBBox: function(a) {
-        this.bbox = a
-    },
-    beginPath: function() {
-        this.path = new Ext.draw.Path()
-    },
-    moveTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.moveTo(a, b);
-        this.path.element = null
-    },
-    lineTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.lineTo(a, b);
-        this.path.element = null
-    },
-    rect: function(b, d, c, a) {
-        this.moveTo(b, d);
-        this.lineTo(b + c, d);
-        this.lineTo(b + c, d + a);
-        this.lineTo(b, d + a);
-        this.closePath()
-    },
-    strokeRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.stroke()
-    },
-    fillRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.fill()
-    },
-    closePath: function() {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.closePath();
-        this.path.element = null
-    },
-    arcSvg: function(d, a, f, g, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcSvg(d, a, f, g, c, b, e);
-        this.path.element = null
-    },
-    arc: function(b, f, a, d, c, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arc(b, f, a, d, c, e);
-        this.path.element = null
-    },
-    ellipse: function(a, h, g, f, d, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.ellipse(a, h, g, f, d, c, b, e);
-        this.path.element = null
-    },
-    arcTo: function(b, e, a, d, g, f, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcTo(b, e, a, d, g, f, c);
-        this.path.element = null
-    },
-    bezierCurveTo: function(d, f, b, e, a, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.bezierCurveTo(d, f, b, e, a, c);
-        this.path.element = null
-    },
-    strokeText: function(d, a, e) {
-        d = String(d);
-        if (this.strokeStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                stroke: this.strokeStyle,
-                fill: "none",
-                opacity: this.globalAlpha,
-                "stroke-opacity": this.strokeOpacity,
-                style: "font: " + this.font,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(b, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    fillText: function(d, a, e) {
-        d = String(d);
-        if (this.fillStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                fill: this.fillStyle,
-                opacity: this.globalAlpha,
-                "fill-opacity": this.fillOpacity,
-                style: "font: " + this.font
-            });
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    drawImage: function(c, k, i, l, e, p, n, a, g) {
-        var f = this,
-            d = f.getElement("image"),
-            j = k,
-            h = i,
-            b = typeof l === "undefined" ? c.width : l,
-            m = typeof e === "undefined" ? c.height : e,
-            o = null;
-        if (typeof g !== "undefined") {
-            o = k + " " + i + " " + l + " " + e;
-            j = p;
-            h = n;
-            b = a;
-            m = g
-        }
-        d.dom.setAttributeNS("http://www.w3.org/1999/xlink", "href", c.src);
-        f.surface.setElementAttributes(d, {
-            viewBox: o,
-            x: j,
-            y: h,
-            width: b,
-            height: m,
-            opacity: f.globalAlpha,
-            transform: f.matrix.toSvg()
-        })
-    },
-    fill: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.fillStyle) {
-            var c, a = this.fillGradient,
-                d = this.bbox,
-                b = this.path.element;
-            if (!b) {
-                c = this.path.toString();
-                b = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(b, {
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(b, {
-                fill: a && d ? a.generateGradient(this, d) : this.fillStyle,
-                "fill-opacity": this.fillOpacity * this.globalAlpha
-            })
-        }
-    },
-    stroke: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.strokeStyle) {
-            var c, b = this.strokeGradient,
-                d = this.bbox,
-                a = this.path.element;
-            if (!a || !this.path.svgString) {
-                c = this.path.toString();
-                if (!c) {
-                    return
-                }
-                a = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(a, {
-                    fill: "none",
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(a, {
-                stroke: b && d ? b.generateGradient(this, d) : this.strokeStyle,
-                "stroke-linecap": this.lineCap,
-                "stroke-linejoin": this.lineJoin,
-                "stroke-width": this.lineWidth,
-                "stroke-opacity": this.strokeOpacity * this.globalAlpha,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(a, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-        }
-    },
-    fillStroke: function(a, e) {
-        var b = this,
-            d = b.fillStyle,
-            g = b.strokeStyle,
-            c = b.fillOpacity,
-            f = b.strokeOpacity;
-        if (e === undefined) {
-            e = a.transformFillStroke
-        }
-        if (!e) {
-            a.inverseMatrix.toContext(b)
-        }
-        if (d && c !== 0) {
-            b.fill()
-        }
-        if (g && f !== 0) {
-            b.stroke()
-        }
-    },
-    appendPath: function(a) {
-        this.path = a.clone()
-    },
-    setLineDash: function(a) {
-        this.lineDash = a
-    },
-    getLineDash: function() {
-        return this.lineDash
-    },
-    createLinearGradient: function(d, g, b, e) {
-        var f = this,
-            c = f.surface.getNextDef("linearGradient"),
-            a = f.group.dom.gradients || (f.group.dom.gradients = {}),
-            h;
-        f.surface.setElementAttributes(c, {
-            x1: d,
-            y1: g,
-            x2: b,
-            y2: e,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(f, f.surface, c);
-        a[c.dom.id] = h;
-        return h
-    },
-    createRadialGradient: function(b, j, d, a, i, c) {
-        var g = this,
-            e = g.surface.getNextDef("radialGradient"),
-            f = g.group.dom.gradients || (g.group.dom.gradients = {}),
-            h;
-        g.surface.setElementAttributes(e, {
-            fx: b,
-            fy: j,
-            cx: a,
-            cy: i,
-            r: c,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(g, g.surface, e, d / c);
-        f[e.dom.id] = h;
-        return h
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext.Gradient", {
-    statics: {
-        map: {}
-    },
-    constructor: function(c, a, d, b) {
-        var f = this.statics().map,
-            e;
-        e = f[d.dom.id];
-        if (e) {
-            e.element = null
-        }
-        f[d.dom.id] = this;
-        this.ctx = c;
-        this.surface = a;
-        this.element = d;
-        this.position = 0;
-        this.compression = b || 0
-    },
-    addColorStop: function(d, b) {
-        var c = this.surface.getSvgElement(this.element, "stop", this.position++),
-            a = this.compression;
-        this.surface.setElementAttributes(c, {
-            offset: (((1 - a) * d + a) * 100).toFixed(2) + "%",
-            "stop-color": b,
-            "stop-opacity": Ext.draw.Color.fly(b).a.toFixed(15)
-        })
-    },
-    toString: function() {
-        var a = this.element.dom.childNodes;
-        while (a.length > this.position) {
-            Ext.fly(a[a.length - 1]).destroy()
-        }
-        return "url(#" + this.element.getId() + ")"
-    },
-    destroy: function() {
-        var b = this.statics().map,
-            a = this.element;
-        if (a && a.dom) {
-            delete b[a.dom.id];
-            a.destroy()
-        }
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.engine.Svg", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.SvgContext"],
-    statics: {
-        BBoxTextCache: {}
-    },
-    config: {
-        highPrecision: false
-    },
-    getElementConfig: function() {
-        return {
-            reference: "element",
-            style: {
-                position: "absolute"
-            },
-            children: [{
-                reference: "innerElement",
-                style: {
-                    width: "100%",
-                    height: "100%",
-                    position: "relative"
-                },
-                children: [{
-                    tag: "svg",
-                    reference: "svgElement",
-                    namespace: "http://www.w3.org/2000/svg",
-                    width: "100%",
-                    height: "100%",
-                    version: 1.1
-                }]
-            }]
-        }
-    },
-    constructor: function(a) {
-        var b = this;
-        b.callParent([a]);
-        b.mainGroup = b.createSvgNode("g");
-        b.defElement = b.createSvgNode("defs");
-        b.svgElement.appendChild(b.mainGroup);
-        b.svgElement.appendChild(b.defElement);
-        b.ctx = new Ext.draw.engine.SvgContext(b)
-    },
-    createSvgNode: function(a) {
-        var b = document.createElementNS("http://www.w3.org/2000/svg", a);
-        return Ext.get(b)
-    },
-    getSvgElement: function(d, b, a) {
-        var c;
-        if (d.dom.childNodes.length > a) {
-            c = d.dom.childNodes[a];
-            if (c.tagName === b) {
-                return Ext.get(c)
-            } else {
-                Ext.destroy(c)
-            }
-        }
-        c = Ext.get(this.createSvgNode(b));
-        if (a === 0) {
-            d.insertFirst(c)
-        } else {
-            c.insertAfter(Ext.fly(d.dom.childNodes[a - 1]))
-        }
-        c.cache = {};
-        return c
-    },
-    setElementAttributes: function(d, b) {
-        var f = d.dom,
-            a = d.cache,
-            c, e;
-        for (c in b) {
-            e = b[c];
-            if (a[c] !== e) {
-                a[c] = e;
-                f.setAttribute(c, e)
-            }
-        }
-    },
-    getNextDef: function(a) {
-        return this.getSvgElement(this.defElement, a, this.defPosition++)
-    },
-    clearTransform: function() {
-        var a = this;
-        a.mainGroup.set({
-            transform: a.matrix.toSvg()
-        })
-    },
-    clear: function() {
-        this.ctx.clear();
-        this.defPosition = 0
-    },
-    renderSprite: function(b) {
-        var d = this,
-            c = d.getRect(),
-            a = d.ctx;
-        if (b.attr.hidden || b.attr.globalAlpha === 0) {
-            a.save();
-            a.restore();
-            return
-        }
-        b.element = a.save();
-        b.preRender(this);
-        b.useAttributes(a, c);
-        if (false === b.render(this, a, [0, 0, c[2], c[3]])) {
-            return false
-        }
-        b.setDirty(false);
-        a.restore()
-    },
-    flatten: function(e, b) {
-        var c = '<?xml version="1.0" standalone="yes"?>',
-            f = Ext.getClassName(this),
-            a, g, d;
-        c += '<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="' + e.width + '" height="' + e.height + '">';
-        for (d = 0; d < b.length; d++) {
-            a = b[d];
-            if (Ext.getClassName(a) !== f) {
-                continue
-            }
-            g = a.getRect();
-            c += '<g transform="translate(' + g[0] + "," + g[1] + ')">';
-            c += this.serializeNode(a.svgElement.dom);
-            c += "</g>"
-        }
-        c += "</svg>";
-        return {
-            data: "data:image/svg+xml;utf8," + encodeURIComponent(c),
-            type: "svg"
-        }
-    },
-    serializeNode: function(d) {
-        var b = "",
-            c, f, a, e;
-        if (d.nodeType === document.TEXT_NODE) {
-            return d.nodeValue
-        }
-        b += "<" + d.nodeName;
-        if (d.attributes.length) {
-            for (c = 0, f = d.attributes.length; c < f; c++) {
-                a = d.attributes[c];
-                b += " " + a.name + '="' + a.value + '"'
-            }
-        }
-        b += ">";
-        if (d.childNodes && d.childNodes.length) {
-            for (c = 0, f = d.childNodes.length; c < f; c++) {
-                e = d.childNodes[c];
-                b += this.serializeNode(e)
-            }
-        }
-        b += "</" + d.nodeName + ">";
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.ctx.destroy();
-        a.mainGroup.destroy();
-        delete a.mainGroup;
-        delete a.ctx;
-        a.callParent()
-    },
-    remove: function(a, b) {
-        if (a && a.element) {
-            if (this.ctx) {
-                this.ctx.removeElement(a.element)
-            } else {
-                a.element.destroy()
-            }
-            a.element = null
-        }
-        this.callParent(arguments)
-    }
-});
-Ext.draw || (Ext.draw = {});
-Ext.draw.engine || (Ext.draw.engine = {});
-Ext.draw.engine.excanvas = true;
-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) {
-            Ext.onReady(function() {
-                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.lineDash = j.lineDash;
-            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.lineDash = [];
-            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(an, j) {
-            var ah, Z, aj, ar, al, ak, ao, av;
-            var ai = an.runtimeStyle.width;
-            var am = an.runtimeStyle.height;
-            an.runtimeStyle.width = "auto";
-            an.runtimeStyle.height = "auto";
-            var ag = an.width;
-            var aq = an.height;
-            an.runtimeStyle.width = ai;
-            an.runtimeStyle.height = am;
-            if (arguments.length == 3) {
-                ah = arguments[1];
-                Z = arguments[2];
-                al = ak = 0;
-                ao = aj = ag;
-                av = ar = aq
-            } else {
-                if (arguments.length == 5) {
-                    ah = arguments[1];
-                    Z = arguments[2];
-                    aj = arguments[3];
-                    ar = arguments[4];
-                    al = ak = 0;
-                    ao = ag;
-                    av = aq
-                } else {
-                    if (arguments.length == 9) {
-                        al = arguments[1];
-                        ak = arguments[2];
-                        ao = arguments[3];
-                        av = arguments[4];
-                        ah = arguments[5];
-                        Z = arguments[6];
-                        aj = arguments[7];
-                        ar = arguments[8]
-                    } else {
-                        throw Error("Invalid number of arguments")
-                    }
-                }
-            }
-            var au = V(this, ah, Z);
-            var at = [];
-            var i = 10;
-            var p = 10;
-            var ap = this.m_;
-            at.push(" <g_vml_:group", ' coordsize="', d * i, ",", d * p, '"', ' coordorigin="0,0"', ' style="width:', n(i * ap[0][0]), "px;height:", n(p * ap[1][1]), "px;position:absolute;", "top:", n(au.y / d), "px;left:", n(au.x / d), "px; rotation:", n(Math.atan(ap[0][1] / ap[1][1]) * 180 / Math.PI), ";");
-            at.push('" >', '<g_vml_:image src="', an.src, '"', ' style="width:', d * aj, "px;", " height:", d * ar, 'px"', ' cropleft="', al / ag, '"', ' croptop="', ak / aq, '"', ' cropright="', (ag - al - ao) / ag, '"', ' cropbottom="', (aq - ak - av) / aq, '"', " />", "</g_vml_:group>");
-            this.element_.insertAdjacentHTML("BeforeEnd", at.join(""))
-        };
-        q.setLineDash = function(i) {
-            if (i.length === 1) {
-                i = i.slice();
-                i[1] = i[0]
-            }
-            this.lineDash = i
-        };
-        q.getLineDash = function() {
-            return this.lineDash
-        };
-        q.stroke = function(ak) {
-            var ai = [];
-            var m = 10;
-            var al = 10;
-            ai.push("<g_vml_:shape", ' filled="', !!ak, '"', ' style="position:absolute;width:', m, "px;height:", al, 'px;left:0px;top:0px;"', ' coordorigin="0,0"', ' coordsize="', d * m, ",", d * al, '"', ' stroked="', !ak, '"', ' path="');
-            var Z = {
-                x: null,
-                y: null
-            };
-            var aj = {
-                x: null,
-                y: null
-            };
-            for (var ag = 0; ag < this.currentPath_.length; ag++) {
-                var j = this.currentPath_[ag];
-                var ah;
-                switch (j.type) {
-                    case "moveTo":
-                        ah = j;
-                        ai.push(" m ", n(j.x), ",", n(j.y));
-                        break;
-                    case "lineTo":
-                        ai.push(" l ", n(j.x), ",", n(j.y));
-                        break;
-                    case "close":
-                        ai.push(" x ");
-                        j = null;
-                        break;
-                    case "bezierCurveTo":
-                        ai.push(" c ", n(j.cp1x), ",", n(j.cp1y), ",", n(j.cp2x), ",", n(j.cp2y), ",", n(j.x), ",", n(j.y));
-                        break;
-                    case "at":
-                    case "wa":
-                        ai.push(" ", j.type, " ", n(j.x - this.arcScaleX_ * j.radius), ",", n(j.y - this.arcScaleY_ * j.radius), " ", n(j.x + this.arcScaleX_ * j.radius), ",", n(j.y + this.arcScaleY_ * j.radius), " ", n(j.xStart), ",", n(j.yStart), " ", n(j.xEnd), ",", n(j.yEnd));
-                        break
-                }
-                if (j) {
-                    if (Z.x == null || j.x < Z.x) {
-                        Z.x = j.x
-                    }
-                    if (aj.x == null || j.x > aj.x) {
-                        aj.x = j.x
-                    }
-                    if (Z.y == null || j.y < Z.y) {
-                        Z.y = j.y
-                    }
-                    if (aj.y == null || j.y > aj.y) {
-                        aj.y = j.y
-                    }
-                }
-            }
-            ai.push(' ">');
-            if (!ak) {
-                w(this, ai)
-            } else {
-                G(this, ai, Z, aj)
-            }
-            ai.push("</g_vml_:shape>");
-            this.element_.insertAdjacentHTML("beforeEnd", ai.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, '"', ' dashstyle="', m.lineDash.join(" "), '"', ' 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 / 3;
-                    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;left:0px;top:0px;">');
-            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
-    })()
-}
-Ext.define("Ext.draw.engine.Canvas", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.excanvas", "Ext.draw.Animator", "Ext.draw.Color"],
-    config: {
-        highPrecision: false
-    },
-    statics: {
-        contextOverrides: {
-            setGradientBBox: function(a) {
-                this.bbox = a
-            },
-            fill: function() {
-                var c = this.fillStyle,
-                    a = this.fillGradient,
-                    b = this.fillOpacity,
-                    d = this.globalAlpha,
-                    e = this.bbox;
-                if (c !== Ext.draw.Color.RGBA_NONE && b !== 0) {
-                    if (a && e) {
-                        this.fillStyle = a.generateGradient(this, e)
-                    }
-                    if (b !== 1) {
-                        this.globalAlpha = d * b
-                    }
-                    this.$fill();
-                    if (b !== 1) {
-                        this.globalAlpha = d
-                    }
-                    if (a && e) {
-                        this.fillStyle = c
-                    }
-                }
-            },
-            stroke: function() {
-                var e = this.strokeStyle,
-                    c = this.strokeGradient,
-                    a = this.strokeOpacity,
-                    b = this.globalAlpha,
-                    d = this.bbox;
-                if (e !== Ext.draw.Color.RGBA_NONE && a !== 0) {
-                    if (c && d) {
-                        this.strokeStyle = c.generateGradient(this, d)
-                    }
-                    if (a !== 1) {
-                        this.globalAlpha = b * a
-                    }
-                    this.$stroke();
-                    if (a !== 1) {
-                        this.globalAlpha = b
-                    }
-                    if (c && d) {
-                        this.strokeStyle = e
-                    }
-                }
-            },
-            fillStroke: function(d, e) {
-                var j = this,
-                    i = this.fillStyle,
-                    h = this.fillOpacity,
-                    f = this.strokeStyle,
-                    c = this.strokeOpacity,
-                    b = j.shadowColor,
-                    a = j.shadowBlur,
-                    g = Ext.draw.Color.RGBA_NONE;
-                if (e === undefined) {
-                    e = d.transformFillStroke
-                }
-                if (!e) {
-                    d.inverseMatrix.toContext(j)
-                }
-                if (i !== g && h !== 0) {
-                    j.fill();
-                    j.shadowColor = g;
-                    j.shadowBlur = 0
-                }
-                if (f !== g && c !== 0) {
-                    j.stroke()
-                }
-                j.shadowColor = b;
-                j.shadowBlur = a
-            },
-            setLineDash: function(a) {
-                if (this.$setLineDash) {
-                    this.$setLineDash(a)
-                }
-            },
-            getLineDash: function() {
-                if (this.$getLineDash) {
-                    return this.$getLineDash()
-                }
-            },
-            ellipse: function(g, e, c, a, j, b, f, d) {
-                var i = Math.cos(j),
-                    h = Math.sin(j);
-                this.transform(i * c, h * c, -h * a, i * a, g, e);
-                this.arc(0, 0, 1, b, f, d);
-                this.transform(i / c, -h / a, h / c, i / a, -(i * g + h * e) / c, (h * g - i * e) / a)
-            },
-            appendPath: function(f) {
-                var e = this,
-                    c = 0,
-                    b = 0,
-                    a = f.commands,
-                    g = f.params,
-                    d = a.length;
-                e.beginPath();
-                for (; c < d; c++) {
-                    switch (a[c]) {
-                        case "M":
-                            e.moveTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "L":
-                            e.lineTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "C":
-                            e.bezierCurveTo(g[b], g[b + 1], g[b + 2], g[b + 3], g[b + 4], g[b + 5]);
-                            b += 6;
-                            break;
-                        case "Z":
-                            e.closePath();
-                            break
-                    }
-                }
-            },
-            save: function() {
-                var c = this.toSave,
-                    d = c.length,
-                    e = d && {},
-                    b = 0,
-                    a;
-                for (; b < d; b++) {
-                    a = c[b];
-                    if (a in this) {
-                        e[a] = this[a]
-                    }
-                }
-                this.state.push(e);
-                this.$save()
-            },
-            restore: function() {
-                var b = this.state.pop(),
-                    a;
-                if (b) {
-                    for (a in b) {
-                        this[a] = b[a]
-                    }
-                }
-                this.$restore()
-            }
-        }
-    },
-    splitThreshold: 3000,
-    toSave: ["fillGradient", "strokeGradient"],
-    element: {
-        reference: "element",
-        style: {
-            position: "absolute"
-        },
-        children: [{
-            reference: "innerElement",
-            style: {
-                width: "100%",
-                height: "100%",
-                position: "relative"
-            }
-        }]
-    },
-    createCanvas: function() {
-        var c = Ext.Element.create({
-            tag: "canvas",
-            cls: Ext.baseCSSPrefix + "surface-canvas"
-        });
-        window.G_vmlCanvasManager && G_vmlCanvasManager.initElement(c.dom);
-        var d = Ext.draw.engine.Canvas.contextOverrides,
-            a = c.dom.getContext("2d"),
-            b;
-        if (a.ellipse) {
-            delete d.ellipse
-        }
-        a.state = [];
-        a.toSave = this.toSave;
-        for (b in d) {
-            a["$" + b] = a[b]
-        }
-        Ext.apply(a, d);
-        if (this.getHighPrecision()) {
-            this.enablePrecisionCompensation(a)
-        } else {
-            this.disablePrecisionCompensation(a)
-        }
-        this.innerElement.appendChild(c);
-        this.canvases.push(c);
-        this.contexts.push(a)
-    },
-    updateHighPrecision: function(d) {
-        var e = this.contexts,
-            c = e.length,
-            b, a;
-        for (b = 0; b < c; b++) {
-            a = e[b];
-            if (d) {
-                this.enablePrecisionCompensation(a)
-            } else {
-                this.disablePrecisionCompensation(a)
-            }
-        }
-    },
-    precisionNames: ["rect", "fillRect", "strokeRect", "clearRect", "moveTo", "lineTo", "arc", "arcTo", "save", "restore", "updatePrecisionCompensate", "setTransform", "transform", "scale", "translate", "rotate", "quadraticCurveTo", "bezierCurveTo", "createLinearGradient", "createRadialGradient", "fillText", "strokeText", "drawImage"],
-    disablePrecisionCompensation: function(b) {
-        var a = Ext.draw.engine.Canvas.contextOverrides,
-            f = this.precisionNames,
-            e = f.length,
-            d, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            if (!(c in a)) {
-                delete b[c]
-            }
-        }
-        this.setDirty(true)
-    },
-    enablePrecisionCompensation: function(j) {
-        var c = this,
-            a = 1,
-            g = 1,
-            l = 0,
-            k = 0,
-            i = new Ext.draw.Matrix(),
-            b = [],
-            e = {},
-            d = Ext.draw.engine.Canvas.contextOverrides,
-            h = j.constructor.prototype;
-        var f = {
-            toSave: c.toSave,
-            rect: function(m, p, n, o) {
-                return h.rect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            fillRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.fillRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            strokeRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.strokeRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            clearRect: function(m, p, n, o) {
-                return h.clearRect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            moveTo: function(m, n) {
-                return h.moveTo.call(this, m * a + l, n * g + k)
-            },
-            lineTo: function(m, n) {
-                return h.lineTo.call(this, m * a + l, n * g + k)
-            },
-            arc: function(n, r, m, p, o, q) {
-                this.updatePrecisionCompensateRect();
-                h.arc.call(this, n * a + l, r * a + k, m * a, p, o, q);
-                this.updatePrecisionCompensate()
-            },
-            arcTo: function(o, q, n, p, m) {
-                this.updatePrecisionCompensateRect();
-                h.arcTo.call(this, o * a + l, q * g + k, n * a + l, p * g + k, m * a);
-                this.updatePrecisionCompensate()
-            },
-            save: function() {
-                b.push(i);
-                i = i.clone();
-                d.save.call(this);
-                h.save.call(this)
-            },
-            restore: function() {
-                i = b.pop();
-                d.restore.call(this);
-                h.restore.call(this);
-                this.updatePrecisionCompensate()
-            },
-            updatePrecisionCompensate: function() {
-                i.precisionCompensate(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            updatePrecisionCompensateRect: function() {
-                i.precisionCompensateRect(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            setTransform: function(q, o, n, m, r, p) {
-                i.set(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            transform: function(q, o, n, m, r, p) {
-                i.append(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            scale: function(n, m) {
-                this.transform(n, 0, 0, m, 0, 0)
-            },
-            translate: function(n, m) {
-                this.transform(1, 0, 0, 1, n, m)
-            },
-            rotate: function(o) {
-                var n = Math.cos(o),
-                    m = Math.sin(o);
-                this.transform(n, m, -m, n, 0, 0)
-            },
-            quadraticCurveTo: function(n, p, m, o) {
-                h.quadraticCurveTo.call(this, n * a + l, p * g + k, m * a + l, o * g + k)
-            },
-            bezierCurveTo: function(r, p, o, n, m, q) {
-                h.bezierCurveTo.call(this, r * a + l, p * g + k, o * a + l, n * g + k, m * a + l, q * g + k)
-            },
-            createLinearGradient: function(n, p, m, o) {
-                this.updatePrecisionCompensateRect();
-                var q = h.createLinearGradient.call(this, n * a + l, p * g + k, m * a + l, o * g + k);
-                this.updatePrecisionCompensate();
-                return q
-            },
-            createRadialGradient: function(p, r, o, n, q, m) {
-                this.updatePrecisionCompensateRect();
-                var s = h.createLinearGradient.call(this, p * a + l, r * a + k, o * a, n * a + l, q * a + k, m * a);
-                this.updatePrecisionCompensate();
-                return s
-            },
-            fillText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.fillText.call(this, o, m, p)
-                } else {
-                    h.fillText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            strokeText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.strokeText.call(this, o, m, p)
-                } else {
-                    h.strokeText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            fill: function() {
-                var m = this.fillGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.fillStyle = m.generateGradient(this, n)
-                }
-                h.fill.call(this);
-                this.updatePrecisionCompensate()
-            },
-            stroke: function() {
-                var m = this.strokeGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.strokeStyle = m.generateGradient(this, n)
-                }
-                h.stroke.call(this);
-                this.updatePrecisionCompensate()
-            },
-            drawImage: function(u, s, r, q, p, o, n, m, t) {
-                switch (arguments.length) {
-                    case 3:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k);
-                    case 5:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k, q * a, p * g);
-                    case 9:
-                        return h.drawImage.call(this, u, s, r, q, p, o * a + l, n * g * k, m * a, t * g)
-                }
-            }
-        };
-        Ext.apply(j, f);
-        this.setDirty(true)
-    },
-    updateRect: function(a) {
-        this.callParent([a]);
-        var C = this,
-            p = Math.floor(a[0]),
-            e = Math.floor(a[1]),
-            g = Math.ceil(a[0] + a[2]),
-            B = Math.ceil(a[1] + a[3]),
-            u = C.devicePixelRatio,
-            D = C.canvases,
-            d = g - p,
-            y = B - e,
-            n = Math.round(C.splitThreshold / u),
-            c = C.xSplits = Math.ceil(d / n),
-            f = C.ySplits = Math.ceil(y / n),
-            v, s, q, A, z, x, o, m;
-        for (s = 0, z = 0; s < f; s++, z += n) {
-            for (v = 0, A = 0; v < c; v++, A += n) {
-                q = s * c + v;
-                if (q >= D.length) {
-                    C.createCanvas()
-                }
-                x = D[q].dom;
-                x.style.left = A + "px";
-                x.style.top = z + "px";
-                m = Math.min(n, y - z);
-                if (m * u !== x.height) {
-                    x.height = m * u;
-                    x.style.height = m + "px"
-                }
-                o = Math.min(n, d - A);
-                if (o * u !== x.width) {
-                    x.width = o * u;
-                    x.style.width = o + "px"
-                }
-                C.applyDefaults(C.contexts[q])
-            }
-        }
-        for (q += 1; q < D.length; q++) {
-            D[q].destroy()
-        }
-        C.activeCanvases = c * f;
-        D.length = C.activeCanvases;
-        C.clear()
-    },
-    clearTransform: function() {
-        var f = this,
-            a = f.xSplits,
-            g = f.ySplits,
-            d = f.contexts,
-            h = f.splitThreshold,
-            l = f.devicePixelRatio,
-            e, c, b, m;
-        for (e = 0; e < a; e++) {
-            for (c = 0; c < g; c++) {
-                b = c * a + e;
-                m = d[b];
-                m.translate(-h * e, -h * c);
-                m.scale(l, l);
-                f.matrix.toContext(m)
-            }
-        }
-    },
-    renderSprite: function(q) {
-        var C = this,
-            b = C.getRect(),
-            e = C.matrix,
-            g = q.getParent(),
-            v = Ext.draw.Matrix.fly([1, 0, 0, 1, 0, 0]),
-            p = C.splitThreshold / C.devicePixelRatio,
-            c = C.xSplits,
-            m = C.ySplits,
-            A, z, s, a, r, o, d = 0,
-            B, n = 0,
-            f, l = b[2],
-            y = b[3],
-            x, u, t;
-        while (g && (g !== C)) {
-            v.prependMatrix(g.matrix || g.attr && g.attr.matrix);
-            g = g.getParent()
-        }
-        v.prependMatrix(e);
-        a = q.getBBox();
-        if (a) {
-            a = v.transformBBox(a)
-        }
-        q.preRender(C);
-        if (q.attr.hidden || q.attr.globalAlpha === 0) {
-            q.setDirty(false);
-            return
-        }
-        for (u = 0, z = 0; u < m; u++, z += p) {
-            for (x = 0, A = 0; x < c; x++, A += p) {
-                t = u * c + x;
-                s = C.contexts[t];
-                r = Math.min(p, l - A);
-                o = Math.min(p, y - z);
-                d = A;
-                B = d + r;
-                n = z;
-                f = n + o;
-                if (a) {
-                    if (a.x > B || a.x + a.width < d || a.y > f || a.y + a.height < n) {
-                        continue
-                    }
-                }
-                s.save();
-                q.useAttributes(s, b);
-                if (false === q.render(C, s, [d, n, r, o], b)) {
-                    return false
-                }
-                s.restore()
-            }
-        }
-        q.setDirty(false)
-    },
-    flatten: function(n, a) {
-        var k = document.createElement("canvas"),
-            f = Ext.getClassName(this),
-            g = this.devicePixelRatio,
-            l = k.getContext("2d"),
-            b, c, h, e, d, m;
-        k.width = Math.ceil(n.width * g);
-        k.height = Math.ceil(n.height * g);
-        for (e = 0; e < a.length; e++) {
-            b = a[e];
-            if (Ext.getClassName(b) !== f) {
-                continue
-            }
-            h = b.getRect();
-            for (d = 0; d < b.canvases.length; d++) {
-                c = b.canvases[d];
-                m = c.getOffsetsTo(c.getParent());
-                l.drawImage(c.dom, (h[0] + m[0]) * g, (h[1] + m[1]) * g)
-            }
-        }
-        return {
-            data: k.toDataURL(),
-            type: "png"
-        }
-    },
-    applyDefaults: function(a) {
-        var b = Ext.draw.Color.RGBA_NONE;
-        a.strokeStyle = b;
-        a.fillStyle = b;
-        a.textAlign = "start";
-        a.textBaseline = "alphabetic";
-        a.miterLimit = 1
-    },
-    clear: function() {
-        var d = this,
-            e = d.activeCanvases,
-            c, b, a;
-        for (c = 0; c < e; c++) {
-            b = d.canvases[c].dom;
-            a = d.contexts[c];
-            a.setTransform(1, 0, 0, 1, 0, 0);
-            a.clearRect(0, 0, b.width, b.height)
-        }
-        d.setDirty(true)
-    },
-    destroy: function() {
-        var c = this,
-            a, b = c.canvases.length;
-        for (a = 0; a < b; a++) {
-            c.contexts[a] = null;
-            c.canvases[a].destroy();
-            c.canvases[a] = null
-        }
-        delete c.contexts;
-        delete c.canvases;
-        c.callParent()
-    },
-    privates: {
-        initElement: function() {
-            var a = this;
-            a.callParent();
-            a.canvases = [];
-            a.contexts = [];
-            a.activeCanvases = (a.xSplits = 0) * (a.ySplits = 0)
-        }
-    }
-}, function() {
-    var c = this,
-        b = c.prototype,
-        a = 10000000000;
-    if (Ext.os.is.Android4 && Ext.browser.is.Chrome) {
-        a = 3000
-    } else {
-        if (Ext.is.iOS) {
-            a = 2200
-        }
-    }
-    b.splitThreshold = a
-});
-Ext.define("Ext.draw.Container", {
-    extend: "Ext.draw.ContainerBase",
-    alternateClassName: "Ext.draw.Component",
-    xtype: "draw",
-    defaultType: "surface",
-    isDrawContainer: true,
-    requires: ["Ext.draw.Surface", "Ext.draw.engine.Svg", "Ext.draw.engine.Canvas", "Ext.draw.gradient.GradientDefinition"],
-    engine: "Ext.draw.engine.Canvas",
-    config: {
-        cls: Ext.baseCSSPrefix + "draw-container",
-        resizeHandler: null,
-        sprites: null,
-        gradients: []
-    },
-    defaultDownloadServerUrl: "http://svg.sencha.io",
-    supportedFormats: ["png", "pdf", "jpeg", "gif"],
-    supportedOptions: {
-        version: Ext.isNumber,
-        data: Ext.isString,
-        format: function(a) {
-            return Ext.Array.indexOf(this.supportedFormats, a) >= 0
-        },
-        filename: Ext.isString,
-        width: Ext.isNumber,
-        height: Ext.isNumber,
-        scale: Ext.isNumber,
-        pdf: Ext.isObject,
-        jpeg: Ext.isObject
-    },
-    initAnimator: function() {
-        this.frameCallbackId = Ext.draw.Animator.addFrameCallback("renderFrame", this)
-    },
-    applyGradients: function(b) {
-        var a = [],
-            c, f, d, e;
-        if (!Ext.isArray(b)) {
-            return a
-        }
-        for (c = 0, f = b.length; c < f; c++) {
-            d = b[c];
-            if (!Ext.isObject(d)) {
-                continue
-            }
-            if (typeof d.type !== "string") {
-                d.type = "linear"
-            }
-            if (d.angle) {
-                d.degrees = d.angle;
-                delete d.angle
-            }
-            if (Ext.isObject(d.stops)) {
-                d.stops = (function(i) {
-                    var g = [],
-                        h;
-                    for (e in i) {
-                        h = i[e];
-                        h.offset = e / 100;
-                        g.push(h)
-                    }
-                    return g
-                })(d.stops)
-            }
-            a.push(d)
-        }
-        Ext.draw.gradient.GradientDefinition.add(a);
-        return a
-    },
-    applySprites: function(f) {
-        if (!f) {
-            return
-        }
-        f = Ext.Array.from(f);
-        var e = f.length,
-            b = [],
-            d, a, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            a = c.surface;
-            if (!(a && a.isSurface)) {
-                if (Ext.isString(a)) {
-                    a = this.getSurface(a)
-                } else {
-                    a = this.getSurface("main")
-                }
-            }
-            c = a.add(c);
-            b.push(c)
-        }
-        return b
-    },
-    onBodyResize: function() {
-        var b = this.element,
-            a;
-        if (!b) {
-            return
-        }
-        a = b.getSize();
-        if (a.width && a.height) {
-            this.setBodySize(a)
-        }
-    },
-    setBodySize: function(c) {
-        var d = this,
-            b = d.getResizeHandler() || d.defaultResizeHandler,
-            a;
-        d.fireEvent("bodyresize", d, c);
-        a = b.call(d, c);
-        if (a !== false) {
-            d.renderFrame()
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.getItems().each(function(b) {
-            b.setRect([0, 0, a.width, a.height])
-        })
-    },
-    getSurface: function(d) {
-        d = this.getId() + "-" + (d || "main");
-        var c = this,
-            b = c.getItems(),
-            a = b.get(d);
-        if (!a) {
-            a = c.add({
-                xclass: c.engine,
-                id: d
-            });
-            c.onBodyResize()
-        }
-        return a
-    },
-    renderFrame: function() {
-        var e = this,
-            a = e.getItems(),
-            b, d, c;
-        for (b = 0, d = a.length; b < d; b++) {
-            c = a.items[b];
-            if (c.isSurface) {
-                c.renderFrame()
-            }
-        }
-    },
-    getImage: function(k) {
-        var l = this.innerElement.getSize(),
-            a = Array.prototype.slice.call(this.items.items),
-            d, g, c = this.surfaceZIndexes,
-            f, e, b, h;
-        for (e = 1; e < a.length; e++) {
-            b = a[e];
-            h = c[b.type];
-            f = e - 1;
-            while (f >= 0 && c[a[f].type] > h) {
-                a[f + 1] = a[f];
-                f--
-            }
-            a[f + 1] = b
-        }
-        d = a[0].flatten(l, a);
-        if (k === "image") {
-            g = new Image();
-            g.src = d.data;
-            d.data = g;
-            return d
-        }
-        if (k === "stream") {
-            d.data = d.data.replace(/^data:image\/[^;]+/, "data:application/octet-stream");
-            return d
-        }
-        return d
-    },
-    download: function(d) {
-        var e = this,
-            a = [],
-            b, c, f;
-        d = Ext.apply({
-            version: 2,
-            data: e.getImage().data
-        }, d);
-        for (c in d) {
-            if (d.hasOwnProperty(c)) {
-                f = d[c];
-                if (c in e.supportedOptions) {
-                    if (e.supportedOptions[c].call(e, f)) {
-                        a.push({
-                            tag: "input",
-                            type: "hidden",
-                            name: c,
-                            value: Ext.String.htmlEncode(Ext.isObject(f) ? Ext.JSON.encode(f) : f)
-                        })
-                    }
-                }
-            }
-        }
-        b = Ext.dom.Helper.markup({
-            tag: "html",
-            children: [{
-                tag: "head"
-            }, {
-                tag: "body",
-                children: [{
-                    tag: "form",
-                    method: "POST",
-                    action: d.url || e.defaultDownloadServerUrl,
-                    children: a
-                }, {
-                    tag: "script",
-                    type: "text/javascript",
-                    children: 'document.getElementsByTagName("form")[0].submit();'
-                }]
-            }]
-        });
-        window.open("", "ImageDownload_" + Date.now()).document.write(b)
-    },
-    destroy: function() {
-        var a = this.frameCallbackId;
-        if (a) {
-            Ext.draw.Animator.removeFrameCallback(a)
-        }
-        this.callParent()
-    }
-}, function() {
-    if (location.search.match("svg")) {
-        Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-    } else {
-        if ((Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) || (Ext.browser.is.AndroidStock4 && (Ext.os.version.getMinor() === 1 || Ext.os.version.getMinor() === 2 || Ext.os.version.getMinor() === 3))) {
-            Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Base", {
-    mixins: {
-        factoryable: "Ext.mixin.Factoryable"
-    },
-    requires: ["Ext.draw.Color"],
-    factoryConfig: {
-        type: "chart.theme"
-    },
-    isTheme: true,
-    config: {
-        baseColor: null,
-        colors: undefined,
-        gradients: null,
-        chart: {
-            defaults: {
-                background: "#23272a"
-            }
-        },
-        axis: {
-            defaults: {
-                label: {
-                    x: 0,
-                    y: 0,
-                    textBaseline: "middle",
-                    textAlign: "center",
-                    fontSize: "default",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fillStyle: "white",
-                    color: "white"
-                },
-                title: {
-                    fillStyle: "black",
-                    fontSize: "default*1.23",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    color: "white"
-                },
-                style: {
-                    strokeStyle: "black"
-                },
-                grid: {
-                    strokeStyle: "rgba(44, 47, 51, 1)"
-                }
-            },
-            top: {
-                style: {
-                    textPadding: 5
-                }
-            },
-            bottom: {
-                style: {
-                    textPadding: 5
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "black",
-                    strokeStyle: "none",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fontSize: "default*1.077",
-                    textBaseline: "middle",
-                    textAlign: "center"
-                },
-                labelOverflowPadding: 5
-            }
-        },
-        sprites: {
-            text: {
-                fontSize: "default",
-                fontWeight: "default",
-                fontFamily: "default",
-                fillStyle: "black",
-                color: "white"
-            }
-        },
-        seriesThemes: undefined,
-        markerThemes: {
-            type: ["circle", "cross", "plus", "square", "triangle", "diamond"]
-        },
-        useGradients: false,
-        background: null
-    },
-    colorDefaults: ["#94ae0a", "#115fa6", "#a61120", "#ff8809", "#ffd13e", "#a61187", "#24ad9a", "#7c7474", "#a66111"],
-    constructor: function(a) {
-        this.initConfig(a);
-        this.resolveDefaults()
-    },
-    defaultRegEx: /^default([+\-/\*]\d+(?:\.\d+)?)?$/,
-    defaultOperators: {
-        "*": function(b, a) {
-            return b * a
-        },
-        "+": function(b, a) {
-            return b + a
-        },
-        "-": function(b, a) {
-            return b - a
-        }
-    },
-    resolveDefaults: function() {
-        var a = this;
-        Ext.onReady(function() {
-            var f = Ext.clone(a.getSprites()),
-                e = Ext.clone(a.getAxis()),
-                d = Ext.clone(a.getSeries()),
-                g, c, b;
-            if (!a.superclass.defaults) {
-                g = Ext.getBody().createChild({
-                    tag: "div",
-                    cls: "x-component"
-                });
-                a.superclass.defaults = {
-                    fontFamily: g.getStyle("fontFamily"),
-                    fontWeight: g.getStyle("fontWeight"),
-                    fontSize: parseFloat(g.getStyle("fontSize")),
-                    fontVariant: g.getStyle("fontVariant"),
-                    fontStyle: g.getStyle("fontStyle")
-                };
-                g.destroy()
-            }
-            a.replaceDefaults(f.text);
-            a.setSprites(f);
-            for (c in e) {
-                b = e[c];
-                a.replaceDefaults(b.label);
-                a.replaceDefaults(b.title)
-            }
-            a.setAxis(e);
-            for (c in d) {
-                b = d[c];
-                a.replaceDefaults(b.label)
-            }
-            a.setSeries(d)
-        })
-    },
-    replaceDefaults: function(h) {
-        var e = this,
-            g = e.superclass.defaults,
-            a = e.defaultRegEx,
-            d, f, c, b;
-        if (Ext.isObject(h)) {
-            for (d in g) {
-                c = a.exec(h[d]);
-                if (c) {
-                    f = g[d];
-                    c = c[1];
-                    if (c) {
-                        b = e.defaultOperators[c.charAt(0)];
-                        f = Math.round(b(f, parseFloat(c.substr(1))))
-                    }
-                    h[d] = f
-                }
-            }
-        }
-    },
-    applyBaseColor: function(c) {
-        var a, b;
-        if (c) {
-            a = c.isColor ? c : Ext.draw.Color.fromString(c);
-            b = a.getHSL()[2];
-            if (b < 0.15) {
-                a = a.createLighter(0.3)
-            } else {
-                if (b < 0.3) {
-                    a = a.createLighter(0.15)
-                } else {
-                    if (b > 0.85) {
-                        a = a.createDarker(0.3)
-                    } else {
-                        if (b > 0.7) {
-                            a = a.createDarker(0.15)
-                        }
-                    }
-                }
-            }
-            this.setColors([a.createDarker(0.3).toString(), a.createDarker(0.15).toString(), a.toString(), a.createLighter(0.12).toString(), a.createLighter(0.24).toString(), a.createLighter(0.31).toString()])
-        }
-        return c
-    },
-    applyColors: function(a) {
-        return a || this.colorDefaults
-    },
-    updateUseGradients: function(a) {
-        if (a) {
-            this.updateGradients({
-                type: "linear",
-                degrees: 90
-            })
-        }
-    },
-    updateBackground: function(a) {
-        if (a) {
-            var b = this.getChart();
-            b.defaults.background = a;
-            this.setChart(b)
-        }
-    },
-    updateGradients: function(a) {
-        var c = this.getColors(),
-            e = [],
-            h, b, d, f, g;
-        if (Ext.isObject(a)) {
-            for (f = 0, g = c && c.length || 0; f < g; f++) {
-                b = Ext.draw.Color.fromString(c[f]);
-                if (b) {
-                    d = b.createLighter(0.15).toString();
-                    h = Ext.apply(Ext.Object.chain(a), {
-                        stops: [{
-                            offset: 1,
-                            color: b.toString()
-                        }, {
-                            offset: 0,
-                            color: d.toString()
-                        }]
-                    });
-                    e.push(h)
-                }
-            }
-            this.setColors(e)
-        }
-    },
-    applySeriesThemes: function(a) {
-        this.getBaseColor();
-        this.getUseGradients();
-        this.getGradients();
-        var b = this.getColors();
-        if (!a) {
-            a = {
-                fillStyle: Ext.Array.clone(b),
-                strokeStyle: Ext.Array.map(b, function(d) {
-                    var c = Ext.draw.Color.fromString(d.stops ? d.stops[0].color : d);
-                    return c.createDarker(0.15).toString()
-                })
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.theme.Default", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default", "chart.theme.Base"]
-});
-Ext.define("Ext.chart.Markers", {
-    extend: "Ext.draw.sprite.Instancing",
-    isMarkers: true,
-    defaultCategory: "default",
-    constructor: function() {
-        this.callParent(arguments);
-        this.categories = {};
-        this.revisions = {}
-    },
-    destroy: function() {
-        this.categories = null;
-        this.revisions = null;
-        this.callParent()
-    },
-    getMarkerFor: function(b, a) {
-        if (b in this.categories) {
-            var c = this.categories[b];
-            if (a in c) {
-                return this.get(c[a])
-            }
-        }
-    },
-    clear: function(a) {
-        a = a || this.defaultCategory;
-        if (!(a in this.revisions)) {
-            this.revisions[a] = 1
-        } else {
-            this.revisions[a]++
-        }
-    },
-    putMarkerFor: function(e, b, c, h, f) {
-        e = e || this.defaultCategory;
-        var d = this,
-            g = d.categories[e] || (d.categories[e] = {}),
-            a;
-        if (c in g) {
-            d.setAttributesFor(g[c], b, h)
-        } else {
-            g[c] = d.getCount();
-            d.createInstance(b, h)
-        }
-        a = d.get(g[c]);
-        if (a) {
-            a.category = e;
-            if (!f) {
-                a.revision = d.revisions[e] || (d.revisions[e] = 1)
-            }
-        }
-    },
-    getMarkerBBoxFor: function(c, a, b) {
-        if (c in this.categories) {
-            var d = this.categories[c];
-            if (a in d) {
-                return this.getBBoxFor(d[a], b)
-            }
-        }
-    },
-    getBBox: function() {
-        return null
-    },
-    render: function(a, l, b) {
-        var f = this,
-            k = f.revisions,
-            j = f.attr.matrix,
-            h = f.getTemplate(),
-            d = h.attr,
-            g, c, e;
-        j.toContext(l);
-        h.preRender(a, l, b);
-        h.useAttributes(l, b);
-        for (c = 0, e = f.instances.length; c < e; c++) {
-            g = f.get(c);
-            if (g.hidden || g.revision !== k[g.category]) {
-                continue
-            }
-            l.save();
-            h.attr = g;
-            h.useAttributes(l, b);
-            h.render(a, l, b);
-            l.restore()
-        }
-        h.attr = d
-    }
-});
-Ext.define("Ext.chart.label.Callout", {
-    extend: "Ext.draw.modifier.Modifier",
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("calloutOriginal")) {
-            a.calloutOriginal = Ext.Object.chain(a);
-            a.calloutOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.calloutOriginal)
-        }
-    },
-    setAttrs: function(e, h) {
-        var d = e.callout,
-            i = e.calloutOriginal,
-            l = e.bbox.plain,
-            c = (l.width || 0) + e.labelOverflowPadding,
-            m = (l.height || 0) + e.labelOverflowPadding,
-            p, o;
-        if ("callout" in h) {
-            d = h.callout
-        }
-        if ("callout" in h || "calloutPlaceX" in h || "calloutPlaceY" in h || "x" in h || "y" in h) {
-            var n = "rotationRads" in h ? i.rotationRads = h.rotationRads : i.rotationRads,
-                g = "x" in h ? (i.x = h.x) : i.x,
-                f = "y" in h ? (i.y = h.y) : i.y,
-                b = "calloutPlaceX" in h ? h.calloutPlaceX : e.calloutPlaceX,
-                a = "calloutPlaceY" in h ? h.calloutPlaceY : e.calloutPlaceY,
-                k = "calloutVertical" in h ? h.calloutVertical : e.calloutVertical,
-                j;
-            n %= Math.PI * 2;
-            if (Math.cos(n) < 0) {
-                n = (n + Math.PI) % (Math.PI * 2)
-            }
-            if (n > Math.PI) {
-                n -= Math.PI * 2
-            }
-            if (k) {
-                n = n * (1 - d) - Math.PI / 2 * d;
-                j = c;
-                c = m;
-                m = j
-            } else {
-                n = n * (1 - d)
-            }
-            h.rotationRads = n;
-            h.x = g * (1 - d) + b * d;
-            h.y = f * (1 - d) + a * d;
-            p = b - g;
-            o = a - f;
-            if (Math.abs(o * c) > Math.abs(p * m)) {
-                if (o > 0) {
-                    h.calloutEndX = h.x - (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y - (m / 2) * d
-                } else {
-                    h.calloutEndX = h.x + (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y + (m / 2) * d
-                }
-            } else {
-                if (p > 0) {
-                    h.calloutEndX = h.x - c / 2;
-                    h.calloutEndY = h.y - (c / 2) * (o / p) * d
-                } else {
-                    h.calloutEndX = h.x + c / 2;
-                    h.calloutEndY = h.y + (c / 2) * (o / p) * d
-                }
-            }
-            if (h.calloutStartX && h.calloutStartY) {
-                h.calloutHasLine = (p > 0 && h.calloutStartX < h.calloutEndX) || (p <= 0 && h.calloutStartX > h.calloutEndX) || (o > 0 && h.calloutStartY < h.calloutEndY) || (o <= 0 && h.calloutStartY > h.calloutEndY)
-            } else {
-                h.calloutHasLine = true
-            }
-        }
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.calloutOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    }
-});
-Ext.define("Ext.chart.label.Label", {
-    extend: "Ext.draw.sprite.Text",
-    requires: ["Ext.chart.label.Callout"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                callout: "limited01",
-                calloutHasLine: "bool",
-                calloutPlaceX: "number",
-                calloutPlaceY: "number",
-                calloutStartX: "number",
-                calloutStartY: "number",
-                calloutEndX: "number",
-                calloutEndY: "number",
-                calloutColor: "color",
-                calloutWidth: "number",
-                calloutVertical: "bool",
-                labelOverflowPadding: "number",
-                display: "enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",
-                orientation: "enums(horizontal,vertical)",
-                renderer: "default"
-            },
-            defaults: {
-                callout: 0,
-                calloutHasLine: true,
-                calloutPlaceX: 0,
-                calloutPlaceY: 0,
-                calloutStartX: 0,
-                calloutStartY: 0,
-                calloutEndX: 0,
-                calloutEndY: 0,
-                calloutWidth: 1,
-                calloutVertical: false,
-                calloutColor: "black",
-                labelOverflowPadding: 5,
-                display: "none",
-                orientation: "",
-                renderer: null
-            },
-            triggers: {
-                callout: "transform",
-                calloutPlaceX: "transform",
-                calloutPlaceY: "transform",
-                labelOverflowPadding: "transform",
-                calloutRotation: "transform",
-                display: "hidden"
-            },
-            updaters: {
-                hidden: function(a) {
-                    a.hidden = a.display === "none"
-                }
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                callout: 200
-            }
-        },
-        field: null,
-        calloutLine: true
-    },
-    applyCalloutLine: function(a) {
-        if (a) {
-            return Ext.apply({}, a)
-        }
-    },
-    prepareModifiers: function() {
-        this.callParent(arguments);
-        this.calloutModifier = new Ext.chart.label.Callout({
-            sprite: this
-        });
-        this.fx.setNext(this.calloutModifier);
-        this.calloutModifier.setNext(this.topModifier)
-    },
-    render: function(b, c) {
-        var e = this,
-            a = e.attr,
-            d = a.calloutColor;
-        c.save();
-        c.globalAlpha *= a.callout;
-        if (c.globalAlpha > 0 && a.calloutHasLine) {
-            if (d && d.isGradient) {
-                d = d.getStops()[0].color
-            }
-            c.strokeStyle = d;
-            c.fillStyle = d;
-            c.lineWidth = a.calloutWidth;
-            c.beginPath();
-            c.moveTo(e.attr.calloutStartX, e.attr.calloutStartY);
-            c.lineTo(e.attr.calloutEndX, e.attr.calloutEndY);
-            c.stroke();
-            c.beginPath();
-            c.arc(e.attr.calloutStartX, e.attr.calloutStartY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill();
-            c.beginPath();
-            c.arc(e.attr.calloutEndX, e.attr.calloutEndY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill()
-        }
-        c.restore();
-        Ext.draw.sprite.Text.prototype.render.apply(e, arguments)
-    }
-});
-Ext.define("Ext.chart.series.Series", {
-    requires: ["Ext.chart.Markers", "Ext.chart.label.Label", "Ext.tip.ToolTip"],
-    mixins: ["Ext.mixin.Observable", "Ext.mixin.Bindable"],
-    isSeries: true,
-    defaultBindProperty: "store",
-    type: null,
-    seriesType: "sprite",
-    identifiablePrefix: "ext-line-",
-    observableType: "series",
-    darkerStrokeRatio: 0.15,
-    config: {
-        chart: null,
-        title: null,
-        renderer: null,
-        showInLegend: true,
-        triggerAfterDraw: false,
-        style: {},
-        subStyle: {},
-        themeStyle: {},
-        colors: null,
-        useDarkerStrokeColor: true,
-        store: null,
-        label: {},
-        labelOverflowPadding: null,
-        showMarkers: true,
-        marker: null,
-        markerSubStyle: null,
-        itemInstancing: null,
-        background: null,
-        highlightItem: null,
-        surface: null,
-        overlaySurface: null,
-        hidden: false,
-        highlight: false,
-        highlightCfg: {
-            merge: function(a) {
-                return a
-            },
-            $value: {
-                fillStyle: "yellow",
-                strokeStyle: "red"
-            }
-        },
-        animation: null,
-        tooltip: null
-    },
-    directions: [],
-    sprites: null,
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 0
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        var a = this.getChart();
-        if (a && a.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    updateTitle: function(a) {
-        var j = this,
-            g = j.getChart();
-        if (!g || g.isInitializing) {
-            return
-        }
-        a = Ext.Array.from(a);
-        var c = g.getSeries(),
-            b = Ext.Array.indexOf(c, j),
-            e = g.getLegendStore(),
-            h = j.getYField(),
-            d, l, k, f;
-        if (e.getCount() && b !== -1) {
-            f = h ? Math.min(a.length, h.length) : a.length;
-            for (d = 0; d < f; d++) {
-                k = a[d];
-                l = e.getAt(b + d);
-                if (k && l) {
-                    l.set("name", k)
-                }
-            }
-        }
-    },
-    applyHighlight: function(a, b) {
-        if (Ext.isObject(a)) {
-            a = Ext.merge({}, this.config.highlightCfg, a)
-        } else {
-            if (a === true) {
-                a = this.config.highlightCfg
-            }
-        }
-        return Ext.apply(b || {}, a)
-    },
-    updateHighlight: function(a) {
-        this.getStyle();
-        if (!Ext.Object.isEmpty(a)) {
-            this.addItemHighlight()
-        }
-    },
-    updateHighlightCfg: function(a) {
-        if (!Ext.Object.equals(a, this.defaultConfig.highlightCfg)) {
-            this.addItemHighlight()
-        }
-    },
-    applyItemInstancing: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    setAttributesForItem: function(c, d) {
-        var b = c && c.sprite,
-            a;
-        if (b) {
-            if (b.itemsMarker && c.category === "items") {
-                b.putMarker(c.category, d, c.index, false, true)
-            }
-            if (b.isMarkerHolder && c.category === "markers") {
-                b.putMarker(c.category, d, c.index, false, true)
-            } else {
-                if (b.isInstancing) {
-                    b.setAttributesFor(c.index, d)
-                } else {
-                    if (Ext.isArray(b)) {
-                        for (a = 0; a < b.length; a++) {
-                            b[a].setAttributes(d)
-                        }
-                    } else {
-                        b.setAttributes(d)
-                    }
-                }
-            }
-        }
-    },
-    getBBoxForItem: function(a) {
-        if (a && a.sprite) {
-            if (a.sprite.itemsMarker && a.category === "items") {
-                return a.sprite.getMarkerBBox(a.category, a.index)
-            } else {
-                if (a.sprite instanceof Ext.draw.sprite.Instancing) {
-                    return a.sprite.getBBoxFor(a.index)
-                } else {
-                    return a.sprite.getBBox()
-                }
-            }
-        }
-        return null
-    },
-    applyHighlightItem: function(d, a) {
-        if (d === a) {
-            return
-        }
-        if (Ext.isObject(d) && Ext.isObject(a)) {
-            var c = d.sprite === a.sprite,
-                b = d.index === a.index;
-            if (c && b) {
-                return
-            }
-        }
-        return d
-    },
-    updateHighlightItem: function(b, a) {
-        this.setAttributesForItem(a, {
-            highlighted: false
-        });
-        this.setAttributesForItem(b, {
-            highlighted: true
-        })
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if (a.tips) {
-            a = Ext.apply({
-                tooltip: a.tips
-            }, a)
-        }
-        if (a.highlightCfg) {
-            a = Ext.apply({
-                highlight: a.highlightCfg
-            }, a)
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.sprites = [];
-        b.dataRange = [];
-        b.mixins.observable.constructor.call(b, a);
-        b.initBindable()
-    },
-    lookupViewModel: function(a) {
-        var b = this.getChart();
-        return b ? b.lookupViewModel(a) : null
-    },
-    applyTooltip: function(c, b) {
-        var a = Ext.apply({
-            xtype: "tooltip",
-            renderer: Ext.emptyFn,
-            constrainPosition: true,
-            shrinkWrapDock: true,
-            autoHide: true,
-            offsetX: 10,
-            offsetY: 10
-        }, c);
-        return Ext.create(a)
-    },
-    updateTooltip: function() {
-        this.addItemHighlight()
-    },
-    addItemHighlight: function() {
-        var d = this.getChart();
-        if (!d) {
-            return
-        }
-        var e = d.getInteractions(),
-            c, a, b;
-        for (c = 0; c < e.length; c++) {
-            a = e[c];
-            if (a.isItemHighlight || a.isItemEdit) {
-                b = true;
-                break
-            }
-        }
-        if (!b) {
-            e.push("itemhighlight");
-            d.setInteractions(e)
-        }
-    },
-    showTooltip: function(l, m) {
-        var d = this,
-            n = d.getTooltip(),
-            j, a, i, f, h, k, g, e, b, c;
-        if (!n) {
-            return
-        }
-        clearTimeout(d.tooltipTimeout);
-        b = n.config;
-        if (n.trackMouse) {
-            m[0] += b.offsetX;
-            m[1] += b.offsetY
-        } else {
-            j = l.sprite;
-            a = j.getSurface();
-            i = Ext.get(a.getId());
-            if (i) {
-                k = l.series.getBBoxForItem(l);
-                g = k.x + k.width / 2;
-                e = k.y + k.height / 2;
-                h = a.matrix.transformPoint([g, e]);
-                f = i.getXY();
-                c = a.getInherited().rtl;
-                g = c ? f[0] + i.getWidth() - h[0] : f[0] + h[0];
-                e = f[1] + h[1];
-                m = [g, e]
-            }
-        }
-        Ext.callback(n.renderer, n.scope, [n, l.record, l], 0, d);
-        n.show(m)
-    },
-    hideTooltip: function(b) {
-        var a = this,
-            c = a.getTooltip();
-        if (!c) {
-            return
-        }
-        clearTimeout(a.tooltipTimeout);
-        a.tooltipTimeout = Ext.defer(function() {
-            c.hide()
-        }, 1)
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    getStore: function() {
-        return this._store || this.getChart() && this.getChart().getStore()
-    },
-    updateStore: function(b, a) {
-        var h = this,
-            g = h.getChart(),
-            c = g && g.getStore(),
-            f, j, e, d;
-        a = a || c;
-        if (a && a !== b) {
-            a.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            })
-        }
-        if (b) {
-            b.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            });
-            f = h.getSprites();
-            for (d = 0, e = f.length; d < e; d++) {
-                j = f[d];
-                if (j.setStore) {
-                    j.setStore(b)
-                }
-            }
-            h.onDataChanged()
-        }
-        h.fireEvent("storechange", h, b, a)
-    },
-    onStoreChange: function(b, a, c) {
-        if (!this._store) {
-            this.updateStore(a, c)
-        }
-    },
-    coordinate: function(o, m, e) {
-        var l = this,
-            p = l.getStore(),
-            h = l.getHidden(),
-            k = p.getData().items,
-            b = l["get" + o + "Axis"](),
-            f = {
-                min: Infinity,
-                max: -Infinity
-            },
-            q = l["fieldCategory" + o] || [o],
-            g = l.getFields(q),
-            d, n, c, a = {},
-            j = l.getSprites();
-        if (j.length > 0) {
-            if (!Ext.isBoolean(h) || !h) {
-                for (d = 0; d < q.length; d++) {
-                    n = g[d];
-                    c = l.coordinateData(k, n, b);
-                    l.getRangeOfData(c, f);
-                    a["data" + q[d]] = c
-                }
-            }
-            l.dataRange[m] = f.min;
-            l.dataRange[m + e] = f.max;
-            a["dataMin" + o] = f.min;
-            a["dataMax" + o] = f.max;
-            if (b) {
-                b.range = null;
-                a["range" + o] = b.getRange()
-            }
-            for (d = 0; d < j.length; d++) {
-                j[d].setAttributes(a)
-            }
-        }
-    },
-    coordinateData: function(b, h, d) {
-        var g = [],
-            f = b.length,
-            e = d && d.getLayout(),
-            c, a;
-        for (c = 0; c < f; c++) {
-            a = b[c].data[h];
-            if (!Ext.isEmpty(a, true)) {
-                if (e) {
-                    g[c] = e.getCoordFor(a, h, c, b)
-                } else {
-                    g[c] = +a
-                }
-            } else {
-                g[c] = a
-            }
-        }
-        return g
-    },
-    getRangeOfData: function(g, b) {
-        var e = g.length,
-            d = b.min,
-            a = b.max,
-            c, f;
-        for (c = 0; c < e; c++) {
-            f = g[c];
-            if (f < d) {
-                d = f
-            }
-            if (f > a) {
-                a = f
-            }
-        }
-        b.min = d;
-        b.max = a
-    },
-    updateLabelData: function() {
-        var h = this,
-            l = h.getStore(),
-            g = l.getData().items,
-            f = h.getSprites(),
-            a = h.getLabel().getTemplate(),
-            n = Ext.Array.from(a.getField()),
-            c, b, e, d, m, k;
-        if (!f.length || !n.length) {
-            return
-        }
-        for (c = 0; c < f.length; c++) {
-            d = [];
-            m = f[c];
-            k = m.getField();
-            if (Ext.Array.indexOf(n, k) < 0) {
-                k = n[c]
-            }
-            for (b = 0, e = g.length; b < e; b++) {
-                d.push(g[b].get(k))
-            }
-            m.setAttributes({
-                labels: d
-            })
-        }
-    },
-    processData: function() {
-        if (!this.getStore()) {
-            return
-        }
-        var d = this,
-            f = this.directions,
-            a, c = f.length,
-            e, b;
-        for (a = 0; a < c; a++) {
-            e = f[a];
-            b = d["get" + e + "Axis"]();
-            if (b) {
-                b.processData(d);
-                continue
-            }
-            if (d["coordinate" + e]) {
-                d["coordinate" + e]()
-            }
-        }
-        d.updateLabelData()
-    },
-    applyBackground: function(a) {
-        if (this.getChart()) {
-            this.getSurface().setBackground(a);
-            return this.getSurface().getBackground()
-        } else {
-            return a
-        }
-    },
-    updateChart: function(d, a) {
-        var c = this,
-            b = c._store;
-        if (a) {
-            a.un("axeschange", "onAxesChange", c);
-            c.clearSprites();
-            c.setSurface(null);
-            c.setOverlaySurface(null);
-            a.unregister(c);
-            c.onChartDetached(a);
-            if (!b) {
-                c.updateStore(null)
-            }
-        }
-        if (d) {
-            c.setSurface(d.getSurface("series"));
-            c.setOverlaySurface(d.getSurface("overlay"));
-            d.on("axeschange", "onAxesChange", c);
-            if (d.getAxes()) {
-                c.onAxesChange(d)
-            }
-            c.onChartAttached(d);
-            d.register(c);
-            if (!b) {
-                c.updateStore(d.getStore())
-            }
-        }
-    },
-    onAxesChange: function(h) {
-        var k = this,
-            g = h.getAxes(),
-            c, a = {},
-            b = {},
-            e = false,
-            j = this.directions,
-            l, d, f;
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            b[l] = k.getFields(k["fieldCategory" + l])
-        }
-        for (d = 0, f = g.length; d < f; d++) {
-            c = g[d];
-            if (!a[c.getDirection()]) {
-                a[c.getDirection()] = [c]
-            } else {
-                a[c.getDirection()].push(c)
-            }
-        }
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            if (k["get" + l + "Axis"]()) {
-                continue
-            }
-            if (a[l]) {
-                c = k.findMatchingAxis(a[l], b[l]);
-                if (c) {
-                    k["set" + l + "Axis"](c);
-                    if (c.getNeedHighPrecision()) {
-                        e = true
-                    }
-                }
-            }
-        }
-        this.getSurface().setHighPrecision(e)
-    },
-    findMatchingAxis: function(f, e) {
-        var d, c, b, a;
-        for (b = 0; b < f.length; b++) {
-            d = f[b];
-            c = d.getFields();
-            if (!c.length) {
-                return d
-            } else {
-                if (e) {
-                    for (a = 0; a < e.length; a++) {
-                        if (Ext.Array.indexOf(c, e[a]) >= 0) {
-                            return d
-                        }
-                    }
-                }
-            }
-        }
-    },
-    onChartDetached: function(a) {
-        var b = this;
-        b.fireEvent("chartdetached", a, b);
-        a.un("storechange", "onStoreChange", b)
-    },
-    onChartAttached: function(a) {
-        var b = this;
-        b.setBackground(b.getBackground());
-        b.fireEvent("chartattached", a, b);
-        a.on("storechange", "onStoreChange", b);
-        b.processData()
-    },
-    updateOverlaySurface: function(a) {
-        var b = this;
-        if (a) {
-            if (b.getLabel()) {
-                b.getOverlaySurface().add(b.getLabel())
-            }
-        }
-    },
-    applyLabel: function(a, b) {
-        if (!b) {
-            b = new Ext.chart.Markers({
-                zIndex: 10
-            });
-            b.setTemplate(new Ext.chart.label.Label(a))
-        } else {
-            b.getTemplate().setAttributes(a)
-        }
-        return b
-    },
-    createItemInstancingSprite: function(c, b) {
-        var e = this,
-            f = new Ext.chart.Markers(),
-            a, d;
-        f.setAttributes({
-            zIndex: Number.MAX_VALUE
-        });
-        a = Ext.apply({}, b);
-        if (e.getHighlight()) {
-            a.highlight = e.getHighlight();
-            a.modifiers = ["highlight"]
-        }
-        f.setTemplate(a);
-        d = f.getTemplate();
-        d.setAttributes(e.getStyle());
-        d.fx.on("animationstart", "onSpriteAnimationStart", this);
-        d.fx.on("animationend", "onSpriteAnimationEnd", this);
-        c.bindMarker("items", f);
-        e.getSurface().add(f);
-        return f
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer()
-        }
-    },
-    updateRenderer: function(c) {
-        var b = this,
-            a = b.getChart(),
-            d;
-        if (a && a.isInitializing) {
-            return
-        }
-        d = b.getSprites();
-        if (d.length) {
-            d[0].setAttributes({
-                renderer: c || null
-            });
-            if (a && !a.isInitializing) {
-                a.redraw()
-            }
-        }
-    },
-    updateShowMarkers: function(a) {
-        var d = this.getSprites(),
-            b = d && d[0],
-            c = b && b.getMarker("markers");
-        if (c) {
-            c.getTemplate().setAttributes({
-                hidden: !a
-            })
-        }
-    },
-    createSprite: function() {
-        var f = this,
-            a = f.getSurface(),
-            e = f.getItemInstancing(),
-            d = a.add(f.getDefaultSpriteConfig()),
-            b = f.getMarker(),
-            g, c;
-        d.setAttributes(f.getStyle());
-        d.setSeries(f);
-        if (e) {
-            d.itemsMarker = f.createItemInstancingSprite(d, e)
-        }
-        if (d.bindMarker) {
-            if (b) {
-                g = new Ext.chart.Markers();
-                c = Ext.Object.merge({}, b);
-                if (f.getHighlight()) {
-                    c.highlight = f.getHighlight();
-                    c.modifiers = ["highlight"]
-                }
-                g.setTemplate(c);
-                g.getTemplate().fx.setCustomDurations({
-                    translationX: 0,
-                    translationY: 0
-                });
-                d.dataMarker = g;
-                d.bindMarker("markers", g);
-                f.getOverlaySurface().add(g)
-            }
-            if (f.getLabel().getTemplate().getField()) {
-                d.bindMarker("labels", f.getLabel())
-            }
-        }
-        if (d.setStore) {
-            d.setStore(f.getStore())
-        }
-        d.fx.on("animationstart", "onSpriteAnimationStart", f);
-        d.fx.on("animationend", "onSpriteAnimationEnd", f);
-        f.sprites.push(d);
-        return d
-    },
-    getSprites: Ext.emptyFn,
-    onDataChanged: function() {
-        var d = this,
-            c = d.getChart(),
-            b = c && c.getStore(),
-            a = d.getStore();
-        if (a !== b) {
-            d.processData()
-        }
-    },
-    isXType: function(a) {
-        return a === "series"
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    applyThemeStyle: function(e, a) {
-        var b = this,
-            d, c;
-        d = e && e.subStyle && e.subStyle.fillStyle;
-        c = d && e.subStyle.strokeStyle;
-        if (d && !c) {
-            e.subStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        d = e && e.markerSubStyle && e.markerSubStyle.fillStyle;
-        c = d && e.markerSubStyle.strokeStyle;
-        if (d && !c) {
-            e.markerSubStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        return Ext.apply(a || {}, e)
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        return Ext.apply({}, c, b)
-    },
-    applySubStyle: function(b, c) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            b = a.def.batchedNormalize(b, true)
-        }
-        return Ext.merge({}, c, b)
-    },
-    applyMarker: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.normalize(Ext.isObject(c) ? c : {}, true);
-            c.type = d
-        }
-        return Ext.merge(a || {}, c)
-    },
-    applyMarkerSubStyle: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.batchedNormalize(c, true)
-        }
-        return Ext.merge(a || {}, c)
-    },
-    updateHidden: function(b) {
-        var a = this;
-        a.getColors();
-        a.getSubStyle();
-        a.setSubStyle({
-            hidden: b
-        });
-        a.processData();
-        a.doUpdateStyles();
-        if (!Ext.isArray(b)) {
-            a.updateLegendStore(b)
-        }
-    },
-    updateLegendStore: function(f, b) {
-        var e = this,
-            d = e.getChart(),
-            c = d.getLegendStore(),
-            g = e.getId(),
-            a;
-        if (c) {
-            if (arguments.length > 1) {
-                a = c.findBy(function(h) {
-                    return h.get("series") === g && h.get("index") === b
-                });
-                if (a !== -1) {
-                    a = c.getAt(a)
-                }
-            } else {
-                a = c.findRecord("series", g)
-            }
-            if (a && a.get("disabled") !== f) {
-                a.set("disabled", f)
-            }
-        }
-    },
-    setHiddenByIndex: function(a, c) {
-        var b = this;
-        if (Ext.isArray(b.getHidden())) {
-            b.getHidden()[a] = c;
-            b.updateHidden(b.getHidden());
-            b.updateLegendStore(c, a)
-        } else {
-            b.setHidden(c)
-        }
-    },
-    getStrokeColorsFromFillColors: function(a) {
-        var c = this,
-            e = c.getUseDarkerStrokeColor(),
-            b = (Ext.isNumber(e) ? e : c.darkerStrokeRatio),
-            d;
-        if (e) {
-            d = Ext.Array.map(a, function(f) {
-                f = Ext.isString(f) ? f : f.stops[0].color;
-                f = Ext.draw.Color.fromString(f);
-                return f.createDarker(b).toString()
-            })
-        } else {
-            d = Ext.Array.clone(a)
-        }
-        return d
-    },
-    updateThemeColors: function(b) {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = Ext.Array.clone(b),
-            f = c.getStrokeColorsFromFillColors(b),
-            e = {
-                fillStyle: a,
-                strokeStyle: f
-            };
-        d.subStyle = Ext.apply(d.subStyle || {}, e);
-        d.markerSubStyle = Ext.apply(d.markerSubStyle || {}, e);
-        c.doUpdateStyles()
-    },
-    themeOnlyIfConfigured: {},
-    updateTheme: function(d) {
-        var h = this,
-            a = d.getSeries(),
-            n = h.getInitialConfig(),
-            c = h.defaultConfig,
-            f = h.getConfigurator().configs,
-            j = a.defaults,
-            k = a[h.type],
-            g = h.themeOnlyIfConfigured,
-            l, i, o, b, m, e;
-        a = Ext.merge({}, j, k);
-        for (l in a) {
-            i = a[l];
-            e = f[l];
-            if (i !== null && i !== undefined && e) {
-                m = n[l];
-                o = Ext.isObject(i);
-                b = m === c[l];
-                if (o) {
-                    if (b && g[l]) {
-                        continue
-                    }
-                    i = Ext.merge({}, i, m)
-                }
-                if (b || o) {
-                    h[e.names.set](i)
-                }
-            }
-        }
-    },
-    updateChartColors: function(a) {
-        var b = this;
-        if (!b.getColors()) {
-            b.updateThemeColors(a)
-        }
-    },
-    updateColors: function(a) {
-        this.updateThemeColors(a)
-    },
-    updateStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateSubStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateThemeStyle: function() {
-        this.doUpdateStyles()
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.sprites,
-            d = g.getItemInstancing(),
-            c = 0,
-            f = h && h.length,
-            a = g.getConfig("showMarkers", true),
-            b = g.getMarker(),
-            e;
-        for (; c < f; c++) {
-            e = g.getStyleByIndex(c);
-            if (d) {
-                h[c].itemsMarker.getTemplate().setAttributes(e)
-            }
-            h[c].setAttributes(e);
-            if (b && h[c].dataMarker) {
-                h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))
-            }
-        }
-    },
-    getStyleWithTheme: function() {
-        var b = this,
-            c = b.getThemeStyle(),
-            d = (c && c.style) || {},
-            a = Ext.applyIf(Ext.apply({}, b.getStyle()), d);
-        return a
-    },
-    getSubStyleWithTheme: function() {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = (d && d.subStyle) || {},
-            b = Ext.applyIf(Ext.apply({}, c.getSubStyle()), a);
-        return b
-    },
-    getStyleByIndex: function(b) {
-        var e = this,
-            h = e.getThemeStyle(),
-            d, g, c, f, a = {};
-        d = e.getStyle();
-        g = (h && h.style) || {};
-        c = e.styleDataForIndex(e.getSubStyle(), b);
-        f = e.styleDataForIndex((h && h.subStyle), b);
-        Ext.apply(a, g);
-        Ext.apply(a, f);
-        Ext.apply(a, d);
-        Ext.apply(a, c);
-        return a
-    },
-    getMarkerStyleByIndex: function(d) {
-        var g = this,
-            c = g.getThemeStyle(),
-            a, e, k, j, b, l, h, f, m = {};
-        a = g.getStyle();
-        e = (c && c.style) || {};
-        k = g.styleDataForIndex(g.getSubStyle(), d);
-        if (k.hasOwnProperty("hidden")) {
-            k.hidden = k.hidden || !this.getConfig("showMarkers", true)
-        }
-        j = g.styleDataForIndex((c && c.subStyle), d);
-        b = g.getMarker();
-        l = (c && c.marker) || {};
-        h = g.getMarkerSubStyle();
-        f = g.styleDataForIndex((c && c.markerSubStyle), d);
-        Ext.apply(m, e);
-        Ext.apply(m, j);
-        Ext.apply(m, l);
-        Ext.apply(m, f);
-        Ext.apply(m, a);
-        Ext.apply(m, k);
-        Ext.apply(m, b);
-        Ext.apply(m, h);
-        return m
-    },
-    styleDataForIndex: function(d, c) {
-        var e, b, a = {};
-        if (d) {
-            for (b in d) {
-                e = d[b];
-                if (Ext.isArray(e)) {
-                    a[b] = e[c % e.length]
-                } else {
-                    a[b] = e
-                }
-            }
-        }
-        return a
-    },
-    getItemForPoint: Ext.emptyFn,
-    getItemByIndex: function(a, e) {
-        var d = this,
-            f = d.getSprites(),
-            b = f && f[0],
-            c;
-        if (!b) {
-            return
-        }
-        if (e === undefined && b.isMarkerHolder) {
-            e = d.getItemInstancing() ? "items" : "markers"
-        } else {
-            if (!e || e === "" || e === "sprites") {
-                b = f[a]
-            }
-        }
-        if (b) {
-            c = {
-                series: d,
-                category: e,
-                index: a,
-                record: d.getStore().getData().items[a],
-                field: d.getYField(),
-                sprite: b
-            };
-            return c
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.fireEvent("animationstart", this, a)
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.fireEvent("animationend", this, a)
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    provideLegendInfo: function(a) {
-        a.push({
-            name: this.getTitle() || this.getId(),
-            mark: "black",
-            disabled: this.getHidden(),
-            series: this.getId(),
-            index: 0
-        })
-    },
-    clearSprites: function() {
-        var d = this.sprites,
-            b, a, c;
-        for (a = 0, c = d.length; a < c; a++) {
-            b = d[a];
-            if (b && b.isSprite) {
-                b.destroy()
-            }
-        }
-        this.sprites = []
-    },
-    destroy: function() {
-        var b = this,
-            a = b._store,
-            c = b.getConfig("tooltip", true);
-        if (a && a.getAutoDestroy()) {
-            Ext.destroy(a)
-        }
-        b.setChart(null);
-        b.clearListeners();
-        if (c) {
-            Ext.destroy(c);
-            clearTimeout(b.tooltipTimeout)
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Abstract", {
-    xtype: "interaction",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        gestures: {
-            tap: "onGesture"
-        },
-        chart: null,
-        enabled: true
-    },
-    throttleGap: 0,
-    stopAnimationBeforeSync: false,
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.call(b, a)
-    },
-    initialize: Ext.emptyFn,
-    updateChart: function(c, a) {
-        var b = this;
-        if (a === c) {
-            return
-        }
-        if (a) {
-            a.unregister(b);
-            b.removeChartListener(a)
-        }
-        if (c) {
-            c.register(b);
-            b.addChartListener()
-        }
-    },
-    updateEnabled: function(a) {
-        var c = this,
-            b = c.getChart();
-        if (b) {
-            if (a) {
-                c.addChartListener()
-            } else {
-                c.removeChartListener(b)
-            }
-        }
-    },
-    onGesture: Ext.emptyFn,
-    getItemForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemForPoint(c[0], c[1])
-    },
-    getItemsForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemsForPoint(c[0], c[1])
-    },
-    addChartListener: function() {
-        var c = this,
-            b = c.getChart(),
-            e = c.getGestures(),
-            a;
-        if (!c.getEnabled()) {
-            return
-        }
-
-        function d(f, g) {
-            b.addElementListener(f, c.listeners[f] = function(j) {
-                var i = c.getLocks(),
-                    h;
-                if (c.getEnabled() && (!(f in i) || i[f] === c)) {
-                    h = (Ext.isFunction(g) ? g : c[g]).apply(this, arguments);
-                    if (h === false && j && j.stopPropagation) {
-                        j.stopPropagation()
-                    }
-                    return h
-                }
-            }, c)
-        }
-        c.listeners = c.listeners || {};
-        for (a in e) {
-            d(a, e[a])
-        }
-    },
-    removeChartListener: function(c) {
-        var d = this,
-            e = d.getGestures(),
-            b;
-
-        function a(f) {
-            var g = d.listeners[f];
-            if (g) {
-                c.removeElementListener(f, g);
-                delete d.listeners[f]
-            }
-        }
-        if (d.listeners) {
-            for (b in e) {
-                a(b)
-            }
-        }
-    },
-    lockEvents: function() {
-        var d = this,
-            c = d.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            c[a[b]] = d
-        }
-    },
-    unlockEvents: function() {
-        var c = this.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            delete c[a[b]]
-        }
-    },
-    getLocks: function() {
-        var a = this.getChart();
-        return a.lockedEvents || (a.lockedEvents = {})
-    },
-    isMultiTouch: function() {
-        if (Ext.browser.is.IE10) {
-            return true
-        }
-        return !Ext.os.is.Desktop
-    },
-    initializeDefaults: Ext.emptyFn,
-    doSync: function() {
-        var b = this,
-            a = b.getChart();
-        if (b.syncTimer) {
-            clearTimeout(b.syncTimer);
-            b.syncTimer = null
-        }
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount++
-        }
-        a.redraw();
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount--
-        }
-        b.syncThrottle = Date.now() + b.throttleGap
-    },
-    sync: function() {
-        var a = this;
-        if (a.throttleGap && Ext.frameStartTime < a.syncThrottle) {
-            if (a.syncTimer) {
-                return
-            }
-            a.syncTimer = Ext.defer(function() {
-                a.doSync()
-            }, a.throttleGap)
-        } else {
-            a.doSync()
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    isXType: function(a) {
-        return a === "interaction"
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        delete a.listeners;
-        a.callParent()
-    }
-}, function() {
-    if (Ext.os.is.Android4) {
-        this.prototype.throttleGap = 40
-    }
-});
-Ext.define("Ext.chart.MarkerHolder", {
-    extend: "Ext.Mixin",
-    mixinConfig: {
-        id: "markerHolder",
-        after: {
-            constructor: "constructor",
-            preRender: "preRender"
-        },
-        before: {
-            destroy: "destroy"
-        }
-    },
-    isMarkerHolder: true,
-    surfaceMatrix: null,
-    inverseSurfaceMatrix: null,
-    deprecated: {
-        6: {
-            methods: {
-                getBoundMarker: {
-                    message: "Please use the 'getMarker' method instead.",
-                    fn: function(b) {
-                        var a = this.boundMarkers[b];
-                        return a ? [a] : a
-                    }
-                }
-            }
-        }
-    },
-    constructor: function() {
-        this.boundMarkers = {};
-        this.cleanRedraw = false
-    },
-    bindMarker: function(b, a) {
-        var c = this,
-            d = c.boundMarkers;
-        if (a && a.isMarkers) {
-            c.releaseMarker(b);
-            d[b] = a;
-            a.on("destroy", c.onMarkerDestroy, c)
-        }
-    },
-    onMarkerDestroy: function(a) {
-        this.releaseMarker(a)
-    },
-    releaseMarker: function(a) {
-        var c = this.boundMarkers,
-            b;
-        if (a && a.isMarkers) {
-            for (b in c) {
-                if (c[b] === a) {
-                    delete c[b];
-                    break
-                }
-            }
-        } else {
-            b = a;
-            a = c[b];
-            delete c[b]
-        }
-        return a || null
-    },
-    getMarker: function(a) {
-        return this.boundMarkers[a] || null
-    },
-    preRender: function() {
-        var f = this,
-            g = f.getId(),
-            d = f.boundMarkers,
-            e = f.getParent(),
-            c, a, b;
-        if (f.surfaceMatrix) {
-            b = f.surfaceMatrix.set(1, 0, 0, 1, 0, 0)
-        } else {
-            b = f.surfaceMatrix = new Ext.draw.Matrix()
-        }
-        f.cleanRedraw = !f.attr.dirty;
-        if (!f.cleanRedraw) {
-            for (c in d) {
-                a = d[c];
-                if (a) {
-                    a.clear(g)
-                }
-            }
-        }
-        while (e && e.attr && e.attr.matrix) {
-            b.prependMatrix(e.attr.matrix);
-            e = e.getParent()
-        }
-        b.prependMatrix(e.matrix);
-        f.surfaceMatrix = b;
-        f.inverseSurfaceMatrix = b.inverse(f.inverseSurfaceMatrix)
-    },
-    putMarker: function(d, a, c, g, e) {
-        var b = this.boundMarkers[d],
-            f = this.getId();
-        if (b) {
-            b.putMarkerFor(f, a, c, g, e)
-        }
-    },
-    getMarkerBBox: function(c, b, d) {
-        var a = this.boundMarkers[c],
-            e = this.getId();
-        if (a) {
-            return a.getMarkerBBoxFor(e, b, d)
-        }
-    },
-    destroy: function() {
-        var c = this.boundMarkers,
-            b, a;
-        for (b in c) {
-            a = c[b];
-            a.destroy()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.axis",
-    type: "axis",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    requires: ["Ext.draw.sprite.Text"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                grid: "bool",
-                axisLine: "bool",
-                minorTicks: "bool",
-                minorTickSize: "number",
-                majorTicks: "bool",
-                majorTickSize: "number",
-                length: "number",
-                startGap: "number",
-                endGap: "number",
-                dataMin: "number",
-                dataMax: "number",
-                visibleMin: "number",
-                visibleMax: "number",
-                position: "enums(left,right,top,bottom,angular,radial,gauge)",
-                minStepSize: "number",
-                estStepSize: "number",
-                titleOffset: "number",
-                textPadding: "number",
-                min: "number",
-                max: "number",
-                centerX: "number",
-                centerY: "number",
-                radius: "number",
-                totalAngle: "number",
-                baseRotation: "number",
-                data: "default",
-                enlargeEstStepSizeByText: "bool"
-            },
-            defaults: {
-                grid: false,
-                axisLine: true,
-                minorTicks: false,
-                minorTickSize: 3,
-                majorTicks: true,
-                majorTickSize: 5,
-                length: 0,
-                startGap: 0,
-                endGap: 0,
-                visibleMin: 0,
-                visibleMax: 1,
-                dataMin: 0,
-                dataMax: 1,
-                position: "",
-                minStepSize: 0,
-                estStepSize: 20,
-                min: 0,
-                max: 1,
-                centerX: 0,
-                centerY: 0,
-                radius: 1,
-                baseRotation: 0,
-                data: null,
-                titleOffset: 0,
-                textPadding: 0,
-                scalingCenterY: 0,
-                scalingCenterX: 0,
-                strokeStyle: "black",
-                enlargeEstStepSizeByText: false
-            },
-            triggers: {
-                minorTickSize: "bbox",
-                majorTickSize: "bbox",
-                position: "bbox,layout",
-                axisLine: "bbox,layout",
-                min: "layout",
-                max: "layout",
-                length: "layout",
-                minStepSize: "layout",
-                estStepSize: "layout",
-                data: "layout",
-                dataMin: "layout",
-                dataMax: "layout",
-                visibleMin: "layout",
-                visibleMax: "layout",
-                enlargeEstStepSizeByText: "layout"
-            },
-            updaters: {
-                layout: "layoutUpdater"
-            }
-        }
-    },
-    config: {
-        label: null,
-        layout: null,
-        segmenter: null,
-        renderer: null,
-        layoutContext: null,
-        axis: null
-    },
-    thickness: 0,
-    stepSize: 0,
-    getBBox: function() {
-        return null
-    },
-    defaultRenderer: function(a) {
-        return this.segmenter.renderer(a, this)
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            c = e.position,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (c === "left" || c === "right") {
-            e.translationX = 0;
-            e.translationY = i * e.length / (i - b);
-            e.scalingX = 1;
-            e.scalingY = -e.length / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (c === "top" || c === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * e.length / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    iterate: function(e, j) {
-        var c, g, a, b, h, d, k = Ext.Array.some,
-            m = Math.abs,
-            f;
-        if (e.getLabel) {
-            if (e.min < e.from) {
-                j.call(this, e.min, e.getLabel(e.min), -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                j.call(this, e.get(c), e.getLabel(c), c, e)
-            }
-            if (e.max > e.to) {
-                j.call(this, e.max, e.getLabel(e.max), e.steps + 1, e)
-            }
-        } else {
-            b = this.getAxis();
-            h = b.floatingAxes;
-            d = [];
-            f = (e.to - e.from) / (e.steps + 1);
-            if (b.getFloating()) {
-                for (a in h) {
-                    d.push(h[a])
-                }
-            }
-
-            function l(i) {
-                return !d.length || k(d, function(n) {
-                    return m(n - i) > f
-                })
-            }
-            if (e.min < e.from && l(e.min)) {
-                j.call(this, e.min, e.min, -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                g = e.get(c);
-                if (l(g)) {
-                    j.call(this, g, g, c, e)
-                }
-            }
-            if (e.max > e.to && l(e.max)) {
-                j.call(this, e.max, e.max, e.steps + 1, e)
-            }
-        }
-    },
-    renderTicks: function(l, m, s, p) {
-        var v = this,
-            k = v.attr,
-            u = k.position,
-            n = k.matrix,
-            e = 0.5 * k.lineWidth,
-            f = n.getXX(),
-            i = n.getDX(),
-            j = n.getYY(),
-            h = n.getDY(),
-            o = s.majorTicks,
-            d = k.majorTickSize,
-            a = s.minorTicks,
-            r = k.minorTickSize;
-        if (o) {
-            switch (u) {
-                case "right":
-                    function q(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(0, x);
-                            m.lineTo(w, x)
-                        }
-                    }
-                    v.iterate(o, q(d));
-                    a && v.iterate(a, q(r));
-                    break;
-                case "left":
-                    function t(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(p[2] - w, x);
-                            m.lineTo(p[2], x)
-                        }
-                    }
-                    v.iterate(o, t(d));
-                    a && v.iterate(a, t(r));
-                    break;
-                case "bottom":
-                    function c(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, 0);
-                            m.lineTo(x, w)
-                        }
-                    }
-                    v.iterate(o, c(d));
-                    a && v.iterate(a, c(r));
-                    break;
-                case "top":
-                    function b(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, p[3]);
-                            m.lineTo(x, p[3] - w)
-                        }
-                    }
-                    v.iterate(o, b(d));
-                    a && v.iterate(a, b(r));
-                    break;
-                case "angular":
-                    v.iterate(o, function(w, y, x) {
-                        w = w / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break;
-                case "gauge":
-                    var g = v.getGaugeAngles();
-                    v.iterate(o, function(w, y, x) {
-                        w = (w - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + g.start;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break
-            }
-        }
-    },
-    renderLabels: function(E, q, D, K) {
-        var o = this,
-            k = o.attr,
-            i = 0.5 * k.lineWidth,
-            u = k.position,
-            y = k.matrix,
-            A = k.textPadding,
-            x = y.getXX(),
-            d = y.getDX(),
-            g = y.getYY(),
-            c = y.getDY(),
-            n = 0,
-            I = D.majorTicks,
-            G = Math.max(k.majorTickSize, k.minorTickSize) + k.lineWidth,
-            f = Ext.draw.Draw.isBBoxIntersect,
-            F = o.getLabel(),
-            J, s, r = null,
-            w = 0,
-            b = 0,
-            m = D.segmenter,
-            B = o.getRenderer(),
-            t = o.getAxis(),
-            z = t.getTitle(),
-            a = z && z.attr.text !== "" && z.getBBox(),
-            l, h = null,
-            p, C, v, e, H;
-        if (I && F && !F.attr.hidden) {
-            J = F.attr.font;
-            if (q.font !== J) {
-                q.font = J
-            }
-            F.setAttributes({
-                translationX: 0,
-                translationY: 0
-            }, true);
-            F.applyTransformations();
-            l = F.attr.inverseMatrix.elements.slice(0);
-            switch (u) {
-                case "left":
-                    e = a ? a.x + a.width : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(e + d) - i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - G + d) - i;
-                            break;
-                        default:
-                            H = E.roundPixel(e + (K[2] - e - G) / 2 + d) - i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "right":
-                    e = a ? K[2] - a.x : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(G + d) + i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - e + d) + i;
-                            break;
-                        default:
-                            H = E.roundPixel(G + (K[2] - G - e) / 2 + d) + i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "top":
-                    e = a ? a.y + a.height : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(e + (K[3] - e - G) / 2) - i
-                    }, true);
-                    break;
-                case "bottom":
-                    e = a ? K[3] - a.y : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(G + (K[3] - G - e) / 2) + i
-                    }, true);
-                    break;
-                case "radial":
-                    F.setAttributes({
-                        translationX: k.centerX
-                    }, true);
-                    break;
-                case "angular":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break;
-                case "gauge":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break
-            }
-            if (u === "left" || u === "right") {
-                o.iterate(I, function(L, N, M) {
-                    if (N === undefined) {
-                        return
-                    }
-                    if (B) {
-                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                    } else {
-                        v = m.renderer(N, D, r)
-                    }
-                    r = N;
-                    F.setAttributes({
-                        text: String(v),
-                        translationY: E.roundPixel(L * g + c)
-                    }, true);
-                    F.applyTransformations();
-                    n = Math.max(n, F.getBBox().width + G);
-                    if (n <= o.thickness) {
-                        C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                        p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                        if (h && !f(p, h, A)) {
-                            return
-                        }
-                        E.renderSprite(F);
-                        h = p;
-                        w += p.height;
-                        b++
-                    }
-                })
-            } else {
-                if (u === "top" || u === "bottom") {
-                    o.iterate(I, function(L, N, M) {
-                        if (N === undefined) {
-                            return
-                        }
-                        if (B) {
-                            v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                        } else {
-                            v = m.renderer(N, D, r)
-                        }
-                        r = N;
-                        F.setAttributes({
-                            text: String(v),
-                            translationX: E.roundPixel(L * x + d)
-                        }, true);
-                        F.applyTransformations();
-                        n = Math.max(n, F.getBBox().height + G);
-                        if (n <= o.thickness) {
-                            C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                            p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                            if (h && !f(p, h, A)) {
-                                return
-                            }
-                            E.renderSprite(F);
-                            h = p;
-                            w += p.width;
-                            b++
-                        }
-                    })
-                } else {
-                    if (u === "radial") {
-                        o.iterate(I, function(L, N, M) {
-                            if (N === undefined) {
-                                return
-                            }
-                            if (B) {
-                                v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                            } else {
-                                v = m.renderer(N, D, r)
-                            }
-                            r = N;
-                            if (typeof v !== "undefined") {
-                                F.setAttributes({
-                                    text: String(v),
-                                    translationX: k.centerX - E.roundPixel(L) / k.max * k.length * Math.cos(k.baseRotation + Math.PI / 2),
-                                    translationY: k.centerY - E.roundPixel(L) / k.max * k.length * Math.sin(k.baseRotation + Math.PI / 2)
-                                }, true);
-                                F.applyTransformations();
-                                p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                if (h && !f(p, h)) {
-                                    return
-                                }
-                                E.renderSprite(F);
-                                h = p;
-                                w += p.width;
-                                b++
-                            }
-                        })
-                    } else {
-                        if (u === "angular") {
-                            s = k.majorTickSize + k.lineWidth * 0.5 + (parseInt(F.attr.fontSize, 10) || 10) / 2;
-                            o.iterate(I, function(L, N, M) {
-                                if (N === undefined) {
-                                    return
-                                }
-                                if (B) {
-                                    v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                } else {
-                                    v = m.renderer(N, D, r)
-                                }
-                                r = N;
-                                n = Math.max(n, Math.max(k.majorTickSize, k.minorTickSize) + (k.lineCap !== "butt" ? k.lineWidth * 0.5 : 0));
-                                if (typeof v !== "undefined") {
-                                    var O = L / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                                    F.setAttributes({
-                                        text: String(v),
-                                        translationX: k.centerX + (k.length + s) * Math.cos(O),
-                                        translationY: k.centerY + (k.length + s) * Math.sin(O)
-                                    }, true);
-                                    F.applyTransformations();
-                                    p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                    if (h && !f(p, h)) {
-                                        return
-                                    }
-                                    E.renderSprite(F);
-                                    h = p;
-                                    w += p.width;
-                                    b++
-                                }
-                            })
-                        } else {
-                            if (u === "gauge") {
-                                var j = o.getGaugeAngles();
-                                o.iterate(I, function(L, N, M) {
-                                    if (N === undefined) {
-                                        return
-                                    }
-                                    if (B) {
-                                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                    } else {
-                                        v = m.renderer(N, D, r)
-                                    }
-                                    r = N;
-                                    if (typeof v !== "undefined") {
-                                        var O = (L - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + j.start;
-                                        F.setAttributes({
-                                            text: String(v),
-                                            translationX: k.centerX + (k.length + 10) * Math.cos(O),
-                                            translationY: k.centerY + (k.length + 10) * Math.sin(O)
-                                        }, true);
-                                        F.applyTransformations();
-                                        p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                        if (h && !f(p, h)) {
-                                            return
-                                        }
-                                        E.renderSprite(F);
-                                        h = p;
-                                        w += p.width;
-                                        b++
-                                    }
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-            if (k.enlargeEstStepSizeByText && b) {
-                w /= b;
-                w += G;
-                w *= 2;
-                if (k.estStepSize < w) {
-                    k.estStepSize = w
-                }
-            }
-            if (Math.abs(o.thickness - (n)) > 1) {
-                o.thickness = n;
-                k.bbox.plain.dirty = true;
-                k.bbox.transform.dirty = true;
-                o.doThicknessChanged();
-                return false
-            }
-        }
-    },
-    renderAxisLine: function(a, i, e, c) {
-        var h = this,
-            g = h.attr,
-            b = g.lineWidth * 0.5,
-            j = g.position,
-            d, f;
-        if (g.axisLine && g.length) {
-            switch (j) {
-                case "left":
-                    d = a.roundPixel(c[2]) - b;
-                    i.moveTo(d, -g.endGap);
-                    i.lineTo(d, g.length + g.startGap + 1);
-                    break;
-                case "right":
-                    i.moveTo(b, -g.endGap);
-                    i.lineTo(b, g.length + g.startGap + 1);
-                    break;
-                case "bottom":
-                    i.moveTo(-g.startGap, b);
-                    i.lineTo(g.length + g.endGap, b);
-                    break;
-                case "top":
-                    d = a.roundPixel(c[3]) - b;
-                    i.moveTo(-g.startGap, d);
-                    i.lineTo(g.length + g.endGap, d);
-                    break;
-                case "angular":
-                    i.moveTo(g.centerX + g.length, g.centerY);
-                    i.arc(g.centerX, g.centerY, g.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    f = h.getGaugeAngles();
-                    i.moveTo(g.centerX + Math.cos(f.start) * g.length, g.centerY + Math.sin(f.start) * g.length);
-                    i.arc(g.centerX, g.centerY, g.length, f.start, f.end, true);
-                    break
-            }
-        }
-    },
-    getGaugeAngles: function() {
-        var a = this,
-            c = a.attr.totalAngle,
-            b;
-        if (c <= Math.PI) {
-            b = (Math.PI - c) * 0.5
-        } else {
-            b = -(Math.PI * 2 - c) * 0.5
-        }
-        b = Math.PI * 2 - b;
-        return {
-            start: b,
-            end: b - c
-        }
-    },
-    renderGridLines: function(m, n, s, r) {
-        var t = this,
-            b = t.getAxis(),
-            l = t.attr,
-            p = l.matrix,
-            d = l.startGap,
-            a = l.endGap,
-            c = p.getXX(),
-            k = p.getYY(),
-            h = p.getDX(),
-            g = p.getDY(),
-            u = l.position,
-            f = b.getGridAlignment(),
-            q = s.majorTicks,
-            e, o, i;
-        if (l.grid) {
-            if (q) {
-                if (u === "left" || u === "right") {
-                    i = l.min * k + g + a + d;
-                    t.iterate(q, function(j, w, v) {
-                        e = j * k + g + a;
-                        t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                            y: e,
-                            height: i - e
-                        }, o = v, true);
-                        i = e
-                    });
-                    o++;
-                    e = 0;
-                    t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                        y: e,
-                        height: i - e
-                    }, o, true)
-                } else {
-                    if (u === "top" || u === "bottom") {
-                        i = l.min * c + h + d;
-                        if (d) {
-                            t.putMarker(f + "-even", {
-                                x: 0,
-                                width: i
-                            }, -1, true)
-                        }
-                        t.iterate(q, function(j, w, v) {
-                            e = j * c + h + d;
-                            t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                x: e,
-                                width: i - e
-                            }, o = v, true);
-                            i = e
-                        });
-                        o++;
-                        e = l.length + l.startGap + l.endGap;
-                        t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                            x: e,
-                            width: i - e
-                        }, o, true)
-                    } else {
-                        if (u === "radial") {
-                            t.iterate(q, function(j, w, v) {
-                                if (!j) {
-                                    return
-                                }
-                                e = j / l.max * l.length;
-                                t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                    scalingX: e,
-                                    scalingY: e
-                                }, v, true);
-                                i = e
-                            })
-                        } else {
-                            if (u === "angular") {
-                                t.iterate(q, function(j, w, v) {
-                                    if (!l.length) {
-                                        return
-                                    }
-                                    e = j / (l.max + 1) * Math.PI * 2 + l.baseRotation;
-                                    t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                        rotationRads: e,
-                                        rotationCenterX: 0,
-                                        rotationCenterY: 0,
-                                        scalingX: l.length,
-                                        scalingY: l.length
-                                    }, v, true);
-                                    i = e
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    renderLimits: function(o) {
-        var t = this,
-            a = t.getAxis(),
-            h = a.getChart(),
-            p = h.getInnerPadding(),
-            d = Ext.Array.from(a.getLimits());
-        if (!d.length) {
-            return
-        }
-        var r = a.limits.surface.getRect(),
-            m = t.attr,
-            n = m.matrix,
-            u = m.position,
-            k = Ext.Object.chain,
-            v = a.limits.titles,
-            c, j, b, s, l, q, f, g, e;
-        v.instances = [];
-        v.position = 0;
-        if (u === "left" || u === "right") {
-            for (q = 0, f = d.length; q < f; q++) {
-                s = k(d[q]);
-                !s.line && (s.line = {});
-                l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                l = l * n.getYY() + n.getDY();
-                s.line.y = l + p.top;
-                s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                t.putMarker("horizontal-limit-lines", s.line, q, true);
-                if (s.line.title) {
-                    v.createInstance(s.line.title);
-                    c = v.getBBoxFor(v.position - 1);
-                    j = s.line.title.position || (u === "left" ? "start" : "end");
-                    switch (j) {
-                        case "start":
-                            g = 10;
-                            break;
-                        case "end":
-                            g = r[2] - 10;
-                            break;
-                        case "middle":
-                            g = r[2] / 2;
-                            break
-                    }
-                    v.setAttributesFor(v.position - 1, {
-                        x: g,
-                        y: s.line.y - c.height / 2,
-                        textAlign: j,
-                        fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                    })
-                }
-            }
-        } else {
-            if (u === "top" || u === "bottom") {
-                for (q = 0, f = d.length; q < f; q++) {
-                    s = k(d[q]);
-                    !s.line && (s.line = {});
-                    l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                    l = l * n.getXX() + n.getDX();
-                    s.line.x = l + p.left;
-                    s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                    t.putMarker("vertical-limit-lines", s.line, q, true);
-                    if (s.line.title) {
-                        v.createInstance(s.line.title);
-                        c = v.getBBoxFor(v.position - 1);
-                        j = s.line.title.position || (u === "top" ? "end" : "start");
-                        switch (j) {
-                            case "start":
-                                e = r[3] - c.width / 2 - 10;
-                                break;
-                            case "end":
-                                e = c.width / 2 + 10;
-                                break;
-                            case "middle":
-                                e = r[3] / 2;
-                                break
-                        }
-                        v.setAttributesFor(v.position - 1, {
-                            x: s.line.x + c.height / 2,
-                            y: e,
-                            fillStyle: s.line.title.fillStyle || s.line.strokeStyle,
-                            rotationRads: Math.PI / 2
-                        })
-                    }
-                }
-            } else {
-                if (u === "radial") {
-                    for (q = 0, f = d.length; q < f; q++) {
-                        s = k(d[q]);
-                        !s.line && (s.line = {});
-                        l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                        if (l > m.max) {
-                            continue
-                        }
-                        l = l / m.max * m.length;
-                        s.line.cx = m.centerX;
-                        s.line.cy = m.centerY;
-                        s.line.scalingX = l;
-                        s.line.scalingY = l;
-                        s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                        t.putMarker("circular-limit-lines", s.line, q, true);
-                        if (s.line.title) {
-                            v.createInstance(s.line.title);
-                            c = v.getBBoxFor(v.position - 1);
-                            v.setAttributesFor(v.position - 1, {
-                                x: m.centerX,
-                                y: m.centerY - l - c.height / 2,
-                                fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                            })
-                        }
-                    }
-                } else {
-                    if (u === "angular") {
-                        for (q = 0, f = d.length; q < f; q++) {
-                            s = k(d[q]);
-                            !s.line && (s.line = {});
-                            l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                            l = l / (m.max + 1) * Math.PI * 2 + m.baseRotation;
-                            s.line.translationX = m.centerX;
-                            s.line.translationY = m.centerY;
-                            s.line.rotationRads = l;
-                            s.line.rotationCenterX = 0;
-                            s.line.rotationCenterY = 0;
-                            s.line.scalingX = m.length;
-                            s.line.scalingY = m.length;
-                            s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                            t.putMarker("radial-limit-lines", s.line, q, true);
-                            if (s.line.title) {
-                                v.createInstance(s.line.title);
-                                c = v.getBBoxFor(v.position - 1);
-                                b = ((l > -0.5 * Math.PI && l < 0.5 * Math.PI) || (l > 1.5 * Math.PI && l < 2 * Math.PI)) ? 1 : -1;
-                                v.setAttributesFor(v.position - 1, {
-                                    x: m.centerX + 0.5 * m.length * Math.cos(l) + b * c.height / 2 * Math.sin(l),
-                                    y: m.centerY + 0.5 * m.length * Math.sin(l) - b * c.height / 2 * Math.cos(l),
-                                    rotationRads: b === 1 ? l : l - Math.PI,
-                                    fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                                })
-                            }
-                        }
-                    } else {
-                        if (u === "gauge") {}
-                    }
-                }
-            }
-        }
-    },
-    doThicknessChanged: function() {
-        var a = this.getAxis();
-        if (a) {
-            a.onThicknessChanged()
-        }
-    },
-    render: function(a, c, d) {
-        var e = this,
-            b = e.getLayoutContext();
-        if (b) {
-            if (false === e.renderLabels(a, c, b, d)) {
-                return false
-            }
-            c.beginPath();
-            e.renderTicks(a, c, b, d);
-            e.renderAxisLine(a, c, b, d);
-            e.renderGridLines(a, c, b, d);
-            e.renderLimits(d);
-            c.stroke()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Segmenter", {
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    renderer: function(b, a) {
-        return String(b)
-    },
-    from: function(a) {
-        return a
-    },
-    diff: Ext.emptyFn,
-    align: Ext.emptyFn,
-    add: Ext.emptyFn,
-    preferredStep: Ext.emptyFn
-});
-Ext.define("Ext.chart.axis.segmenter.Names", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.names",
-    renderer: function(b, a) {
-        return b
-    },
-    diff: function(b, a, c) {
-        return Math.floor(a - b)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c)
-    },
-    add: function(c, b, a) {
-        return c + b
-    },
-    preferredStep: function(c, a, b, d) {
-        return {
-            unit: 1,
-            step: 1
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Numeric", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.numeric",
-    isNumeric: true,
-    renderer: function(b, a) {
-        return b.toFixed(Math.max(0, a.majorTicks.unit.fixes))
-    },
-    diff: function(b, a, c) {
-        return Math.floor((a - b) / c.scale)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c / (a.scale * b)) * a.scale * b
-    },
-    add: function(c, b, a) {
-        return c + b * a.scale
-    },
-    preferredStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        b /= d;
-        if (b < 2) {
-            b = 2
-        } else {
-            if (b < 5) {
-                b = 5
-            } else {
-                if (b < 10) {
-                    b = 10;
-                    a++
-                }
-            }
-        }
-        return {
-            unit: {
-                fixes: -a,
-                scale: d
-            },
-            step: b
-        }
-    },
-    exactStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        return {
-            unit: {
-                fixes: -a + (b % d === 0 ? 0 : 1),
-                scale: 1
-            },
-            step: b
-        }
-    },
-    adjustByMajorUnit: function(e, g, c) {
-        var d = c[0],
-            b = c[1],
-            a = e * g,
-            f = d % a;
-        if (f !== 0) {
-            c[0] = d - f + (d < 0 ? -a : 0)
-        }
-        f = b % a;
-        if (f !== 0) {
-            c[1] = b - f + (b > 0 ? a : 0)
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Time", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.time",
-    config: {
-        step: null
-    },
-    renderer: function(c, b) {
-        var a = Ext.Date;
-        switch (b.majorTicks.unit) {
-            case "y":
-                return a.format(c, "Y");
-            case "mo":
-                return a.format(c, "Y-m");
-            case "d":
-                return a.format(c, "Y-m-d")
-        }
-        return a.format(c, "Y-m-d\nH:i:s")
-    },
-    from: function(a) {
-        return new Date(a)
-    },
-    diff: function(b, a, c) {
-        if (isFinite(b)) {
-            b = new Date(b)
-        }
-        if (isFinite(a)) {
-            a = new Date(a)
-        }
-        return Ext.Date.diff(b, a, c)
-    },
-    align: function(a, c, b) {
-        if (b === "d" && c >= 7) {
-            a = Ext.Date.align(a, "d", c);
-            a.setDate(a.getDate() - a.getDay() + 1);
-            return a
-        } else {
-            return Ext.Date.align(a, b, c)
-        }
-    },
-    add: function(c, b, a) {
-        return Ext.Date.add(new Date(c), a, b)
-    },
-    stepUnits: [
-        [Ext.Date.YEAR, 1, 2, 5, 10, 20, 50, 100, 200, 500],
-        [Ext.Date.MONTH, 1, 3, 6],
-        [Ext.Date.DAY, 1, 7, 14],
-        [Ext.Date.HOUR, 1, 6, 12],
-        [Ext.Date.MINUTE, 1, 5, 15, 30],
-        [Ext.Date.SECOND, 1, 5, 15, 30],
-        [Ext.Date.MILLI, 1, 2, 5, 10, 20, 50, 100, 200, 500]
-    ],
-    preferredStep: function(b, e) {
-        if (this.getStep()) {
-            return this.getStep()
-        }
-        var f = new Date(+b),
-            g = new Date(+b + Math.ceil(e)),
-            d = this.stepUnits,
-            l, k, h, c, a;
-        for (c = 0; c < d.length; c++) {
-            k = d[c][0];
-            h = this.diff(f, g, k);
-            if (h > 0) {
-                for (a = 1; a < d[c].length; a++) {
-                    if (h <= d[c][a]) {
-                        l = {
-                            unit: k,
-                            step: d[c][a]
-                        };
-                        break
-                    }
-                }
-                if (!l) {
-                    c--;
-                    l = {
-                        unit: d[c][0],
-                        step: 1
-                    }
-                }
-                break
-            }
-        }
-        if (!l) {
-            l = {
-                unit: Ext.Date.DAY,
-                step: 1
-            }
-        }
-        return l
-    }
-});
-Ext.define("Ext.chart.axis.layout.Layout", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    processData: function(b) {
-        var e = this,
-            c = e.getAxis(),
-            f = c.getDirection(),
-            g = c.boundSeries,
-            a, d;
-        if (b) {
-            b["coordinate" + f]()
-        } else {
-            for (a = 0, d = g.length; a < d; a++) {
-                g[a]["coordinate" + f]()
-            }
-        }
-    },
-    calculateMajorTicks: function(a) {
-        var f = this,
-            e = a.attr,
-            d = e.max - e.min,
-            i = d / Math.max(1, e.length) * (e.visibleMax - e.visibleMin),
-            h = e.min + d * e.visibleMin,
-            b = e.min + d * e.visibleMax,
-            g = e.estStepSize * i,
-            c = f.snapEnds(a, e.min, e.max, g);
-        if (c) {
-            f.trimByRange(a, c, h, b);
-            a.majorTicks = c
-        }
-    },
-    calculateMinorTicks: function(a) {
-        if (this.snapMinorEnds) {
-            a.minorTicks = this.snapMinorEnds(a)
-        }
-    },
-    calculateLayout: function(b) {
-        var c = this,
-            a = b.attr;
-        if (a.length === 0) {
-            return null
-        }
-        if (a.majorTicks) {
-            c.calculateMajorTicks(b);
-            if (a.minorTicks) {
-                c.calculateMinorTicks(b)
-            }
-        }
-    },
-    snapEnds: Ext.emptyFn,
-    trimByRange: function(b, f, i, a) {
-        var g = b.segmenter,
-            j = f.unit,
-            h = g.diff(f.from, i, j),
-            d = g.diff(f.from, a, j),
-            c = Math.max(0, Math.ceil(h / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = g.add(f.from, e * f.step, j)
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < i) {
-            f.from = g.add(f.from, c * f.step, j);
-            while (f.from < i) {
-                c++;
-                f.from = g.add(f.from, f.step, j)
-            }
-        }
-        if (f.min < i) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    }
-});
-Ext.define("Ext.chart.axis.layout.Discrete", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.discrete",
-    isDiscrete: true,
-    processData: function() {
-        var f = this,
-            d = f.getAxis(),
-            c = d.boundSeries,
-            g = d.getDirection(),
-            b, e, a;
-        f.labels = [];
-        f.labelMap = {};
-        for (b = 0, e = c.length; b < e; b++) {
-            a = c[b];
-            if (a["get" + g + "Axis"]() === d) {
-                a["coordinate" + g]()
-            }
-        }
-        d.getSprites()[0].setAttributes({
-            data: f.labels
-        });
-        f.fireEvent("datachange", f.labels)
-    },
-    calculateLayout: function(a) {
-        a.data = this.labels;
-        this.callParent([a])
-    },
-    calculateMajorTicks: function(a) {
-        var g = this,
-            f = a.attr,
-            d = a.data,
-            e = f.max - f.min,
-            j = e / Math.max(1, f.length) * (f.visibleMax - f.visibleMin),
-            i = f.min + e * f.visibleMin,
-            b = f.min + e * f.visibleMax,
-            h = f.estStepSize * j;
-        var c = g.snapEnds(a, Math.max(0, f.min), Math.min(f.max, d.length - 1), h);
-        if (c) {
-            g.trimByRange(a, c, i, b);
-            a.majorTicks = c
-        }
-    },
-    snapEnds: function(e, d, a, b) {
-        b = Math.ceil(b);
-        var c = Math.floor((a - d) / b),
-            f = e.data;
-        return {
-            min: d,
-            max: a,
-            from: d,
-            to: c * b + d,
-            step: b,
-            steps: c,
-            unit: 1,
-            getLabel: function(g) {
-                return f[this.from + this.step * g]
-            },
-            get: function(g) {
-                return this.from + this.step * g
-            }
-        }
-    },
-    trimByRange: function(b, f, h, a) {
-        var i = f.unit,
-            g = Math.ceil((h - f.from) / i) * i,
-            d = Math.floor((a - f.from) / i) * i,
-            c = Math.max(0, Math.ceil(g / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = e
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < h && f.step > 0) {
-            f.from = f.from + c * f.step * i;
-            while (f.from < h) {
-                c++;
-                f.from += f.step * i
-            }
-        }
-        if (f.min < h) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    },
-    getCoordFor: function(c, d, a, b) {
-        this.labels.push(c);
-        return this.labels.length - 1
-    }
-});
-Ext.define("Ext.chart.axis.layout.CombineDuplicate", {
-    extend: "Ext.chart.axis.layout.Discrete",
-    alias: "axisLayout.combineDuplicate",
-    getCoordFor: function(d, e, b, c) {
-        if (!(d in this.labelMap)) {
-            var a = this.labelMap[d] = this.labels.length;
-            this.labels.push(d);
-            return a
-        }
-        return this.labelMap[d]
-    }
-});
-Ext.define("Ext.chart.axis.layout.Continuous", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.continuous",
-    isContinuous: true,
-    config: {
-        adjustMinimumByMajorUnit: false,
-        adjustMaximumByMajorUnit: false
-    },
-    getCoordFor: function(c, d, a, b) {
-        return +c
-    },
-    snapEnds: function(a, d, i, h) {
-        var f = a.segmenter,
-            c = this.getAxis(),
-            l = c.getMajorTickSteps(),
-            e = l && f.exactStep ? f.exactStep(d, (i - d) / l) : f.preferredStep(d, h),
-            k = e.unit,
-            b = e.step,
-            j = f.align(d, b, k),
-            g = (l || f.diff(d, i, k)) + 1;
-        return {
-            min: f.from(d),
-            max: f.from(i),
-            from: j,
-            to: f.add(j, g * b, k),
-            step: b,
-            steps: g,
-            unit: k,
-            get: function(m) {
-                return f.add(this.from, this.step * m, k)
-            }
-        }
-    },
-    snapMinorEnds: function(a) {
-        var e = a.majorTicks,
-            m = this.getAxis().getMinorTickSteps(),
-            f = a.segmenter,
-            d = e.min,
-            i = e.max,
-            k = e.from,
-            l = e.unit,
-            b = e.step / m,
-            n = b * l.scale,
-            j = k - d,
-            c = Math.floor(j / n),
-            h = c + Math.floor((i - e.to) / n) + 1,
-            g = e.steps * m + h;
-        return {
-            min: d,
-            max: i,
-            from: d + j % n,
-            to: f.add(k, g * b, l),
-            step: b,
-            steps: g,
-            unit: l,
-            get: function(o) {
-                return (o % m + c + 1 !== 0) ? f.add(this.from, this.step * o, l) : null
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis", {
-    xtype: "axis",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.chart.axis.sprite.Axis", "Ext.chart.axis.segmenter.*", "Ext.chart.axis.layout.*"],
-    isAxis: true,
-    config: {
-        position: "bottom",
-        fields: [],
-        label: undefined,
-        grid: false,
-        limits: null,
-        renderer: null,
-        chart: null,
-        style: null,
-        margin: 0,
-        titleMargin: 4,
-        background: null,
-        minimum: NaN,
-        maximum: NaN,
-        reconcileRange: false,
-        minZoom: 1,
-        maxZoom: 10000,
-        layout: "continuous",
-        segmenter: "numeric",
-        hidden: false,
-        majorTickSteps: 0,
-        minorTickSteps: 0,
-        adjustByMajorUnit: true,
-        title: null,
-        increment: 0.5,
-        length: 0,
-        center: null,
-        radius: null,
-        totalAngle: Math.PI,
-        rotation: null,
-        labelInSpan: null,
-        visibleRange: [0, 1],
-        needHighPrecision: false,
-        linkedTo: null,
-        floating: null
-    },
-    titleOffset: 0,
-    spriteAnimationCount: 0,
-    prevMin: 0,
-    prevMax: 1,
-    boundSeries: [],
-    sprites: null,
-    surface: null,
-    range: null,
-    xValues: [],
-    yValues: [],
-    masterAxis: null,
-    applyRotation: function(b) {
-        var a = Math.PI * 2;
-        return (b % a + Math.PI) % a - Math.PI
-    },
-    updateRotation: function(b) {
-        var c = this.getSprites(),
-            a = this.getPosition();
-        if (!this.getHidden() && a === "angular" && c[0]) {
-            c[0].setAttributes({
-                baseRotation: b
-            })
-        }
-    },
-    applyTitle: function(c, b) {
-        var a;
-        if (Ext.isString(c)) {
-            c = {
-                text: c
-            }
-        }
-        if (!b) {
-            b = Ext.create("sprite.text", c);
-            if ((a = this.getSurface())) {
-                a.add(b)
-            }
-        } else {
-            b.setAttributes(c)
-        }
-        return b
-    },
-    applyFloating: function(b, a) {
-        if (b === null) {
-            b = {
-                value: null,
-                alongAxis: null
-            }
-        } else {
-            if (Ext.isNumber(b)) {
-                b = {
-                    value: b,
-                    alongAxis: null
-                }
-            }
-        }
-        if (Ext.isObject(b)) {
-            if (a && a.alongAxis) {
-                delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]
-            }
-            return b
-        }
-        return a
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        b.sprites = [];
-        b.labels = [];
-        b.floatingAxes = {};
-        a = a || {};
-        if (a.position === "angular") {
-            a.style = a.style || {};
-            a.style.estStepSize = 1
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.apply(b, arguments)
-    },
-    getAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "vertical";
-            case "top":
-            case "bottom":
-                return "horizontal";
-            case "radial":
-                return "radial";
-            case "angular":
-                return "angular"
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal";
-            case "top":
-            case "bottom":
-                return "vertical";
-            case "radial":
-                return "circular";
-            case "angular":
-                return "radial"
-        }
-    },
-    getSurface: function() {
-        var e = this,
-            d = e.getChart();
-        if (d && !e.surface) {
-            var b = e.surface = d.getSurface(e.getId(), "axis"),
-                c = e.gridSurface = d.getSurface("main"),
-                a = e.getSprites()[0],
-                f = e.getGridAlignment();
-            c.waitFor(b);
-            e.getGrid();
-            if (e.getLimits() && f) {
-                f = f.replace("3d", "");
-                e.limits = {
-                    surface: d.getSurface("overlay"),
-                    lines: new Ext.chart.Markers(),
-                    titles: new Ext.draw.sprite.Instancing()
-                };
-                e.limits.lines.setTemplate({
-                    xclass: "grid." + f
-                });
-                e.limits.lines.getTemplate().setAttributes({
-                    strokeStyle: "black"
-                }, true);
-                e.limits.surface.add(e.limits.lines);
-                a.bindMarker(f + "-limit-lines", e.limits.lines);
-                e.limitTitleTpl = new Ext.draw.sprite.Text();
-                e.limits.titles.setTemplate(e.limitTitleTpl);
-                e.limits.surface.add(e.limits.titles);
-                d.on("redraw", e.renderLimits, e)
-            }
-        }
-        return e.surface
-    },
-    applyGrid: function(a) {
-        if (a === true) {
-            return {}
-        }
-        return a
-    },
-    updateGrid: function(b) {
-        var e = this,
-            d = e.getChart();
-        if (!d) {
-            e.on({
-                chartattached: Ext.bind(e.updateGrid, e, [b]),
-                single: true
-            });
-            return
-        }
-        var c = e.gridSurface,
-            a = e.getSprites()[0],
-            f = e.getGridAlignment(),
-            g;
-        if (b) {
-            g = e.gridSpriteEven;
-            if (!g) {
-                g = e.gridSpriteEven = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-even", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.even)) {
-                    g.getTemplate().setAttributes(b.even)
-                }
-            }
-            g = e.gridSpriteOdd;
-            if (!g) {
-                g = e.gridSpriteOdd = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-odd", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.odd)) {
-                    g.getTemplate().setAttributes(b.odd)
-                }
-            }
-        }
-    },
-    renderLimits: function() {
-        this.getSprites()[0].renderLimits()
-    },
-    getCoordFor: function(c, d, a, b) {
-        return this.getLayout().getCoordFor(c, d, a, b)
-    },
-    applyPosition: function(a) {
-        return a.toLowerCase()
-    },
-    applyLength: function(b, a) {
-        return b > 0 ? b : a
-    },
-    applyLabel: function(b, a) {
-        if (!a) {
-            a = new Ext.draw.sprite.Text({})
-        }
-        if (this.limitTitleTpl) {
-            this.limitTitleTpl.setAttributes(b)
-        }
-        a.setAttributes(b);
-        return a
-    },
-    applyLayout: function(b, a) {
-        b = Ext.factory(b, null, a, "axisLayout");
-        b.setAxis(this);
-        return b
-    },
-    applySegmenter: function(a, b) {
-        a = Ext.factory(a, null, b, "segmenter");
-        a.setAxis(this);
-        return a
-    },
-    updateMinimum: function() {
-        this.range = null
-    },
-    updateMaximum: function() {
-        this.range = null
-    },
-    hideLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: true
-        })
-    },
-    showLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: false
-        })
-    },
-    renderFrame: function() {
-        this.getSurface().renderFrame()
-    },
-    updateChart: function(d, b) {
-        var c = this,
-            a;
-        if (b) {
-            b.unregister(c);
-            b.un("serieschange", c.onSeriesChange, c);
-            b.un("redraw", c.renderLimits, c);
-            c.linkAxis();
-            c.fireEvent("chartdetached", b, c)
-        }
-        if (d) {
-            d.on("serieschange", c.onSeriesChange, c);
-            c.surface = null;
-            a = c.getSurface();
-            c.getLabel().setSurface(a);
-            a.add(c.getSprites());
-            a.add(c.getTitle());
-            d.register(c);
-            c.fireEvent("chartattached", d, c)
-        }
-    },
-    applyBackground: function(a) {
-        var b = Ext.ClassManager.getByAlias("sprite.rect");
-        return b.def.normalize(a)
-    },
-    processData: function() {
-        this.getLayout().processData();
-        this.range = null
-    },
-    getDirection: function() {
-        return this.getChart().getDirectionForAxis(this.getPosition())
-    },
-    isSide: function() {
-        var a = this.getPosition();
-        return a === "left" || a === "right"
-    },
-    applyFields: function(a) {
-        return Ext.Array.from(a)
-    },
-    applyVisibleRange: function(a, c) {
-        this.getChart();
-        if (a[0] > a[1]) {
-            var b = a[0];
-            a[0] = a[1];
-            a[0] = b
-        }
-        if (a[1] === a[0]) {
-            a[1] += 1 / this.getMaxZoom()
-        }
-        if (a[1] > a[0] + 1) {
-            a[0] = 0;
-            a[1] = 1
-        } else {
-            if (a[0] < 0) {
-                a[1] -= a[0];
-                a[0] = 0
-            } else {
-                if (a[1] > 1) {
-                    a[0] -= a[1] - 1;
-                    a[1] = 1
-                }
-            }
-        }
-        if (c && a[0] === c[0] && a[1] === c[1]) {
-            return undefined
-        }
-        return a
-    },
-    updateVisibleRange: function(a) {
-        this.fireEvent("visiblerangechange", this, a)
-    },
-    onSeriesChange: function(e) {
-        var f = this,
-            b = e.getSeries(),
-            j = "get" + f.getDirection() + "Axis",
-            g = [],
-            c, d = b.length,
-            a, h;
-        for (c = 0; c < d; c++) {
-            if (this === b[c][j]()) {
-                g.push(b[c])
-            }
-        }
-        f.boundSeries = g;
-        a = f.getLinkedTo();
-        h = !Ext.isEmpty(a) && e.getAxis(a);
-        if (h) {
-            f.linkAxis(h)
-        } else {
-            f.getLayout().processData()
-        }
-    },
-    linkAxis: function(a) {
-        var c = this;
-
-        function b(f, d, e) {
-            e.getLayout()[f]("datachange", "onDataChange", d);
-            e[f]("rangechange", "onMasterAxisRangeChange", d)
-        }
-        if (c.masterAxis) {
-            b("un", c, c.masterAxis);
-            c.masterAxis = null
-        }
-        if (a) {
-            if (a.type !== this.type) {
-                Ext.Error.raise("Linked axes must be of the same type.")
-            }
-            b("on", c, a);
-            c.onDataChange(a.getLayout().labels);
-            c.onMasterAxisRangeChange(a, a.range);
-            c.setStyle(Ext.apply({}, c.config.style, a.config.style));
-            c.setTitle(Ext.apply({}, c.config.title, a.config.title));
-            c.setLabel(Ext.apply({}, c.config.label, a.config.label));
-            c.masterAxis = a
-        }
-    },
-    onDataChange: function(a) {
-        this.getLayout().labels = a
-    },
-    onMasterAxisRangeChange: function(b, a) {
-        this.range = a
-    },
-    applyRange: function(a) {
-        if (!a) {
-            return this.dataRange.slice(0)
-        } else {
-            return [a[0] === null ? this.dataRange[0] : a[0], a[1] === null ? this.dataRange[1] : a[1]]
-        }
-    },
-    getRange: function() {
-        var m = this;
-        if (m.range) {
-            return m.range
-        } else {
-            if (m.masterAxis) {
-                return m.masterAxis.range
-            }
-        }
-        if (Ext.isNumber(m.getMinimum() + m.getMaximum())) {
-            return m.range = [m.getMinimum(), m.getMaximum()]
-        }
-        var d = Infinity,
-            n = -Infinity,
-            o = m.boundSeries,
-            h = m.getLayout(),
-            l = m.getSegmenter(),
-            p = m.getVisibleRange(),
-            b = "get" + m.getDirection() + "Range",
-            a, j, g, f, e, k;
-        for (e = 0, k = o.length; e < k; e++) {
-            f = o[e];
-            var c = f[b]();
-            if (c) {
-                if (c[0] < d) {
-                    d = c[0]
-                }
-                if (c[1] > n) {
-                    n = c[1]
-                }
-            }
-        }
-        if (!isFinite(n)) {
-            n = m.prevMax
-        }
-        if (!isFinite(d)) {
-            d = m.prevMin
-        }
-        if (m.getLabelInSpan() || d === n) {
-            n += m.getIncrement();
-            d -= m.getIncrement()
-        }
-        if (Ext.isNumber(m.getMinimum())) {
-            d = m.getMinimum()
-        } else {
-            m.prevMin = d
-        }
-        if (Ext.isNumber(m.getMaximum())) {
-            n = m.getMaximum()
-        } else {
-            m.prevMax = n
-        }
-        m.range = [Ext.Number.correctFloat(d), Ext.Number.correctFloat(n)];
-        if (m.getReconcileRange()) {
-            m.reconcileRange()
-        }
-        if (m.getAdjustByMajorUnit() && l.adjustByMajorUnit && !m.getMajorTickSteps()) {
-            j = Ext.Object.chain(m.getSprites()[0].attr);
-            j.min = m.range[0];
-            j.max = m.range[1];
-            j.visibleMin = p[0];
-            j.visibleMax = p[1];
-            a = {
-                attr: j,
-                segmenter: l
-            };
-            h.calculateLayout(a);
-            g = a.majorTicks;
-            if (g) {
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range);
-                j.min = m.range[0];
-                j.max = m.range[1];
-                delete a.majorTicks;
-                h.calculateLayout(a);
-                g = a.majorTicks;
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range)
-            } else {
-                if (!m.hasClearRangePending) {
-                    m.hasClearRangePending = true;
-                    m.getChart().on("layout", "clearRange", m)
-                }
-            }
-        }
-        if (!Ext.Array.equals(m.range, m.oldRange || [])) {
-            m.fireEvent("rangechange", m, m.range);
-            m.oldRange = m.range
-        }
-        return m.range
-    },
-    clearRange: function() {
-        delete this.hasClearRangePending;
-        this.range = null
-    },
-    reconcileRange: function() {
-        var e = this,
-            g = e.getChart().getAxes(),
-            f = e.getDirection(),
-            b, d, c, a;
-        if (!g) {
-            return
-        }
-        for (b = 0, d = g.length; b < d; b++) {
-            c = g[b];
-            a = c.getRange();
-            if (c === e || c.getDirection() !== f || !a || !c.getReconcileRange()) {
-                continue
-            }
-            if (a[0] < e.range[0]) {
-                e.range[0] = a[0]
-            }
-            if (a[1] > e.range[1]) {
-                e.range[1] = a[1]
-            }
-        }
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.getByAlias("sprite." + this.seriesType);
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        b = Ext.apply(b || {}, c);
-        return b
-    },
-    themeOnlyIfConfigured: {
-        grid: true
-    },
-    updateTheme: function(d) {
-        var i = this,
-            k = d.getAxis(),
-            e = i.getPosition(),
-            o = i.getInitialConfig(),
-            c = i.defaultConfig,
-            g = i.getConfigurator().configs,
-            a = k.defaults,
-            n = k[e],
-            h = i.themeOnlyIfConfigured,
-            l, j, p, b, m, f;
-        k = Ext.merge({}, a, n);
-        for (l in k) {
-            j = k[l];
-            f = g[l];
-            if (j !== null && j !== undefined && f) {
-                m = o[l];
-                p = Ext.isObject(j);
-                b = m === c[l];
-                if (p) {
-                    if (b && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (b || p) {
-                    i[f.names.set](j)
-                }
-            }
-        }
-    },
-    updateCenter: function(b) {
-        var e = this.getSprites(),
-            a = e[0],
-            d = b[0],
-            c = b[1];
-        if (a) {
-            a.setAttributes({
-                centerX: d,
-                centerY: c
-            })
-        }
-        if (this.gridSpriteEven) {
-            this.gridSpriteEven.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-        if (this.gridSpriteOdd) {
-            this.gridSpriteOdd.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-    },
-    getSprites: function() {
-        if (!this.getChart()) {
-            return
-        }
-        var i = this,
-            e = i.getRange(),
-            f = i.getPosition(),
-            g = i.getChart(),
-            c = g.getAnimation(),
-            d, a, b = i.getLength(),
-            h = i.superclass;
-        if (c === false) {
-            c = {
-                duration: 0
-            }
-        }
-        if (e) {
-            a = Ext.applyIf({
-                position: f,
-                axis: i,
-                min: e[0],
-                max: e[1],
-                length: b,
-                grid: i.getGrid(),
-                hidden: i.getHidden(),
-                titleOffset: i.titleOffset,
-                layout: i.getLayout(),
-                segmenter: i.getSegmenter(),
-                totalAngle: i.getTotalAngle(),
-                label: i.getLabel()
-            }, i.getStyle());
-            if (!i.sprites.length) {
-                while (!h.xtype) {
-                    h = h.superclass
-                }
-                d = Ext.create("sprite." + h.xtype, a);
-                d.fx.setCustomDurations({
-                    baseRotation: 0
-                });
-                d.fx.on("animationstart", "onAnimationStart", i);
-                d.fx.on("animationend", "onAnimationEnd", i);
-                d.setLayout(i.getLayout());
-                d.setSegmenter(i.getSegmenter());
-                d.setLabel(i.getLabel());
-                i.sprites.push(d);
-                i.updateTitleSprite()
-            } else {
-                d = i.sprites[0];
-                d.setAnimation(c);
-                d.setAttributes(a)
-            }
-            if (i.getRenderer()) {
-                d.setRenderer(i.getRenderer())
-            }
-        }
-        return i.sprites
-    },
-    updateTitleSprite: function() {
-        var f = this,
-            b = f.getLength();
-        if (!f.sprites[0] || !Ext.isNumber(b)) {
-            return
-        }
-        var h = this.sprites[0].thickness,
-            a = f.getSurface(),
-            g = f.getTitle(),
-            e = f.getPosition(),
-            c = f.getMargin(),
-            i = f.getTitleMargin(),
-            d = a.roundPixel(b / 2);
-        if (g) {
-            switch (e) {
-                case "top":
-                    g.setAttributes({
-                        x: d,
-                        y: c + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "bottom":
-                    g.setAttributes({
-                        x: d,
-                        y: h + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "left":
-                    g.setAttributes({
-                        x: c + i / 2,
-                        y: d,
-                        textBaseline: "top",
-                        textAlign: "center",
-                        rotationCenterX: c + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: -Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break;
-                case "right":
-                    g.setAttributes({
-                        x: h - c + i / 2,
-                        y: d,
-                        textBaseline: "bottom",
-                        textAlign: "center",
-                        rotationCenterX: h + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        this.getChart().onThicknessChanged()
-    },
-    getThickness: function() {
-        if (this.getHidden()) {
-            return 0
-        }
-        return (this.sprites[0] && this.sprites[0].thickness || 1) + this.titleOffset + this.getMargin()
-    },
-    onAnimationStart: function() {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart", this)
-        }
-    },
-    onAnimationEnd: function() {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend", this)
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    getAncestorIds: function() {
-        return [this.getChart().getId()]
-    },
-    isXType: function(a) {
-        return a === "axis"
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        a.surface.destroy();
-        a.surface = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.chart.LegendBase", {
-    extend: "Ext.view.View",
-    config: {
-        tpl: ['<div class="', Ext.baseCSSPrefix, 'legend-container">', '<tpl for=".">', '<div class="', Ext.baseCSSPrefix, 'legend-item">', "<span ", 'class="', Ext.baseCSSPrefix, "legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ", 'style="background:{mark};">', "</span>{name}", "</div>", "</tpl>", "</div>"],
-        nodeContainerSelector: "div." + Ext.baseCSSPrefix + "legend-container",
-        itemSelector: "div." + Ext.baseCSSPrefix + "legend-item",
-        docked: "bottom"
-    },
-    setDocked: function(d) {
-        var c = this,
-            a = c.ownerCt,
-            b;
-        c.docked = d;
-        switch (d) {
-            case "top":
-            case "bottom":
-                c.addCls(Ext.baseCSSPrefix + "horizontal");
-                b = "hbox";
-                break;
-            case "left":
-            case "right":
-                c.removeCls(Ext.baseCSSPrefix + "horizontal");
-                b = "vbox";
-                break
-        }
-        if (a) {
-            a.setDocked(d)
-        }
-    },
-    setStore: function(a) {
-        this.bindStore(a)
-    },
-    clearViewEl: function() {
-        this.callParent(arguments);
-        Ext.removeNode(this.getNodeContainer())
-    },
-    onItemClick: function(a, c, b, d) {
-        this.callParent(arguments);
-        this.toggleItem(b)
-    }
-});
-Ext.define("Ext.chart.Legend", {
-    xtype: "legend",
-    extend: "Ext.chart.LegendBase",
-    config: {
-        baseCls: Ext.baseCSSPrefix + "legend",
-        padding: 5,
-        rect: null,
-        disableSelection: true,
-        toggleable: true
-    },
-    toggleItem: function(c) {
-        if (!this.getToggleable()) {
-            return
-        }
-        var b = this.getStore(),
-            h = 0,
-            e, g = true,
-            d, f, a;
-        if (b) {
-            f = b.getCount();
-            for (d = 0; d < f; d++) {
-                a = b.getAt(d);
-                if (a.get("disabled")) {
-                    h++
-                }
-            }
-            g = f - h > 1;
-            a = b.getAt(c);
-            if (a) {
-                e = a.get("disabled");
-                if (e || g) {
-                    a.set("disabled", !e)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.AbstractChart", {
-    extend: "Ext.draw.Container",
-    requires: ["Ext.chart.theme.Default", "Ext.chart.series.Series", "Ext.chart.interactions.Abstract", "Ext.chart.axis.Axis", "Ext.data.StoreManager", "Ext.chart.Legend", "Ext.data.Store"],
-    isChart: true,
-    defaultBindProperty: "store",
-    config: {
-        store: "ext-empty-store",
-        theme: "default",
-        style: null,
-        animation: !Ext.isIE8,
-        series: [],
-        axes: [],
-        legend: null,
-        colors: null,
-        insetPadding: {
-            top: 10,
-            left: 10,
-            right: 10,
-            bottom: 10
-        },
-        background: null,
-        interactions: [],
-        mainRect: null,
-        resizeHandler: null,
-        highlightItem: null
-    },
-    animationSuspendCount: 0,
-    chartLayoutSuspendCount: 0,
-    axisThicknessSuspendCount: 0,
-    isThicknessChanged: false,
-    surfaceZIndexes: {
-        background: 0,
-        main: 1,
-        grid: 2,
-        series: 3,
-        axis: 4,
-        chart: 5,
-        overlay: 6,
-        events: 7
-    },
-    constructor: function(a) {
-        var b = this;
-        b.itemListeners = {};
-        b.surfaceMap = {};
-        b.chartComponents = {};
-        b.isInitializing = true;
-        b.suspendChartLayout();
-        b.animationSuspendCount++;
-        b.callParent(arguments);
-        delete b.isInitializing;
-        b.getSurface("main");
-        b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);
-        b.getSurface("overlay").waitFor(b.getSurface("series"));
-        b.animationSuspendCount--;
-        b.resumeChartLayout()
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        if (this.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    applyInsetPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    suspendAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            e = c.length,
-            b = -1,
-            a;
-        d.animationSuspendCount++;
-        if (d.animationSuspendCount === 1) {
-            while (++b < e) {
-                a = c[b];
-                a.setAnimation(a.getAnimation())
-            }
-        }
-    },
-    resumeAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            f = c.length,
-            b = -1,
-            a, e;
-        d.animationSuspendCount--;
-        if (d.animationSuspendCount === 0) {
-            while (++b < f) {
-                a = c[b];
-                e = a.getAnimation();
-                a.setAnimation(e.duration && e || d.getAnimation())
-            }
-        }
-    },
-    suspendChartLayout: function() {
-        this.chartLayoutSuspendCount++;
-        if (this.chartLayoutSuspendCount === 1) {
-            if (this.scheduledLayoutId) {
-                this.layoutInSuspension = true;
-                this.cancelChartLayout()
-            } else {
-                this.layoutInSuspension = false
-            }
-        }
-    },
-    resumeChartLayout: function() {
-        this.chartLayoutSuspendCount--;
-        if (this.chartLayoutSuspendCount === 0) {
-            if (this.layoutInSuspension) {
-                this.scheduleLayout()
-            }
-        }
-    },
-    cancelChartLayout: function() {
-        if (this.scheduledLayoutId) {
-            Ext.draw.Animator.cancel(this.scheduledLayoutId);
-            this.scheduledLayoutId = null
-        }
-    },
-    scheduleLayout: function() {
-        var a = this;
-        if (a.allowSchedule() && !a.scheduledLayoutId) {
-            a.scheduledLayoutId = Ext.draw.Animator.schedule("doScheduleLayout", a)
-        }
-    },
-    allowSchedule: function() {
-        return true
-    },
-    doScheduleLayout: function() {
-        if (this.chartLayoutSuspendCount) {
-            this.layoutInSuspension = true
-        } else {
-            this.performLayout()
-        }
-    },
-    suspendThicknessChanged: function() {
-        this.axisThicknessSuspendCount++
-    },
-    resumeThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount > 0) {
-            this.axisThicknessSuspendCount--;
-            if (this.axisThicknessSuspendCount === 0 && this.isThicknessChanged) {
-                this.onThicknessChanged()
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount === 0) {
-            this.isThicknessChanged = false;
-            this.performLayout()
-        } else {
-            this.isThicknessChanged = true
-        }
-    },
-    applySprites: function(b) {
-        var a = this.getSurface("chart");
-        b = Ext.Array.from(b);
-        a.removeAll(true);
-        a.add(b);
-        return b
-    },
-    initItems: function() {
-        var a = this.items,
-            b, d, c;
-        if (a && !a.isMixedCollection) {
-            this.items = [];
-            a = Ext.Array.from(a);
-            for (b = 0, d = a.length; b < d; b++) {
-                c = a[b];
-                if (c.type) {
-                    Ext.raise("To add custom sprites to the chart use the 'sprites' config.")
-                } else {
-                    this.items.push(c)
-                }
-            }
-        }
-        this.callParent()
-    },
-    applyBackground: function(c, e) {
-        var b = this.getSurface("background"),
-            d, a, f;
-        if (c) {
-            if (e) {
-                d = e.attr.width;
-                a = e.attr.height;
-                f = e.type === (c.type || "rect")
-            }
-            if (c.isSprite) {
-                e = c
-            } else {
-                if (c.type === "image" && Ext.isString(c.src)) {
-                    if (f) {
-                        e.setAttributes({
-                            src: c.src
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add(c)
-                    }
-                } else {
-                    if (f) {
-                        e.setAttributes({
-                            fillStyle: c
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add({
-                            type: "rect",
-                            fillStyle: c,
-                            fx: {
-                                customDurations: {
-                                    x: 0,
-                                    y: 0,
-                                    width: 0,
-                                    height: 0
-                                }
-                            }
-                        })
-                    }
-                }
-            }
-        }
-        if (d && a) {
-            e.setAttributes({
-                width: d,
-                height: a
-            })
-        }
-        e.setAnimation(this.getAnimation());
-        return e
-    },
-    getLegendStore: function() {
-        return this.legendStore
-    },
-    refreshLegendStore: function() {
-        if (this.getLegendStore()) {
-            var d, e, c = this.getSeries(),
-                b, a = [];
-            if (c) {
-                for (d = 0, e = c.length; d < e; d++) {
-                    b = c[d];
-                    if (b.getShowInLegend()) {
-                        b.provideLegendInfo(a)
-                    }
-                }
-            }
-            this.getLegendStore().setData(a)
-        }
-    },
-    resetLegendStore: function() {
-        var c = this.getLegendStore(),
-            e, d, a, b;
-        if (c) {
-            e = this.getLegendStore().getData().items;
-            for (d = 0, a = e.length; d < a; d++) {
-                b = e[d];
-                b.beginEdit();
-                b.set("disabled", false);
-                b.commit()
-            }
-        }
-    },
-    onUpdateLegendStore: function(b, a) {
-        var d = this.getSeries(),
-            c;
-        if (a && d) {
-            c = d.map[a.get("series")];
-            if (c) {
-                c.setHiddenByIndex(a.get("index"), a.get("disabled"));
-                this.redraw()
-            }
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.scheduleLayout();
-        return false
-    },
-    applyMainRect: function(a, b) {
-        if (!b) {
-            return a
-        }
-        this.getSeries();
-        this.getAxes();
-        if (a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return b
-        } else {
-            return a
-        }
-    },
-    register: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        b[c] = a
-    },
-    unregister: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        delete b[c]
-    },
-    get: function(a) {
-        return this.chartComponents[a]
-    },
-    getAxis: function(a) {
-        if (a instanceof Ext.chart.axis.Axis) {
-            return a
-        } else {
-            if (Ext.isNumber(a)) {
-                return this.getAxes()[a]
-            } else {
-                if (Ext.isString(a)) {
-                    return this.get(a)
-                }
-            }
-        }
-    },
-    getSurface: function(b, c) {
-        b = b || "main";
-        c = c || b;
-        var d = this,
-            a = this.callParent([b]),
-            f = d.surfaceZIndexes,
-            e = d.surfaceMap;
-        if (c in f) {
-            a.element.setStyle("zIndex", f[c])
-        }
-        if (!e[c]) {
-            e[c] = []
-        }
-        if (Ext.Array.indexOf(e[c], a) < 0) {
-            a.type = c;
-            e[c].push(a);
-            a.on("destroy", d.forgetSurface, d)
-        }
-        return a
-    },
-    forgetSurface: function(a) {
-        var d = this.surfaceMap;
-        if (!d || this.isDestroying) {
-            return
-        }
-        var c = d[a.type],
-            b = c ? Ext.Array.indexOf(c, a) : -1;
-        if (b >= 0) {
-            c.splice(b, 1)
-        }
-    },
-    applyAxes: function(b, k) {
-        var l = this,
-            g = {
-                left: "right",
-                right: "left"
-            },
-            m = [],
-            c, d, e, a, f, h, j;
-        l.animationSuspendCount++;
-        l.getStore();
-        if (!k) {
-            k = [];
-            k.map = {}
-        }
-        j = k.map;
-        m.map = {};
-        b = Ext.Array.from(b, true);
-        for (f = 0, h = b.length; f < h; f++) {
-            c = b[f];
-            if (!c) {
-                continue
-            }
-            if (c instanceof Ext.chart.axis.Axis) {
-                d = j[c.getId()];
-                c.setChart(l)
-            } else {
-                c = Ext.Object.chain(c);
-                e = c.linkedTo;
-                a = c.id;
-                if (Ext.isNumber(e)) {
-                    c = Ext.merge({}, b[e], c)
-                } else {
-                    if (Ext.isString(e)) {
-                        Ext.Array.each(b, function(i) {
-                            if (i.id === c.linkedTo) {
-                                c = Ext.merge({}, i, c);
-                                return false
-                            }
-                        })
-                    }
-                }
-                c.id = a;
-                c.chart = l;
-                if (l.getInherited().rtl) {
-                    c.position = g[c.position] || c.position
-                }
-                a = c.getId && c.getId() || c.id;
-                c = Ext.factory(c, null, d = j[a], "axis")
-            }
-            if (c) {
-                m.push(c);
-                m.map[c.getId()] = c;
-                if (!d) {
-                    c.on("animationstart", "onAnimationStart", l);
-                    c.on("animationend", "onAnimationEnd", l)
-                }
-            }
-        }
-        for (f in j) {
-            if (!m.map[f]) {
-                j[f].destroy()
-            }
-        }
-        l.animationSuspendCount--;
-        return m
-    },
-    updateAxes: function() {
-        if (!this.isDestroying) {
-            this.scheduleLayout()
-        }
-    },
-    circularCopyArray: function(e, f, d) {
-        var c = [],
-            b, a = e && e.length;
-        if (a) {
-            for (b = 0; b < d; b++) {
-                c.push(e[(f + b) % a])
-            }
-        }
-        return c
-    },
-    circularCopyObject: function(f, g, d) {
-        var c = this,
-            b, e, a = {};
-        if (d) {
-            for (b in f) {
-                if (f.hasOwnProperty(b)) {
-                    e = f[b];
-                    if (Ext.isArray(e)) {
-                        a[b] = c.circularCopyArray(e, g, d)
-                    } else {
-                        a[b] = e
-                    }
-                }
-            }
-        }
-        return a
-    },
-    getColors: function() {
-        var b = this,
-            a = b.config.colors,
-            c = b.getTheme();
-        if (Ext.isArray(a) && a.length > 0) {
-            a = b.applyColors(a)
-        }
-        return a || (c && c.getColors())
-    },
-    applyColors: function(a) {
-        a = Ext.Array.map(a, function(b) {
-            if (Ext.isString(b)) {
-                return b
-            } else {
-                return b.toString()
-            }
-        });
-        return a
-    },
-    updateColors: function(c) {
-        var k = this,
-            e = k.getTheme(),
-            a = c || (e && e.getColors()),
-            l = 0,
-            f = k.getSeries(),
-            d = f && f.length,
-            g, j, b, h;
-        if (a.length) {
-            for (g = 0; g < d; g++) {
-                j = f[g];
-                h = j.themeColorCount();
-                b = k.circularCopyArray(a, l, h);
-                l += h;
-                j.updateChartColors(b)
-            }
-        }
-        k.refreshLegendStore()
-    },
-    applyTheme: function(a) {
-        if (a && a.isTheme) {
-            return a
-        }
-        return Ext.Factory.chartTheme(a)
-    },
-    updateTheme: function(g) {
-        var e = this,
-            f = e.getAxes(),
-            d = e.getSeries(),
-            a = e.getColors(),
-            c, b;
-        e.updateChartTheme(g);
-        for (b = 0; b < f.length; b++) {
-            f[b].updateTheme(g)
-        }
-        for (b = 0; b < d.length; b++) {
-            c = d[b];
-            c.updateTheme(g)
-        }
-        e.updateSpriteTheme(g);
-        e.updateColors(a);
-        e.redraw()
-    },
-    themeOnlyIfConfigured: {},
-    updateChartTheme: function(c) {
-        var i = this,
-            k = c.getChart(),
-            n = i.getInitialConfig(),
-            b = i.defaultConfig,
-            e = i.getConfigurator().configs,
-            f = k.defaults,
-            g = k[i.xtype],
-            h = i.themeOnlyIfConfigured,
-            l, j, o, a, m, d;
-        k = Ext.merge({}, f, g);
-        for (l in k) {
-            j = k[l];
-            d = e[l];
-            if (j !== null && j !== undefined && d) {
-                m = n[l];
-                o = Ext.isObject(j);
-                a = m === b[l];
-                if (o) {
-                    if (a && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (a || o) {
-                    i[d.names.set](j)
-                }
-            }
-        }
-    },
-    updateSpriteTheme: function(c) {
-        this.getSprites();
-        var j = this,
-            e = j.getSurface("chart"),
-            h = e.getItems(),
-            m = c.getSprites(),
-            k, a, l, f, d, b, g;
-        for (b = 0, g = h.length; b < g; b++) {
-            k = h[b];
-            a = m[k.type];
-            if (a) {
-                f = {};
-                d = k.type === "text";
-                for (l in a) {
-                    if (!(l in k.config)) {
-                        if (!(d && l.indexOf("font") === 0 && k.config.font)) {
-                            f[l] = a[l]
-                        }
-                    }
-                }
-                k.setAttributes(f)
-            }
-        }
-    },
-    addSeries: function(b) {
-        var a = this.getSeries();
-        Ext.Array.push(a, b);
-        this.setSeries(a)
-    },
-    removeSeries: function(d) {
-        d = Ext.Array.from(d);
-        var b = this.getSeries(),
-            f = [],
-            a = d.length,
-            g = {},
-            c, e;
-        for (c = 0; c < a; c++) {
-            e = d[c];
-            if (typeof e !== "string") {
-                e = e.getId()
-            }
-            g[e] = true
-        }
-        for (c = 0, a = b.length; c < a; c++) {
-            if (!g[b[c].getId()]) {
-                f.push(b[c])
-            }
-        }
-        this.setSeries(f)
-    },
-    applySeries: function(e, d) {
-        var g = this,
-            j = [],
-            h, a, c, f, b;
-        g.animationSuspendCount++;
-        g.getAxes();
-        if (d) {
-            h = d.map
-        } else {
-            d = [];
-            h = d.map = {}
-        }
-        j.map = {};
-        e = Ext.Array.from(e, true);
-        for (c = 0, f = e.length; c < f; c++) {
-            b = e[c];
-            if (!b) {
-                continue
-            }
-            a = h[b.getId && b.getId() || b.id];
-            if (b instanceof Ext.chart.series.Series) {
-                if (a && a !== b) {
-                    a.destroy()
-                }
-                b.setChart(g)
-            } else {
-                if (Ext.isObject(b)) {
-                    if (a) {
-                        a.setConfig(b);
-                        b = a
-                    } else {
-                        if (Ext.isString(b)) {
-                            b = {
-                                type: b
-                            }
-                        }
-                        b.chart = g;
-                        b = Ext.create(b.xclass || ("series." + b.type), b);
-                        b.on("animationstart", "onAnimationStart", g);
-                        b.on("animationend", "onAnimationEnd", g)
-                    }
-                }
-            }
-            j.push(b);
-            j.map[b.getId()] = b
-        }
-        for (c in h) {
-            if (!j.map[h[c].getId()]) {
-                h[c].destroy()
-            }
-        }
-        g.animationSuspendCount--;
-        return j
-    },
-    applyLegend: function(b, a) {
-        return Ext.factory(b, Ext.chart.Legend, a)
-    },
-    updateLegend: function(b, a) {
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            this.getItems();
-            this.legendStore = new Ext.data.Store({
-                autoDestroy: true,
-                fields: ["id", "name", "mark", "disabled", "series", "index"]
-            });
-            b.setStore(this.legendStore);
-            this.refreshLegendStore();
-            this.legendStore.on("update", "onUpdateLegendStore", this)
-        }
-    },
-    updateSeries: function(b, a) {
-        var c = this;
-        if (c.isDestroying) {
-            return
-        }
-        c.animationSuspendCount++;
-        c.fireEvent("serieschange", c, b, a);
-        c.refreshLegendStore();
-        if (!Ext.isEmpty(b)) {
-            c.updateTheme(c.getTheme())
-        }
-        c.scheduleLayout();
-        c.animationSuspendCount--
-    },
-    applyInteractions: function(h, d) {
-        if (!d) {
-            d = [];
-            d.map = {}
-        }
-        var g = this,
-            a = [],
-            c = d.map,
-            e, f, b;
-        a.map = {};
-        h = Ext.Array.from(h, true);
-        for (e = 0, f = h.length; e < f; e++) {
-            b = h[e];
-            if (!b) {
-                continue
-            }
-            b = Ext.factory(b, null, c[b.getId && b.getId() || b.id], "interaction");
-            if (b) {
-                b.setChart(g);
-                a.push(b);
-                a.map[b.getId()] = b
-            }
-        }
-        for (e in c) {
-            if (!a.map[e]) {
-                c[e].destroy()
-            }
-        }
-        return a
-    },
-    getInteraction: function(e) {
-        var f = this.getInteractions(),
-            a = f && f.length,
-            c = null,
-            b, d;
-        if (a) {
-            for (d = 0; d < a; ++d) {
-                b = f[d];
-                if (b.type === e) {
-                    c = b;
-                    break
-                }
-            }
-        }
-        return c
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    updateStore: function(a, c) {
-        var b = this;
-        if (c) {
-            c.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            });
-            if (c.autoDestroy) {
-                c.destroy()
-            }
-        }
-        if (a) {
-            a.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            })
-        }
-        b.fireEvent("storechange", b, a, c);
-        b.onDataChanged()
-    },
-    redraw: function() {
-        this.fireEvent("redraw", this)
-    },
-    performLayout: function() {
-        var d = this,
-            b = d.getChartSize(true),
-            c = [0, 0, b.width, b.height],
-            a = d.getBackground();
-        d.hasFirstLayout = true;
-        d.fireEvent("layout", d);
-        d.cancelChartLayout();
-        d.getSurface("background").setRect(c);
-        d.getSurface("chart").setRect(c);
-        a.setAttributes({
-            width: b.width,
-            height: b.height
-        })
-    },
-    getChartSize: function(b) {
-        var a = this;
-        if (b) {
-            a.chartSize = null
-        }
-        return a.chartSize || (a.chartSize = a.innerElement.getSize())
-    },
-    getEventXY: function(a) {
-        return this.getSurface().getEventXY(a)
-    },
-    getItemForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            e = f.getMainRect(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            c, j;
-        if (!(e && h >= 0 && h <= e[2] && g >= 0 && g <= e[3])) {
-            return null
-        }
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                return j
-            }
-        }
-        return null
-    },
-    getItemsForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            e = [],
-            c, j;
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                e.push(j)
-            }
-        }
-        return e
-    },
-    onAnimationStart: function() {
-        this.fireEvent("animationstart", this)
-    },
-    onAnimationEnd: function() {
-        this.fireEvent("animationend", this)
-    },
-    onDataChanged: function() {
-        var d = this;
-        if (d.isInitializing) {
-            return
-        }
-        var c = d.getMainRect(),
-            a = d.getStore(),
-            b = d.getSeries(),
-            e = d.getAxes();
-        if (!a || !e || !b) {
-            return
-        }
-        if (!c) {
-            d.on({
-                redraw: d.onDataChanged,
-                scope: d,
-                single: true
-            });
-            return
-        }
-        d.processData();
-        d.redraw()
-    },
-    recordCount: 0,
-    processData: function() {
-        var g = this,
-            e = g.getStore().getCount(),
-            c = g.getSeries(),
-            f = c.length,
-            d = false,
-            b = 0,
-            a;
-        for (; b < f; b++) {
-            a = c[b];
-            a.processData();
-            if (!d && a.isStoreDependantColorCount) {
-                d = true
-            }
-        }
-        if (d && e > g.recordCount) {
-            g.updateColors(g.getColors());
-            g.recordCount = e
-        }
-    },
-    bindStore: function(a) {
-        this.setStore(a)
-    },
-    applyHighlightItem: function(f, a) {
-        if (f === a) {
-            return
-        }
-        if (Ext.isObject(f) && Ext.isObject(a)) {
-            var e = f,
-                d = a,
-                c = e.sprite && (e.sprite[0] || e.sprite),
-                b = d.sprite && (d.sprite[0] || d.sprite);
-            if (c === b && e.index === d.index) {
-                return
-            }
-        }
-        return f
-    },
-    updateHighlightItem: function(b, a) {
-        if (a) {
-            a.series.setAttributesForItem(a, {
-                highlighted: false
-            })
-        }
-        if (b) {
-            b.series.setAttributesForItem(b, {
-                highlighted: true
-            });
-            this.fireEvent("itemhighlight", this, b, a)
-        }
-        this.fireEvent("itemhighlightchange", this, b, a)
-    },
-    destroyChart: function() {
-        var f = this,
-            d = f.getLegend(),
-            g = f.getAxes(),
-            c = f.getSeries(),
-            h = f.getInteractions(),
-            b = [],
-            a, e;
-        f.surfaceMap = null;
-        for (a = 0, e = h.length; a < e; a++) {
-            h[a].destroy()
-        }
-        for (a = 0, e = g.length; a < e; a++) {
-            g[a].destroy()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            c[a].destroy()
-        }
-        f.setInteractions(b);
-        f.setAxes(b);
-        f.setSeries(b);
-        if (d) {
-            d.destroy();
-            f.setLegend(null)
-        }
-        f.legendStore = null;
-        f.setStore(null);
-        f.cancelChartLayout()
-    },
-    getRefItems: function(b) {
-        var g = this,
-            e = g.getSeries(),
-            h = g.getAxes(),
-            a = g.getInteractions(),
-            c = [],
-            d, f;
-        for (d = 0, f = e.length; d < f; d++) {
-            c.push(e[d]);
-            if (e[d].getRefItems) {
-                c.push.apply(c, e[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = h.length; d < f; d++) {
-            c.push(h[d]);
-            if (h[d].getRefItems) {
-                c.push.apply(c, h[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = a.length; d < f; d++) {
-            c.push(a[d]);
-            if (a[d].getRefItems) {
-                c.push.apply(c, a[d].getRefItems(b))
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.overrides.AbstractChart", {
-    override: "Ext.chart.AbstractChart",
-    updateLegend: function(b, a) {
-        var c;
-        this.callParent([b, a]);
-        if (b) {
-            c = b.docked;
-            this.addDocked({
-                dock: c,
-                xtype: "panel",
-                shrinkWrap: true,
-                scrollable: true,
-                layout: {
-                    type: c === "top" || c === "bottom" ? "hbox" : "vbox",
-                    pack: "center"
-                },
-                items: b,
-                cls: Ext.baseCSSPrefix + "legend-panel"
-            })
-        }
-    },
-    performLayout: function() {
-        if (this.isVisible(true)) {
-            return this.callParent()
-        }
-        this.cancelChartLayout();
-        return false
-    },
-    afterComponentLayout: function(c, a, b, d) {
-        this.callParent([c, a, b, d]);
-        this.scheduleLayout()
-    },
-    allowSchedule: function() {
-        return this.rendered
-    },
-    onDestroy: function() {
-        this.destroyChart();
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.horizontal",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(b, c, e) {
-        var a = this.attr,
-            f = b.roundPixel(a.y),
-            d = c.lineWidth * 0.5;
-        c.beginPath();
-        c.rect(e[0] - b.matrix.getDX(), f + d, +e[2], a.height);
-        c.fill();
-        c.beginPath();
-        c.moveTo(e[0] - b.matrix.getDX(), f + d);
-        c.lineTo(e[0] + e[2] - b.matrix.getDX(), f + d);
-        c.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.vertical",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    }
-});
-Ext.define("Ext.chart.CartesianChart", {
-    extend: "Ext.chart.AbstractChart",
-    alternateClassName: "Ext.chart.Chart",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid"],
-    xtype: ["cartesian", "chart"],
-    isCartesian: true,
-    config: {
-        flipXY: false,
-        innerRect: [0, 0, 1, 1],
-        innerPadding: {
-            top: 0,
-            left: 0,
-            right: 0,
-            bottom: 0
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    getDirectionForAxis: function(a) {
-        var b = this.getFlipXY();
-        if (a === "left" || a === "right") {
-            if (b) {
-                return "X"
-            } else {
-                return "Y"
-            }
-        } else {
-            if (b) {
-                return "Y"
-            } else {
-                return "X"
-            }
-        }
-    },
-    performLayout: function() {
-        var A = this;
-        A.animationSuspendCount++;
-        if (A.callParent() === false) {
-            --A.animationSuspendCount;
-            return
-        }
-        A.suspendThicknessChanged();
-        var d = A.getSurface("chart").getRect(),
-            o = d[2],
-            n = d[3],
-            z = A.getAxes(),
-            b, q = A.getSeries(),
-            h, l, a, f = A.getInsetPadding(),
-            v = A.getInnerPadding(),
-            r, c, e = Ext.apply({}, f),
-            u, p, s, k, m, y, t, x, g, j = A.getInherited().rtl,
-            w = A.getFlipXY();
-        if (o <= 0 || n <= 0) {
-            return
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            m = b.getFloating();
-            y = m ? m.value : null;
-            a = b.getThickness();
-            switch (b.getPosition()) {
-                case "top":
-                    l.setRect([0, e.top + 1, o, a]);
-                    break;
-                case "bottom":
-                    l.setRect([0, n - (e.bottom + a), o, a]);
-                    break;
-                case "left":
-                    l.setRect([e.left, 0, a, n]);
-                    break;
-                case "right":
-                    l.setRect([o - (e.right + a), 0, a, n]);
-                    break
-            }
-            if (y === null) {
-                e[b.getPosition()] += a
-            }
-        }
-        o -= e.left + e.right;
-        n -= e.top + e.bottom;
-        u = [e.left, e.top, o, n];
-        e.left += v.left;
-        e.top += v.top;
-        e.right += v.right;
-        e.bottom += v.bottom;
-        p = o - v.left - v.right;
-        s = n - v.top - v.bottom;
-        A.setInnerRect([e.left, e.top, p, s]);
-        if (p <= 0 || s <= 0) {
-            return
-        }
-        A.setMainRect(u);
-        A.getSurface().setRect(u);
-        for (x = 0, g = A.surfaceMap.grid && A.surfaceMap.grid.length; x < g; x++) {
-            c = A.surfaceMap.grid[x];
-            c.setRect(u);
-            c.matrix.set(1, 0, 0, 1, v.left, v.top);
-            c.matrix.inverse(c.inverseMatrix)
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            t = l.matrix;
-            k = t.elements;
-            switch (b.getPosition()) {
-                case "top":
-                case "bottom":
-                    k[4] = e.left;
-                    b.setLength(p);
-                    break;
-                case "left":
-                case "right":
-                    k[5] = e.top;
-                    b.setLength(s);
-                    break
-            }
-            b.updateTitleSprite();
-            t.inverse(l.inverseMatrix)
-        }
-        for (x = 0, g = q.length; x < g; x++) {
-            h = q[x];
-            r = h.getSurface();
-            r.setRect(u);
-            if (w) {
-                if (j) {
-                    r.matrix.set(0, -1, -1, 0, v.left + p, v.top + s)
-                } else {
-                    r.matrix.set(0, -1, 1, 0, v.left, v.top + s)
-                }
-            } else {
-                r.matrix.set(1, 0, 0, -1, v.left, v.top + s)
-            }
-            r.matrix.inverse(r.inverseMatrix);
-            h.getOverlaySurface().setRect(u)
-        }
-        A.redraw();
-        A.animationSuspendCount--;
-        A.resumeThicknessChanged()
-    },
-    refloatAxes: function() {
-        var h = this,
-            g = h.getAxes(),
-            o = (g && g.length) || 0,
-            c, d, n, f, l, b, k, r = h.getChartSize(),
-            q = h.getInsetPadding(),
-            p = h.getInnerPadding(),
-            a = r.width - q.left - q.right,
-            m = r.height - q.top - q.bottom,
-            j, e;
-        for (e = 0; e < o; e++) {
-            c = g[e];
-            f = c.getFloating();
-            l = f ? f.value : null;
-            if (l === null) {
-                delete c.floatingAtCoord;
-                continue
-            }
-            d = c.getSurface();
-            n = d.getRect();
-            if (!n) {
-                continue
-            }
-            n = n.slice();
-            b = h.getAxis(f.alongAxis);
-            if (b) {
-                j = b.getAlignment() === "horizontal";
-                if (Ext.isString(l)) {
-                    l = b.getCoordFor(l)
-                }
-                b.floatingAxes[c.getId()] = l;
-                k = b.getSprites()[0].attr.matrix;
-                if (j) {
-                    l = l * k.getXX() + k.getDX();
-                    c.floatingAtCoord = l + p.left + p.right
-                } else {
-                    l = l * k.getYY() + k.getDY();
-                    c.floatingAtCoord = l + p.top + p.bottom
-                }
-            } else {
-                j = c.getAlignment() === "horizontal";
-                if (j) {
-                    c.floatingAtCoord = l + p.top + p.bottom
-                } else {
-                    c.floatingAtCoord = l + p.left + p.right
-                }
-                l = d.roundPixel(0.01 * l * (j ? m : a))
-            }
-            switch (c.getPosition()) {
-                case "top":
-                    n[1] = q.top + p.top + l - n[3] + 1;
-                    break;
-                case "bottom":
-                    n[1] = q.top + p.top + (b ? l : m - l);
-                    break;
-                case "left":
-                    n[0] = q.left + p.left + l - n[2];
-                    break;
-                case "right":
-                    n[0] = q.left + p.left + (b ? l : a - l) - 1;
-                    break
-            }
-            d.setRect(n)
-        }
-    },
-    redraw: function() {
-        var C = this,
-            r = C.getSeries(),
-            z = C.getAxes(),
-            b = C.getMainRect(),
-            p, t, w = C.getInnerPadding(),
-            f, l, s, e, q, A, v, g, d, c, a, k, n, y = C.getFlipXY(),
-            x = 1000,
-            m, u, h, o, B;
-        if (!b) {
-            return
-        }
-        p = b[2] - w.left - w.right;
-        t = b[3] - w.top - w.bottom;
-        for (A = 0; A < r.length; A++) {
-            h = r[A];
-            if ((c = h.getXAxis())) {
-                n = c.getVisibleRange();
-                l = c.getRange();
-                l = [l[0] + (l[1] - l[0]) * n[0], l[0] + (l[1] - l[0]) * n[1]]
-            } else {
-                l = h.getXRange()
-            }
-            if ((a = h.getYAxis())) {
-                n = a.getVisibleRange();
-                s = a.getRange();
-                s = [s[0] + (s[1] - s[0]) * n[0], s[0] + (s[1] - s[0]) * n[1]]
-            } else {
-                s = h.getYRange()
-            }
-            q = {
-                visibleMinX: l[0],
-                visibleMaxX: l[1],
-                visibleMinY: s[0],
-                visibleMaxY: s[1],
-                innerWidth: p,
-                innerHeight: t,
-                flipXY: y
-            };
-            f = h.getSprites();
-            for (v = 0, g = f.length; v < g; v++) {
-                o = f[v];
-                m = o.attr.zIndex;
-                if (m < x) {
-                    m += (A + 1) * 100 + x;
-                    o.attr.zIndex = m;
-                    B = o.getMarker("items");
-                    if (B) {
-                        u = B.attr.zIndex;
-                        if (u === Number.MAX_VALUE) {
-                            B.attr.zIndex = m
-                        } else {
-                            if (u < x) {
-                                B.attr.zIndex = m + u
-                            }
-                        }
-                    }
-                }
-                o.setAttributes(q, true)
-            }
-        }
-        for (A = 0; A < z.length; A++) {
-            d = z[A];
-            e = d.isSide();
-            f = d.getSprites();
-            k = d.getRange();
-            n = d.getVisibleRange();
-            q = {
-                dataMin: k[0],
-                dataMax: k[1],
-                visibleMin: n[0],
-                visibleMax: n[1]
-            };
-            if (e) {
-                q.length = t;
-                q.startGap = w.bottom;
-                q.endGap = w.top
-            } else {
-                q.length = p;
-                q.startGap = w.left;
-                q.endGap = w.right
-            }
-            for (v = 0, g = f.length; v < g; v++) {
-                f[v].setAttributes(q, true)
-            }
-        }
-        C.renderFrame();
-        C.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.grid.CircularGrid", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "grid.circular",
-    inheritableStatics: {
-        def: {
-            defaults: {
-                r: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.grid.RadialGrid", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "grid.radial",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startRadius: "number",
-                endRadius: "number"
-            },
-            defaults: {
-                startRadius: 0,
-                endRadius: 1,
-                scalingCenterX: 0,
-                scalingCenterY: 0,
-                strokeStyle: "#DDD"
-            },
-            triggers: {
-                startRadius: "path,bbox",
-                endRadius: "path,bbox"
-            }
-        }
-    },
-    render: function() {
-        this.callParent(arguments)
-    },
-    updatePath: function(d, a) {
-        var b = a.startRadius,
-            c = a.endRadius;
-        d.moveTo(b, 0);
-        d.lineTo(c, 0)
-    }
-});
-Ext.define("Ext.chart.PolarChart", {
-    extend: "Ext.chart.AbstractChart",
-    requires: ["Ext.chart.grid.CircularGrid", "Ext.chart.grid.RadialGrid"],
-    xtype: "polar",
-    isPolar: true,
-    config: {
-        center: [0, 0],
-        radius: 0,
-        innerPadding: 0
-    },
-    getDirectionForAxis: function(a) {
-        return a === "radial" ? "Y" : "X"
-    },
-    applyCenter: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1]) {
-            return
-        }
-        return [+a[0], +a[1]]
-    },
-    updateCenter: function(a) {
-        var g = this,
-            h = g.getAxes(),
-            d = g.getSeries(),
-            c, f, e, b;
-        for (c = 0, f = h.length; c < f; c++) {
-            e = h[c];
-            e.setCenter(a)
-        }
-        for (c = 0, f = d.length; c < f; c++) {
-            b = d[c];
-            b.setCenter(a)
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        return Ext.isNumber(b) ? b : a
-    },
-    doSetSurfaceRect: function(b, c) {
-        var a = this.getMainRect();
-        b.setRect(c);
-        b.matrix.set(1, 0, 0, 1, a[0] - c[0], a[1] - c[1]);
-        b.inverseMatrix.set(1, 0, 0, 1, c[0] - a[0], c[1] - a[1])
-    },
-    applyAxes: function(f, h) {
-        var e = this,
-            g = Ext.Array.from(e.config.series)[0],
-            b, d, c, a;
-        if (g.type === "radar" && f && f.length) {
-            for (b = 0, d = f.length; b < d; b++) {
-                c = f[b];
-                if (c.position === "angular") {
-                    a = true;
-                    break
-                }
-            }
-            if (!a) {
-                f.push({
-                    type: "category",
-                    position: "angular",
-                    fields: g.xField || g.angleField,
-                    style: {
-                        estStepSize: 1
-                    },
-                    grid: true
-                })
-            }
-        }
-        return this.callParent(arguments)
-    },
-    performLayout: function() {
-        var F = this,
-            g = true;
-        try {
-            F.animationSuspendCount++;
-            if (this.callParent() === false) {
-                g = false;
-                return
-            }
-            F.suspendThicknessChanged();
-            var h = F.getSurface("chart").getRect(),
-                v = F.getInsetPadding(),
-                G = F.getInnerPadding(),
-                l = Ext.apply({}, v),
-                d, s = h[2] - v.left - v.right,
-                r = h[3] - v.top - v.bottom,
-                x = [v.left, v.top, s, r],
-                u = F.getSeries(),
-                p, t = s - G * 2,
-                w = r - G * 2,
-                D = [t * 0.5 + G, w * 0.5 + G],
-                j = Math.min(t, w) * 0.5,
-                A = F.getAxes(),
-                f, a, k, m = [],
-                o = [],
-                E = j - G,
-                z, n, b, q, y, c, C;
-            F.setMainRect(x);
-            F.doSetSurfaceRect(F.getSurface(), x);
-            for (z = 0, n = F.surfaceMap.grid && F.surfaceMap.grid.length; z < n; z++) {
-                F.doSetSurfaceRect(F.surfaceMap.grid[z], h)
-            }
-            for (z = 0, n = A.length; z < n; z++) {
-                f = A[z];
-                switch (f.getPosition()) {
-                    case "angular":
-                        m.push(f);
-                        break;
-                    case "radial":
-                        o.push(f);
-                        break
-                }
-            }
-            for (z = 0, n = m.length; z < n; z++) {
-                f = m[z];
-                q = f.getFloating();
-                y = q ? q.value : null;
-                F.doSetSurfaceRect(f.getSurface(), h);
-                a = f.getThickness();
-                for (d in l) {
-                    l[d] += a
-                }
-                s = h[2] - l.left - l.right;
-                r = h[3] - l.top - l.bottom;
-                b = Math.min(s, r) * 0.5;
-                if (z === 0) {
-                    E = b - G
-                }
-                f.setMinimum(0);
-                f.setLength(b);
-                f.getSprites();
-                k = f.sprites[0].attr.lineWidth * 0.5;
-                for (d in l) {
-                    l[d] += k
-                }
-            }
-            for (z = 0, n = o.length; z < n; z++) {
-                f = o[z];
-                F.doSetSurfaceRect(f.getSurface(), h);
-                f.setMinimum(0);
-                f.setLength(E);
-                f.getSprites()
-            }
-            for (z = 0, n = u.length; z < n; z++) {
-                p = u[z];
-                if (p.type === "gauge" && !c) {
-                    c = p
-                } else {
-                    p.setRadius(E)
-                }
-                F.doSetSurfaceRect(p.getSurface(), x)
-            }
-            F.doSetSurfaceRect(F.getSurface("overlay"), h);
-            if (c) {
-                c.setRect(x);
-                C = c.getRadius() - G;
-                F.setRadius(C);
-                F.setCenter(c.getCenter());
-                c.setRadius(C);
-                if (A.length && A[0].getPosition() === "gauge") {
-                    f = A[0];
-                    F.doSetSurfaceRect(f.getSurface(), h);
-                    f.setTotalAngle(c.getTotalAngle());
-                    f.setLength(C)
-                }
-            } else {
-                F.setRadius(j);
-                F.setCenter(D)
-            }
-            F.redraw()
-        } catch (B) {
-            throw B
-        } finally {
-            F.animationSuspendCount--;
-            if (g) {
-                F.resumeThicknessChanged()
-            }
-        }
-    },
-    refloatAxes: function() {
-        var j = this,
-            g = j.getAxes(),
-            h = j.getMainRect(),
-            f, k, b, d, a, c, e;
-        if (!h) {
-            return
-        }
-        e = 0.5 * Math.min(h[2], h[3]);
-        for (d = 0, a = g.length; d < a; d++) {
-            c = g[d];
-            f = c.getFloating();
-            k = f ? f.value : null;
-            if (k !== null) {
-                b = j.getAxis(f.alongAxis);
-                if (c.getPosition() === "angular") {
-                    if (b) {
-                        k = b.getLength() * k / b.getRange()[1]
-                    } else {
-                        k = 0.01 * k * e
-                    }
-                    c.sprites[0].setAttributes({
-                        length: k
-                    }, true)
-                } else {
-                    if (b) {
-                        if (Ext.isString(k)) {
-                            k = b.getCoordFor(k)
-                        }
-                        k = k / (b.getRange()[1] + 1) * Math.PI * 2 - Math.PI * 1.5 + c.getRotation()
-                    } else {
-                        k = Ext.draw.Draw.rad(k)
-                    }
-                    c.sprites[0].setAttributes({
-                        baseRotation: k
-                    }, true)
-                }
-            }
-        }
-    },
-    redraw: function() {
-        var f = this,
-            g = f.getAxes(),
-            d, c = f.getSeries(),
-            b, a, e;
-        for (a = 0, e = g.length; a < e; a++) {
-            d = g[a];
-            d.getSprites()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        f.renderFrame();
-        f.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.SpaceFillingChart", {
-    extend: "Ext.chart.AbstractChart",
-    xtype: "spacefilling",
-    config: {},
-    performLayout: function() {
-        var j = this;
-        try {
-            j.animationSuspendCount++;
-            if (j.callParent() === false) {
-                return
-            }
-            var k = j.getSurface("chart").getRect(),
-                l = j.getInsetPadding(),
-                a = k[2] - l.left - l.right,
-                m = k[3] - l.top - l.bottom,
-                h = [l.left, l.top, a, m],
-                b = j.getSeries(),
-                d, c, g;
-            j.getSurface().setRect(h);
-            j.setMainRect(h);
-            for (c = 0, g = b.length; c < g; c++) {
-                d = b[c];
-                d.getSurface().setRect(h);
-                if (d.setRect) {
-                    d.setRect(h)
-                }
-                d.getOverlaySurface().setRect(k)
-            }
-            j.redraw()
-        } catch (f) {
-            throw f
-        } finally {
-            j.animationSuspendCount--
-        }
-    },
-    redraw: function() {
-        var e = this,
-            c = e.getSeries(),
-            b, a, d;
-        for (a = 0, d = c.length; a < d; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        e.renderFrame();
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis3D", {
-    extend: "Ext.chart.axis.sprite.Axis",
-    alias: "sprite.axis3d",
-    type: "axis3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            },
-            triggers: {
-                depth: "layout"
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                depth: 0
-            }
-        }
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            c = d.isDiscrete ? 0 : e.depth,
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (e.position === "left" || e.position === "right") {
-            e.translationX = 0;
-            e.translationY = i * (e.length - c) / (i - b) + c;
-            e.scalingX = 1;
-            e.scalingY = (-e.length + c) / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (e.position === "top" || e.position === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * (e.length - c) / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    renderAxisLine: function(a, j, f, c) {
-        var i = this,
-            h = i.attr,
-            b = h.lineWidth * 0.5,
-            f = i.getLayout(),
-            d = f.isDiscrete ? 0 : h.depth,
-            k = h.position,
-            e, g;
-        if (h.axisLine && h.length) {
-            switch (k) {
-                case "left":
-                    e = a.roundPixel(c[2]) - b;
-                    j.moveTo(e, -h.endGap + d);
-                    j.lineTo(e, h.length + h.startGap);
-                    break;
-                case "right":
-                    j.moveTo(b, -h.endGap);
-                    j.lineTo(b, h.length + h.startGap);
-                    break;
-                case "bottom":
-                    j.moveTo(-h.startGap, b);
-                    j.lineTo(h.length - d + h.endGap, b);
-                    break;
-                case "top":
-                    e = a.roundPixel(c[3]) - b;
-                    j.moveTo(-h.startGap, e);
-                    j.lineTo(h.length + h.endGap, e);
-                    break;
-                case "angular":
-                    j.moveTo(h.centerX + h.length, h.centerY);
-                    j.arc(h.centerX, h.centerY, h.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    g = i.getGaugeAngles();
-                    j.moveTo(h.centerX + Math.cos(g.start) * h.length, h.centerY + Math.sin(g.start) * h.length);
-                    j.arc(h.centerX, h.centerY, h.length, g.start, g.end, true);
-                    break
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis3D", {
-    extend: "Ext.chart.axis.Axis",
-    xtype: "axis3d",
-    requires: ["Ext.chart.axis.sprite.Axis3D"],
-    config: {
-        depth: 0
-    },
-    onSeriesChange: function(e) {
-        var g = this,
-            b = "depthchange",
-            f = "onSeriesDepthChange",
-            d, c;
-
-        function a(h) {
-            var i = g.boundSeries;
-            for (d = 0; d < i.length; d++) {
-                c = i[d];
-                c[h](b, f, g)
-            }
-        }
-        a("un");
-        g.callParent(arguments);
-        a("on")
-    },
-    onSeriesDepthChange: function(b, f) {
-        var d = this,
-            g = f,
-            e = d.boundSeries,
-            a, c;
-        if (f > d.getDepth()) {
-            g = f
-        } else {
-            for (a = 0; a < e.length; a++) {
-                c = e[a];
-                if (c !== b && c.getDepth) {
-                    f = c.getDepth();
-                    if (f > g) {
-                        g = f
-                    }
-                }
-            }
-        }
-        d.setDepth(g)
-    },
-    updateDepth: function(d) {
-        var b = this,
-            c = b.getSprites(),
-            a = {
-                depth: d
-            };
-        if (c && c.length) {
-            c[0].setAttributes(a)
-        }
-        if (b.gridSpriteEven && b.gridSpriteOdd) {
-            b.gridSpriteEven.getTemplate().setAttributes(a);
-            b.gridSpriteOdd.getTemplate().setAttributes(a)
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal3d";
-            case "top":
-            case "bottom":
-                return "vertical3d"
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Category", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis",
-    alias: "axis.category",
-    type: "category",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Category3D", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis3D",
-    alias: "axis.category3d",
-    type: "category3d",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric", {
-    extend: "Ext.chart.axis.Axis",
-    type: "numeric",
-    alias: ["axis.numeric", "axis.radial"],
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric3D", {
-    extend: "Ext.chart.axis.Axis3D",
-    alias: ["axis.numeric3d"],
-    type: "numeric3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Time", {
-    extend: "Ext.chart.axis.Numeric",
-    alias: "axis.time",
-    type: "time",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.axis.Time3D", {
-    extend: "Ext.chart.axis.Numeric3D",
-    alias: "axis.time3d",
-    type: "time3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid3D", {
-    extend: "Ext.chart.grid.HorizontalGrid",
-    alias: "grid.horizontal3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render: function(a, k, d) {
-        var f = this.attr,
-            i = a.roundPixel(f.x),
-            h = a.roundPixel(f.y),
-            l = a.matrix.getDX(),
-            c = k.lineWidth * 0.5,
-            j = f.height,
-            e = f.depth,
-            b, g;
-        if (h <= d[1]) {
-            return
-        }
-        b = d[0] + e - l;
-        g = h + c - e;
-        k.beginPath();
-        k.rect(b, g, d[2], j);
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + d[2], g);
-        k.stroke();
-        b = d[0] + i - l;
-        g = h + c;
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.lineTo(b + e, g - e + j);
-        k.lineTo(b, g + j);
-        k.closePath();
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid3D", {
-    extend: "Ext.chart.grid.VerticalGrid",
-    alias: "grid.vertical3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render_: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    },
-    render: function(b, j, e) {
-        var g = this.attr,
-            i = b.roundPixel(g.x),
-            k = b.matrix.getDY(),
-            d = j.lineWidth * 0.5,
-            a = g.width,
-            f = g.depth,
-            c, h;
-        if (i >= e[2]) {
-            return
-        }
-        c = i - d + f;
-        h = e[1] - f - k;
-        j.beginPath();
-        j.rect(c, h, a, e[3]);
-        j.fill();
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c, h + e[3]);
-        j.stroke();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.lineTo(c + f + a, h - f);
-        j.lineTo(c + a, h);
-        j.closePath();
-        j.fill();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.stroke()
-    }
-});
-Ext.define("Ext.chart.interactions.CrossZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "crosszoom",
-    alias: "interaction.crosszoom",
-    isCrossZoom: true,
-    config: {
-        axes: true,
-        gestures: {
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd",
-            dblclick: "onDoubleTap"
-        },
-        undoButton: {}
-    },
-    stopAnimationBeforeSync: false,
-    zoomAnimationInProgress: false,
-    constructor: function() {
-        this.callParent(arguments);
-        this.zoomHistory = []
-    },
-    applyAxes: function(b) {
-        var a = {};
-        if (b === true) {
-            return {
-                top: {},
-                right: {},
-                bottom: {},
-                left: {}
-            }
-        } else {
-            if (Ext.isArray(b)) {
-                a = {};
-                Ext.each(b, function(c) {
-                    a[c] = {}
-                })
-            } else {
-                if (Ext.isObject(b)) {
-                    Ext.iterate(b, function(c, d) {
-                        if (d === true) {
-                            a[c] = {}
-                        } else {
-                            if (d !== false) {
-                                a[c] = d
-                            }
-                        }
-                    })
-                }
-            }
-        }
-        return a
-    },
-    applyUndoButton: function(b, a) {
-        var c = this;
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            return Ext.create("Ext.Button", Ext.apply({
-                cls: [],
-                text: "Undo Zoom",
-                disabled: true,
-                handler: function() {
-                    c.undoZoom()
-                }
-            }, b))
-        }
-    },
-    getSurface: function() {
-        return this.getChart() && this.getChart().getSurface("main")
-    },
-    setSeriesOpacity: function(b) {
-        var a = this.getChart() && this.getChart().getSurface("series");
-        if (a) {
-            a.element.setStyle("opacity", b)
-        }
-    },
-    onGestureStart: function(h) {
-        var j = this,
-            i = j.getChart(),
-            d = j.getSurface(),
-            l = i.getInnerRect(),
-            c = i.getInnerPadding(),
-            g = c.left,
-            b = g + l[2],
-            f = c.top,
-            a = f + l[3],
-            n = i.getEventXY(h),
-            m = n[0],
-            k = n[1];
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (m > g && m < b && k > f && k < a) {
-            j.gestureEvent = "drag";
-            j.lockEvents(j.gestureEvent);
-            j.startX = m;
-            j.startY = k;
-            j.selectionRect = d.add({
-                type: "rect",
-                globalAlpha: 0.5,
-                fillStyle: "rgba(80,80,140,0.5)",
-                strokeStyle: "rgba(80,80,140,1)",
-                lineWidth: 2,
-                x: m,
-                y: k,
-                width: 0,
-                height: 0,
-                zIndex: 10000
-            });
-            j.setSeriesOpacity(0.8);
-            return false
-        }
-    },
-    onGesture: function(h) {
-        var j = this;
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (j.getLocks()[j.gestureEvent] === j) {
-            var i = j.getChart(),
-                d = j.getSurface(),
-                l = i.getInnerRect(),
-                c = i.getInnerPadding(),
-                g = c.left,
-                b = g + l[2],
-                f = c.top,
-                a = f + l[3],
-                n = i.getEventXY(h),
-                m = n[0],
-                k = n[1];
-            if (m < g) {
-                m = g
-            } else {
-                if (m > b) {
-                    m = b
-                }
-            }
-            if (k < f) {
-                k = f
-            } else {
-                if (k > a) {
-                    k = a
-                }
-            }
-            j.selectionRect.setAttributes({
-                width: m - j.startX,
-                height: k - j.startY
-            });
-            if (Math.abs(j.startX - m) < 11 || Math.abs(j.startY - k) < 11) {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 0.5
-                })
-            } else {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 1
-                })
-            }
-            d.renderFrame();
-            return false
-        }
-    },
-    onGestureEnd: function(i) {
-        var l = this;
-        if (l.zoomAnimationInProgress) {
-            return
-        }
-        if (l.getLocks()[l.gestureEvent] === l) {
-            var k = l.getChart(),
-                d = l.getSurface(),
-                n = k.getInnerRect(),
-                c = k.getInnerPadding(),
-                g = c.left,
-                b = g + n[2],
-                f = c.top,
-                a = f + n[3],
-                h = n[2],
-                j = n[3],
-                p = k.getEventXY(i),
-                o = p[0],
-                m = p[1];
-            if (o < g) {
-                o = g
-            } else {
-                if (o > b) {
-                    o = b
-                }
-            }
-            if (m < f) {
-                m = f
-            } else {
-                if (m > a) {
-                    m = a
-                }
-            }
-            if (Math.abs(l.startX - o) < 11 || Math.abs(l.startY - m) < 11) {
-                d.remove(l.selectionRect)
-            } else {
-                l.zoomBy([Math.min(l.startX, o) / h, 1 - Math.max(l.startY, m) / j, Math.max(l.startX, o) / h, 1 - Math.min(l.startY, m) / j]);
-                l.selectionRect.setAttributes({
-                    x: Math.min(l.startX, o),
-                    y: Math.min(l.startY, m),
-                    width: Math.abs(l.startX - o),
-                    height: Math.abs(l.startY - m)
-                });
-                l.selectionRect.setAnimation(k.getAnimation() || {
-                    duration: 0
-                });
-                l.selectionRect.setAttributes({
-                    globalAlpha: 0,
-                    x: 0,
-                    y: 0,
-                    width: h,
-                    height: j
-                });
-                l.zoomAnimationInProgress = true;
-                k.suspendThicknessChanged();
-                l.selectionRect.fx.on("animationend", function() {
-                    k.resumeThicknessChanged();
-                    d.remove(l.selectionRect);
-                    l.selectionRect = null;
-                    l.zoomAnimationInProgress = false
-                })
-            }
-            d.renderFrame();
-            l.sync();
-            l.unlockEvents(l.gestureEvent);
-            l.setSeriesOpacity(1);
-            if (!l.zoomAnimationInProgress) {
-                d.remove(l.selectionRect);
-                l.selectionRect = null
-            }
-        }
-    },
-    zoomBy: function(o) {
-        var n = this,
-            a = n.getAxes(),
-            k = n.getChart(),
-            j = k.getAxes(),
-            l = k.getInherited().rtl,
-            f, d = {},
-            c, b;
-        if (l) {
-            o = o.slice();
-            c = 1 - o[0];
-            b = 1 - o[2];
-            o[0] = Math.min(c, b);
-            o[2] = Math.max(c, b)
-        }
-        for (var h = 0; h < j.length; h++) {
-            var g = j[h];
-            f = a[g.getPosition()];
-            if (f && f.allowZoom !== false) {
-                var e = g.isSide(),
-                    m = g.getVisibleRange();
-                d[g.getId()] = m.slice(0);
-                if (!e) {
-                    g.setVisibleRange([(m[1] - m[0]) * o[0] + m[0], (m[1] - m[0]) * o[2] + m[0]])
-                } else {
-                    g.setVisibleRange([(m[1] - m[0]) * o[1] + m[0], (m[1] - m[0]) * o[3] + m[0]])
-                }
-            }
-        }
-        n.zoomHistory.push(d);
-        n.getUndoButton().setDisabled(false)
-    },
-    undoZoom: function() {
-        var c = this.zoomHistory.pop(),
-            d = this.getChart().getAxes();
-        if (c) {
-            for (var a = 0; a < d.length; a++) {
-                var b = d[a];
-                if (c[b.getId()]) {
-                    b.setVisibleRange(c[b.getId()])
-                }
-            }
-        }
-        this.getUndoButton().setDisabled(this.zoomHistory.length === 0);
-        this.sync()
-    },
-    onDoubleTap: function(a) {
-        this.undoZoom()
-    },
-    destroy: function() {
-        this.setUndoButton(null);
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.interactions.Crosshair", {
-    extend: "Ext.chart.interactions.Abstract",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid", "Ext.chart.CartesianChart", "Ext.chart.axis.layout.Discrete"],
-    type: "crosshair",
-    alias: "interaction.crosshair",
-    config: {
-        axes: {
-            top: {
-                label: {},
-                rect: {}
-            },
-            right: {
-                label: {},
-                rect: {}
-            },
-            bottom: {
-                label: {},
-                rect: {}
-            },
-            left: {
-                label: {},
-                rect: {}
-            }
-        },
-        lines: {
-            horizontal: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            },
-            vertical: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            }
-        },
-        gesture: "drag"
-    },
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyLines: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    updateChart: function(a) {
-        if (a && !a.isCartesian) {
-            Ext.raise("Crosshair interaction can only be used on cartesian charts.")
-        }
-        this.callParent(arguments)
-    },
-    getGestures: function() {
-        var a = this,
-            b = {};
-        b[a.getGesture()] = "onGesture";
-        b[a.getGesture() + "start"] = "onGestureStart";
-        b[a.getGesture() + "end"] = "onGestureEnd";
-        return b
-    },
-    onGestureStart: function(N) {
-        var m = this,
-            O = m.getChart(),
-            B = O.getTheme().getAxis(),
-            A, F = O.getSurface("overlay"),
-            s = O.getInnerRect(),
-            n = s[2],
-            M = s[3],
-            r = O.getEventXY(N),
-            D = r[0],
-            C = r[1],
-            E = O.getAxes(),
-            u = m.getAxes(),
-            h = m.getLines(),
-            q, v, b, d, k, z, G, L, J, o, I, w, l, f, p, j, t, a, g, H, c, K;
-        if (D > 0 && D < n && C > 0 && C < M) {
-            m.lockEvents(m.getGesture());
-            H = Ext.apply({
-                xclass: "Ext.chart.grid.HorizontalGrid",
-                x: 0,
-                y: C,
-                width: n
-            }, h.horizontal);
-            c = Ext.apply({
-                xclass: "Ext.chart.grid.VerticalGrid",
-                x: D,
-                y: 0,
-                height: M
-            }, h.vertical);
-            m.axesLabels = m.axesLabels || {};
-            for (K = 0; K < E.length; K++) {
-                q = E[K];
-                v = q.getSurface();
-                b = v.getRect();
-                w = q.getSprites()[0];
-                d = b[2];
-                k = b[3];
-                z = q.getPosition();
-                G = q.getAlignment();
-                t = q.getTitle();
-                a = t && t.attr.text !== "" && t.getBBox();
-                l = w.attr;
-                f = w.thickness;
-                p = l.axisLine ? l.lineWidth : 0;
-                j = p / 2;
-                I = Math.max(l.majorTickSize, l.minorTickSize) + p;
-                L = m.axesLabels[z] = v.add({
-                    type: "composite"
-                });
-                L.labelRect = L.add(Ext.apply({
-                    type: "rect",
-                    fillStyle: "white",
-                    x: z === "right" ? p : 0,
-                    y: z === "bottom" ? p : 0,
-                    width: d - p - (G === "vertical" && a ? a.width : 0),
-                    height: k - p - (G === "horizontal" && a ? a.height : 0),
-                    translationX: z === "left" && a ? a.width : 0,
-                    translationY: z === "top" && a ? a.height : 0
-                }, u.rect || u[z].rect));
-                if (G === "vertical" && !c.strokeStyle) {
-                    c.strokeStyle = l.strokeStyle
-                }
-                if (G === "horizontal" && !H.strokeStyle) {
-                    H.strokeStyle = l.strokeStyle
-                }
-                A = Ext.merge({}, B.defaults, B[z]);
-                J = Ext.apply({}, q.config.label, A.label);
-                o = u.label || u[z].label;
-                L.labelText = L.add(Ext.apply(J, o, {
-                    type: "text",
-                    x: (function() {
-                        switch (z) {
-                            case "left":
-                                g = a ? a.x + a.width : 0;
-                                return g + (d - g - I) / 2 - j;
-                            case "right":
-                                g = a ? d - a.x : 0;
-                                return I + (d - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })(),
-                    y: (function() {
-                        switch (z) {
-                            case "top":
-                                g = a ? a.y + a.height : 0;
-                                return g + (k - g - I) / 2 - j;
-                            case "bottom":
-                                g = a ? k - a.y : 0;
-                                return I + (k - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })()
-                }))
-            }
-            m.horizontalLine = F.add(H);
-            m.verticalLine = F.add(c);
-            return false
-        }
-    },
-    onGesture: function(G) {
-        var K = this;
-        if (K.getLocks()[K.getGesture()] !== K) {
-            return
-        }
-        var u = K.getChart(),
-            z = u.getSurface("overlay"),
-            a = Ext.Array.slice(u.getInnerRect()),
-            r = u.getInnerPadding(),
-            t = r.left,
-            q = r.top,
-            E = a[2],
-            f = a[3],
-            d = u.getEventXY(G),
-            k = d[0],
-            j = d[1],
-            D = u.getAxes(),
-            c, h, m, p, J, w, I, H, s, b, C, g, v, n, l, A, F, o, B;
-        if (k < 0) {
-            k = 0
-        } else {
-            if (k > E) {
-                k = E
-            }
-        }
-        if (j < 0) {
-            j = 0
-        } else {
-            if (j > f) {
-                j = f
-            }
-        }
-        k += t;
-        j += q;
-        for (B = 0; B < D.length; B++) {
-            c = D[B];
-            h = c.getPosition();
-            m = c.getAlignment();
-            p = c.getSurface();
-            J = c.getSprites()[0];
-            w = J.attr.matrix;
-            C = J.attr.textPadding * 2;
-            s = K.axesLabels[h];
-            I = J.getLayoutContext();
-            H = c.getSegmenter();
-            if (s) {
-                if (m === "vertical") {
-                    v = w.getYY();
-                    l = w.getDY();
-                    F = (j - l - q) / v;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        j = Math.round(F) * v + l + q;
-                        F = H.from(Math.round(F));
-                        F = J.attr.data[F]
-                    } else {
-                        F = H.from(F)
-                    }
-                    o = H.renderer(F, I);
-                    s.setAttributes({
-                        translationY: j - q
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        height: b.height + C,
-                        y: -(b.height + C) / 2
-                    });
-                    p.renderFrame()
-                } else {
-                    g = w.getXX();
-                    n = w.getDX();
-                    A = (k - n - t) / g;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        k = Math.round(A) * g + n + t;
-                        A = H.from(Math.round(A));
-                        A = J.attr.data[A]
-                    } else {
-                        A = H.from(A)
-                    }
-                    o = H.renderer(A, I);
-                    s.setAttributes({
-                        translationX: k - t
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        width: b.width + C,
-                        x: -(b.width + C) / 2
-                    });
-                    p.renderFrame()
-                }
-            }
-        }
-        K.horizontalLine.setAttributes({
-            y: j,
-            strokeStyle: J.attr.strokeStyle
-        });
-        K.verticalLine.setAttributes({
-            x: k,
-            strokeStyle: J.attr.strokeStyle
-        });
-        z.renderFrame();
-        return false
-    },
-    onGestureEnd: function(h) {
-        var l = this,
-            k = l.getChart(),
-            a = k.getSurface("overlay"),
-            j = k.getAxes(),
-            c, g, d, b, f;
-        a.remove(l.verticalLine);
-        a.remove(l.horizontalLine);
-        for (f = 0; f < j.length; f++) {
-            c = j[f];
-            g = c.getPosition();
-            d = c.getSurface();
-            b = l.axesLabels[g];
-            if (b) {
-                delete l.axesLabels[g];
-                d.remove(b)
-            }
-            d.renderFrame()
-        }
-        a.renderFrame();
-        l.unlockEvents(l.getGesture())
-    }
-});
-Ext.define("Ext.chart.interactions.ItemHighlight", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "itemhighlight",
-    alias: "interaction.itemhighlight",
-    isItemHighlight: true,
-    config: {
-        gestures: {
-            tap: "onTapGesture",
-            mousemove: "onMouseMoveGesture",
-            mousedown: "onMouseDownGesture",
-            mouseup: "onMouseUpGesture",
-            mouseleave: "onMouseUpGesture"
-        },
-        sticky: false
-    },
-    stickyHighlightItem: null,
-    onMouseMoveGesture: function(g) {
-        var d = this,
-            h = d.tipItem,
-            a = g.pointerType === "mouse",
-            c, f, b;
-        if (d.getSticky()) {
-            return true
-        }
-        if (d.isDragging) {
-            if (h && a) {
-                h.series.hideTooltip(h);
-                d.tipItem = null
-            }
-        } else {
-            if (!d.stickyHighlightItem) {
-                c = d.getItemForEvent(g);
-                b = d.getChart();
-                if (c !== b.getHighlightItem()) {
-                    d.highlight(c);
-                    d.sync()
-                }
-                if (a) {
-                    if (h && (!c || h.field !== c.field || h.record !== c.record)) {
-                        h.series.hideTooltip(h);
-                        d.tipItem = h = null
-                    }
-                    if (c && (f = c.series.getTooltip())) {
-                        if (f.trackMouse || !h) {
-                            c.series.showTooltip(c, g.getXY())
-                        }
-                        d.tipItem = c
-                    }
-                }
-                return false
-            }
-        }
-    },
-    highlight: function(a) {
-        this.getChart().setHighlightItem(a)
-    },
-    showTooltip: function(b, a) {
-        a.series.showTooltip(a, b.getXY());
-        this.tipItem = a
-    },
-    onMouseDownGesture: function() {
-        this.isDragging = true
-    },
-    onMouseUpGesture: function() {
-        this.isDragging = false
-    },
-    onTapGesture: function(c) {
-        var b = this;
-        if (c.pointerType === "mouse" && !b.getSticky()) {
-            return
-        }
-        var a = b.getItemForEvent(c);
-        if (b.stickyHighlightItem && a && (b.stickyHighlightItem.index === a.index)) {
-            a = null
-        }
-        b.stickyHighlightItem = a;
-        b.highlight(a)
-    }
-});
-Ext.define("Ext.chart.interactions.ItemEdit", {
-    extend: "Ext.chart.interactions.ItemHighlight",
-    requires: ["Ext.tip.ToolTip"],
-    type: "itemedit",
-    alias: "interaction.itemedit",
-    isItemEdit: true,
-    config: {
-        style: null,
-        renderer: null,
-        tooltip: true,
-        gestures: {
-            dragstart: "onDragStart",
-            drag: "onDrag",
-            dragend: "onDragEnd"
-        },
-        cursors: {
-            ewResize: "ew-resize",
-            nsResize: "ns-resize",
-            move: "move"
-        }
-    },
-    item: null,
-    applyTooltip: function(b) {
-        if (b) {
-            var a = Ext.apply({}, b, {
-                renderer: this.defaultTooltipRenderer,
-                constrainPosition: true,
-                shrinkWrapDock: true,
-                autoHide: true,
-                offsetX: 10,
-                offsetY: 10
-            });
-            b = new Ext.tip.ToolTip(a)
-        }
-        return b
-    },
-    defaultTooltipRenderer: function(b, a, f, d) {
-        var c = [];
-        if (f.xField) {
-            c.push(f.xField + ": " + f.xValue)
-        }
-        if (f.yField) {
-            c.push(f.yField + ": " + f.yValue)
-        }
-        b.setHtml(c.join("<br>"))
-    },
-    onDragStart: function(d) {
-        var c = this,
-            a = c.getChart(),
-            b = a.getHighlightItem();
-        if (b) {
-            a.fireEvent("beginitemedit", a, c, c.item = b);
-            return false
-        }
-    },
-    onDrag: function(f) {
-        var d = this,
-            b = d.getChart(),
-            c = b.getHighlightItem(),
-            a = c && c.sprite.type;
-        if (c) {
-            switch (a) {
-                case "barSeries":
-                    return d.onDragBar(f);
-                    break;
-                case "scatterSeries":
-                    return d.onDragScatter(f);
-                    break
-            }
-        }
-    },
-    highlight: function(f) {
-        var e = this,
-            d = e.getChart(),
-            a = d.getFlipXY(),
-            g = e.getCursors(),
-            c = f && f.sprite.type,
-            b = d.el.dom.style;
-        e.callParent([f]);
-        if (f) {
-            switch (c) {
-                case "barSeries":
-                    if (a) {
-                        b.cursor = g.ewResize
-                    } else {
-                        b.cursor = g.nsResize
-                    }
-                    break;
-                case "scatterSeries":
-                    b.cursor = g.move;
-                    break
-            }
-        } else {
-            d.el.dom.style.cursor = "default"
-        }
-    },
-    onDragBar: function(i) {
-        var m = this,
-            k = m.getChart(),
-            l = k.getInherited().rtl,
-            f = k.isCartesian && k.getFlipXY(),
-            q = k.getHighlightItem(),
-            g = q.sprite.getMarker("items"),
-            p = g.getMarkerFor(q.sprite.getId(), q.index),
-            b = q.sprite.getSurface(),
-            c = b.getRect(),
-            r = b.getEventXY(i),
-            o = q.sprite.attr.matrix,
-            j = m.getRenderer(),
-            a, n, d, h;
-        if (f) {
-            h = l ? c[2] - r[0] : r[0]
-        } else {
-            h = c[3] - r[1]
-        }
-        a = {
-            x: p.x,
-            y: h,
-            width: p.width,
-            height: p.height + (p.y - h),
-            radius: p.radius,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(a, m.getStyle());
-        if (Ext.isArray(q.series.getYField())) {
-            h = h - p.y - p.height
-        }
-        m.target = {
-            index: q.index,
-            yField: q.field,
-            yValue: (h - o.getDY()) / o.getYY()
-        };
-        d = [k, {
-            target: m.target,
-            style: a,
-            item: q
-        }];
-        n = Ext.callback(j, null, d, 0, k);
-        if (n) {
-            Ext.apply(a, n)
-        }
-        q.sprite.putMarker("items", a, "itemedit");
-        m.showTooltip(i, m.target, q);
-        b.renderFrame()
-    },
-    onDragScatter: function(n) {
-        var t = this,
-            g = t.getChart(),
-            d = g.getInherited().rtl,
-            l = g.isCartesian && g.getFlipXY(),
-            o = g.getHighlightItem(),
-            b = o.sprite.getMarker("items"),
-            p = b.getMarkerFor(o.sprite.getId(), o.index),
-            j = o.sprite.getSurface(),
-            h = j.getRect(),
-            a = j.getEventXY(n),
-            k = o.sprite.attr.matrix,
-            c = o.series.getXAxis(),
-            f = c && c.getLayout().isContinuous,
-            i = t.getRenderer(),
-            m, u, q, s, r;
-        if (l) {
-            r = d ? h[2] - a[0] : a[0]
-        } else {
-            r = h[3] - a[1]
-        }
-        if (f) {
-            if (l) {
-                s = h[3] - a[1]
-            } else {
-                s = a[0]
-            }
-        } else {
-            s = p.translationX
-        }
-        m = {
-            translationX: s,
-            translationY: r,
-            scalingX: p.scalingX,
-            scalingY: p.scalingY,
-            r: p.r,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(m, t.getStyle());
-        t.target = {
-            index: o.index,
-            yField: o.field,
-            yValue: (r - k.getDY()) / k.getYY()
-        };
-        if (f) {
-            Ext.apply(t.target, {
-                xField: o.series.getXField(),
-                xValue: (s - k.getDX()) / k.getXX()
-            })
-        }
-        q = [g, {
-            target: t.target,
-            style: m,
-            item: o
-        }];
-        u = Ext.callback(i, null, q, 0, g);
-        if (u) {
-            Ext.apply(m, u)
-        }
-        o.sprite.putMarker("items", m, "itemedit");
-        t.showTooltip(n, t.target, o);
-        j.renderFrame()
-    },
-    showTooltip: function(g, f, c) {
-        var d = this.getTooltip(),
-            a, b;
-        if (d && Ext.toolkit !== "modern") {
-            a = d.config;
-            b = this.getChart();
-            Ext.callback(a.renderer, null, [d, c, f, g], 0, b);
-            d.show([g.x + a.offsetX, g.y + a.offsetY])
-        }
-    },
-    hideTooltip: function() {
-        var a = this.getTooltip();
-        if (a && Ext.toolkit !== "modern") {
-            a.hide()
-        }
-    },
-    onDragEnd: function(g) {
-        var d = this,
-            f = d.target,
-            c = d.getChart(),
-            b = c.getStore(),
-            a;
-        if (f) {
-            a = b.getAt(f.index);
-            if (f.yField) {
-                a.set(f.yField, f.yValue, {
-                    convert: false
-                })
-            }
-            if (f.xField) {
-                a.set(f.xField, f.xValue, {
-                    convert: false
-                })
-            }
-            if (f.yField || f.xField) {
-                d.getChart().onDataChanged()
-            }
-            d.target = null
-        }
-        d.hideTooltip();
-        if (d.item) {
-            c.fireEvent("enditemedit", c, d, d.item, f)
-        }
-        d.highlight(d.item = null)
-    },
-    destroy: function() {
-        var a = this.getConfig("tooltip", true);
-        Ext.destroy(a);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.PanZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "panzoom",
-    alias: "interaction.panzoom",
-    requires: ["Ext.draw.Animator"],
-    config: {
-        axes: {
-            top: {},
-            right: {},
-            bottom: {},
-            left: {}
-        },
-        minZoom: null,
-        maxZoom: null,
-        showOverflowArrows: true,
-        panGesture: "drag",
-        zoomGesture: "pinch",
-        zoomOnPanGesture: false,
-        modeToggleButton: {
-            xtype: "segmentedbutton",
-            width: 200,
-            defaults: {
-                ui: "default-toolbar"
-            },
-            cls: Ext.baseCSSPrefix + "panzoom-toggle",
-            items: [{
-                text: "Pan"
-            }, {
-                text: "Zoom"
-            }]
-        },
-        hideLabelInGesture: false
-    },
-    stopAnimationBeforeSync: true,
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyZoomOnPanGesture: function(a) {
-        this.getChart();
-        if (this.isMultiTouch()) {
-            return false
-        }
-        return a
-    },
-    updateZoomOnPanGesture: function(b) {
-        var a = this.getModeToggleButton();
-        if (!this.isMultiTouch()) {
-            a.show();
-            a.setValue(b ? 1 : 0)
-        } else {
-            a.hide()
-        }
-    },
-    toggleMode: function() {
-        var a = this;
-        if (!a.isMultiTouch()) {
-            a.setZoomOnPanGesture(!a.getZoomOnPanGesture())
-        }
-    },
-    applyModeToggleButton: function(c, b) {
-        var d = this,
-            a = Ext.factory(c, "Ext.button.Segmented", b);
-        if (!a && b) {
-            b.destroy()
-        }
-        if (a && !b) {
-            a.addListener("toggle", function(e) {
-                d.setZoomOnPanGesture(e.getValue() === 1)
-            })
-        }
-        return a
-    },
-    getGestures: function() {
-        var c = this,
-            e = {},
-            d = c.getPanGesture(),
-            b = c.getZoomGesture(),
-            a = Ext.supports.Touch;
-        e[b] = "onZoomGestureMove";
-        e[b + "start"] = "onZoomGestureStart";
-        e[b + "end"] = "onZoomGestureEnd";
-        e[d] = "onPanGestureMove";
-        e[d + "start"] = "onPanGestureStart";
-        e[d + "end"] = "onPanGestureEnd";
-        e.doubletap = "onDoubleTap";
-        return e
-    },
-    onDoubleTap: function(h) {
-        var f = this,
-            c = f.getChart(),
-            g = c.getAxes(),
-            b, a, d;
-        for (a = 0, d = g.length; a < d; a++) {
-            b = g[a];
-            b.setVisibleRange([0, 1])
-        }
-        c.redraw()
-    },
-    onPanGestureStart: function(d) {
-        if (!d || !d.touches || d.touches.length < 2) {
-            var b = this,
-                a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            b.startX = d.getX() - c[0] - a[0];
-            b.startY = d.getY() - c[1] - a[1];
-            b.oldVisibleRanges = null;
-            b.hideLabels();
-            b.getChart().suspendThicknessChanged();
-            b.lockEvents(b.getPanGesture());
-            return false
-        }
-    },
-    onPanGestureMove: function(d) {
-        var b = this;
-        if (b.getLocks()[b.getPanGesture()] === b) {
-            var a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            if (b.getZoomOnPanGesture()) {
-                b.transformAxesBy(b.getZoomableAxes(d), 0, 0, (d.getX() - c[0] - a[0]) / b.startX, b.startY / (d.getY() - c[1] - a[1]))
-            } else {
-                b.transformAxesBy(b.getPannableAxes(d), d.getX() - c[0] - a[0] - b.startX, d.getY() - c[1] - a[1] - b.startY, 1, 1)
-            }
-            b.sync();
-            return false
-        }
-    },
-    onPanGestureEnd: function(b) {
-        var a = this,
-            c = a.getPanGesture();
-        if (a.getLocks()[c] === a) {
-            a.getChart().resumeThicknessChanged();
-            a.showLabels();
-            a.sync();
-            a.unlockEvents(c);
-            return false
-        }
-    },
-    onZoomGestureStart: function(b) {
-        if (b.touches && b.touches.length === 2) {
-            var c = this,
-                i = c.getChart().element.getXY(),
-                f = c.getChart().getInnerRect(),
-                h = i[0] + f[0],
-                d = i[1] + f[1],
-                j = [b.touches[0].point.x - h, b.touches[0].point.y - d, b.touches[1].point.x - h, b.touches[1].point.y - d],
-                g = Math.max(44, Math.abs(j[2] - j[0])),
-                a = Math.max(44, Math.abs(j[3] - j[1]));
-            c.getChart().suspendThicknessChanged();
-            c.lastZoomDistances = [g, a];
-            c.lastPoints = j;
-            c.oldVisibleRanges = null;
-            c.hideLabels();
-            c.lockEvents(c.getZoomGesture());
-            return false
-        }
-    },
-    onZoomGestureMove: function(d) {
-        var f = this;
-        if (f.getLocks()[f.getZoomGesture()] === f) {
-            var i = f.getChart().getInnerRect(),
-                n = f.getChart().element.getXY(),
-                k = n[0] + i[0],
-                h = n[1] + i[1],
-                o = Math.abs,
-                c = f.lastPoints,
-                m = [d.touches[0].point.x - k, d.touches[0].point.y - h, d.touches[1].point.x - k, d.touches[1].point.y - h],
-                g = Math.max(44, o(m[2] - m[0])),
-                b = Math.max(44, o(m[3] - m[1])),
-                a = this.lastZoomDistances || [g, b],
-                l = g / a[0],
-                j = b / a[1];
-            f.transformAxesBy(f.getZoomableAxes(d), i[2] * (l - 1) / 2 + m[2] - c[2] * l, i[3] * (j - 1) / 2 + m[3] - c[3] * j, l, j);
-            f.sync();
-            return false
-        }
-    },
-    onZoomGestureEnd: function(c) {
-        var b = this,
-            a = b.getZoomGesture();
-        if (b.getLocks()[a] === b) {
-            b.getChart().resumeThicknessChanged();
-            b.showLabels();
-            b.sync();
-            b.unlockEvents(a);
-            return false
-        }
-    },
-    hideLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.hideLabels()
-            })
-        }
-    },
-    showLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.showLabels()
-            })
-        }
-    },
-    isEventOnAxis: function(c, a) {
-        var b = a.getSurface().getRect();
-        return b[0] <= c.getX() && c.getX() <= b[0] + b[2] && b[1] <= c.getY() && c.getY() <= b[1] + b[3]
-    },
-    getPannableAxes: function(d) {
-        var h = this,
-            a = h.getAxes(),
-            f = h.getChart().getAxes(),
-            c, g = f.length,
-            k = [],
-            j = false,
-            b;
-        if (d) {
-            for (c = 0; c < g; c++) {
-                if (this.isEventOnAxis(d, f[c])) {
-                    j = true;
-                    break
-                }
-            }
-        }
-        for (c = 0; c < g; c++) {
-            b = a[f[c].getPosition()];
-            if (b && b.allowPan !== false && (!j || this.isEventOnAxis(d, f[c]))) {
-                k.push(f[c])
-            }
-        }
-        return k
-    },
-    getZoomableAxes: function(f) {
-        var j = this,
-            a = j.getAxes(),
-            g = j.getChart().getAxes(),
-            l = [],
-            d, h = g.length,
-            c, k = false,
-            b;
-        if (f) {
-            for (d = 0; d < h; d++) {
-                if (this.isEventOnAxis(f, g[d])) {
-                    k = true;
-                    break
-                }
-            }
-        }
-        for (d = 0; d < h; d++) {
-            c = g[d];
-            b = a[c.getPosition()];
-            if (b && b.allowZoom !== false && (!k || this.isEventOnAxis(f, c))) {
-                l.push(c)
-            }
-        }
-        return l
-    },
-    eachInteractiveAxes: function(c) {
-        var d = this,
-            b = d.getAxes(),
-            e = d.getChart().getAxes();
-        for (var a = 0; a < e.length; a++) {
-            if (b[e[a].getPosition()]) {
-                if (false === c.call(this, e[a])) {
-                    return
-                }
-            }
-        }
-    },
-    transformAxesBy: function(d, j, g, h, e) {
-        var f = this.getChart().getInnerRect(),
-            a = this.getAxes(),
-            k, b = this.oldVisibleRanges,
-            l = false;
-        if (!b) {
-            this.oldVisibleRanges = b = {};
-            this.eachInteractiveAxes(function(i) {
-                b[i.getId()] = i.getVisibleRange()
-            })
-        }
-        if (!f) {
-            return
-        }
-        for (var c = 0; c < d.length; c++) {
-            k = a[d[c].getPosition()];
-            l = this.transformAxisBy(d[c], b[d[c].getId()], j, g, h, e, this.minZoom || k.minZoom, this.maxZoom || k.maxZoom) || l
-        }
-        return l
-    },
-    transformAxisBy: function(c, o, r, q, k, i, h, m) {
-        var s = this,
-            b = o[1] - o[0],
-            l = c.getVisibleRange(),
-            g = h || s.getMinZoom() || c.config.minZoom,
-            j = m || s.getMaxZoom() || c.config.maxZoom,
-            a = s.getChart().getInnerRect(),
-            f, p;
-        if (!a) {
-            return
-        }
-        var d = c.isSide(),
-            e = d ? a[3] : a[2],
-            n = d ? -q : r;
-        b /= d ? i : k;
-        if (b < 0) {
-            b = -b
-        }
-        if (b * g > 1) {
-            b = 1
-        }
-        if (b * j < 1) {
-            b = 1 / j
-        }
-        f = o[0];
-        p = o[1];
-        l = l[1] - l[0];
-        if (b === l && l === 1) {
-            return
-        }
-        c.setVisibleRange([(o[0] + o[1] - b) * 0.5 - n / e * b, (o[0] + o[1] + b) * 0.5 - n / e * b]);
-        return (Math.abs(f - c.getVisibleRange()[0]) > 1e-10 || Math.abs(p - c.getVisibleRange()[1]) > 1e-10)
-    },
-    destroy: function() {
-        this.setModeToggleButton(null);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Rotate", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "rotate",
-    alias: "interaction.rotate",
-    config: {
-        gesture: "rotate",
-        gestures: {
-            rotate: "onRotate",
-            rotateend: "onRotate",
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd"
-        },
-        rotation: 0
-    },
-    oldRotations: null,
-    getAngle: function(f) {
-        var c = this,
-            b = c.getChart(),
-            d = b.getEventXY(f),
-            a = b.getCenter();
-        return Math.atan2(d[1] - a[1], d[0] - a[0])
-    },
-    getRadius: function(a) {
-        return this.getChart().getRadius()
-    },
-    getEventRadius: function(h) {
-        var f = this,
-            d = f.getChart(),
-            g = d.getEventXY(h),
-            a = d.getCenter(),
-            c = g[0] - a[0],
-            b = g[1] - a[1];
-        return Math.sqrt(c * c + b * b)
-    },
-    onGestureStart: function(d) {
-        var c = this,
-            b = c.getRadius(d),
-            a = c.getEventRadius(d);
-        if (b >= a) {
-            c.lockEvents("drag");
-            c.angle = c.getAngle(d);
-            c.oldRotations = {};
-            return false
-        }
-    },
-    onGesture: function(b) {
-        var a = this,
-            c = a.getAngle(b) - a.angle;
-        if (a.getLocks().drag === a) {
-            a.doRotateTo(c, true);
-            return false
-        }
-    },
-    doRotateTo: function(d, a, b) {
-        var n = this,
-            l = n.getChart(),
-            k = l.getAxes(),
-            f = l.getSeries(),
-            m = n.oldRotations,
-            c, j, g, e, h;
-        if (!b) {
-            l.suspendAnimation()
-        }
-        for (e = 0, h = k.length; e < h; e++) {
-            c = k[e];
-            g = m[c.getId()] || (m[c.getId()] = c.getRotation());
-            c.setRotation(d + (a ? g : 0))
-        }
-        for (e = 0, h = f.length; e < h; e++) {
-            j = f[e];
-            g = m[j.getId()] || (m[j.getId()] = j.getRotation());
-            j.setRotation(d + (a ? g : 0))
-        }
-        n.setRotation(d + (a ? g : 0));
-        n.fireEvent("rotate", n, n.getRotation());
-        n.sync();
-        if (!b) {
-            l.resumeAnimation()
-        }
-    },
-    rotateTo: function(c, b, a) {
-        this.doRotateTo(c, b, a);
-        this.oldRotations = {}
-    },
-    onGestureEnd: function(b) {
-        var a = this;
-        if (a.getLocks().drag === a) {
-            a.onGesture(b);
-            a.unlockEvents("drag");
-            a.fireEvent("rotationEnd", a, a.getRotation());
-            return false
-        }
-    },
-    onRotate: function(a) {}
-});
-Ext.define("Ext.chart.interactions.RotatePie3D", {
-    extend: "Ext.chart.interactions.Rotate",
-    type: "rotatePie3d",
-    alias: "interaction.rotatePie3d",
-    getAngle: function(g) {
-        var a = this.getChart(),
-            f = a.getInherited().rtl,
-            d = f ? -1 : 1,
-            h = g.getXY(),
-            c = a.element.getXY(),
-            b = a.getMainRect();
-        return d * Math.atan2(h[1] - c[1] - b[3] * 0.5, h[0] - c[0] - b[2] * 0.5)
-    },
-    getRadius: function(j) {
-        var f = this.getChart(),
-            a = f.getRadius(),
-            d = f.getSeries(),
-            h = d.length,
-            c = 0,
-            b, g;
-        for (; c < h; c++) {
-            b = d[c];
-            if (b.isPie3D) {
-                g = b.getRadius();
-                if (g > a) {
-                    a = g
-                }
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.plugin.ItemEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.chartitemevents",
-    moveEvents: false,
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    itemMouseMoveEvents: {
-        itemmousemove: true,
-        itemmouseover: true,
-        itemmouseout: true
-    },
-    init: function(b) {
-        var a = "handleEvent";
-        this.chart = b;
-        b.addElementListener({
-            click: a,
-            dblclick: a,
-            mousedown: a,
-            mousemove: a,
-            mouseup: a,
-            mouseover: a,
-            mouseout: a,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasItemMouseMoveListeners: function() {
-        var b = this.chart.hasListeners,
-            a;
-        for (a in this.itemMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    handleEvent: function(g) {
-        var d = this,
-            a = d.chart,
-            h = g.type in d.mouseMoveEvents,
-            c = d.lastItem,
-            f, b;
-        if (h && !d.hasItemMouseMoveListeners() && !d.moveEvents) {
-            return
-        }
-        f = a.getEventXY(g);
-        b = a.getItemForPoint(f[0], f[1]);
-        if (h && !Ext.Object.equals(b, c)) {
-            if (c) {
-                a.fireEvent("itemmouseout", a, c, g);
-                c.series.fireEvent("itemmouseout", c.series, c, g)
-            }
-            if (b) {
-                a.fireEvent("itemmouseover", a, b, g);
-                b.series.fireEvent("itemmouseover", b.series, b, g)
-            }
-        }
-        if (b) {
-            a.fireEvent("item" + g.type, a, b, g);
-            b.series.fireEvent("item" + g.type, b.series, b, g)
-        }
-        d.lastItem = b
-    }
-});
-Ext.define("Ext.chart.series.Cartesian", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        xField: null,
-        yField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    updateXAxis: function(a) {
-        a.processData(this)
-    },
-    updateYAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    getItemForPoint: function(a, g) {
-        if (this.getSprites()) {
-            var f = this,
-                d = f.getSprites()[0],
-                b = f.getStore(),
-                e, c;
-            if (f.getHidden()) {
-                return null
-            }
-            if (d) {
-                c = d.getIndexNearPoint(a, g);
-                if (c !== -1) {
-                    e = {
-                        series: f,
-                        category: f.getItemInstancing() ? "items" : "markers",
-                        index: c,
-                        record: b.getData().items[c],
-                        field: f.getYField(),
-                        sprite: d
-                    };
-                    return e
-                }
-            }
-        }
-    },
-    createSprite: function() {
-        var c = this,
-            a = c.callParent(),
-            b = c.getChart(),
-            d = c.getXAxis();
-        a.setAttributes({
-            flipXY: b.getFlipXY(),
-            xAxis: d
-        });
-        if (a.setAggregator && d && d.getAggregator) {
-            if (d.getAggregator) {
-                a.setAggregator({
-                    strategy: d.getAggregator()
-                })
-            } else {
-                a.setAggregator({})
-            }
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = this.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.getItemInstancing(),
-            f = d.sprites,
-            a;
-        if (!c) {
-            return []
-        }
-        if (!f.length) {
-            a = d.createSprite()
-        } else {
-            a = f[0]
-        }
-        if (e) {
-            if (b) {
-                a.itemsMarker.getTemplate().setAnimation(e)
-            }
-            a.setAnimation(e)
-        }
-        return f
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    }
-});
-Ext.define("Ext.chart.series.StackedCartesian", {
-    extend: "Ext.chart.series.Cartesian",
-    config: {
-        stacked: true,
-        splitStacks: true,
-        fullStack: false,
-        fullStackTotal: 100,
-        hidden: []
-    },
-    spriteAnimationCount: 0,
-    themeColorCount: function() {
-        var b = this,
-            a = b.getYField();
-        return Ext.isArray(a) ? a.length : 1
-    },
-    updateStacked: function() {
-        this.processData()
-    },
-    updateSplitStacks: function() {
-        this.processData()
-    },
-    coordinateY: function() {
-        return this.coordinateStacked("Y", 1, 2)
-    },
-    coordinateStacked: function(D, e, m) {
-        var F = this,
-            f = F.getStore(),
-            r = f.getData().items,
-            B = r.length,
-            c = F["get" + D + "Axis"](),
-            x = F.getHidden(),
-            a = F.getSplitStacks(),
-            z = F.getFullStack(),
-            l = F.getFullStackTotal(),
-            p = {
-                min: 0,
-                max: 0
-            },
-            n = F["fieldCategory" + D],
-            C = [],
-            o = [],
-            E = [],
-            h, A = F.getStacked(),
-            g = F.getSprites(),
-            q = [],
-            w, v, u, s, H, y, b, d, G, t;
-        if (!g.length) {
-            return
-        }
-        for (w = 0; w < n.length; w++) {
-            d = n[w];
-            s = F.getFields([d]);
-            H = s.length;
-            for (v = 0; v < B; v++) {
-                C[v] = 0;
-                o[v] = 0;
-                E[v] = 0
-            }
-            for (v = 0; v < H; v++) {
-                if (!x[v]) {
-                    q[v] = F.coordinateData(r, s[v], c)
-                }
-            }
-            if (A && z) {
-                y = [];
-                if (a) {
-                    b = []
-                }
-                for (v = 0; v < B; v++) {
-                    y[v] = 0;
-                    if (a) {
-                        b[v] = 0
-                    }
-                    for (u = 0; u < H; u++) {
-                        G = q[u];
-                        if (!G) {
-                            continue
-                        }
-                        G = G[v];
-                        if (G >= 0 || !a) {
-                            y[v] += G
-                        } else {
-                            if (G < 0) {
-                                b[v] += G
-                            }
-                        }
-                    }
-                }
-            }
-            for (v = 0; v < H; v++) {
-                t = {};
-                if (x[v]) {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = C;
-                    g[v].setAttributes(t);
-                    continue
-                }
-                G = q[v];
-                if (A) {
-                    h = [];
-                    for (u = 0; u < B; u++) {
-                        if (!G[u]) {
-                            G[u] = 0
-                        }
-                        if (G[u] >= 0 || !a) {
-                            if (z && y[u]) {
-                                G[u] *= l / y[u]
-                            }
-                            C[u] = o[u];
-                            o[u] += G[u];
-                            h[u] = o[u]
-                        } else {
-                            if (z && b[u]) {
-                                G[u] *= l / b[u]
-                            }
-                            C[u] = E[u];
-                            E[u] += G[u];
-                            h[u] = E[u]
-                        }
-                    }
-                    t["dataStart" + d] = C;
-                    t["data" + d] = h;
-                    F.getRangeOfData(C, p);
-                    F.getRangeOfData(h, p)
-                } else {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = G;
-                    F.getRangeOfData(G, p)
-                }
-                g[v].setAttributes(t)
-            }
-        }
-        F.dataRange[e] = p.min;
-        F.dataRange[e + m] = p.max;
-        t = {};
-        t["dataMin" + D] = p.min;
-        t["dataMax" + D] = p.max;
-        for (w = 0; w < g.length; w++) {
-            g[w].setAttributes(t)
-        }
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    updateLabelOverflowPadding: function(a) {
-        this.getLabel().setAttributes({
-            labelOverflowPadding: a
-        })
-    },
-    getSprites: function() {
-        var k = this,
-            j = k.getChart(),
-            c = k.getAnimation() || j && j.getAnimation(),
-            f = k.getFields(k.fieldCategoryY),
-            b = k.getItemInstancing(),
-            h = k.sprites,
-            l, e = k.getHidden(),
-            g = false,
-            d, a = f.length;
-        if (!j) {
-            return []
-        }
-        for (d = 0; d < a; d++) {
-            l = h[d];
-            if (!l) {
-                l = k.createSprite();
-                l.setAttributes({
-                    zIndex: -d
-                });
-                l.setField(f[d]);
-                g = true;
-                e.push(false);
-                if (b) {
-                    l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))
-                } else {
-                    l.setAttributes(k.getStyleByIndex(d))
-                }
-            }
-            if (c) {
-                if (b) {
-                    l.itemsMarker.getTemplate().setAnimation(c)
-                }
-                l.setAnimation(c)
-            }
-        }
-        if (g) {
-            k.updateHidden(e)
-        }
-        return h
-    },
-    getItemForPoint: function(k, j) {
-        if (this.getSprites()) {
-            var h = this,
-                b, g, m, a = h.getItemInstancing(),
-                f = h.getSprites(),
-                l = h.getStore(),
-                c = h.getHidden(),
-                n, d, e;
-            for (b = 0, g = f.length; b < g; b++) {
-                if (!c[b]) {
-                    m = f[b];
-                    d = m.getIndexNearPoint(k, j);
-                    if (d !== -1) {
-                        e = h.getYField();
-                        n = {
-                            series: h,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: l.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: m
-                        };
-                        return n
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(e) {
-        var g = this,
-            f = g.getSprites(),
-            h = g.getTitle(),
-            j = g.getYField(),
-            d = g.getHidden(),
-            k = f.length === 1,
-            b, l, c, a;
-        for (c = 0; c < f.length; c++) {
-            b = g.getStyleByIndex(c);
-            l = b.fillStyle;
-            if (h) {
-                if (Ext.isArray(h)) {
-                    a = h[c]
-                } else {
-                    if (k) {
-                        a = h
-                    }
-                }
-            } else {
-                if (Ext.isArray(j)) {
-                    a = j[c]
-                } else {
-                    a = g.getId()
-                }
-            }
-            e.push({
-                name: a,
-                mark: (Ext.isObject(l) ? l.stops && l.stops[0].color : l) || b.strokeStyle || "black",
-                disabled: d[c],
-                series: g.getId(),
-                index: c
-            })
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart")
-        }
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend")
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Series", {
-    extend: "Ext.draw.sprite.Sprite",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataMinX: "number",
-                dataMaxX: "number",
-                dataMinY: "number",
-                dataMaxY: "number",
-                rangeX: "data",
-                rangeY: "data",
-                dataX: "data",
-                dataY: "data"
-            },
-            defaults: {
-                dataMinX: 0,
-                dataMaxX: 1,
-                dataMinY: 0,
-                dataMaxY: 1,
-                rangeX: null,
-                rangeY: null,
-                dataX: null,
-                dataY: null
-            },
-            triggers: {
-                dataX: "bbox",
-                dataY: "bbox",
-                dataMinX: "bbox",
-                dataMaxX: "bbox",
-                dataMinY: "bbox",
-                dataMaxY: "bbox"
-            }
-        }
-    },
-    config: {
-        store: null,
-        series: null,
-        field: null
-    }
-});
-Ext.define("Ext.chart.series.sprite.Cartesian", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                labels: "default",
-                labelOverflowPadding: "number",
-                selectionTolerance: "number",
-                flipXY: "bool",
-                renderer: "default",
-                visibleMinX: "number",
-                visibleMinY: "number",
-                visibleMaxX: "number",
-                visibleMaxY: "number",
-                innerWidth: "number",
-                innerHeight: "number"
-            },
-            defaults: {
-                labels: null,
-                labelOverflowPadding: 10,
-                selectionTolerance: 20,
-                flipXY: false,
-                renderer: null,
-                transformFillStroke: false,
-                visibleMinX: 0,
-                visibleMinY: 0,
-                visibleMaxX: 1,
-                visibleMaxY: 1,
-                innerWidth: 1,
-                innerHeight: 1
-            },
-            triggers: {
-                dataX: "dataX,bbox",
-                dataY: "dataY,bbox",
-                visibleMinX: "panzoom",
-                visibleMinY: "panzoom",
-                visibleMaxX: "panzoom",
-                visibleMaxY: "panzoom",
-                innerWidth: "panzoom",
-                innerHeight: "panzoom"
-            },
-            updaters: {
-                dataX: function(a) {
-                    this.processDataX();
-                    this.scheduleUpdater(a, "dataY", ["dataY"])
-                },
-                dataY: function() {
-                    this.processDataY()
-                },
-                panzoom: function(c) {
-                    var e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        g = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = this.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * g / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = g / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    this.applyTransformations(true)
-                }
-            }
-        }
-    },
-    processDataY: Ext.emptyFn,
-    processDataX: Ext.emptyFn,
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.dataMinX;
-        b.y = a.dataMinY;
-        b.width = a.dataMaxX - a.dataMinX;
-        b.height = a.dataMaxY - a.dataMinY
-    },
-    binarySearch: function(d) {
-        var b = this.attr.dataX,
-            f = 0,
-            a = b.length;
-        if (d <= b[0]) {
-            return f
-        }
-        if (d >= b[a - 1]) {
-            return a - 1
-        }
-        while (f + 1 < a) {
-            var c = (f + a) >> 1,
-                e = b[c];
-            if (e === d) {
-                return c
-            } else {
-                if (e < d) {
-                    f = c
-                } else {
-                    a = c
-                }
-            }
-        }
-        return f
-    },
-    render: function(b, c, g) {
-        var f = this,
-            a = f.attr,
-            e = a.inverseMatrix.clone();
-        e.appendMatrix(b.inverseMatrix);
-        if (a.dataX === null || a.dataX === undefined) {
-            return
-        }
-        if (a.dataY === null || a.dataY === undefined) {
-            return
-        }
-        if (e.getXX() * e.getYX() || e.getXY() * e.getYY()) {
-            console.log("Cartesian Series sprite does not support rotation/sheering");
-            return
-        }
-        var d = e.transformList([
-            [g[0] - 1, g[3] + 1],
-            [g[0] + g[2] + 1, -1]
-        ]);
-        d = d[0].concat(d[1]);
-        f.renderClipped(b, c, d, g)
-    },
-    renderClipped: Ext.emptyFn,
-    getIndexNearPoint: function(f, e) {
-        var w = this,
-            q = w.attr.matrix,
-            h = w.attr.dataX,
-            g = w.attr.dataY,
-            k = w.attr.selectionTolerance,
-            t, r, c = -1,
-            j = q.clone().prependMatrix(w.surfaceMatrix).inverse(),
-            u = j.transformPoint([f, e]),
-            b = j.transformPoint([f - k, e - k]),
-            n = j.transformPoint([f + k, e + k]),
-            a = Math.min(b[0], n[0]),
-            s = Math.max(b[0], n[0]),
-            l = Math.min(b[1], n[1]),
-            d = Math.max(b[1], n[1]),
-            m, v, o, p;
-        for (o = 0, p = h.length; o < p; o++) {
-            m = h[o];
-            v = g[o];
-            if (m > a && m < s && v > l && v < d) {
-                if (c === -1 || (Math.abs(m - u[0]) < t) && (Math.abs(v - u[1]) < r)) {
-                    t = Math.abs(m - u[0]);
-                    r = Math.abs(v - u[1]);
-                    c = o
-                }
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.series.sprite.StackedCartesian", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                groupCount: "number",
-                groupOffset: "number",
-                dataStartY: "data"
-            },
-            defaults: {
-                selectionTolerance: 20,
-                groupCount: 1,
-                groupOffset: 0,
-                dataStartY: null
-            },
-            triggers: {
-                dataStartY: "dataY,bbox"
-            }
-        }
-    },
-    getIndexNearPoint: function(e, d) {
-        var o = this,
-            q = o.attr.matrix,
-            h = o.attr.dataX,
-            f = o.attr.dataY,
-            u = o.attr.dataStartY,
-            l = o.attr.selectionTolerance,
-            s = 0.5,
-            r = Infinity,
-            b = -1,
-            k = q.clone().prependMatrix(this.surfaceMatrix).inverse(),
-            t = k.transformPoint([e, d]),
-            a = k.transformPoint([e - l, d - l]),
-            n = k.transformPoint([e + l, d + l]),
-            m = Math.min(a[1], n[1]),
-            c = Math.max(a[1], n[1]),
-            j, g;
-        for (var p = 0; p < h.length; p++) {
-            if (Math.min(u[p], f[p]) <= c && m <= Math.max(u[p], f[p])) {
-                j = Math.abs(h[p] - t[0]);
-                g = Math.max(-Math.min(f[p] - t[1], t[1] - u[p]), 0);
-                if (j < s && g <= r) {
-                    s = j;
-                    r = g;
-                    b = p
-                }
-            }
-        }
-        return b
-    }
-});
-Ext.define("Ext.chart.series.sprite.Area", {
-    alias: "sprite.areaSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                step: "bool"
-            },
-            defaults: {
-                step: false
-            }
-        }
-    },
-    renderClipped: function(q, s, A) {
-        var B = this,
-            p = B.attr,
-            l = p.dataX,
-            j = p.dataY,
-            C = p.dataStartY,
-            t = p.matrix,
-            h, g, v, f, d, z, w, e = t.elements[0],
-            m = t.elements[4],
-            o = t.elements[3],
-            k = t.elements[5],
-            c = B.surfaceMatrix,
-            n = {},
-            r = Math.min(A[0], A[2]),
-            u = Math.max(A[0], A[2]),
-            b = Math.max(0, this.binarySearch(r)),
-            a = Math.min(l.length - 1, this.binarySearch(u) + 1);
-        s.beginPath();
-        z = l[b] * e + m;
-        w = j[b] * o + k;
-        s.moveTo(z, w);
-        if (p.step) {
-            d = w;
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g)
-            }
-        }
-        if (C) {
-            if (p.step) {
-                f = l[a] * e + m;
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(f, g);
-                    s.lineTo(f = h, g)
-                }
-            } else {
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(h, g)
-                }
-            }
-        } else {
-            s.lineTo(l[a] * e + m, g);
-            s.lineTo(l[a] * e + m, k);
-            s.lineTo(z, k);
-            s.lineTo(z, j[v] * o + k)
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.fill();
-        if (p.transformFillStroke) {
-            p.inverseMatrix.toContext(s)
-        }
-        s.beginPath();
-        s.moveTo(z, w);
-        if (p.step) {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.stroke()
-    }
-});
-Ext.define("Ext.chart.series.Area", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.area",
-    type: "area",
-    seriesType: "areaSeries",
-    requires: ["Ext.chart.series.sprite.Area"],
-    config: {
-        splitStacks: false
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar", {
-    alias: "sprite.barSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                minBarWidth: "number",
-                maxBarWidth: "number",
-                minGapWidth: "number",
-                radius: "number",
-                inGroupGapWidth: "number"
-            },
-            defaults: {
-                minBarWidth: 2,
-                maxBarWidth: 100,
-                minGapWidth: 5,
-                inGroupGapWidth: 3,
-                radius: 0
-            }
-        }
-    },
-    drawLabel: function(k, i, s, h, o) {
-        var q = this,
-            n = q.attr,
-            f = q.getMarker("labels"),
-            d = f.getTemplate(),
-            l = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            j = n.labelOverflowPadding,
-            b = d.attr.display,
-            m = d.attr.orientation,
-            g, e, a, r, t, p;
-        l.x = c.x(i, h);
-        l.y = c.y(i, h);
-        if (!n.flipXY) {
-            l.rotationRads = -Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        l.calloutVertical = !n.flipXY;
-        switch (m) {
-            case "horizontal":
-                l.rotationRads = 0;
-                l.calloutVertical = false;
-                break;
-            case "vertical":
-                l.rotationRads = -Math.PI * 0.5;
-                l.calloutVertical = true;
-                break
-        }
-        l.text = k;
-        if (d.attr.renderer) {
-            p = [k, f, l, {
-                store: q.getStore()
-            }, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                l.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        l.text = r.text
-                    }
-                    t = true
-                }
-            }
-        }
-        a = q.getMarkerBBox("labels", o, true);
-        if (!a) {
-            q.putMarker("labels", l, o);
-            a = q.getMarkerBBox("labels", o, true)
-        }
-        e = (a.width / 2 + j);
-        if (s > h) {
-            e = -e
-        }
-        if ((m === "horizontal" && n.flipXY) || (m === "vertical" && !n.flipXY) || !m) {
-            g = (b === "insideStart") ? s + e : h - e
-        } else {
-            g = (b === "insideStart") ? s + j * 2 : h - j * 2
-        }
-        l.x = c.x(i, g);
-        l.y = c.y(i, g);
-        g = (b === "insideStart") ? s - e : h + e;
-        l.calloutPlaceX = c.x(i, g);
-        l.calloutPlaceY = c.y(i, g);
-        g = (b === "insideStart") ? s : h;
-        l.calloutStartX = c.x(i, g);
-        l.calloutStartY = c.y(i, g);
-        if (s > h) {
-            e = -e
-        }
-        if (Math.abs(h - s) <= e * 2 || b === "outside") {
-            l.callout = 1
-        } else {
-            l.callout = 0
-        }
-        if (t) {
-            Ext.apply(l, r)
-        }
-        q.putMarker("labels", l, o)
-    },
-    drawBar: function(l, b, d, c, h, k, a, e) {
-        var g = this,
-            j = {},
-            f = g.attr.renderer,
-            i;
-        j.x = c;
-        j.y = h;
-        j.width = k - c;
-        j.height = a - h;
-        j.radius = g.attr.radius;
-        if (f) {
-            i = Ext.callback(f, null, [g, j, {
-                store: g.getStore()
-            }, e], 0, g.getSeries());
-            Ext.apply(j, i)
-        }
-        g.putMarker("items", j, e, !f)
-    },
-    renderClipped: function(G, u, F, C) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var q = this,
-            o = q.attr,
-            w = o.dataX,
-            v = o.dataY,
-            H = o.labels,
-            n = o.dataStartY,
-            m = o.groupCount,
-            E = o.groupOffset - (m - 1) * 0.5,
-            z = o.inGroupGapWidth,
-            t = u.lineWidth,
-            D = o.matrix,
-            B = D.elements[0],
-            j = D.elements[3],
-            e = D.elements[4],
-            d = G.roundPixel(D.elements[5]) - 1,
-            J = (B < 0 ? -1 : 1) * B - o.minGapWidth,
-            k = (Math.min(J, o.maxBarWidth) - z * (m - 1)) / m,
-            A = G.roundPixel(Math.max(o.minBarWidth, k)),
-            c = q.surfaceMatrix,
-            g, I, b, h, K, a, l = 0.5 * o.lineWidth,
-            L = Math.min(F[0], F[2]),
-            x = Math.max(F[0], F[2]),
-            y = Math.max(0, Math.floor(L)),
-            p = Math.min(w.length - 1, Math.ceil(x)),
-            f = H && q.getMarker("labels"),
-            s, r;
-        for (K = y; K <= p; K++) {
-            s = n ? n[K] : 0;
-            r = v[K];
-            a = w[K] * B + e + E * (A + z);
-            g = G.roundPixel(a - A / 2) + l;
-            h = G.roundPixel(r * j + d + t);
-            I = G.roundPixel(a + A / 2) - l;
-            b = G.roundPixel(s * j + d + t);
-            q.drawBar(u, G, F, g, h - l, I, b - l, K);
-            if (f && H[K] != null) {
-                q.drawLabel(H[K], a, b, h, K)
-            }
-            q.putMarker("markers", {
-                translationX: c.x(a, h),
-                translationY: c.y(a, h)
-            }, K, true)
-        }
-    },
-    getIndexNearPoint: function(l, k) {
-        var m = this,
-            g = m.attr,
-            h = g.dataX,
-            a = m.getSurface(),
-            b = a.getRect() || [0, 0, 0, 0],
-            j = b[3],
-            e, d, c, n, f = -1;
-        if (g.flipXY) {
-            e = j - k;
-            if (a.getInherited().rtl) {
-                d = b[2] - l
-            } else {
-                d = l
-            }
-        } else {
-            e = l;
-            d = j - k
-        }
-        for (c = 0; c < h.length; c++) {
-            n = m.getMarkerBBox("items", c);
-            if (Ext.draw.Draw.isPointInBBox(e, d, n)) {
-                f = c;
-                break
-            }
-        }
-        return f
-    }
-});
-Ext.define("Ext.chart.series.Bar", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.bar",
-    type: "bar",
-    seriesType: "barSeries",
-    requires: ["Ext.chart.series.sprite.Bar", "Ext.draw.sprite.Rect"],
-    config: {
-        itemInstancing: {
-            type: "rect",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    radius: 0
-                }
-            }
-        }
-    },
-    getItemForPoint: function(a, f) {
-        if (this.getSprites()) {
-            var d = this,
-                c = d.getChart(),
-                e = c.getInnerPadding(),
-                b = c.getInherited().rtl;
-            arguments[0] = a + (b ? e.right : -e.left);
-            arguments[1] = f + e.bottom;
-            return d.callParent(arguments)
-        }
-    },
-    updateXAxis: function(a) {
-        a.setLabelInSpan(true);
-        this.callParent(arguments)
-    },
-    updateHidden: function(a) {
-        this.callParent(arguments);
-        this.updateStacked()
-    },
-    updateStacked: function(c) {
-        var e = this,
-            g = e.getSprites(),
-            d = g.length,
-            f = [],
-            a = {},
-            b;
-        for (b = 0; b < d; b++) {
-            if (!g[b].attr.hidden) {
-                f.push(g[b])
-            }
-        }
-        d = f.length;
-        if (e.getStacked()) {
-            a.groupCount = 1;
-            a.groupOffset = 0;
-            for (b = 0; b < d; b++) {
-                f[b].setAttributes(a)
-            }
-        } else {
-            a.groupCount = f.length;
-            for (b = 0; b < d; b++) {
-                a.groupOffset = b;
-                f[b].setAttributes(a)
-            }
-        }
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar3D", {
-    extend: "Ext.chart.series.sprite.Bar",
-    alias: "sprite.bar3dSeries",
-    requires: ["Ext.draw.gradient.Linear"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                depthWidthRatio: "number",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            defaults: {
-                depthWidthRatio: 1 / 3,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                transformFillStroke: true
-            },
-            triggers: {
-                groupCount: "panzoom"
-            },
-            updaters: {
-                panzoom: function(c) {
-                    var g = this,
-                        e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        h = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = g.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * (h - g.depth) / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = (h - g.depth) / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    g.applyTransformations(true)
-                }
-            }
-        }
-    },
-    config: {
-        showStroke: false
-    },
-    depth: 0,
-    drawBar: function(p, b, d, c, l, o, a, h) {
-        var k = this,
-            i = k.attr,
-            n = {},
-            j = i.renderer,
-            m, g, f, e;
-        n.x = (c + o) * 0.5;
-        n.y = l;
-        n.width = (o - c) * 0.75;
-        n.height = a - l;
-        n.depth = g = n.width * i.depthWidthRatio;
-        n.orientation = i.flipXY ? "horizontal" : "vertical";
-        n.saturationFactor = i.saturationFactor;
-        n.brightnessFactor = i.brightnessFactor;
-        n.colorSpread = i.colorSpread;
-        if (g !== k.depth) {
-            k.depth = g;
-            f = k.getSeries();
-            f.fireEvent("depthchange", f, g)
-        }
-        if (j) {
-            e = [k, n, {
-                store: k.getStore()
-            }, h];
-            m = Ext.callback(j, null, e, 0, k.getSeries());
-            Ext.apply(n, m)
-        }
-        k.putMarker("items", n, h, !j)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Box", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.box",
-    type: "box",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                depth: "number",
-                orientation: "enums(vertical,horizontal)",
-                showStroke: "bool",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            triggers: {
-                x: "bbox",
-                y: "bbox",
-                width: "bbox",
-                height: "bbox",
-                depth: "bbox",
-                orientation: "bbox"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                depth: 8,
-                orientation: "vertical",
-                showStroke: false,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                lineJoin: "bevel"
-            }
-        }
-    },
-    constructor: function(a) {
-        this.callParent([a]);
-        this.topGradient = new Ext.draw.gradient.Linear({});
-        this.rightGradient = new Ext.draw.gradient.Linear({});
-        this.frontGradient = new Ext.draw.gradient.Linear({})
-    },
-    updatePlainBBox: function(d) {
-        var c = this.attr,
-            b = c.x,
-            g = c.y,
-            e = c.width,
-            a = c.height,
-            f = c.depth;
-        d.x = b - e * 0.5;
-        d.width = e + f;
-        if (a > 0) {
-            d.y = g;
-            d.height = a + f
-        } else {
-            d.y = g + f;
-            d.height = a - f
-        }
-    },
-    render: function(l, m) {
-        var u = this,
-            k = u.attr,
-            r = k.x,
-            j = k.y,
-            f = j + k.height,
-            i = j < f,
-            e = k.width * 0.5,
-            v = k.depth,
-            d = k.orientation === "horizontal",
-            g = k.globalAlpha < 1,
-            c = k.fillStyle,
-            n = Ext.draw.Color.create(c.isGradient ? c.getStops()[0].color : c),
-            h = k.saturationFactor,
-            o = k.brightnessFactor,
-            t = k.colorSpread,
-            b = n.getHSV(),
-            a = {},
-            s, q, p;
-        if (!k.showStroke) {
-            m.strokeStyle = Ext.draw.Color.RGBA_NONE
-        }
-        if (i) {
-            p = j;
-            j = f;
-            f = p
-        }
-        u.topGradient.setDegrees(d ? 0 : 80);
-        u.topGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.11) * o, 0, 1))
-        }]);
-        u.rightGradient.setDegrees(d ? 45 : 90);
-        u.rightGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.14) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.4) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.32) * o, 0, 1))
-        }]);
-        if (d) {
-            u.frontGradient.setDegrees(0)
-        } else {
-            u.frontGradient.setRadians(Math.atan2(j - f, e * 2))
-        }
-        u.frontGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 - t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.23) * o, 0, 1))
-        }]);
-        if (g || i) {
-            m.beginPath();
-            m.moveTo(r - e, f);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r + e + v, f + v);
-            m.lineTo(r + e, f);
-            m.closePath();
-            a.x = r - e;
-            a.y = j;
-            a.width = e + v;
-            a.height = v;
-            m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        if (g) {
-            m.beginPath();
-            m.moveTo(r - e, j);
-            m.lineTo(r - e + v, j + v);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r - e, f);
-            m.closePath();
-            a.x = r + e;
-            a.y = f;
-            a.width = v;
-            a.height = j + v - f;
-            m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, q);
-        m.lineTo(r - e + v, j + v);
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e, q);
-        m.closePath();
-        a.x = r - e;
-        a.y = j;
-        a.width = e + v;
-        a.height = v;
-        m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        m.beginPath();
-        m.moveTo(s, l.roundPixel(j));
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e + v, f + v);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r + e;
-        a.y = f;
-        a.width = v;
-        a.height = j + v - f;
-        m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, f);
-        m.lineTo(r - e, q);
-        m.lineTo(s, q);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r - e;
-        a.y = f;
-        a.width = e * 2;
-        a.height = j - f;
-        m.fillStyle = u.frontGradient.generateGradient(m, a);
-        m.fillStroke(k)
-    }
-});
-Ext.define("Ext.chart.series.Bar3D", {
-    extend: "Ext.chart.series.Bar",
-    requires: ["Ext.chart.series.sprite.Bar3D", "Ext.chart.series.sprite.Box"],
-    alias: "series.bar3d",
-    type: "bar3d",
-    seriesType: "bar3dSeries",
-    config: {
-        itemInstancing: {
-            type: "box",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    depth: 0
-                }
-            }
-        },
-        highlightCfg: {
-            opacity: 0.8
-        }
-    },
-    getSprites: function() {
-        var c = this.callParent(arguments),
-            b, d, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            d = b.attr.zIndex;
-            if (d < 0) {
-                b.setAttributes({
-                    zIndex: -d
-                })
-            }
-            if (b.setSeries) {
-                b.setSeries(this)
-            }
-        }
-        return c
-    },
-    getDepth: function() {
-        var a = this.getSprites()[0];
-        return a ? (a.depth || 0) : 0
-    },
-    getItemForPoint: function(m, k) {
-        if (this.getSprites()) {
-            var j = this,
-                b, o, a = j.getItemInstancing(),
-                h = j.getSprites(),
-                n = j.getStore(),
-                c = j.getHidden(),
-                g = j.getChart(),
-                l = g.getInnerPadding(),
-                f = g.getInherited().rtl,
-                p, d, e;
-            m = m + (f ? l.right : -l.left);
-            k = k + l.bottom;
-            for (b = h.length - 1; b >= 0; b--) {
-                if (!c[b]) {
-                    o = h[b];
-                    d = o.getIndexNearPoint(m, k);
-                    if (d !== -1) {
-                        e = j.getYField();
-                        p = {
-                            series: j,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: n.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: o
-                        };
-                        return p
-                    }
-                }
-            }
-            return null
-        }
-    }
-});
-Ext.define("Ext.draw.LimitedCache", {
-    config: {
-        limit: 40,
-        feeder: function() {
-            return 0
-        },
-        scope: null
-    },
-    cache: null,
-    constructor: function(a) {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0;
-        this.initConfig(a)
-    },
-    get: function(e) {
-        var c = this.cache,
-            b = this.getLimit(),
-            a = this.getFeeder(),
-            d = this.getScope() || this;
-        if (c[e]) {
-            return c[e].value
-        }
-        if (c.list[c.tail]) {
-            delete c[c.list[c.tail].cacheId]
-        }
-        c[e] = c.list[c.tail] = {
-            value: a.apply(d, Array.prototype.slice.call(arguments, 1)),
-            cacheId: e
-        };
-        c.tail++;
-        if (c.tail === b) {
-            c.tail = 0
-        }
-        return c[e].value
-    },
-    clear: function() {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0
-    }
-});
-Ext.define("Ext.draw.SegmentTree", {
-    config: {
-        strategy: "double"
-    },
-    time: function(m, l, n, c, E, d, e) {
-        var f = 0,
-            o, A, s = new Date(n[m.startIdx[0]]),
-            x = new Date(n[m.endIdx[l - 1]]),
-            D = Ext.Date,
-            u = [
-                [D.MILLI, 1, "ms1", null],
-                [D.MILLI, 2, "ms2", "ms1"],
-                [D.MILLI, 5, "ms5", "ms1"],
-                [D.MILLI, 10, "ms10", "ms5"],
-                [D.MILLI, 50, "ms50", "ms10"],
-                [D.MILLI, 100, "ms100", "ms50"],
-                [D.MILLI, 500, "ms500", "ms100"],
-                [D.SECOND, 1, "s1", "ms500"],
-                [D.SECOND, 10, "s10", "s1"],
-                [D.SECOND, 30, "s30", "s10"],
-                [D.MINUTE, 1, "mi1", "s10"],
-                [D.MINUTE, 5, "mi5", "mi1"],
-                [D.MINUTE, 10, "mi10", "mi5"],
-                [D.MINUTE, 30, "mi30", "mi10"],
-                [D.HOUR, 1, "h1", "mi30"],
-                [D.HOUR, 6, "h6", "h1"],
-                [D.HOUR, 12, "h12", "h6"],
-                [D.DAY, 1, "d1", "h12"],
-                [D.DAY, 7, "d7", "d1"],
-                [D.MONTH, 1, "mo1", "d1"],
-                [D.MONTH, 3, "mo3", "mo1"],
-                [D.MONTH, 6, "mo6", "mo3"],
-                [D.YEAR, 1, "y1", "mo3"],
-                [D.YEAR, 5, "y5", "y1"],
-                [D.YEAR, 10, "y10", "y5"],
-                [D.YEAR, 100, "y100", "y10"]
-            ],
-            z, b, k = f,
-            F = l,
-            j = false,
-            r = m.startIdx,
-            h = m.endIdx,
-            w = m.minIdx,
-            C = m.maxIdx,
-            a = m.open,
-            y = m.close,
-            g = m.minX,
-            q = m.minY,
-            p = m.maxX,
-            B = m.maxY,
-            v, t;
-        for (z = 0; l > f + 1 && z < u.length; z++) {
-            s = new Date(n[r[0]]);
-            b = u[z];
-            s = D.align(s, b[0], b[1]);
-            if (D.diff(s, x, b[0]) > n.length * 2 * b[1]) {
-                continue
-            }
-            if (b[3] && m.map["time_" + b[3]]) {
-                o = m.map["time_" + b[3]][0];
-                A = m.map["time_" + b[3]][1]
-            } else {
-                o = k;
-                A = F
-            }
-            f = l;
-            t = s;
-            j = true;
-            r[l] = r[o];
-            h[l] = h[o];
-            w[l] = w[o];
-            C[l] = C[o];
-            a[l] = a[o];
-            y[l] = y[o];
-            g[l] = g[o];
-            q[l] = q[o];
-            p[l] = p[o];
-            B[l] = B[o];
-            t = Ext.Date.add(t, b[0], b[1]);
-            for (v = o + 1; v < A; v++) {
-                if (n[h[v]] < +t) {
-                    h[l] = h[v];
-                    y[l] = y[v];
-                    if (B[v] > B[l]) {
-                        B[l] = B[v];
-                        p[l] = p[v];
-                        C[l] = C[v]
-                    }
-                    if (q[v] < q[l]) {
-                        q[l] = q[v];
-                        g[l] = g[v];
-                        w[l] = w[v]
-                    }
-                } else {
-                    l++;
-                    r[l] = r[v];
-                    h[l] = h[v];
-                    w[l] = w[v];
-                    C[l] = C[v];
-                    a[l] = a[v];
-                    y[l] = y[v];
-                    g[l] = g[v];
-                    q[l] = q[v];
-                    p[l] = p[v];
-                    B[l] = B[v];
-                    t = Ext.Date.add(t, b[0], b[1])
-                }
-            }
-            if (l > f) {
-                m.map["time_" + b[2]] = [f, l]
-            }
-        }
-    },
-    "double": function(h, u, j, a, t, b, c) {
-        var e = 0,
-            k, f = 1,
-            n, d, v, g, s, l, m, r, q, p, o;
-        while (u > e + 1) {
-            k = e;
-            e = u;
-            f += f;
-            for (n = k; n < e; n += 2) {
-                if (n === e - 1) {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n];
-                    g = h.minIdx[n];
-                    s = h.maxIdx[n];
-                    l = h.open[n];
-                    m = h.close[n];
-                    r = h.minX[n];
-                    q = h.minY[n];
-                    p = h.maxX[n];
-                    o = h.maxY[n]
-                } else {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n + 1];
-                    l = h.open[n];
-                    m = h.close[n];
-                    if (h.minY[n] <= h.minY[n + 1]) {
-                        g = h.minIdx[n];
-                        r = h.minX[n];
-                        q = h.minY[n]
-                    } else {
-                        g = h.minIdx[n + 1];
-                        r = h.minX[n + 1];
-                        q = h.minY[n + 1]
-                    }
-                    if (h.maxY[n] >= h.maxY[n + 1]) {
-                        s = h.maxIdx[n];
-                        p = h.maxX[n];
-                        o = h.maxY[n]
-                    } else {
-                        s = h.maxIdx[n + 1];
-                        p = h.maxX[n + 1];
-                        o = h.maxY[n + 1]
-                    }
-                }
-                h.startIdx[u] = d;
-                h.endIdx[u] = v;
-                h.minIdx[u] = g;
-                h.maxIdx[u] = s;
-                h.open[u] = l;
-                h.close[u] = m;
-                h.minX[u] = r;
-                h.minY[u] = q;
-                h.maxX[u] = p;
-                h.maxY[u] = o;
-                u++
-            }
-            h.map["double_" + f] = [e, u]
-        }
-    },
-    none: Ext.emptyFn,
-    aggregateData: function(h, a, r, c, d) {
-        var b = h.length,
-            e = [],
-            s = [],
-            f = [],
-            q = [],
-            j = [],
-            p = [],
-            n = [],
-            o = [],
-            m = [],
-            k = [],
-            g = {
-                startIdx: e,
-                endIdx: s,
-                minIdx: f,
-                maxIdx: q,
-                open: j,
-                minX: p,
-                minY: n,
-                maxX: o,
-                maxY: m,
-                close: k
-            },
-            l;
-        for (l = 0; l < b; l++) {
-            e[l] = l;
-            s[l] = l;
-            f[l] = l;
-            q[l] = l;
-            j[l] = a[l];
-            p[l] = h[l];
-            n[l] = c[l];
-            o[l] = h[l];
-            m[l] = r[l];
-            k[l] = d[l]
-        }
-        g.map = {
-            original: [0, b]
-        };
-        if (b) {
-            this[this.getStrategy()](g, b, h, a, r, c, d)
-        }
-        return g
-    },
-    binarySearchMin: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.startIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.startIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.startIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return g
-    },
-    binarySearchMax: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.endIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.endIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.endIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return a
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    setData: function(d, a, b, c, e) {
-        if (!b) {
-            e = c = b = a
-        }
-        this.dataX = d;
-        this.dataOpen = a;
-        this.dataHigh = b;
-        this.dataLow = c;
-        this.dataClose = e;
-        if (d.length === b.length && d.length === c.length) {
-            this.cache = this.aggregateData(d, a, b, c, e)
-        }
-    },
-    getAggregation: function(d, k, i) {
-        if (!this.cache) {
-            return null
-        }
-        var c = Infinity,
-            g = this.dataX[this.dataX.length - 1] - this.dataX[0],
-            l = this.cache.map,
-            m = l.original,
-            a, e, j, b, f, h;
-        for (a in l) {
-            e = l[a];
-            j = e[1] - e[0] - 1;
-            b = g / j;
-            if (i <= b && b < c) {
-                m = e;
-                c = b
-            }
-        }
-        f = Math.max(this.binarySearchMin(this.cache, m[0], m[1], d), m[0]);
-        h = Math.min(this.binarySearchMax(this.cache, m[0], m[1], k) + 1, m[1]);
-        return {
-            data: this.cache,
-            start: f,
-            end: h
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Aggregative", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    requires: ["Ext.draw.LimitedCache", "Ext.draw.SegmentTree"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataHigh: "data",
-                dataLow: "data",
-                dataClose: "data"
-            },
-            aliases: {
-                dataOpen: "dataY"
-            },
-            defaults: {
-                dataHigh: null,
-                dataLow: null,
-                dataClose: null
-            }
-        }
-    },
-    config: {
-        aggregator: {}
-    },
-    applyAggregator: function(b, a) {
-        return Ext.factory(b, Ext.draw.SegmentTree, a)
-    },
-    constructor: function() {
-        this.callParent(arguments)
-    },
-    processDataY: function() {
-        var d = this,
-            b = d.attr,
-            e = b.dataHigh,
-            a = b.dataLow,
-            f = b.dataClose,
-            c = b.dataY;
-        d.callParent(arguments);
-        if (b.dataX && c && c.length > 0) {
-            if (e) {
-                d.getAggregator().setData(b.dataX, b.dataY, e, a, f)
-            } else {
-                d.getAggregator().setData(b.dataX, b.dataY)
-            }
-        }
-    },
-    getGapWidth: function() {
-        return 1
-    },
-    renderClipped: function(b, c, g, f) {
-        var e = this,
-            d = Math.min(g[0], g[2]),
-            a = Math.max(g[0], g[2]),
-            h = e.getAggregator() && e.getAggregator().getAggregation(d, a, (a - d) / f[2] * e.getGapWidth());
-        if (h) {
-            e.dataStart = h.data.startIdx[h.start];
-            e.dataEnd = h.data.endIdx[h.end - 1];
-            e.renderAggregates(h.data, h.start, h.end, b, c, g, f)
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.CandleStick", {
-    alias: "sprite.candlestickSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                raiseStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                dropStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                barWidth: "number",
-                padding: "number",
-                ohlcType: "enums(candlestick,ohlc)"
-            },
-            defaults: {
-                raiseStyle: {
-                    strokeStyle: "green",
-                    fillStyle: "green"
-                },
-                dropStyle: {
-                    strokeStyle: "red",
-                    fillStyle: "red"
-                },
-                planar: false,
-                barWidth: 15,
-                padding: 3,
-                lineJoin: "miter",
-                miterLimit: 5,
-                ohlcType: "candlestick"
-            },
-            triggers: {
-                raiseStyle: "raiseStyle",
-                dropStyle: "dropStyle"
-            },
-            updaters: {
-                raiseStyle: function() {
-                    this.raiseTemplate && this.raiseTemplate.setAttributes(this.attr.raiseStyle)
-                },
-                dropStyle: function() {
-                    this.dropTemplate && this.dropTemplate.setAttributes(this.attr.dropStyle)
-                }
-            }
-        }
-    },
-    candlestick: function(i, c, a, e, h, f, b) {
-        var d = Math.min(c, h),
-            g = Math.max(c, h);
-        i.moveTo(f, e);
-        i.lineTo(f, g);
-        i.moveTo(f + b, g);
-        i.lineTo(f + b, d);
-        i.lineTo(f - b, d);
-        i.lineTo(f - b, g);
-        i.closePath();
-        i.moveTo(f, a);
-        i.lineTo(f, d)
-    },
-    ohlc: function(b, d, e, a, f, c, g) {
-        b.moveTo(c, e);
-        b.lineTo(c, a);
-        b.moveTo(c, d);
-        b.lineTo(c - g, d);
-        b.moveTo(c, f);
-        b.lineTo(c + g, f)
-    },
-    constructor: function() {
-        this.callParent(arguments);
-        this.raiseTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        });
-        this.dropTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        })
-    },
-    getGapWidth: function() {
-        var a = this.attr,
-            b = a.barWidth,
-            c = a.padding;
-        return b + c
-    },
-    renderAggregates: function(d, c, b, t, u, z) {
-        var D = this,
-            s = this.attr,
-            j = s.dataX,
-            v = s.matrix,
-            e = v.getXX(),
-            r = v.getYY(),
-            l = v.getDX(),
-            h = v.getDY(),
-            o = s.barWidth / e,
-            C, k = s.ohlcType,
-            f = Math.round(o * 0.5 * e),
-            a = d.open,
-            y = d.close,
-            B = d.maxY,
-            p = d.minY,
-            q = d.startIdx,
-            m, g, E, n, A, x, w = s.lineWidth * t.devicePixelRatio / 2;
-        w -= Math.floor(w);
-        u.save();
-        C = this.raiseTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] <= y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore();
-        u.save();
-        C = this.dropTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] > y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore()
-    }
-});
-Ext.define("Ext.chart.series.CandleStick", {
-    extend: "Ext.chart.series.Cartesian",
-    requires: ["Ext.chart.series.sprite.CandleStick"],
-    alias: "series.candlestick",
-    type: "candlestick",
-    seriesType: "candlestickSeries",
-    config: {
-        openField: null,
-        highField: null,
-        lowField: null,
-        closeField: null
-    },
-    fieldCategoryY: ["Open", "High", "Low", "Close"],
-    themeColorCount: function() {
-        return 2
-    }
-});
-Ext.define("Ext.chart.series.Polar", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        rotation: 0,
-        radius: null,
-        center: [0, 0],
-        offsetX: 0,
-        offsetY: 0,
-        showInLegend: true,
-        xField: null,
-        yField: null,
-        angleField: null,
-        radiusField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    deprecatedConfigs: {
-        field: "angleField",
-        lengthField: "radiusField"
-    },
-    constructor: function(b) {
-        var c = this,
-            a = c.getConfigurator(),
-            e = a.configs,
-            d;
-        if (b) {
-            for (d in c.deprecatedConfigs) {
-                if (d in b && !(b in e)) {
-                    Ext.raise("'" + d + "' config has been deprecated. Please use the '" + c.deprecatedConfigs[d] + "' config instead.")
-                }
-            }
-        }
-        c.callParent([b])
-    },
-    getXField: function() {
-        return this.getAngleField()
-    },
-    updateXField: function(a) {
-        this.setAngleField(a)
-    },
-    getYField: function() {
-        return this.getRadiusField()
-    },
-    updateYField: function(a) {
-        this.setRadiusField(a)
-    },
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b
-    },
-    isStoreDependantColorCount: true,
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            centerX: 0,
-            centerY: 0,
-            rotationCenterX: 0,
-            rotationCenterY: 0
-        }
-    },
-    applyRotation: function(a) {
-        return Ext.draw.sprite.AttributeParser.angle(a)
-    },
-    updateRotation: function(a) {
-        var b = this.getSprites();
-        if (b && b[0]) {
-            b[0].setAttributes({
-                baseRotation: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.Gauge", {
-    alias: "series.gauge",
-    extend: "Ext.chart.series.Polar",
-    type: "gauge",
-    seriesType: "pieslice",
-    requires: ["Ext.draw.sprite.Sector"],
-    config: {
-        needle: false,
-        needleLength: 90,
-        needleWidth: 4,
-        donut: 30,
-        showInLegend: false,
-        value: null,
-        colors: null,
-        sectors: null,
-        minimum: 0,
-        maximum: 100,
-        rotation: 0,
-        totalAngle: Math.PI / 2,
-        rect: [0, 0, 1, 1],
-        center: [0.5, 0.75],
-        radius: 0.5,
-        wholeDisk: false
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateNeedle: function(b) {
-        var a = this,
-            d = a.getSprites(),
-            c = a.valueToAngle(a.getValue());
-        if (d && d.length) {
-            d[0].setAttributes({
-                startAngle: (b ? c : 0),
-                endAngle: c,
-                strokeOpacity: (b ? 1 : 0),
-                lineWidth: (b ? a.getNeedleWidth() : 0)
-            });
-            a.doUpdateStyles()
-        }
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b + (c.getNeedle() ? 0 : 1)
-    },
-    updateColors: function(a, b) {
-        var f = this,
-            h = f.getSectors(),
-            j = h && h.length,
-            e = f.getSprites(),
-            c = Ext.Array.clone(a),
-            g = a && a.length,
-            d;
-        if (!g || !a[0]) {
-            return
-        }
-        for (d = 0; d < j; d++) {
-            c[d + 1] = h[d].color || c[d + 1] || a[d % g]
-        }
-        if (e.length) {
-            e[0].setAttributes({
-                strokeStyle: c[0]
-            })
-        }
-        this.setSubStyle({
-            fillStyle: c,
-            strokeStyle: c
-        });
-        this.doUpdateStyles()
-    },
-    updateRect: function(f) {
-        var d = this.getWholeDisk(),
-            c = d ? Math.PI : this.getTotalAngle() / 2,
-            g = this.getDonut() / 100,
-            e, b, a;
-        if (c <= Math.PI / 2) {
-            e = 2 * Math.sin(c);
-            b = 1 - g * Math.cos(c)
-        } else {
-            e = 2;
-            b = 1 - Math.cos(c)
-        }
-        a = Math.min(f[2] / e, f[3] / b);
-        this.setRadius(a);
-        this.setCenter([f[2] / 2, a + (f[3] - b * a) / 2])
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            centerX: a[0],
-            centerY: a[1],
-            rotationCenterX: a[0],
-            rotationCenterY: a[1]
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a - (this.getTotalAngle() + Math.PI) / 2
-        });
-        this.doUpdateStyles()
-    },
-    doUpdateShape: function(b, f) {
-        var a, d = this.getSectors(),
-            c = (d && d.length) || 0,
-            e = this.getNeedleLength() / 100;
-        a = [b * e, b];
-        while (c--) {
-            a.push(b)
-        }
-        this.setSubStyle({
-            endRho: a,
-            startRho: b / 100 * f
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        var b = this.getDonut();
-        this.doUpdateShape(a, b)
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.doUpdateShape(a, b)
-    },
-    valueToAngle: function(a) {
-        a = this.applyValue(a);
-        return this.getTotalAngle() * (a - this.getMinimum()) / (this.getMaximum() - this.getMinimum())
-    },
-    applyValue: function(a) {
-        return Math.min(this.getMaximum(), Math.max(a, this.getMinimum()))
-    },
-    updateValue: function(b) {
-        var a = this,
-            c = a.getNeedle(),
-            e = a.valueToAngle(b),
-            d = a.getSprites();
-        d[0].rendererData.value = b;
-        d[0].setAttributes({
-            startAngle: (c ? e : 0),
-            endAngle: e
-        });
-        a.doUpdateStyles()
-    },
-    processData: function() {
-        var f = this,
-            j = f.getStore(),
-            a, d, h, b, g, e = j && j.first(),
-            c, i;
-        if (e) {
-            c = f.getXField();
-            if (c) {
-                i = e.get(c)
-            }
-        }
-        if (a = f.getXAxis()) {
-            d = a.getMinimum();
-            h = a.getMaximum();
-            b = a.getSprites()[0].fx;
-            g = b.getDuration();
-            b.setDuration(0);
-            if (Ext.isNumber(d)) {
-                f.setMinimum(d)
-            } else {
-                a.setMinimum(f.getMinimum())
-            }
-            if (Ext.isNumber(h)) {
-                f.setMaximum(h)
-            } else {
-                a.setMaximum(f.getMaximum())
-            }
-            b.setDuration(g)
-        }
-        if (!Ext.isNumber(i)) {
-            i = f.getMinimum()
-        }
-        f.setValue(i)
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationCenterX: 0,
-                    rotationCenterY: 0,
-                    centerX: 0,
-                    centerY: 0,
-                    startRho: 0,
-                    endRho: 0,
-                    baseRotation: 0
-                }
-            }
-        }
-    },
-    normalizeSectors: function(f) {
-        var d = this,
-            c = (f && f.length) || 0,
-            b, e, g, a;
-        if (c) {
-            for (b = 0; b < c; b++) {
-                e = f[b];
-                if (typeof e === "number") {
-                    f[b] = {
-                        start: (b > 0 ? f[b - 1].end : d.getMinimum()),
-                        end: Math.min(e, d.getMaximum())
-                    };
-                    if (b == (c - 1) && f[b].end < d.getMaximum()) {
-                        f[b + 1] = {
-                            start: f[b].end,
-                            end: d.getMaximum()
-                        }
-                    }
-                } else {
-                    if (typeof e.start === "number") {
-                        g = Math.max(e.start, d.getMinimum())
-                    } else {
-                        g = (b > 0 ? f[b - 1].end : d.getMinimum())
-                    }
-                    if (typeof e.end === "number") {
-                        a = Math.min(e.end, d.getMaximum())
-                    } else {
-                        a = d.getMaximum()
-                    }
-                    f[b].start = g;
-                    f[b].end = a
-                }
-            }
-        } else {
-            f = [{
-                start: d.getMinimum(),
-                end: d.getMaximum()
-            }]
-        }
-        return f
-    },
-    getSprites: function() {
-        var j = this,
-            m = j.getStore(),
-            l = j.getValue(),
-            c, g;
-        if (!m && !Ext.isNumber(l)) {
-            return []
-        }
-        var h = j.getChart(),
-            b = j.getAnimation() || h && h.getAnimation(),
-            f = j.sprites,
-            k = 0,
-            o, n, e, d, a = [];
-        if (f && f.length) {
-            f[0].setAnimation(b);
-            return f
-        }
-        d = {
-            store: m,
-            field: j.getXField(),
-            angleField: j.getXField(),
-            value: l,
-            series: j
-        };
-        o = j.createSprite();
-        o.setAttributes({
-            zIndex: 10
-        }, true);
-        o.rendererData = d;
-        o.rendererIndex = k++;
-        a.push(j.getNeedleWidth());
-        j.getLabel().getTemplate().setField(true);
-        n = j.normalizeSectors(j.getSectors());
-        for (c = 0, g = n.length; c < g; c++) {
-            e = {
-                startAngle: j.valueToAngle(n[c].start),
-                endAngle: j.valueToAngle(n[c].end),
-                label: n[c].label,
-                fillStyle: n[c].color,
-                strokeOpacity: 0,
-                doCallout: false,
-                labelOverflowPadding: -1
-            };
-            Ext.apply(e, n[c].style);
-            o = j.createSprite();
-            o.rendererData = d;
-            o.rendererIndex = k++;
-            o.setAttributes(e, true);
-            a.push(e.lineWidth)
-        }
-        j.setSubStyle({
-            lineWidth: a
-        });
-        j.doUpdateStyles();
-        return f
-    }
-});
-Ext.define("Ext.chart.series.sprite.Line", {
-    alias: "sprite.lineSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                smooth: "bool",
-                fillArea: "bool",
-                step: "bool",
-                preciseStroke: "bool",
-                xAxis: "default",
-                yCap: "default"
-            },
-            defaults: {
-                smooth: false,
-                fillArea: false,
-                step: false,
-                preciseStroke: true,
-                xAxis: null,
-                yCap: Math.pow(2, 20),
-                yJump: 50
-            },
-            triggers: {
-                dataX: "dataX,bbox,smooth",
-                dataY: "dataY,bbox,smooth",
-                smooth: "smooth"
-            },
-            updaters: {
-                smooth: function(a) {
-                    var c = a.dataX,
-                        b = a.dataY;
-                    if (a.smooth && c && b && c.length > 2 && b.length > 2) {
-                        this.smoothX = Ext.draw.Draw.spline(c);
-                        this.smoothY = Ext.draw.Draw.spline(b)
-                    } else {
-                        delete this.smoothX;
-                        delete this.smoothY
-                    }
-                }
-            }
-        }
-    },
-    list: null,
-    updatePlainBBox: function(d) {
-        var b = this.attr,
-            c = Math.min(0, b.dataMinY),
-            a = Math.max(0, b.dataMaxY);
-        d.x = b.dataMinX;
-        d.y = c;
-        d.width = b.dataMaxX - b.dataMinX;
-        d.height = a - c
-    },
-    drawStrip: function(a, c) {
-        a.moveTo(c[0], c[1]);
-        for (var b = 2, d = c.length; b < d; b += 2) {
-            a.lineTo(c[b], c[b + 1])
-        }
-    },
-    drawStraightStroke: function(p, q, e, d, u, h) {
-        var w = this,
-            o = w.attr,
-            n = o.renderer,
-            g = o.step,
-            a = true,
-            l = {
-                type: "line",
-                smooth: false,
-                step: g
-            },
-            m = [],
-            l, z, v, f, k, j, t, c, s, b, r;
-        for (r = 3; r < u.length; r += 3) {
-            t = u[r - 3];
-            c = u[r - 2];
-            k = u[r];
-            j = u[r + 1];
-            s = u[r + 3];
-            b = u[r + 4];
-            if (n) {
-                l.x = k;
-                l.y = j;
-                l.x0 = t;
-                l.y0 = c;
-                v = [w, l, w.rendererData, e + r / 3];
-                z = Ext.callback(n, null, v, 0, w.getSeries())
-            }
-            if (Ext.isNumber(k + j + t + c)) {
-                if (a) {
-                    q.beginPath();
-                    q.moveTo(t, c);
-                    m.push(t, c);
-                    f = t;
-                    a = false
-                }
-            } else {
-                continue
-            }
-            if (g) {
-                q.lineTo(k, c);
-                m.push(k, c)
-            }
-            q.lineTo(k, j);
-            m.push(k, j);
-            if (z || !(Ext.isNumber(s + b))) {
-                q.save();
-                Ext.apply(q, z);
-                if (o.fillArea) {
-                    q.lineTo(k, h);
-                    q.lineTo(f, h);
-                    q.closePath();
-                    q.fill()
-                }
-                q.beginPath();
-                w.drawStrip(q, m);
-                m = [];
-                q.stroke();
-                q.restore();
-                q.beginPath();
-                a = true
-            }
-        }
-    },
-    calculateScale: function(c, a) {
-        var b = 0,
-            d = c;
-        while (d < a && c > 0) {
-            b++;
-            d += c >> b
-        }
-        return Math.pow(2, b > 0 ? b - 1 : b)
-    },
-    drawSmoothStroke: function(u, v, c, b, C, f) {
-        var G = this,
-            t = G.attr,
-            d = t.step,
-            z = t.matrix,
-            s = t.renderer,
-            e = z.getXX(),
-            p = z.getYY(),
-            m = z.getDX(),
-            k = z.getDY(),
-            r = G.smoothX,
-            q = G.smoothY,
-            I = G.calculateScale(t.dataX.length, b),
-            o, F, n, E, h, g, B, a, A, w, H, D, l = {
-                type: "line",
-                smooth: true,
-                step: d
-            };
-        v.beginPath();
-        v.moveTo(r[c * 3] * e + m, q[c * 3] * p + k);
-        for (A = 0, w = c * 3 + 1; A < C.length - 3; A += 3, w += 3 * I) {
-            o = r[w] * e + m;
-            F = q[w] * p + k;
-            n = r[w + 1] * e + m;
-            E = q[w + 1] * p + k;
-            h = u.roundPixel(C[A + 3]);
-            g = C[A + 4];
-            B = u.roundPixel(C[A]);
-            a = C[A + 1];
-            if (s) {
-                l.x0 = B;
-                l.y0 = a;
-                l.cx1 = o;
-                l.cy1 = F;
-                l.cx2 = n;
-                l.cy2 = E;
-                l.x = h;
-                l.y = g;
-                D = [G, l, G.rendererData, c + A / 3 + 1];
-                H = Ext.callback(s, null, D, 0, G.getSeries());
-                v.save();
-                Ext.apply(v, H)
-            }
-            if (t.fillArea) {
-                v.moveTo(B, a);
-                v.bezierCurveTo(o, F, n, E, h, g);
-                v.lineTo(h, f);
-                v.lineTo(B, f);
-                v.lineTo(B, a);
-                v.closePath();
-                v.fill();
-                v.beginPath()
-            }
-            v.moveTo(B, a);
-            v.bezierCurveTo(o, F, n, E, h, g);
-            v.stroke();
-            v.moveTo(B, a);
-            v.closePath();
-            if (s) {
-                v.restore()
-            }
-            v.beginPath();
-            v.moveTo(h, g)
-        }
-        v.beginPath()
-    },
-    drawLabel: function(k, i, h, o, a) {
-        var q = this,
-            n = q.attr,
-            e = q.getMarker("labels"),
-            d = e.getTemplate(),
-            m = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            g, f, j = n.labelOverflowPadding,
-            l, b, r, p, s;
-        m.x = c.x(i, h);
-        m.y = c.y(i, h);
-        if (n.flipXY) {
-            m.rotationRads = Math.PI * 0.5
-        } else {
-            m.rotationRads = 0
-        }
-        m.text = k;
-        if (d.attr.renderer) {
-            p = [k, e, m, q.rendererData, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                m.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        m.text = r.text
-                    }
-                    s = true
-                }
-            }
-        }
-        b = q.getMarkerBBox("labels", o, true);
-        if (!b) {
-            q.putMarker("labels", m, o);
-            b = q.getMarkerBBox("labels", o, true)
-        }
-        l = b.height / 2;
-        g = i;
-        switch (d.attr.display) {
-            case "under":
-                f = h - l - j;
-                break;
-            case "rotate":
-                g += j;
-                f = h - j;
-                m.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                f = h + l + j
-        }
-        m.x = c.x(g, f);
-        m.y = c.y(g, f);
-        if (s) {
-            Ext.apply(m, r)
-        }
-        q.putMarker("labels", m, o)
-    },
-    drawMarker: function(j, h, d) {
-        var g = this,
-            e = g.attr,
-            f = e.renderer,
-            c = g.surfaceMatrix,
-            b = {},
-            i, a;
-        if (f && g.getMarker("markers")) {
-            b.type = "marker";
-            b.x = j;
-            b.y = h;
-            a = [g, b, g.rendererData, d];
-            i = Ext.callback(f, null, a, 0, g.getSeries());
-            if (i) {
-                Ext.apply(b, i)
-            }
-        }
-        b.translationX = c.x(j, h);
-        b.translationY = c.y(j, h);
-        delete b.x;
-        delete b.y;
-        g.putMarker("markers", b, d, !f)
-    },
-    drawStroke: function(a, c, h, b, f, e) {
-        var d = this,
-            g = d.attr.smooth && d.smoothX && d.smoothY;
-        if (g) {
-            d.drawSmoothStroke(a, c, h, b, f, e)
-        } else {
-            d.drawStraightStroke(a, c, h, b, f, e)
-        }
-    },
-    renderAggregates: function(B, w, l, N, o, I, D) {
-        var m = this,
-            k = m.attr,
-            s = k.dataX,
-            r = k.dataY,
-            h = k.labels,
-            v = k.xAxis,
-            a = k.yCap,
-            g = k.smooth && m.smoothX && m.smoothY,
-            d = h && m.getMarker("labels"),
-            t = m.getMarker("markers"),
-            E = k.matrix,
-            u = N.devicePixelRatio,
-            C = E.getXX(),
-            f = E.getYY(),
-            c = E.getDX(),
-            b = E.getDY(),
-            q = m.list || (m.list = []),
-            F = B.minX,
-            e = B.maxX,
-            j = B.minY,
-            P = B.maxY,
-            U = B.startIdx,
-            S = true,
-            Q, T, L, K, R, G;
-        m.rendererData = {
-            store: m.getStore()
-        };
-        q.length = 0;
-        for (R = w; R < l; R++) {
-            var O = F[R],
-                p = e[R],
-                M = j[R],
-                n = P[R];
-            if (O < p) {
-                q.push(O * C + c, M * f + b, U[R]);
-                q.push(p * C + c, n * f + b, U[R])
-            } else {
-                if (O > p) {
-                    q.push(p * C + c, n * f + b, U[R]);
-                    q.push(O * C + c, M * f + b, U[R])
-                } else {
-                    q.push(p * C + c, n * f + b, U[R])
-                }
-            }
-        }
-        if (q.length) {
-            for (R = 0; R < q.length; R += 3) {
-                L = q[R];
-                K = q[R + 1];
-                if (Ext.isNumber(L + K)) {
-                    if (K > a) {
-                        K = a
-                    } else {
-                        if (K < -a) {
-                            K = -a
-                        }
-                    }
-                    q[R + 1] = K
-                } else {
-                    S = false;
-                    continue
-                }
-                G = q[R + 2];
-                if (t) {
-                    m.drawMarker(L, K, G)
-                }
-                if (d && h[G]) {
-                    m.drawLabel(h[G], L, K, G, D)
-                }
-            }
-            m.isContinuousLine = S;
-            if (g && !S) {
-                Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")
-            }
-            if (v) {
-                T = v.getAlignment() === "vertical";
-                if (Ext.isNumber(v.floatingAtCoord)) {
-                    Q = (T ? D[2] : D[3]) - v.floatingAtCoord
-                } else {
-                    Q = T ? D[0] : D[1]
-                }
-            } else {
-                Q = k.flipXY ? D[0] : D[1]
-            }
-            if (k.preciseStroke) {
-                if (k.fillArea) {
-                    o.fill()
-                }
-                if (k.transformFillStroke) {
-                    k.inverseMatrix.toContext(o)
-                }
-                m.drawStroke(N, o, w, l, q, Q);
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                o.stroke()
-            } else {
-                m.drawStroke(N, o, w, l, q, Q);
-                if (S && g && k.fillArea && !k.renderer) {
-                    var A = s[s.length - 1] * C + c + u,
-                        z = r[r.length - 1] * f + b,
-                        J = s[0] * C + c - u,
-                        H = r[0] * f + b;
-                    o.lineTo(A, z);
-                    o.lineTo(A, Q - k.lineWidth);
-                    o.lineTo(J, Q - k.lineWidth);
-                    o.lineTo(J, H)
-                }
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                if (k.fillArea) {
-                    o.fillStroke(k, true)
-                } else {
-                    o.stroke(true)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.Line", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.line",
-    type: "line",
-    seriesType: "lineSeries",
-    requires: ["Ext.chart.series.sprite.Line"],
-    config: {
-        selectionTolerance: 20,
-        smooth: false,
-        step: false,
-        fill: undefined,
-        aggregator: {
-            strategy: "double"
-        }
-    },
-    defaultSmoothness: 3,
-    overflowBuffer: 1,
-    themeMarkerCount: function() {
-        return 1
-    },
-    getDefaultSpriteConfig: function() {
-        var d = this,
-            e = d.callParent(arguments),
-            c = Ext.apply({}, d.getStyle()),
-            b, a = false;
-        if (typeof d.config.fill != "undefined") {
-            if (d.config.fill) {
-                a = true;
-                if (typeof c.fillStyle == "undefined") {
-                    if (typeof c.strokeStyle == "undefined") {
-                        b = d.getStyleWithTheme();
-                        c.fillStyle = b.fillStyle;
-                        c.strokeStyle = b.strokeStyle
-                    } else {
-                        c.fillStyle = c.strokeStyle
-                    }
-                }
-            }
-        } else {
-            if (c.fillStyle) {
-                a = true
-            }
-        }
-        if (!a) {
-            delete c.fillStyle
-        }
-        c = Ext.apply(e || {}, c);
-        return Ext.apply(c, {
-            fillArea: a,
-            step: d.config.step,
-            smooth: d.config.smooth,
-            selectionTolerance: d.config.selectionTolerance
-        })
-    },
-    updateStep: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.step !== b) {
-            a.setAttributes({
-                step: b
-            })
-        }
-    },
-    updateFill: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.fillArea !== b) {
-            a.setAttributes({
-                fillArea: b
-            })
-        }
-    },
-    updateSmooth: function(a) {
-        var b = this.getSprites()[0];
-        if (b && b.attr.smooth !== a) {
-            b.setAttributes({
-                smooth: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.PieSlice", {
-    extend: "Ext.draw.sprite.Sector",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pieslice",
-    inheritableStatics: {
-        def: {
-            processors: {
-                doCallout: "bool",
-                label: "string",
-                rotateLabels: "bool",
-                labelOverflowPadding: "number",
-                renderer: "default"
-            },
-            defaults: {
-                doCallout: true,
-                rotateLabels: true,
-                label: "",
-                labelOverflowPadding: 10,
-                renderer: null
-            }
-        }
-    },
-    config: {
-        rendererData: null,
-        rendererIndex: 0,
-        series: null
-    },
-    setGradientBBox: function(q, k) {
-        var j = this,
-            i = j.attr,
-            g = (i.fillStyle && i.fillStyle.isGradient) || (i.strokeStyle && i.strokeStyle.isGradient);
-        if (g && !i.constrainGradients) {
-            var b = j.getMidAngle(),
-                d = i.margin,
-                e = i.centerX,
-                c = i.centerY,
-                a = i.endRho,
-                l = i.matrix,
-                o = l.getScaleX(),
-                n = l.getScaleY(),
-                m = o * a,
-                f = n * a,
-                p = {
-                    width: m + m,
-                    height: f + f
-                };
-            if (d) {
-                e += d * Math.cos(b);
-                c += d * Math.sin(b)
-            }
-            p.x = l.x(e, c) - m;
-            p.y = l.y(e, c) - f;
-            q.setGradientBBox(p)
-        } else {
-            j.callParent([q, k])
-        }
-    },
-    render: function(b, c, g, f) {
-        var e = this,
-            a = e.attr,
-            h = {},
-            d;
-        if (a.renderer) {
-            h = {
-                type: "sector",
-                text: a.text,
-                centerX: a.centerX,
-                centerY: a.centerY,
-                margin: a.margin,
-                startAngle: Math.min(a.startAngle, a.endAngle),
-                endAngle: Math.max(a.startAngle, a.endAngle),
-                startRho: Math.min(a.startRho, a.endRho),
-                endRho: Math.max(a.startRho, a.endRho)
-            };
-            d = Ext.callback(a.renderer, null, [e, h, e.rendererData, e.rendererIndex], 0, e.getSeries());
-            e.setAttributes(d);
-            e.useAttributes(c, g)
-        }
-        e.callParent([b, c, g, f]);
-        if (a.label && e.getMarker("labels")) {
-            e.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            s = z.attr,
-            r = s.attributeId,
-            t = Math.min(s.startAngle, s.endAngle),
-            p = Math.max(s.startAngle, s.endAngle),
-            k = (t + p) * 0.5,
-            n = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            f = Math.sin(k),
-            c = Math.cos(k),
-            v = Math.min(s.startRho, s.endRho) + n,
-            m = Math.max(s.startRho, s.endRho) + n,
-            l = (v + m) * 0.5,
-            b = z.surfaceMatrix,
-            o = z.labelCfg || (z.labelCfg = {}),
-            e = z.getMarker("labels"),
-            d = e.getTemplate(),
-            a = d.getCalloutLine(),
-            q = a && a.length || 40,
-            u, j, i, A, w;
-        b.appendMatrix(s.matrix);
-        o.text = s.label;
-        j = h + c * l;
-        i = g + f * l;
-        o.x = b.x(j, i);
-        o.y = b.y(j, i);
-        j = h + c * m;
-        i = g + f * m;
-        o.calloutStartX = b.x(j, i);
-        o.calloutStartY = b.y(j, i);
-        j = h + c * (m + q);
-        i = g + f * (m + q);
-        o.calloutPlaceX = b.x(j, i);
-        o.calloutPlaceY = b.y(j, i);
-        if (!s.rotateLabels) {
-            o.rotationRads = 0
-        } else {
-            switch (d.attr.orientation) {
-                case "horizontal":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0)) + Math.PI / 2;
-                    break;
-                case "vertical":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0));
-                    break
-            }
-        }
-        o.calloutColor = (a && a.color) || z.attr.fillStyle;
-        if (a) {
-            if (a.width) {
-                o.calloutWidth = a.width
-            }
-        } else {
-            o.calloutHasLine = false
-        }
-        o.globalAlpha = s.globalAlpha * s.fillOpacity;
-        o.hidden = (s.startAngle == s.endAngle);
-        if (d.attr.renderer) {
-            w = [z.attr.label, e, o, z.rendererData, z.rendererIndex];
-            A = Ext.callback(d.attr.renderer, null, w, 0, z.getSeries());
-            if (typeof A === "string") {
-                o.text = A
-            } else {
-                Ext.apply(o, A)
-            }
-        }
-        z.putMarker("labels", o, r);
-        u = z.getMarkerBBox("labels", r, true);
-        if (u) {
-            if (s.doCallout) {
-                if (d.attr.display === "outside") {
-                    z.putMarker("labels", {
-                        callout: 1
-                    }, r)
-                } else {
-                    if (d.attr.display === "inside") {
-                        z.putMarker("labels", {
-                            callout: 0
-                        }, r)
-                    } else {
-                        z.putMarker("labels", {
-                            callout: 1 - z.sliceContainsLabel(s, u)
-                        }, r)
-                    }
-                }
-            } else {
-                z.putMarker("labels", {
-                    globalAlpha: z.sliceContainsLabel(s, u)
-                }, r)
-            }
-        }
-    },
-    sliceContainsLabel: function(d, f) {
-        var e = d.labelOverflowPadding,
-            h = (d.endRho + d.startRho) / 2,
-            g = h + (f.width + e) / 2,
-            i = h - (f.width + e) / 2,
-            j, c, b, a;
-        if (e < 0) {
-            return 1
-        }
-        if (f.width + e * 2 > (d.endRho - d.startRho)) {
-            return 0
-        }
-        c = Math.sqrt(d.endRho * d.endRho - g * g);
-        b = Math.sqrt(d.endRho * d.endRho - i * i);
-        j = Math.abs(d.endAngle - d.startAngle);
-        a = (j > Math.PI / 2 ? i : Math.abs(Math.tan(j / 2)) * i);
-        if (f.height + e * 2 > Math.min(c, b, a) * 2) {
-            return 0
-        }
-        return 1
-    }
-});
-Ext.define("Ext.chart.series.Pie", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.PieSlice"],
-    type: "pie",
-    alias: "series.pie",
-    seriesType: "pieslice",
-    config: {
-        donut: 0,
-        rotation: 0,
-        clockwise: true,
-        totalAngle: 2 * Math.PI,
-        hidden: [],
-        radiusFactor: 100,
-        highlightCfg: {
-            margin: 20
-        },
-        style: {}
-    },
-    directions: ["X"],
-    applyLabel: function(a, b) {
-        if (Ext.isObject(a) && !Ext.isString(a.orientation)) {
-            Ext.apply(a = Ext.Object.chain(a), {
-                orientation: "vertical"
-            })
-        }
-        return this.callParent([a, b])
-    },
-    updateLabelData: function() {
-        var h = this,
-            j = h.getStore(),
-            g = j.getData().items,
-            e = h.getSprites(),
-            a = h.getLabel().getTemplate().getField(),
-            d = h.getHidden(),
-            b, f, c, k;
-        if (e.length && a) {
-            c = [];
-            for (b = 0, f = g.length; b < f; b++) {
-                c.push(g[b].get(a))
-            }
-            for (b = 0, f = e.length; b < f; b++) {
-                k = e[b];
-                k.setAttributes({
-                    label: c[b]
-                });
-                k.putMarker("labels", {
-                    hidden: d[b]
-                }, k.attr.attributeId)
-            }
-        }
-    },
-    coordinateX: function() {
-        var t = this,
-            f = t.getStore(),
-            q = f.getData().items,
-            c = q.length,
-            b = t.getXField(),
-            e = t.getYField(),
-            l, a = 0,
-            m, k, s = 0,
-            o = t.getHidden(),
-            d = [],
-            p, g = 0,
-            h = t.getTotalAngle(),
-            r = t.getClockwise() ? 1 : -1,
-            j = t.getSprites(),
-            n;
-        if (!j) {
-            return
-        }
-        for (p = 0; p < c; p++) {
-            l = Math.abs(Number(q[p].get(b))) || 0;
-            k = e && Math.abs(Number(q[p].get(e))) || 0;
-            if (!o[p]) {
-                a += l;
-                if (k > s) {
-                    s = k
-                }
-            }
-            d[p] = a;
-            if (p >= o.length) {
-                o[p] = false
-            }
-        }
-        o.length = c;
-        t.maxY = s;
-        if (a !== 0) {
-            m = h / a
-        }
-        for (p = 0; p < c; p++) {
-            j[p].setAttributes({
-                startAngle: g,
-                endAngle: g = (m ? r * d[p] * m : 0),
-                globalAlpha: 1
-            })
-        }
-        if (c < t.sprites.length) {
-            for (p = c; p < t.sprites.length; p++) {
-                n = t.sprites[p];
-                n.getMarker("labels").clear(n.getId());
-                n.releaseMarker("labels");
-                n.destroy()
-            }
-            t.sprites.length = c
-        }
-        for (p = c; p < t.sprites.length; p++) {
-            j[p].setAttributes({
-                startAngle: h,
-                endAngle: h,
-                globalAlpha: 0
-            })
-        }
-        t.getChart().refreshLegendStore()
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            startRho: a * this.getDonut() * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    getStyleByIndex: function(c) {
-        var g = this,
-            j = g.getStore(),
-            k = j.getAt(c),
-            f = g.getYField(),
-            d = g.getRadius(),
-            a = {},
-            e, b, h;
-        if (k) {
-            h = f && Math.abs(Number(k.get(f))) || 0;
-            e = d * g.getDonut() * 0.01;
-            b = d * g.getRadiusFactor() * 0.01;
-            a = g.callParent([c]);
-            a.startRho = e;
-            a.endRho = g.maxY ? (e + (b - e) * h / g.maxY) : b
-        }
-        return a
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.setStyle({
-            startRho: a * b * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    rotationOffset: -Math.PI / 2,
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getSprites: function() {
-        var k = this,
-            h = k.getChart(),
-            n = k.getStore();
-        if (!h || !n) {
-            return []
-        }
-        k.getColors();
-        k.getSubStyle();
-        var j = n.getData().items,
-            b = j.length,
-            d = k.getAnimation() || h && h.getAnimation(),
-            g = k.sprites,
-            o, l = 0,
-            f, e, c = false,
-            m = k.getLabel(),
-            a = m.getTemplate();
-        f = {
-            store: n,
-            field: k.getXField(),
-            angleField: k.getXField(),
-            radiusField: k.getYField(),
-            series: k
-        };
-        for (e = 0; e < b; e++) {
-            o = g[e];
-            if (!o) {
-                o = k.createSprite();
-                if (k.getHighlight()) {
-                    o.config.highlight = k.getHighlight();
-                    o.addModifier("highlight", true)
-                }
-                if (a.getField()) {
-                    a.setAttributes({
-                        labelOverflowPadding: k.getLabelOverflowPadding()
-                    });
-                    a.fx.setCustomDurations({
-                        callout: 200
-                    })
-                }
-                o.setAttributes(k.getStyleByIndex(e));
-                o.rendererData = f;
-                o.rendererIndex = l++;
-                c = true
-            }
-            o.setAnimation(d)
-        }
-        if (c) {
-            k.doUpdateStyles()
-        }
-        return k.sprites
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        if (!this.getClockwise()) {
-            d *= -1;
-            f *= -1;
-            c *= -1;
-            f -= g;
-            c -= g
-        } else {
-            f += g;
-            c += g
-        }
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForAngle: function(a) {
-        var h = this,
-            f = h.getSprites(),
-            d;
-        a %= Math.PI * 2;
-        while (a < 0) {
-            a += Math.PI * 2
-        }
-        if (f) {
-            var j = h.getStore(),
-                g = j.getData().items,
-                c = h.getHidden(),
-                b = 0,
-                e = j.getCount();
-            for (; b < e; b++) {
-                if (!c[b]) {
-                    d = f[b].attr;
-                    if (d.startAngle <= a && d.endAngle >= a) {
-                        return {
-                            series: h,
-                            sprite: f[b],
-                            index: b,
-                            record: g[b],
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-        }
-        return null
-    },
-    getItemForPoint: function(f, e) {
-        var t = this,
-            c = t.getSprites();
-        if (c) {
-            var s = t.getCenter(),
-                q = t.getOffsetX(),
-                p = t.getOffsetY(),
-                j = f - s[0] + q,
-                h = e - s[1] + p,
-                b = t.getStore(),
-                g = t.getDonut(),
-                o = b.getData().items,
-                r = Math.atan2(h, j) - t.getRotation(),
-                a = Math.sqrt(j * j + h * h),
-                l = t.getRadius() * g * 0.01,
-                m = t.getHidden(),
-                n, d, k;
-            for (n = 0, d = o.length; n < d; n++) {
-                if (!m[n]) {
-                    k = c[n].attr;
-                    if (a >= l + k.margin && a <= k.endRho + k.margin) {
-                        if (t.betweenAngle(r, k.startAngle, k.endAngle)) {
-                            return {
-                                series: t,
-                                sprite: c[n],
-                                index: n,
-                                record: o[n],
-                                field: t.getXField()
-                            }
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            j = h.getStore();
-        if (j) {
-            var g = j.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                c = h.getXField(),
-                e = h.getHidden(),
-                d, a, k;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                k = a.fillStyle;
-                if (Ext.isObject(k)) {
-                    k = k.stops && k.stops[0].color
-                }
-                f.push({
-                    name: b ? String(g[d].get(b)) : c + " " + d,
-                    mark: k || a.strokeStyle || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Pie3DPart", {
-    extend: "Ext.draw.sprite.Path",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pie3dPart",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number",
-                thickness: "number",
-                bevelWidth: "number",
-                distortion: "number",
-                baseColor: "color",
-                colorSpread: "number",
-                baseRotation: "number",
-                part: "enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",
-                label: "string"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,partZIndex",
-                endAngle: "path,partZIndex",
-                startRho: "path",
-                endRho: "path,bbox",
-                margin: "path,bbox",
-                thickness: "path",
-                distortion: "path",
-                baseRotation: "path,partZIndex",
-                baseColor: "partZIndex,partColor",
-                colorSpread: "partColor",
-                part: "path,partZIndex",
-                globalAlpha: "canvas,alpha"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: Math.PI * 2,
-                endAngle: Math.PI * 2,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                thickness: 35,
-                distortion: 0.5,
-                baseRotation: 0,
-                baseColor: "white",
-                colorSpread: 1,
-                miterLimit: 1,
-                bevelWidth: 5,
-                strokeOpacity: 0,
-                part: "top",
-                label: ""
-            },
-            updaters: {
-                alpha: "alphaUpdater",
-                partColor: "partColorUpdater",
-                partZIndex: "partZIndexUpdater"
-            }
-        }
-    },
-    bevelParams: [],
-    constructor: function(a) {
-        this.callParent([a]);
-        this.bevelGradient = new Ext.draw.gradient.Linear({
-            stops: [{
-                offset: 0,
-                color: "rgba(255,255,255,0)"
-            }, {
-                offset: 0.7,
-                color: "rgba(255,255,255,0.6)"
-            }, {
-                offset: 1,
-                color: "rgba(255,255,255,0)"
-            }]
-        })
-    },
-    alphaUpdater: function(a) {
-        var d = this,
-            c = a.globalAlpha,
-            b = d.oldOpacity;
-        if (c !== b && (c === 1 || b === 1)) {
-            d.scheduleUpdater(a, "path", ["globalAlpha"]);
-            d.oldOpacity = c
-        }
-    },
-    partColorUpdater: function(a) {
-        var d = Ext.draw.Color.fly(a.baseColor),
-            b = d.toString(),
-            e = a.colorSpread,
-            c;
-        switch (a.part) {
-            case "top":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createLighter(0.1 * e)
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e)
-                    }]
-                });
-                break;
-            case "bottom":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.2 * e)
-                    }, {
-                        offset: 1,
-                        color: d.toString()
-                    }]
-                });
-                break;
-            case "outerFront":
-            case "outerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.15 * e).toString()
-                    }, {
-                        offset: 0.3,
-                        color: b
-                    }, {
-                        offset: 0.8,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.25 * e).toString()
-                    }]
-                });
-                break;
-            case "start":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "end":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "innerFront":
-            case "innerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 0.2,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 0.7,
-                        color: b
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e).toString()
-                    }]
-                });
-                break
-        }
-        a.fillStyle = c;
-        a.canvasAttributes.fillStyle = c
-    },
-    partZIndexUpdater: function(a) {
-        var c = Ext.draw.sprite.AttributeParser.angle,
-            e = a.baseRotation,
-            d = a.startAngle,
-            b = a.endAngle,
-            f;
-        switch (a.part) {
-            case "top":
-                a.zIndex = 5;
-                break;
-            case "outerFront":
-                d = c(d + e);
-                b = c(b + e);
-                if (d >= 0 && b < 0) {
-                    f = Math.sin(d)
-                } else {
-                    if (d <= 0 && b > 0) {
-                        f = Math.sin(b)
-                    } else {
-                        if (d >= 0 && b > 0) {
-                            if (d > b) {
-                                f = 0
-                            } else {
-                                f = Math.max(Math.sin(d), Math.sin(b))
-                            }
-                        } else {
-                            f = 1
-                        }
-                    }
-                }
-                a.zIndex = 4 + f;
-                break;
-            case "outerBack":
-                a.zIndex = 1;
-                break;
-            case "start":
-                a.zIndex = 4 + Math.sin(c(d + e));
-                break;
-            case "end":
-                a.zIndex = 4 + Math.sin(c(b + e));
-                break;
-            case "innerFront":
-                a.zIndex = 2;
-                break;
-            case "innerBack":
-                a.zIndex = 4 + Math.sin(c((d + b) / 2 + e));
-                break;
-            case "bottom":
-                a.zIndex = 0;
-                break
-        }
-        a.dirtyZIndex = true
-    },
-    updatePlainBBox: function(k) {
-        var f = this.attr,
-            a = f.part,
-            b = f.baseRotation,
-            e = f.centerX,
-            d = f.centerY,
-            j, c, i, h, g, l;
-        if (a === "start") {
-            c = f.startAngle + b
-        } else {
-            if (a === "end") {
-                c = f.endAngle + b
-            }
-        }
-        if (Ext.isNumber(c)) {
-            g = Math.sin(c);
-            l = Math.cos(c);
-            i = Math.min(e + l * f.startRho, e + l * f.endRho);
-            h = d + g * f.startRho * f.distortion;
-            k.x = i;
-            k.y = h;
-            k.width = l * (f.endRho - f.startRho);
-            k.height = f.thickness + g * (f.endRho - f.startRho) * 2;
-            return
-        }
-        if (a === "innerFront" || a === "innerBack") {
-            j = f.startRho
-        } else {
-            j = f.endRho
-        }
-        k.width = j * 2;
-        k.height = j * f.distortion * 2 + f.thickness;
-        k.x = f.centerX - j;
-        k.y = f.centerY - j * f.distortion
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.part === "start" || this.attr.part === "end") {
-            return this.callParent(arguments)
-        }
-        return this.updatePlainBBox(a)
-    },
-    updatePath: function(a) {
-        if (!this.attr.globalAlpha) {
-            return
-        }
-        if (this.attr.endAngle < this.attr.startAngle) {
-            return
-        }
-        this[this.attr.part + "Renderer"](a)
-    },
-    render: function(b, c) {
-        var d = this,
-            a = d.attr;
-        if (!a.globalAlpha) {
-            return
-        }
-        d.callParent([b, c]);
-        d.bevelRenderer(b, c);
-        if (a.label && d.getMarker("labels")) {
-            d.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            u = z.attr,
-            t = u.attributeId,
-            p = u.margin,
-            c = u.distortion,
-            i = u.centerX,
-            h = u.centerY,
-            j = u.baseRotation,
-            v = u.startAngle + j,
-            r = u.endAngle + j,
-            m = (v + r) / 2,
-            w = u.startRho + p,
-            o = u.endRho + p,
-            n = (w + o) / 2,
-            a = Math.sin(m),
-            b = Math.cos(m),
-            e = z.surfaceMatrix,
-            g = z.getMarker("labels"),
-            f = g.getTemplate(),
-            d = f.getCalloutLine(),
-            s = d && d.length || 40,
-            q = {},
-            l, k;
-        e.appendMatrix(u.matrix);
-        q.text = u.label;
-        l = i + b * n;
-        k = h + a * n * c;
-        q.x = e.x(l, k);
-        q.y = e.y(l, k);
-        l = i + b * o;
-        k = h + a * o * c;
-        q.calloutStartX = e.x(l, k);
-        q.calloutStartY = e.y(l, k);
-        l = i + b * (o + s);
-        k = h + a * (o + s) * c;
-        q.calloutPlaceX = e.x(l, k);
-        q.calloutPlaceY = e.y(l, k);
-        q.calloutWidth = 2;
-        z.putMarker("labels", q, t);
-        z.putMarker("labels", {
-            callout: 1
-        }, t)
-    },
-    bevelRenderer: function(b, c) {
-        var f = this,
-            a = f.attr,
-            e = a.bevelWidth,
-            g = f.bevelParams,
-            d;
-        for (d = 0; d < g.length; d++) {
-            c.beginPath();
-            c.ellipse.apply(c, g[d]);
-            c.save();
-            c.lineWidth = e;
-            c.strokeOpacity = e ? 1 : 0;
-            c.strokeGradient = f.bevelGradient;
-            c.stroke(a);
-            c.restore()
-        }
-    },
-    lidRenderer: function(o, m) {
-        var k = this.attr,
-            g = k.margin,
-            c = k.distortion,
-            i = k.centerX,
-            h = k.centerY,
-            f = k.baseRotation,
-            j = k.startAngle + f,
-            e = k.endAngle + f,
-            d = (j + e) / 2,
-            l = k.startRho,
-            b = k.endRho,
-            n = Math.sin(e),
-            a = Math.cos(e);
-        i += Math.cos(d) * g;
-        h += Math.sin(d) * g * c;
-        o.ellipse(i, h + m, l, l * c, 0, j, e, false);
-        o.lineTo(i + a * b, h + m + n * b * c);
-        o.ellipse(i, h + m, b, b * c, 0, e, j, true);
-        o.closePath()
-    },
-    topRenderer: function(a) {
-        this.lidRenderer(a, 0)
-    },
-    bottomRenderer: function(b) {
-        var a = this.attr;
-        if (a.globalAlpha < 1 || a.shadowColor !== Ext.draw.Color.RGBA_NONE) {
-            this.lidRenderer(b, a.thickness)
-        }
-    },
-    sideRenderer: function(l, s) {
-        var o = this.attr,
-            k = o.margin,
-            g = o.centerX,
-            f = o.centerY,
-            e = o.distortion,
-            h = o.baseRotation,
-            p = o.startAngle + h,
-            m = o.endAngle + h,
-            a = o.thickness,
-            q = o.startRho,
-            j = o.endRho,
-            r = (s === "start" && p) || (s === "end" && m),
-            b = Math.sin(r),
-            d = Math.cos(r),
-            c = o.globalAlpha < 1,
-            n = s === "start" && d < 0 || s === "end" && d > 0 || c,
-            i;
-        if (n) {
-            i = (p + m) / 2;
-            g += Math.cos(i) * k;
-            f += Math.sin(i) * k * e;
-            l.moveTo(g + d * q, f + b * q * e);
-            l.lineTo(g + d * j, f + b * j * e);
-            l.lineTo(g + d * j, f + b * j * e + a);
-            l.lineTo(g + d * q, f + b * q * e + a);
-            l.closePath()
-        }
-    },
-    startRenderer: function(a) {
-        this.sideRenderer(a, "start")
-    },
-    endRenderer: function(a) {
-        this.sideRenderer(a, "end")
-    },
-    rimRenderer: function(q, e, o, j) {
-        var w = this,
-            s = w.attr,
-            p = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            d = s.distortion,
-            i = s.baseRotation,
-            t = Ext.draw.sprite.AttributeParser.angle,
-            u = s.startAngle + i,
-            r = s.endAngle + i,
-            k = t((u + r) / 2),
-            a = s.thickness,
-            b = s.globalAlpha < 1,
-            c, n, v;
-        w.bevelParams = [];
-        u = t(u);
-        r = t(r);
-        h += Math.cos(k) * p;
-        g += Math.sin(k) * p * d;
-        c = u >= 0 && r >= 0;
-        n = u <= 0 && r <= 0;
-
-        function l() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, u, true);
-            q.lineTo(h + Math.cos(u) * e, g + Math.sin(u) * e * d);
-            v = [h, g, e, e * d, 0, u, Math.PI, false];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function f() {
-            q.ellipse(h, g + a, e, e * d, 0, 0, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, 0, true];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function x() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, Math.PI, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function m() {
-            q.ellipse(h, g + a, e, e * d, 0, u, 0, false);
-            q.lineTo(h + e, g);
-            v = [h, g, e, e * d, 0, 0, u, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-        if (j) {
-            if (!o || b) {
-                if (u >= 0 && r < 0) {
-                    l()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        f()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, 0, Math.PI, false);
-                                q.lineTo(h - e, g);
-                                v = [h, g, e, e * d, 0, Math.PI, 0, true];
-                                if (!o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                l();
-                                f()
-                            } else {
-                                v = [h, g, e, e * d, 0, u, r, false];
-                                if (c && !o || n && o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d + a);
-                                q.ellipse(h, g + a, e, e * d, 0, r, u, true);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        } else {
-            if (o || b) {
-                if (u >= 0 && r < 0) {
-                    x()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        m()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                x();
-                                m()
-                            } else {
-                                q.ellipse(h, g + a, e, e * d, 0, u, r, false);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-                                v = [h, g, e, e * d, 0, r, u, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, -Math.PI, 0, false);
-                                q.lineTo(h + e, g);
-                                v = [h, g, e, e * d, 0, 0, -Math.PI, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    innerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, true)
-    },
-    innerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, false)
-    },
-    outerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, true)
-    },
-    outerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, false)
-    }
-});
-Ext.define("Ext.draw.PathUtil", function() {
-    var a = Math.abs,
-        c = Math.pow,
-        e = Math.cos,
-        b = Math.acos,
-        d = Math.sqrt,
-        f = Math.PI;
-    return {
-        singleton: true,
-        requires: ["Ext.draw.overrides.Path", "Ext.draw.overrides.sprite.Path", "Ext.draw.overrides.sprite.Instancing", "Ext.draw.overrides.Surface"],
-        cubicRoots: function(m) {
-            var z = m[0],
-                x = m[1],
-                w = m[2],
-                v = m[3];
-            if (z === 0) {
-                return this.quadraticRoots(x, w, v)
-            }
-            var s = x / z,
-                r = w / z,
-                q = v / z,
-                k = (3 * r - c(s, 2)) / 9,
-                j = (9 * s * r - 27 * q - 2 * c(s, 3)) / 54,
-                p = c(k, 3) + c(j, 2),
-                n = [],
-                h, g, o, l, u, y = Ext.Number.sign;
-            if (p >= 0) {
-                h = y(j + d(p)) * c(a(j + d(p)), 1 / 3);
-                g = y(j - d(p)) * c(a(j - d(p)), 1 / 3);
-                n[0] = -s / 3 + (h + g);
-                n[1] = -s / 3 - (h + g) / 2;
-                n[2] = n[1];
-                o = a(d(3) * (h - g) / 2);
-                if (o !== 0) {
-                    n[1] = -1;
-                    n[2] = -1
-                }
-            } else {
-                l = b(j / d(-c(k, 3)));
-                n[0] = 2 * d(-k) * e(l / 3) - s / 3;
-                n[1] = 2 * d(-k) * e((l + 2 * f) / 3) - s / 3;
-                n[2] = 2 * d(-k) * e((l + 4 * f) / 3) - s / 3
-            }
-            for (u = 0; u < 3; u++) {
-                if (n[u] < 0 || n[u] > 1) {
-                    n[u] = -1
-                }
-            }
-            return n
-        },
-        quadraticRoots: function(h, g, n) {
-            var m, l, k, j;
-            if (h === 0) {
-                return this.linearRoot(g, n)
-            }
-            m = g * g - 4 * h * n;
-            if (m === 0) {
-                k = [-g / (2 * h)]
-            } else {
-                if (m > 0) {
-                    l = d(m);
-                    k = [(-g - l) / (2 * h), (-g + l) / (2 * h)]
-                } else {
-                    return []
-                }
-            }
-            for (j = 0; j < k.length; j++) {
-                if (k[j] < 0 || k[j] > 1) {
-                    k[j] = -1
-                }
-            }
-            return k
-        },
-        linearRoot: function(h, g) {
-            var i = -g / h;
-            if (h === 0 || i < 0 || i > 1) {
-                return []
-            }
-            return [i]
-        },
-        bezierCoeffs: function(h, g, k, j) {
-            var i = [];
-            i[0] = -h + 3 * g - 3 * k + j;
-            i[1] = 3 * h - 6 * g + 3 * k;
-            i[2] = -3 * h + 3 * g;
-            i[3] = h;
-            return i
-        },
-        cubicLineIntersections: function(I, G, F, E, l, k, j, h, M, p, K, n) {
-            var u = [],
-                N = [],
-                D = p - n,
-                z = K - M,
-                y = M * (n - p) - p * (K - M),
-                L = this.bezierCoeffs(I, G, F, E),
-                J = this.bezierCoeffs(l, k, j, h),
-                H, x, w, v, g, q, o, m;
-            u[0] = D * L[0] + z * J[0];
-            u[1] = D * L[1] + z * J[1];
-            u[2] = D * L[2] + z * J[2];
-            u[3] = D * L[3] + z * J[3] + y;
-            x = this.cubicRoots(u);
-            for (H = 0; H < x.length; H++) {
-                v = x[H];
-                if (v < 0 || v > 1) {
-                    continue
-                }
-                g = v * v;
-                q = g * v;
-                o = L[0] * q + L[1] * g + L[2] * v + L[3];
-                m = J[0] * q + J[1] * g + J[2] * v + J[3];
-                if ((K - M) !== 0) {
-                    w = (o - M) / (K - M)
-                } else {
-                    w = (m - p) / (n - p)
-                }
-                if (!(w < 0 || w > 1)) {
-                    N.push([o, m])
-                }
-            }
-            return N
-        },
-        splitCubic: function(g, q, p, o, m) {
-            var j = m * m,
-                n = m * j,
-                i = m - 1,
-                h = i * i,
-                k = i * h,
-                l = n * o - 3 * j * i * p + 3 * m * h * q - k * g;
-            return [
-                [g, m * q - i * g, j * p - 2 * m * i * q + h * g, l],
-                [l, j * o - 2 * m * i * p + h * q, m * o - i * p, o]
-            ]
-        },
-        cubicDimension: function(p, o, l, k) {
-            var j = 3 * (-p + 3 * (o - l) + k),
-                i = 6 * (p - 2 * o + l),
-                h = -3 * (p - o),
-                q, n, g = Math.min(p, k),
-                m = Math.max(p, k),
-                r;
-            if (j === 0) {
-                if (i === 0) {
-                    return [g, m]
-                } else {
-                    q = -h / i;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                }
-            } else {
-                r = i * i - 4 * j * h;
-                if (r >= 0) {
-                    r = d(r);
-                    q = (r - i) / 2 / j;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                    if (r > 0) {
-                        q -= r / j;
-                        if (0 < q && q < 1) {
-                            n = this.interpolateCubic(p, o, l, k, q);
-                            g = Math.min(g, n);
-                            m = Math.max(m, n)
-                        }
-                    }
-                }
-            }
-            return [g, m]
-        },
-        interpolateCubic: function(h, g, l, k, i) {
-            if (i === 0) {
-                return h
-            }
-            if (i === 1) {
-                return k
-            }
-            var j = (1 - i) / i;
-            return i * i * i * (k + j * (3 * l + j * (3 * g + j * h)))
-        },
-        cubicsIntersections: function(r, q, p, o, A, z, y, v, g, F, E, D, m, l, k, i) {
-            var C = this,
-                x = C.cubicDimension(r, q, p, o),
-                B = C.cubicDimension(A, z, y, v),
-                n = C.cubicDimension(g, F, E, D),
-                s = C.cubicDimension(m, l, k, i),
-                j, h, u, t, w = [];
-            if (x[0] > n[1] || x[1] < n[0] || B[0] > s[1] || B[1] < s[0]) {
-                return []
-            }
-            if (a(A - z) < 1 && a(y - v) < 1 && a(r - o) < 1 && a(q - p) < 1 && a(m - l) < 1 && a(k - i) < 1 && a(g - D) < 1 && a(F - E) < 1) {
-                return [
-                    [(r + o) * 0.5, (A + z) * 0.5]
-                ]
-            }
-            j = C.splitCubic(r, q, p, o, 0.5);
-            h = C.splitCubic(A, z, y, v, 0.5);
-            u = C.splitCubic(g, F, E, D, 0.5);
-            t = C.splitCubic(m, l, k, i, 0.5);
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[1], t[1])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[1], t[1])));
-            return w
-        },
-        linesIntersection: function(k, p, j, o, h, n, q, m) {
-            var l = (j - k) * (m - n) - (o - p) * (q - h),
-                i, g;
-            if (l === 0) {
-                return null
-            }
-            i = ((q - h) * (p - n) - (k - h) * (m - n)) / l;
-            g = ((j - k) * (p - n) - (o - p) * (k - h)) / l;
-            if (i >= 0 && i <= 1 && g >= 0 && g <= 1) {
-                return [k + i * (j - k), p + i * (o - p)]
-            }
-            return null
-        },
-        pointOnLine: function(j, m, h, l, g, n) {
-            var k, i;
-            if (a(h - j) < a(l - m)) {
-                i = j;
-                j = m;
-                m = i;
-                i = h;
-                h = l;
-                l = i;
-                i = g;
-                g = n;
-                n = i
-            }
-            k = (g - j) / (h - j);
-            if (k < 0 || k > 1) {
-                return false
-            }
-            return a(m + k * (l - m) - n) < 4
-        },
-        pointOnCubic: function(w, u, s, r, l, k, h, g, p, o) {
-            var C = this,
-                B = C.bezierCoeffs(w, u, s, r),
-                A = C.bezierCoeffs(l, k, h, g),
-                z, v, n, m, q;
-            B[3] -= p;
-            A[3] -= o;
-            n = C.cubicRoots(B);
-            m = C.cubicRoots(A);
-            for (z = 0; z < n.length; z++) {
-                q = n[z];
-                for (v = 0; v < m.length; v++) {
-                    if (q >= 0 && q <= 1 && a(q - m[v]) < 0.05) {
-                        return true
-                    }
-                }
-            }
-            return false
-        }
-    }
-});
-Ext.define("Ext.chart.series.Pie3D", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.Pie3DPart", "Ext.draw.PathUtil"],
-    type: "pie3d",
-    seriesType: "pie3d",
-    alias: "series.pie3d",
-    isPie3D: true,
-    config: {
-        rect: [0, 0, 0, 0],
-        thickness: 35,
-        distortion: 0.5,
-        donut: false,
-        hidden: [],
-        highlightCfg: {
-            margin: 20
-        },
-        shadow: false
-    },
-    rotationOffset: -Math.PI / 2,
-    setField: function(a) {
-        return this.setXField(a)
-    },
-    getField: function() {
-        return this.getXField()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            baseRotation: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateDistortion: function() {
-        this.setRadius()
-    },
-    updateThickness: function() {
-        this.setRadius()
-    },
-    updateColors: function(a) {
-        this.setSubStyle({
-            baseColor: a
-        })
-    },
-    applyShadow: function(a) {
-        if (a === true) {
-            a = {
-                shadowColor: "rgba(0,0,0,0.8)",
-                shadowBlur: 30
-            }
-        } else {
-            if (!Ext.isObject(a)) {
-                a = {
-                    shadowColor: Ext.draw.Color.RGBA_NONE
-                }
-            }
-        }
-        return a
-    },
-    updateShadow: function(g) {
-        var e = this,
-            f = e.getSprites(),
-            d = e.spritesPerSlice,
-            c = f && f.length,
-            b, a;
-        for (b = 1; b < c; b += d) {
-            a = f[b];
-            if (a.attr.part = "bottom") {
-                a.setAttributes(g)
-            }
-        }
-    },
-    getStyleByIndex: function(b) {
-        var d = this.callParent([b]),
-            c = this.getStyle(),
-            a = d.fillStyle || d.fill || d.color,
-            e = c.strokeStyle || c.stroke;
-        if (a) {
-            d.baseColor = a;
-            delete d.fillStyle;
-            delete d.fill;
-            delete d.color
-        }
-        if (e) {
-            d.strokeStyle = e
-        }
-        return d
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.getSprites(),
-            f = g.spritesPerSlice,
-            e = h && h.length,
-            c = 0,
-            b = 0,
-            a, d;
-        for (; c < e; c += f, b++) {
-            d = g.getStyleByIndex(b);
-            for (a = 0; a < f; a++) {
-                h[c + a].setAttributes(d)
-            }
-        }
-    },
-    coordinateX: function() {
-        var w = this,
-            m = w.getChart(),
-            u = m && m.getAnimation(),
-            f = w.getStore(),
-            t = f.getData().items,
-            d = t.length,
-            b = w.getXField(),
-            p = w.getRotation(),
-            s = w.getHidden(),
-            n, c = 0,
-            h, e = [],
-            k = w.getSprites(),
-            a = k.length,
-            l = w.spritesPerSlice,
-            g = 0,
-            o = Math.PI * 2,
-            v = 1e-10,
-            r, q;
-        for (r = 0; r < d; r++) {
-            n = Math.abs(Number(t[r].get(b))) || 0;
-            if (!s[r]) {
-                c += n
-            }
-            e[r] = c;
-            if (r >= s.length) {
-                s[r] = false
-            }
-        }
-        s.length = d;
-        if (c === 0) {
-            return
-        }
-        h = 2 * Math.PI / c;
-        for (r = 0; r < d; r++) {
-            e[r] *= h
-        }
-        for (r = 0; r < a; r++) {
-            k[r].setAnimation(u)
-        }
-        for (r = 0; r < d; r++) {
-            for (q = 0; q < l; q++) {
-                k[r * l + q].setAttributes({
-                    startAngle: g,
-                    endAngle: e[r] - v,
-                    globalAlpha: 1,
-                    baseRotation: p
-                })
-            }
-            g = e[r]
-        }
-        for (r *= l; r < a; r++) {
-            k[r].setAnimation(u);
-            k[r].setAttributes({
-                startAngle: o,
-                endAngle: o,
-                globalAlpha: 0,
-                baseRotation: p
-            })
-        }
-    },
-    updateLabelData: function() {
-        var l = this,
-            m = l.getStore(),
-            k = m.getData().items,
-            h = l.getSprites(),
-            b = l.getLabel().getTemplate().getField(),
-            f = l.getHidden(),
-            a = l.spritesPerSlice,
-            d, c, g, e, n;
-        if (h.length && b) {
-            e = [];
-            for (d = 0, g = k.length; d < g; d++) {
-                e.push(k[d].get(b))
-            }
-            for (d = 0, c = 0, g = h.length; d < g; d += a, c++) {
-                n = h[d];
-                n.setAttributes({
-                    label: e[c]
-                });
-                n.putMarker("labels", {
-                    hidden: f[c]
-                }, n.attr.attributeId)
-            }
-        }
-    },
-    applyRadius: function() {
-        var f = this,
-            d = f.getChart(),
-            h = d.getInnerPadding(),
-            e = d.getMainRect() || [0, 0, 1, 1],
-            c = e[2] - h * 2,
-            a = e[3] - h * 2 - f.getThickness(),
-            g = c / 2,
-            b = g * f.getDistortion();
-        if (b > a / 2) {
-            return a / (f.getDistortion() * 2)
-        } else {
-            return g
-        }
-    },
-    getSprites: function() {
-        var y = this,
-            e = y.getStore();
-        if (!e) {
-            return []
-        }
-        var n = y.getChart(),
-            p = y.getSurface(),
-            t = e.getData().items,
-            l = y.spritesPerSlice,
-            a = t.length,
-            v = y.getAnimation() || n && n.getAnimation(),
-            x = y.getCenter(),
-            w = y.getOffsetX(),
-            u = y.getOffsetY(),
-            b = y.getRadius(),
-            q = y.getRotation(),
-            d = y.getHighlight(),
-            c = {
-                centerX: x[0] + w,
-                centerY: x[1] + u - y.getThickness() / 2,
-                endRho: b,
-                startRho: b * y.getDonut() / 100,
-                thickness: y.getThickness(),
-                distortion: y.getDistortion()
-            },
-            k = y.sprites,
-            h = y.getLabel(),
-            f = h.getTemplate(),
-            m, g, o, s, r;
-        for (s = 0; s < a; s++) {
-            g = Ext.apply({}, this.getStyleByIndex(s), c);
-            if (!k[s * l]) {
-                for (r = 0; r < y.partNames.length; r++) {
-                    o = p.add({
-                        type: "pie3dPart",
-                        part: y.partNames[r]
-                    });
-                    if (r === 0 && f.getField()) {
-                        o.bindMarker("labels", h)
-                    }
-                    o.fx.setDurationOn("baseRotation", q);
-                    if (d) {
-                        o.config.highlight = d;
-                        o.addModifier("highlight", true)
-                    }
-                    o.setAttributes(g);
-                    k.push(o)
-                }
-            } else {
-                m = k.slice(s * l, (s + 1) * l);
-                for (r = 0; r < m.length; r++) {
-                    o = m[r];
-                    if (v) {
-                        o.setAnimation(v)
-                    }
-                    o.setAttributes(g)
-                }
-            }
-        }
-        return k
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        f += g;
-        c += g;
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            g = h.getSprites();
-        if (g) {
-            var l = h.getStore(),
-                b = l.getData().items,
-                a = h.spritesPerSlice,
-                e = h.getHidden(),
-                c, f, m, d;
-            for (c = 0, f = b.length; c < f; c++) {
-                if (!e[c]) {
-                    d = c * a;
-                    m = g[d];
-                    if (m.hitTest([k, j])) {
-                        return {
-                            series: h,
-                            sprite: g.slice(d, d + a),
-                            index: c,
-                            record: b[c],
-                            category: "sprites",
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            k = h.getStore();
-        if (k) {
-            var g = k.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                j = h.getField(),
-                e = h.getHidden(),
-                d, a, c;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                c = a.baseColor;
-                f.push({
-                    name: b ? String(g[d].get(b)) : j + " " + d,
-                    mark: c || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-}, function() {
-    var b = this.prototype,
-        a = Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;
-    b.partNames = a.replace(/^enums\(|\)/g, "").split(",");
-    b.spritesPerSlice = b.partNames.length
-});
-Ext.define("Ext.chart.series.sprite.Polar", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                baseRotation: "number",
-                labels: "default",
-                labelOverflowPadding: "number"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: Math.PI,
-                startRho: 0,
-                endRho: 150,
-                baseRotation: 0,
-                labels: null,
-                labelOverflowPadding: 10
-            },
-            triggers: {
-                centerX: "bbox",
-                centerY: "bbox",
-                startAngle: "bbox",
-                endAngle: "bbox",
-                startRho: "bbox",
-                endRho: "bbox",
-                baseRotation: "bbox"
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.centerX - a.endRho;
-        b.y = a.centerY + a.endRho;
-        b.width = a.endRho * 2;
-        b.height = a.endRho * 2
-    }
-});
-Ext.define("Ext.chart.series.sprite.Radar", {
-    alias: "sprite.radar",
-    extend: "Ext.chart.series.sprite.Polar",
-    getDataPointXY: function(d) {
-        var u = this,
-            n = u.attr,
-            f = n.centerX,
-            e = n.centerY,
-            o = n.matrix,
-            t = n.dataMinX,
-            s = n.dataMaxX,
-            k = n.dataX,
-            j = n.dataY,
-            l = n.endRho,
-            p = n.startRho,
-            g = n.baseRotation,
-            i, h, m, c, b, a, q;
-        if (n.rangeY) {
-            q = n.rangeY[1]
-        } else {
-            q = n.dataMaxY
-        }
-        c = (k[d] - t) / (s - t + 1) * 2 * Math.PI + g;
-        m = j[d] / q * (l - p) + p;
-        b = f + Math.cos(c) * m;
-        a = e + Math.sin(c) * m;
-        i = o.x(b, a);
-        h = o.y(b, a);
-        return [i, h]
-    },
-    render: function(a, l) {
-        var h = this,
-            f = h.attr,
-            g = f.dataX,
-            b = g.length,
-            e = h.surfaceMatrix,
-            d = {},
-            c, k, j, m;
-        l.beginPath();
-        for (c = 0; c < b; c++) {
-            m = h.getDataPointXY(c);
-            k = m[0];
-            j = m[1];
-            if (c === 0) {
-                l.moveTo(k, j)
-            }
-            l.lineTo(k, j);
-            d.translationX = e.x(k, j);
-            d.translationY = e.y(k, j);
-            h.putMarker("markers", d, c, true)
-        }
-        l.closePath();
-        l.fillStroke(f)
-    }
-});
-Ext.define("Ext.chart.series.Radar", {
-    extend: "Ext.chart.series.Polar",
-    type: "radar",
-    seriesType: "radar",
-    alias: "series.radar",
-    requires: ["Ext.chart.series.sprite.Radar"],
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 1
-    },
-    updateAngularAxis: function(a) {
-        a.processData(this)
-    },
-    updateRadialAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            endRho: a
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            m = h.sprites && h.sprites[0],
-            f = m.attr,
-            g = f.dataX,
-            a = g.length,
-            l = h.getStore(),
-            e = h.getMarker(),
-            b, o, p, d, n, c;
-        if (h.getHidden()) {
-            return null
-        }
-        if (m && e) {
-            c = m.getMarker("markers");
-            for (d = 0; d < a; d++) {
-                n = c.getBBoxFor(d);
-                b = (n.width + n.height) * 0.25;
-                p = m.getDataPointXY(d);
-                if (Math.abs(p[0] - k) < b && Math.abs(p[1] - j) < b) {
-                    o = {
-                        series: h,
-                        sprite: m,
-                        index: d,
-                        category: "markers",
-                        record: l.getData().items[d],
-                        field: h.getYField()
-                    };
-                    return o
-                }
-            }
-        }
-        return h.callParent(arguments)
-    },
-    getDefaultSpriteConfig: function() {
-        var a = this.callParent(),
-            b = {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationRads: 0,
-                    dataMinX: 0,
-                    dataMaxX: 0
-                }
-            };
-        if (a.fx) {
-            Ext.apply(a.fx, b)
-        } else {
-            a.fx = b
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = d.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.sprites[0],
-            a;
-        if (!c) {
-            return []
-        }
-        if (!b) {
-            b = d.createSprite()
-        }
-        if (e) {
-            a = b.getMarker("markers");
-            if (a) {
-                a.getTemplate().setAnimation(e)
-            }
-            b.setAnimation(e)
-        }
-        return d.sprites
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.series.sprite.Scatter", {
-    alias: "sprite.scatterSeries",
-    extend: "Ext.chart.series.sprite.Cartesian",
-    renderClipped: function(r, s, w, u) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var C = this,
-            q = C.attr,
-            l = q.dataX,
-            h = q.dataY,
-            z = q.labels,
-            j = C.getSeries(),
-            b = z && C.getMarker("labels"),
-            t = C.attr.matrix,
-            c = t.getXX(),
-            p = t.getYY(),
-            m = t.getDX(),
-            k = t.getDY(),
-            n = {},
-            D, B, d = r.getInherited().rtl && !q.flipXY ? -1 : 1,
-            a, A, o, e, g, f, v;
-        if (q.flipXY) {
-            a = u[1] - c * d;
-            A = u[1] + u[3] + c * d;
-            o = u[0] - p;
-            e = u[0] + u[2] + p
-        } else {
-            a = u[0] - c * d;
-            A = u[0] + u[2] + c * d;
-            o = u[1] - p;
-            e = u[1] + u[3] + p
-        }
-        for (v = 0; v < l.length; v++) {
-            g = l[v];
-            f = h[v];
-            g = g * c + m;
-            f = f * p + k;
-            if (a <= g && g <= A && o <= f && f <= e) {
-                if (q.renderer) {
-                    n = {
-                        type: "items",
-                        translationX: g,
-                        translationY: f
-                    };
-                    B = [C, n, {
-                        store: C.getStore()
-                    }, v];
-                    D = Ext.callback(q.renderer, null, B, 0, j);
-                    n = Ext.apply(n, D)
-                } else {
-                    n.translationX = g;
-                    n.translationY = f
-                }
-                C.putMarker("items", n, v, !q.renderer);
-                if (b && z[v]) {
-                    C.drawLabel(z[v], g, f, v, u)
-                }
-            }
-        }
-    },
-    drawLabel: function(j, h, g, p, a) {
-        var r = this,
-            m = r.attr,
-            d = r.getMarker("labels"),
-            c = d.getTemplate(),
-            l = r.labelCfg || (r.labelCfg = {}),
-            b = r.surfaceMatrix,
-            f, e, i = m.labelOverflowPadding,
-            o = m.flipXY,
-            k, n, s, q;
-        l.text = j;
-        n = r.getMarkerBBox("labels", p, true);
-        if (!n) {
-            r.putMarker("labels", l, p);
-            n = r.getMarkerBBox("labels", p, true)
-        }
-        if (o) {
-            l.rotationRads = Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        k = n.height / 2;
-        f = h;
-        switch (c.attr.display) {
-            case "under":
-                e = g - k - i;
-                break;
-            case "rotate":
-                f += i;
-                e = g - i;
-                l.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                e = g + k + i
-        }
-        l.x = b.x(f, e);
-        l.y = b.y(f, e);
-        if (c.attr.renderer) {
-            q = [j, d, l, {
-                store: r.getStore()
-            }, p];
-            s = Ext.callback(c.attr.renderer, null, q, 0, r.getSeries());
-            if (typeof s === "string") {
-                l.text = s
-            } else {
-                Ext.apply(l, s)
-            }
-        }
-        r.putMarker("labels", l, p)
-    }
-});
-Ext.define("Ext.chart.series.Scatter", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.scatter",
-    type: "scatter",
-    seriesType: "scatterSeries",
-    requires: ["Ext.chart.series.sprite.Scatter"],
-    config: {
-        itemInstancing: {
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0
-                }
-            }
-        }
-    },
-    themeMarkerCount: function() {
-        return 1
-    },
-    applyMarker: function(b, a) {
-        this.getItemInstancing();
-        this.setItemInstancing(b);
-        return this.callParent(arguments)
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getMarkerStyleByIndex(0),
-            c = a.fillStyle;
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.theme.Blue", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue", "chart.theme.Blue"],
-    config: {
-        baseColor: "#4d7fe6"
-    }
-});
-Ext.define("Ext.chart.theme.BlueGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue-gradients", "chart.theme.Blue:gradients"],
-    config: {
-        baseColor: "#4d7fe6",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category1", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1", "chart.theme.Category1"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"]
-    }
-});
-Ext.define("Ext.chart.theme.Category1Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1-gradients", "chart.theme.Category1:gradients"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category2", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2", "chart.theme.Category2"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"]
-    }
-});
-Ext.define("Ext.chart.theme.Category2Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2-gradients", "chart.theme.Category2:gradients"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category3", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3", "chart.theme.Category3"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"]
-    }
-});
-Ext.define("Ext.chart.theme.Category3Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3-gradients", "chart.theme.Category3:gradients"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category4", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4", "chart.theme.Category4"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"]
-    }
-});
-Ext.define("Ext.chart.theme.Category4Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4-gradients", "chart.theme.Category4:gradients"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category5", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5", "chart.theme.Category5"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"]
-    }
-});
-Ext.define("Ext.chart.theme.Category5Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5-gradients", "chart.theme.Category5:gradients"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category6", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6", "chart.theme.Category6"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"]
-    }
-});
-Ext.define("Ext.chart.theme.Category6Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6-gradients", "chart.theme.Category6:gradients"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.DefaultGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default-gradients", "chart.theme.Base:gradients"],
-    config: {
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Green", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green", "chart.theme.Green"],
-    config: {
-        baseColor: "#b1da5a"
-    }
-});
-Ext.define("Ext.chart.theme.GreenGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green-gradients", "chart.theme.Green:gradients"],
-    config: {
-        baseColor: "#b1da5a",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Midnight", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.midnight", "chart.theme.Midnight"],
-    config: {
-        colors: ["#A837FF", "#4AC0F2", "#FF4D35", "#FF8809", "#61C102", "#FF37EA"],
-        chart: {
-            defaults: {
-                background: "rgb(52, 52, 53)"
-            }
-        },
-        axis: {
-            defaults: {
-                style: {
-                    strokeStyle: "rgb(224, 224, 227)"
-                },
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                title: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                grid: {
-                    strokeStyle: "rgb(112, 112, 115)"
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                }
-            }
-        },
-        sprites: {
-            text: {
-                fillStyle: "rgb(224, 224, 227)"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Muted", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.muted", "chart.theme.Muted"],
-    config: {
-        colors: ["#8ca640", "#974144", "#4091ba", "#8e658e", "#3b8d8b", "#b86465", "#d2af69", "#6e8852", "#3dcc7e", "#a6bed1", "#cbaa4b", "#998baa"]
-    }
-});
-Ext.define("Ext.chart.theme.Purple", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple", "chart.theme.Purple"],
-    config: {
-        baseColor: "#da5abd"
-    }
-});
-Ext.define("Ext.chart.theme.PurpleGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple-gradients", "chart.theme.Purple:gradients"],
-    config: {
-        baseColor: "#da5abd",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Red", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red", "chart.theme.Red"],
-    config: {
-        baseColor: "#e84b67"
-    }
-});
-Ext.define("Ext.chart.theme.RedGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red-gradients", "chart.theme.Red:gradients"],
-    config: {
-        baseColor: "#e84b67",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Sky", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky", "chart.theme.Sky"],
-    config: {
-        baseColor: "#4ce0e7"
-    }
-});
-Ext.define("Ext.chart.theme.SkyGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky-gradients", "chart.theme.Sky:gradients"],
-    config: {
-        baseColor: "#4ce0e7",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Yellow", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow", "chart.theme.Yellow"],
-    config: {
-        baseColor: "#fec935"
-    }
-});
-Ext.define("Ext.chart.theme.YellowGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow-gradients", "chart.theme.Yellow:gradients"],
-    config: {
-        baseColor: "#fec935",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.draw.Point", {
-    requires: ["Ext.draw.Draw", "Ext.draw.Matrix"],
-    isPoint: true,
-    x: 0,
-    y: 0,
-    length: 0,
-    angle: 0,
-    angleUnits: "degrees",
-    statics: {
-        fly: (function() {
-            var a = null;
-            return function(b, c) {
-                if (!a) {
-                    a = new Ext.draw.Point()
-                }
-                a.constructor(b, c);
-                return a
-            }
-        })()
-    },
-    constructor: function(a, c) {
-        var b = this;
-        if (typeof a === "number") {
-            b.x = a;
-            if (typeof c === "number") {
-                b.y = c
-            } else {
-                b.y = a
-            }
-        } else {
-            if (Ext.isArray(a)) {
-                b.x = a[0];
-                b.y = a[1]
-            } else {
-                if (a) {
-                    b.x = a.x;
-                    b.y = a.y
-                }
-            }
-        }
-        b.calculatePolar()
-    },
-    calculateCartesian: function() {
-        var b = this,
-            a = b.length,
-            c = b.angle;
-        if (b.angleUnits === "degrees") {
-            c = Ext.draw.Draw.rad(c)
-        }
-        b.x = Math.cos(c) * a;
-        b.y = Math.sin(c) * a
-    },
-    calculatePolar: function() {
-        var b = this,
-            a = b.x,
-            c = b.y;
-        b.length = Math.sqrt(a * a + c * c);
-        b.angle = Math.atan2(c, a);
-        if (b.angleUnits === "degrees") {
-            b.angle = Ext.draw.Draw.degrees(b.angle)
-        }
-    },
-    setX: function(a) {
-        this.x = a;
-        this.calculatePolar()
-    },
-    setY: function(a) {
-        this.y = a;
-        this.calculatePolar()
-    },
-    set: function(a, b) {
-        this.constructor(a, b)
-    },
-    setAngle: function(a) {
-        this.angle = a;
-        this.calculateCartesian()
-    },
-    setLength: function(a) {
-        this.length = a;
-        this.calculateCartesian()
-    },
-    setPolar: function(b, a) {
-        this.angle = b;
-        this.length = a;
-        this.calculateCartesian()
-    },
-    clone: function() {
-        return new Ext.draw.Point(this.x, this.y)
-    },
-    add: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x + b.x, this.y + b.y)
-    },
-    sub: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x - b.x, this.y - b.y)
-    },
-    mul: function(a) {
-        return new Ext.draw.Point(this.x * a, this.y * a)
-    },
-    div: function(a) {
-        return new Ext.draw.Point(this.x / a, this.y / a)
-    },
-    dot: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x * b.x + this.y * b.y
-    },
-    equals: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x === b.x && this.y === b.y
-    },
-    rotate: function(f, c) {
-        var d, e, b, g, a;
-        if (this.angleUnits === "degrees") {
-            f = Ext.draw.Draw.rad(f);
-            d = Math.sin(f);
-            e = Math.cos(f)
-        }
-        if (c) {
-            b = c.x;
-            g = c.y
-        } else {
-            b = 0;
-            g = 0
-        }
-        a = Ext.draw.Matrix.fly([e, d, -d, e, b - e * b + g * d, g - e * g + b * -d]).transformPoint(this);
-        return new Ext.draw.Point(a)
-    },
-    transform: function(a) {
-        if (a && a.isMatrix) {
-            return new Ext.draw.Point(a.transformPoint(this))
-        } else {
-            if (arguments.length === 6) {
-                return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))
-            } else {
-                Ext.raise("Invalid parameters.")
-            }
-        }
-    },
-    round: function() {
-        return new Ext.draw.Point(Math.round(this.x), Math.round(this.y))
-    },
-    ceil: function() {
-        return new Ext.draw.Point(Math.ceil(this.x), Math.ceil(this.y))
-    },
-    floor: function() {
-        return new Ext.draw.Point(Math.floor(this.x), Math.floor(this.y))
-    },
-    abs: function(a, b) {
-        return new Ext.draw.Point(Math.abs(this.x), Math.abs(this.y))
-    },
-    normalize: function(c) {
-        var b = this.x,
-            f = this.y,
-            a, e, d;
-        c = c || 1;
-        if (b === 0) {
-            a = 0;
-            e = c * Ext.Number.sign(f)
-        } else {
-            d = f / b;
-            a = c / Math.sqrt(1 + d * d);
-            e = a * d
-        }
-        return new Ext.draw.Point(a, e)
-    },
-    getDistanceToLine: function(c, b) {
-        if (arguments.length === 4) {
-            c = new Ext.draw.Point(arguments[0], arguments[1]);
-            b = new Ext.draw.Point(arguments[2], arguments[3])
-        }
-        var d = b.sub(c).normalize(),
-            a = c.sub(this);
-        return a.sub(d.mul(a.dot(d)))
-    },
-    isZero: function() {
-        return this.x === 0 && this.y === 0
-    },
-    isNumber: function() {
-        return Ext.isNumber(this.x + this.y)
-    }
-});
-Ext.define("Ext.draw.plugin.SpriteEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.spriteevents",
-    requires: ["Ext.draw.PathUtil"],
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    spriteMouseMoveEvents: {
-        spritemousemove: true,
-        spritemouseover: true,
-        spritemouseout: true
-    },
-    init: function(a) {
-        var b = "handleEvent";
-        this.drawContainer = a;
-        a.addElementListener({
-            click: b,
-            dblclick: b,
-            mousedown: b,
-            mousemove: b,
-            mouseup: b,
-            mouseover: b,
-            mouseout: b,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasSpriteMouseMoveListeners: function() {
-        var b = this.drawContainer.hasListeners,
-            a;
-        for (a in this.spriteMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    hitTestEvent: function(f) {
-        var b = this.drawContainer.getItems(),
-            a, d, c;
-        for (c = b.length - 1; c >= 0; c--) {
-            a = b.get(c);
-            d = a.hitTestEvent(f);
-            if (d) {
-                return d
-            }
-        }
-        return null
-    },
-    handleEvent: function(f) {
-        var d = this,
-            b = d.drawContainer,
-            g = f.type in d.mouseMoveEvents,
-            a = d.lastSprite,
-            c;
-        if (g && !d.hasSpriteMouseMoveListeners()) {
-            return
-        }
-        c = d.hitTestEvent(f);
-        if (g && !Ext.Object.equals(c, a)) {
-            if (a) {
-                b.fireEvent("spritemouseout", a, f)
-            }
-            if (c) {
-                b.fireEvent("spritemouseover", c, f)
-            }
-        }
-        if (c) {
-            b.fireEvent("sprite" + f.type, c, f)
-        }
-        d.lastSprite = c
-    }
-});
-Ext.define("Ext.chart.TipSurface", {
-    extend: "Ext.draw.Container",
-    spriteArray: false,
-    renderFirst: true,
-    constructor: function(a) {
-        this.callParent([a]);
-        if (a.sprites) {
-            this.spriteArray = [].concat(a.sprites);
-            delete a.sprites
-        }
-    },
-    onRender: function() {
-        var c = this,
-            b = 0,
-            a = 0,
-            d, e;
-        this.callParent(arguments);
-        e = c.spriteArray;
-        if (c.renderFirst && e) {
-            c.renderFirst = false;
-            for (a = e.length; b < a; b++) {
-                d = c.surface.add(e[b]);
-                d.setAttributes({
-                    hidden: false
-                }, true)
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.interactions.ItemInfo", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "iteminfo",
-    alias: "interaction.iteminfo",
-    config: {
-        extjsGestures: {
-            start: {
-                event: "click",
-                handler: "onInfoGesture"
-            },
-            move: {
-                event: "mousemove",
-                handler: "onInfoGesture"
-            },
-            end: {
-                event: "mouseleave",
-                handler: "onInfoGesture"
-            }
-        }
-    },
-    item: null,
-    onInfoGesture: function(f, a) {
-        var c = this,
-            b = c.getItemForEvent(f),
-            d = b && b.series.tooltip;
-        if (d) {
-            d.onMouseMove.call(d, f)
-        }
-        if (b !== c.item) {
-            if (b) {
-                b.series.showTip(b)
-            } else {
-                c.item.series.hideTip(c.item)
-            }
-            c.item = b
-        }
-        return false
-    }
-});
diff --git a/serverside/jsmod/5.4-3/charts.js.original b/serverside/jsmod/5.4-3/charts.js.original
deleted file mode 100644
index a7eb0894ab5b6431916903f3d856e0ca408fe88b..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/charts.js.original
+++ /dev/null
@@ -1,22010 +0,0 @@
-Ext.define("Ext.draw.ContainerBase", {
-    extend: "Ext.panel.Panel",
-    requires: ["Ext.window.Window"],
-    previewTitleText: "Chart Preview",
-    previewAltText: "Chart preview",
-    layout: "container",
-    addElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.on.apply(b.el, a)
-        } else {
-            b.on("render", function() {
-                b.el.on.apply(b.el, a)
-            })
-        }
-    },
-    removeElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.un.apply(b.el, a)
-        }
-    },
-    afterRender: function() {
-        this.callParent(arguments);
-        this.initAnimator()
-    },
-    getItems: function() {
-        var b = this,
-            a = b.items;
-        if (!a || !a.isMixedCollection) {
-            b.initItems()
-        }
-        return b.items
-    },
-    onRender: function() {
-        this.callParent(arguments);
-        this.element = this.el;
-        this.innerElement = this.body
-    },
-    setItems: function(a) {
-        this.items = a;
-        return a
-    },
-    setSurfaceSize: function(b, a) {
-        this.resizeHandler({
-            width: b,
-            height: a
-        });
-        this.renderFrame()
-    },
-    onResize: function(c, a, b, e) {
-        var d = this;
-        d.callParent([c, a, b, e]);
-        d.setBodySize({
-            width: c,
-            height: a
-        })
-    },
-    preview: function() {
-        var a = this.getImage();
-        new Ext.window.Window({
-            title: this.previewTitleText,
-            closeable: true,
-            renderTo: Ext.getBody(),
-            autoShow: true,
-            maximizeable: true,
-            maximized: true,
-            border: true,
-            layout: {
-                type: "hbox",
-                pack: "center",
-                align: "middle"
-            },
-            items: {
-                xtype: "container",
-                items: {
-                    xtype: "image",
-                    mode: "img",
-                    cls: Ext.baseCSSPrefix + "chart-image",
-                    alt: this.previewAltText,
-                    src: a.data,
-                    listeners: {
-                        afterrender: function() {
-                            var e = this,
-                                b = e.imgEl.dom,
-                                d = a.type === "svg" ? 1 : (window.devicePixelRatio || 1),
-                                c;
-                            if (!b.naturalWidth || !b.naturalHeight) {
-                                b.onload = function() {
-                                    var g = b.naturalWidth,
-                                        f = b.naturalHeight;
-                                    e.setWidth(Math.floor(g / d));
-                                    e.setHeight(Math.floor(f / d))
-                                }
-                            } else {
-                                c = e.getSize();
-                                e.setWidth(Math.floor(c.width / d));
-                                e.setHeight(Math.floor(c.height / d))
-                            }
-                        }
-                    }
-                }
-            }
-        })
-    },
-    privates: {
-        getTargetEl: function() {
-            return this.innerElement
-        },
-        reattachToBody: function() {
-            var a = this;
-            if (a.pendingDetachSize) {
-                a.onBodyResize()
-            }
-            a.pendingDetachSize = false;
-            a.callParent()
-        }
-    }
-});
-Ext.define("Ext.draw.SurfaceBase", {
-    extend: "Ext.Widget",
-    getOwnerBody: function() {
-        return this.ownerCt.body
-    },
-    destroy: function() {
-        var a = this;
-        if (a.hasListeners.destroy) {
-            a.fireEvent("destroy", a)
-        }
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.Color", {
-    statics: {
-        colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbToHexRe: /\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbaToHexRe: /\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,
-        hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,
-        NONE: "none",
-        RGBA_NONE: "rgba(0, 0, 0, 0)"
-    },
-    isColor: true,
-    lightnessFactor: 0.2,
-    constructor: function(d, b, a, c) {
-        this.setRGB(d, b, a, c)
-    },
-    setRGB: function(e, c, a, d) {
-        var b = this;
-        b.r = Math.min(255, Math.max(0, e));
-        b.g = Math.min(255, Math.max(0, c));
-        b.b = Math.min(255, Math.max(0, a));
-        if (d === undefined) {
-            b.a = 1
-        } else {
-            b.a = Math.min(1, Math.max(0, d))
-        }
-    },
-    getGrayscale: function() {
-        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11
-    },
-    getHSL: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            m = k - d,
-            e, n = 0,
-            c = 0.5 * (k + d);
-        if (d !== k) {
-            n = (c <= 0.5) ? m / (k + d) : m / (2 - k - d);
-            if (a === k) {
-                e = 60 * (f - j) / m
-            } else {
-                if (f === k) {
-                    e = 120 + 60 * (j - a) / m
-                } else {
-                    e = 240 + 60 * (a - f) / m
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, n, c]
-    },
-    getHSV: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            c = k - d,
-            e, m = 0,
-            l = k;
-        if (d != k) {
-            m = l ? c / l : 0;
-            if (a === k) {
-                e = 60 * (f - j) / c
-            } else {
-                if (f === k) {
-                    e = 60 * (j - a) / c + 120
-                } else {
-                    e = 60 * (a - f) / c + 240
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, m, l]
-    },
-    setHSL: function(g, f, e) {
-        var i = this,
-            d = Math.abs,
-            j, b, a;
-        g = (g % 360 + 360) % 360;
-        f = f > 1 ? 1 : f < 0 ? 0 : f;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        if (f === 0 || g === null) {
-            e *= 255;
-            i.setRGB(e, e, e)
-        } else {
-            g /= 60;
-            j = f * (1 - d(2 * e - 1));
-            b = j * (1 - d(g % 2 - 1));
-            a = e - j / 2;
-            a *= 255;
-            j *= 255;
-            b *= 255;
-            switch (Math.floor(g)) {
-                case 0:
-                    i.setRGB(j + a, b + a, a);
-                    break;
-                case 1:
-                    i.setRGB(b + a, j + a, a);
-                    break;
-                case 2:
-                    i.setRGB(a, j + a, b + a);
-                    break;
-                case 3:
-                    i.setRGB(a, b + a, j + a);
-                    break;
-                case 4:
-                    i.setRGB(b + a, a, j + a);
-                    break;
-                case 5:
-                    i.setRGB(j + a, a, b + a);
-                    break
-            }
-        }
-        return i
-    },
-    setHSV: function(f, e, d) {
-        var g = this,
-            i, b, a;
-        f = (f % 360 + 360) % 360;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        d = d > 1 ? 1 : d < 0 ? 0 : d;
-        if (e === 0 || f === null) {
-            d *= 255;
-            g.setRGB(d, d, d)
-        } else {
-            f /= 60;
-            i = d * e;
-            b = i * (1 - Math.abs(f % 2 - 1));
-            a = d - i;
-            a *= 255;
-            i *= 255;
-            b *= 255;
-            switch (Math.floor(f)) {
-                case 0:
-                    g.setRGB(i + a, b + a, a);
-                    break;
-                case 1:
-                    g.setRGB(b + a, i + a, a);
-                    break;
-                case 2:
-                    g.setRGB(a, i + a, b + a);
-                    break;
-                case 3:
-                    g.setRGB(a, b + a, i + a);
-                    break;
-                case 4:
-                    g.setRGB(b + a, a, i + a);
-                    break;
-                case 5:
-                    g.setRGB(i + a, a, b + a);
-                    break
-            }
-        }
-        return g
-    },
-    createLighter: function(b) {
-        if (!b && b !== 0) {
-            b = this.lightnessFactor
-        }
-        var a = this.getHSL();
-        a[2] = Ext.Number.constrain(a[2] + b, 0, 1);
-        return Ext.draw.Color.fromHSL(a[0], a[1], a[2])
-    },
-    createDarker: function(a) {
-        if (!a && a !== 0) {
-            a = this.lightnessFactor
-        }
-        return this.createLighter(-a)
-    },
-    toString: function() {
-        var f = this,
-            c = Math.round;
-        if (f.a === 1) {
-            var e = c(f.r).toString(16),
-                d = c(f.g).toString(16),
-                a = c(f.b).toString(16);
-            e = (e.length === 1) ? "0" + e : e;
-            d = (d.length === 1) ? "0" + d : d;
-            a = (a.length === 1) ? "0" + a : a;
-            return ["#", e, d, a].join("")
-        } else {
-            return "rgba(" + [c(f.r), c(f.g), c(f.b), f.a === 0 ? 0 : f.a.toFixed(15)].join(", ") + ")"
-        }
-    },
-    toHex: function(b) {
-        if (Ext.isArray(b)) {
-            b = b[0]
-        }
-        if (!Ext.isString(b)) {
-            return ""
-        }
-        if (b.substr(0, 1) === "#") {
-            return b
-        }
-        var e = Ext.draw.Color.colorToHexRe.exec(b);
-        if (Ext.isArray(e)) {
-            var f = parseInt(e[2], 10),
-                d = parseInt(e[3], 10),
-                a = parseInt(e[4], 10),
-                c = a | (d << 8) | (f << 16);
-            return e[1] + "#" + ("000000" + c.toString(16)).slice(-6)
-        } else {
-            return ""
-        }
-    },
-    setFromString: function(j) {
-        var e, h, f, c, d = 1,
-            i = parseInt;
-        if (j === Ext.draw.Color.NONE) {
-            this.r = this.g = this.b = this.a = 0;
-            return this
-        }
-        if ((j.length === 4 || j.length === 7) && j.substr(0, 1) === "#") {
-            e = j.match(Ext.draw.Color.hexRe);
-            if (e) {
-                h = i(e[1], 16) >> 0;
-                f = i(e[2], 16) >> 0;
-                c = i(e[3], 16) >> 0;
-                if (j.length === 4) {
-                    h += (h * 16);
-                    f += (f * 16);
-                    c += (c * 16)
-                }
-            }
-        } else {
-            if ((e = j.match(Ext.draw.Color.rgbToHexRe))) {
-                h = +e[1];
-                f = +e[2];
-                c = +e[3]
-            } else {
-                if ((e = j.match(Ext.draw.Color.rgbaToHexRe))) {
-                    h = +e[1];
-                    f = +e[2];
-                    c = +e[3];
-                    d = +e[4]
-                } else {
-                    if (Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())) {
-                        return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])
-                    }
-                }
-            }
-        }
-        if (typeof h === "undefined") {
-            return this
-        }
-        this.r = h;
-        this.g = f;
-        this.b = c;
-        this.a = d;
-        return this
-    }
-}, function() {
-    var a = new this();
-    this.addStatics({
-        fly: function(f, e, c, d) {
-            switch (arguments.length) {
-                case 1:
-                    a.setFromString(f);
-                    break;
-                case 3:
-                case 4:
-                    a.setRGB(f, e, c, d);
-                    break;
-                default:
-                    return null
-            }
-            return a
-        },
-        ColorList: {
-            aliceblue: "#f0f8ff",
-            antiquewhite: "#faebd7",
-            aqua: "#00ffff",
-            aquamarine: "#7fffd4",
-            azure: "#f0ffff",
-            beige: "#f5f5dc",
-            bisque: "#ffe4c4",
-            black: "#000000",
-            blanchedalmond: "#ffebcd",
-            blue: "#0000ff",
-            blueviolet: "#8a2be2",
-            brown: "#a52a2a",
-            burlywood: "#deb887",
-            cadetblue: "#5f9ea0",
-            chartreuse: "#7fff00",
-            chocolate: "#d2691e",
-            coral: "#ff7f50",
-            cornflowerblue: "#6495ed",
-            cornsilk: "#fff8dc",
-            crimson: "#dc143c",
-            cyan: "#00ffff",
-            darkblue: "#00008b",
-            darkcyan: "#008b8b",
-            darkgoldenrod: "#b8860b",
-            darkgray: "#a9a9a9",
-            darkgreen: "#006400",
-            darkkhaki: "#bdb76b",
-            darkmagenta: "#8b008b",
-            darkolivegreen: "#556b2f",
-            darkorange: "#ff8c00",
-            darkorchid: "#9932cc",
-            darkred: "#8b0000",
-            darksalmon: "#e9967a",
-            darkseagreen: "#8fbc8f",
-            darkslateblue: "#483d8b",
-            darkslategray: "#2f4f4f",
-            darkturquoise: "#00ced1",
-            darkviolet: "#9400d3",
-            deeppink: "#ff1493",
-            deepskyblue: "#00bfff",
-            dimgray: "#696969",
-            dodgerblue: "#1e90ff",
-            firebrick: "#b22222",
-            floralwhite: "#fffaf0",
-            forestgreen: "#228b22",
-            fuchsia: "#ff00ff",
-            gainsboro: "#dcdcdc",
-            ghostwhite: "#f8f8ff",
-            gold: "#ffd700",
-            goldenrod: "#daa520",
-            gray: "#808080",
-            green: "#008000",
-            greenyellow: "#adff2f",
-            honeydew: "#f0fff0",
-            hotpink: "#ff69b4",
-            indianred: "#cd5c5c",
-            indigo: "#4b0082",
-            ivory: "#fffff0",
-            khaki: "#f0e68c",
-            lavender: "#e6e6fa",
-            lavenderblush: "#fff0f5",
-            lawngreen: "#7cfc00",
-            lemonchiffon: "#fffacd",
-            lightblue: "#add8e6",
-            lightcoral: "#f08080",
-            lightcyan: "#e0ffff",
-            lightgoldenrodyellow: "#fafad2",
-            lightgray: "#d3d3d3",
-            lightgrey: "#d3d3d3",
-            lightgreen: "#90ee90",
-            lightpink: "#ffb6c1",
-            lightsalmon: "#ffa07a",
-            lightseagreen: "#20b2aa",
-            lightskyblue: "#87cefa",
-            lightslategray: "#778899",
-            lightsteelblue: "#b0c4de",
-            lightyellow: "#ffffe0",
-            lime: "#00ff00",
-            limegreen: "#32cd32",
-            linen: "#faf0e6",
-            magenta: "#ff00ff",
-            maroon: "#800000",
-            mediumaquamarine: "#66cdaa",
-            mediumblue: "#0000cd",
-            mediumorchid: "#ba55d3",
-            mediumpurple: "#9370d8",
-            mediumseagreen: "#3cb371",
-            mediumslateblue: "#7b68ee",
-            mediumspringgreen: "#00fa9a",
-            mediumturquoise: "#48d1cc",
-            mediumvioletred: "#c71585",
-            midnightblue: "#191970",
-            mintcream: "#f5fffa",
-            mistyrose: "#ffe4e1",
-            moccasin: "#ffe4b5",
-            navajowhite: "#ffdead",
-            navy: "#000080",
-            oldlace: "#fdf5e6",
-            olive: "#808000",
-            olivedrab: "#6b8e23",
-            orange: "#ffa500",
-            orangered: "#ff4500",
-            orchid: "#da70d6",
-            palegoldenrod: "#eee8aa",
-            palegreen: "#98fb98",
-            paleturquoise: "#afeeee",
-            palevioletred: "#d87093",
-            papayawhip: "#ffefd5",
-            peachpuff: "#ffdab9",
-            peru: "#cd853f",
-            pink: "#ffc0cb",
-            plum: "#dda0dd",
-            powderblue: "#b0e0e6",
-            purple: "#800080",
-            red: "#ff0000",
-            rosybrown: "#bc8f8f",
-            royalblue: "#4169e1",
-            saddlebrown: "#8b4513",
-            salmon: "#fa8072",
-            sandybrown: "#f4a460",
-            seagreen: "#2e8b57",
-            seashell: "#fff5ee",
-            sienna: "#a0522d",
-            silver: "#c0c0c0",
-            skyblue: "#87ceeb",
-            slateblue: "#6a5acd",
-            slategray: "#708090",
-            snow: "#fffafa",
-            springgreen: "#00ff7f",
-            steelblue: "#4682b4",
-            tan: "#d2b48c",
-            teal: "#008080",
-            thistle: "#d8bfd8",
-            tomato: "#ff6347",
-            turquoise: "#40e0d0",
-            violet: "#ee82ee",
-            wheat: "#f5deb3",
-            white: "#ffffff",
-            whitesmoke: "#f5f5f5",
-            yellow: "#ffff00",
-            yellowgreen: "#9acd32"
-        },
-        fromHSL: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromHSV: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromString: function(b) {
-            return (new this(0, 0, 0, 0)).setFromString(b)
-        },
-        create: function(b) {
-            if (b instanceof this) {
-                return b
-            } else {
-                if (Ext.isArray(b)) {
-                    return new Ext.draw.Color(b[0], b[1], b[2], b[3])
-                } else {
-                    if (Ext.isString(b)) {
-                        return Ext.draw.Color.fromString(b)
-                    } else {
-                        if (arguments.length > 2) {
-                            return new Ext.draw.Color(arguments[0], arguments[1], arguments[2], arguments[3])
-                        } else {
-                            return new Ext.draw.Color(0, 0, 0, 0)
-                        }
-                    }
-                }
-            }
-        }
-    })
-});
-Ext.define("Ext.draw.sprite.AnimationParser", function() {
-    function a(d, c, b) {
-        return d + (c - d) * b
-    }
-    return {
-        singleton: true,
-        attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-        requires: ["Ext.draw.Color"],
-        color: {
-            parseInitial: function(c, b) {
-                if (Ext.isString(c)) {
-                    c = Ext.draw.Color.create(c)
-                }
-                if (Ext.isString(b)) {
-                    b = Ext.draw.Color.create(b)
-                }
-                if ((c instanceof Ext.draw.Color) && (b instanceof Ext.draw.Color)) {
-                    return [
-                        [c.r, c.g, c.b, c.a],
-                        [b.r, b.g, b.b, b.a]
-                    ]
-                } else {
-                    return [c || b, b || c]
-                }
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isArray(d) || !Ext.isArray(c)) {
-                    return c || d
-                } else {
-                    return [a(d[0], c[0], b), a(d[1], c[1], b), a(d[2], c[2], b), a(d[3], c[3], b)]
-                }
-            },
-            serve: function(c) {
-                var b = Ext.draw.Color.fly(c[0], c[1], c[2], c[3]);
-                return b.toString()
-            }
-        },
-        number: {
-            parse: function(b) {
-                return b === null ? null : +b
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        angle: {
-            parseInitial: function(c, b) {
-                if (b - c > Math.PI) {
-                    b -= Math.PI * 2
-                } else {
-                    if (b - c < -Math.PI) {
-                        b += Math.PI * 2
-                    }
-                }
-                return [c, b]
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        path: {
-            parseInitial: function(m, n) {
-                var c = m.toStripes(),
-                    o = n.toStripes(),
-                    e, d, k = c.length,
-                    p = o.length,
-                    h, f, b, g = o[p - 1],
-                    l = [g[g.length - 2], g[g.length - 1]];
-                for (e = k; e < p; e++) {
-                    c.push(c[k - 1].slice(0))
-                }
-                for (e = p; e < k; e++) {
-                    o.push(l.slice(0))
-                }
-                b = c.length;
-                o.path = n;
-                o.temp = new Ext.draw.Path();
-                for (e = 0; e < b; e++) {
-                    h = c[e];
-                    f = o[e];
-                    k = h.length;
-                    p = f.length;
-                    o.temp.commands.push("M");
-                    for (d = p; d < k; d += 6) {
-                        f.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    g = o[o.length - 1];
-                    l = [g[g.length - 2], g[g.length - 1]];
-                    for (d = k; d < p; d += 6) {
-                        h.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    for (e = 0; e < f.length; e++) {
-                        f[e] -= h[e]
-                    }
-                    for (e = 2; e < f.length; e += 6) {
-                        o.temp.commands.push("C")
-                    }
-                }
-                return [c, o]
-            },
-            compute: function(c, l, m) {
-                if (m >= 1) {
-                    return l.path
-                }
-                var e = 0,
-                    f = c.length,
-                    d = 0,
-                    b, k, h, n = l.temp.params,
-                    g = 0;
-                for (; e < f; e++) {
-                    k = c[e];
-                    h = l[e];
-                    b = k.length;
-                    for (d = 0; d < b; d++) {
-                        n[g++] = h[d] * m + k[d]
-                    }
-                }
-                return l.temp
-            }
-        },
-        data: {
-            compute: function(h, j, k, g) {
-                var m = h.length - 1,
-                    b = j.length - 1,
-                    e = Math.max(m, b),
-                    d, l, c;
-                if (!g || g === h) {
-                    g = []
-                }
-                g.length = e + 1;
-                for (c = 0; c <= e; c++) {
-                    d = h[Math.min(c, m)];
-                    l = j[Math.min(c, b)];
-                    if (Ext.isNumber(d)) {
-                        if (!Ext.isNumber(l)) {
-                            l = 0
-                        }
-                        g[c] = (l - d) * k + d
-                    } else {
-                        g[c] = l
-                    }
-                }
-                return g
-            }
-        },
-        text: {
-            compute: function(d, c, b) {
-                return d.substr(0, Math.round(d.length * (1 - b))) + c.substr(Math.round(c.length * (1 - b)))
-            }
-        },
-        limited: "number",
-        limited01: "number"
-    }
-});
-(function() {
-    if (!Ext.global.Float32Array) {
-        var a = function(d) {
-            if (typeof d === "number") {
-                this.length = d
-            } else {
-                if ("length" in d) {
-                    this.length = d.length;
-                    for (var c = 0, b = d.length; c < b; c++) {
-                        this[c] = +d[c]
-                    }
-                }
-            }
-        };
-        a.prototype = [];
-        Ext.global.Float32Array = a
-    }
-})();
-Ext.define("Ext.draw.Draw", {
-    singleton: true,
-    radian: Math.PI / 180,
-    pi2: Math.PI * 2,
-    reflectFn: function(b) {
-        return b
-    },
-    rad: function(a) {
-        return (a % 360) * this.radian
-    },
-    degrees: function(a) {
-        return (a / this.radian) % 360
-    },
-    isBBoxIntersect: function(b, a, c) {
-        c = c || 0;
-        return (Math.max(b.x, a.x) - c > Math.min(b.x + b.width, a.x + a.width)) || (Math.max(b.y, a.y) - c > Math.min(b.y + b.height, a.y + a.height))
-    },
-    isPointInBBox: function(a, c, b) {
-        return !!b && a >= b.x && a <= (b.x + b.width) && c >= b.y && c <= (b.y + b.height)
-    },
-    spline: function(m) {
-        var e, c, k = m.length,
-            b, h, l, f, a = 0,
-            g = new Float32Array(m.length),
-            n = new Float32Array(m.length * 3 - 2);
-        g[0] = 0;
-        g[k - 1] = 0;
-        for (e = 1; e < k - 1; e++) {
-            g[e] = (m[e + 1] + m[e - 1] - 2 * m[e]) - g[e - 1];
-            a = 1 / (4 - a);
-            g[e] *= a
-        }
-        for (e = k - 2; e > 0; e--) {
-            a = 3.732050807568877 + 48.248711305964385 / (-13.928203230275537 + Math.pow(0.07179676972449123, e));
-            g[e] -= g[e + 1] * a
-        }
-        f = m[0];
-        b = f - g[0];
-        for (e = 0, c = 0; e < k - 1; c += 3) {
-            l = f;
-            h = b;
-            e++;
-            f = m[e];
-            b = f - g[e];
-            n[c] = l;
-            n[c + 1] = (b + 2 * h) / 3;
-            n[c + 2] = (b * 2 + h) / 3
-        }
-        n[c] = f;
-        return n
-    },
-    getAnchors: function(e, d, i, h, t, s, o) {
-        o = o || 4;
-        var n = Math.PI,
-            p = n / 2,
-            k = Math.abs,
-            a = Math.sin,
-            b = Math.cos,
-            f = Math.atan,
-            r, q, g, j, m, l, v, u, c;
-        r = (i - e) / o;
-        q = (t - i) / o;
-        if ((h >= d && h >= s) || (h <= d && h <= s)) {
-            g = j = p
-        } else {
-            g = f((i - e) / k(h - d));
-            if (d < h) {
-                g = n - g
-            }
-            j = f((t - i) / k(h - s));
-            if (s < h) {
-                j = n - j
-            }
-        }
-        c = p - ((g + j) % (n * 2)) / 2;
-        if (c > p) {
-            c -= n
-        }
-        g += c;
-        j += c;
-        m = i - r * a(g);
-        l = h + r * b(g);
-        v = i + q * a(j);
-        u = h + q * b(j);
-        if ((h > d && l < d) || (h < d && l > d)) {
-            m += k(d - l) * (m - i) / (l - h);
-            l = d
-        }
-        if ((h > s && u < s) || (h < s && u > s)) {
-            v -= k(s - u) * (v - i) / (u - h);
-            u = s
-        }
-        return {
-            x1: m,
-            y1: l,
-            x2: v,
-            y2: u
-        }
-    },
-    smooth: function(l, j, o) {
-        var k = l.length,
-            h, g, c, b, q, p, n, m, f = [],
-            e = [],
-            d, a;
-        for (d = 0; d < k - 1; d++) {
-            h = l[d];
-            g = j[d];
-            if (d === 0) {
-                n = h;
-                m = g;
-                f.push(n);
-                e.push(m);
-                if (k === 1) {
-                    break
-                }
-            }
-            c = l[d + 1];
-            b = j[d + 1];
-            q = l[d + 2];
-            p = j[d + 2];
-            if (!Ext.isNumber(q + p)) {
-                f.push(n, c, c);
-                e.push(m, b, b);
-                break
-            }
-            a = this.getAnchors(h, g, c, b, q, p, o);
-            f.push(n, a.x1, c);
-            e.push(m, a.y1, b);
-            n = a.x2;
-            m = a.y2
-        }
-        return {
-            smoothX: f,
-            smoothY: e
-        }
-    },
-    beginUpdateIOS: Ext.os.is.iOS ? function() {
-        this.iosUpdateEl = Ext.getBody().createChild({
-            style: "position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"
-        })
-    } : Ext.emptyFn,
-    endUpdateIOS: function() {
-        this.iosUpdateEl = Ext.destroy(this.iosUpdateEl)
-    }
-});
-Ext.define("Ext.draw.gradient.Gradient", {
-    requires: ["Ext.draw.Color"],
-    isGradient: true,
-    config: {
-        stops: []
-    },
-    applyStops: function(f) {
-        var e = [],
-            d = f.length,
-            c, b, a;
-        for (c = 0; c < d; c++) {
-            b = f[c];
-            a = b.color;
-            if (!(a && a.isColor)) {
-                a = Ext.draw.Color.fly(a || Ext.draw.Color.NONE)
-            }
-            e.push({
-                offset: Math.min(1, Math.max(0, "offset" in b ? b.offset : b.position || 0)),
-                color: a.toString()
-            })
-        }
-        e.sort(function(h, g) {
-            return h.offset - g.offset
-        });
-        return e
-    },
-    onClassExtended: function(a, b) {
-        if (!b.alias && b.type) {
-            b.alias = "gradient." + b.type
-        }
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    generateGradient: Ext.emptyFn
-});
-Ext.define("Ext.draw.gradient.GradientDefinition", {
-    singleton: true,
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    gradients: {},
-    add: function(a) {
-        var b = this.gradients,
-            c, e, d;
-        for (c = 0, e = a.length; c < e; c++) {
-            d = a[c];
-            if (Ext.isString(d.id)) {
-                b[d.id] = d
-            }
-        }
-    },
-    get: function(d) {
-        var a = this.gradients,
-            b = d.match(this.urlStringRe),
-            c;
-        if (b && b[1] && (c = a[b[1]])) {
-            return c || d
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeParser", {
-    singleton: true,
-    attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-    requires: ["Ext.draw.Color", "Ext.draw.gradient.GradientDefinition"],
-    "default": Ext.identityFn,
-    string: function(a) {
-        return String(a)
-    },
-    number: function(a) {
-        if (Ext.isNumber(+a)) {
-            return a
-        }
-    },
-    angle: function(a) {
-        if (Ext.isNumber(a)) {
-            a %= Math.PI * 2;
-            if (a < -Math.PI) {
-                a += Math.PI * 2
-            } else {
-                if (a >= Math.PI) {
-                    a -= Math.PI * 2
-                }
-            }
-            return a
-        }
-    },
-    data: function(a) {
-        if (Ext.isArray(a)) {
-            return a.slice()
-        } else {
-            if (a instanceof Float32Array) {
-                return new Float32Array(a)
-            }
-        }
-    },
-    bool: function(a) {
-        return !!a
-    },
-    color: function(a) {
-        if (a instanceof Ext.draw.Color) {
-            return a.toString()
-        } else {
-            if (a instanceof Ext.draw.gradient.Gradient) {
-                return a
-            } else {
-                if (!a) {
-                    return Ext.draw.Color.NONE
-                } else {
-                    if (Ext.isString(a)) {
-                        if (a.substr(0, 3) === "url") {
-                            a = Ext.draw.gradient.GradientDefinition.get(a);
-                            if (Ext.isString(a)) {
-                                return a
-                            }
-                        } else {
-                            return Ext.draw.Color.fly(a).toString()
-                        }
-                    }
-                }
-            }
-        }
-        if (a.type === "linear") {
-            return Ext.create("Ext.draw.gradient.Linear", a)
-        } else {
-            if (a.type === "radial") {
-                return Ext.create("Ext.draw.gradient.Radial", a)
-            } else {
-                if (a.type === "pattern") {
-                    return Ext.create("Ext.draw.gradient.Pattern", a)
-                } else {
-                    return Ext.draw.Color.NONE
-                }
-            }
-        }
-    },
-    limited: function(a, b) {
-        return function(c) {
-            c = +c;
-            return Ext.isNumber(c) ? Math.min(Math.max(c, a), b) : undefined
-        }
-    },
-    limited01: function(a) {
-        a = +a;
-        return Ext.isNumber(a) ? Math.min(Math.max(a, 0), 1) : undefined
-    },
-    enums: function() {
-        var d = {},
-            a = Array.prototype.slice.call(arguments, 0),
-            b, c;
-        for (b = 0, c = a.length; b < c; b++) {
-            d[a[b]] = true
-        }
-        return function(e) {
-            return e in d ? e : undefined
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeDefinition", {
-    requires: ["Ext.draw.sprite.AttributeParser", "Ext.draw.sprite.AnimationParser"],
-    config: {
-        defaults: {
-            $value: {},
-            lazy: true
-        },
-        aliases: {},
-        animationProcessors: {},
-        processors: {
-            $value: {},
-            lazy: true
-        },
-        dirtyTriggers: {},
-        triggers: {},
-        updaters: {}
-    },
-    inheritableStatics: {
-        processorFactoryRe: /^(\w+)\(([\w\-,]*)\)$/
-    },
-    spriteClass: null,
-    constructor: function(a) {
-        var b = this;
-        b.initConfig(a)
-    },
-    applyDefaults: function(b, a) {
-        a = Ext.apply(a || {}, this.normalize(b));
-        return a
-    },
-    applyAliases: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    applyProcessors: function(e, i) {
-        this.getAnimationProcessors();
-        var j = i || {},
-            h = Ext.draw.sprite.AttributeParser,
-            a = this.self.processorFactoryRe,
-            g = {},
-            d, b, c, f;
-        for (b in e) {
-            f = e[b];
-            if (typeof f === "string") {
-                c = f.match(a);
-                if (c) {
-                    f = h[c[1]].apply(h, c[2].split(","))
-                } else {
-                    if (h[f]) {
-                        g[b] = f;
-                        d = true;
-                        f = h[f]
-                    }
-                }
-            }
-            j[b] = f
-        }
-        if (d) {
-            this.setAnimationProcessors(g)
-        }
-        return j
-    },
-    applyAnimationProcessors: function(c, a) {
-        var e = Ext.draw.sprite.AnimationParser,
-            b, d;
-        if (!a) {
-            a = {}
-        }
-        for (b in c) {
-            d = c[b];
-            if (d === "none") {
-                a[b] = null
-            } else {
-                if (Ext.isString(d) && !(b in a)) {
-                    if (d in e) {
-                        while (Ext.isString(e[d])) {
-                            d = e[d]
-                        }
-                        a[b] = e[d]
-                    }
-                } else {
-                    if (Ext.isObject(d)) {
-                        a[b] = d
-                    }
-                }
-            }
-        }
-        return a
-    },
-    updateDirtyTriggers: function(a) {
-        this.setTriggers(a)
-    },
-    applyTriggers: function(b, c) {
-        if (!c) {
-            c = {}
-        }
-        for (var a in b) {
-            c[a] = b[a].split(",")
-        }
-        return c
-    },
-    applyUpdaters: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    batchedNormalize: function(f, n) {
-        if (!f) {
-            return {}
-        }
-        var j = this.getProcessors(),
-            d = this.getAliases(),
-            a = f.translation || f.translate,
-            o = {},
-            g, h, b, e, p, c, m, l, k;
-        if ("rotation" in f) {
-            p = f.rotation
-        } else {
-            p = ("rotate" in f) ? f.rotate : undefined
-        }
-        if ("scaling" in f) {
-            c = f.scaling
-        } else {
-            c = ("scale" in f) ? f.scale : undefined
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                o.scalingX = c;
-                o.scalingY = c
-            } else {
-                if ("x" in c) {
-                    o.scalingX = c.x
-                }
-                if ("y" in c) {
-                    o.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    o.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    o.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof p !== "undefined") {
-            if (Ext.isNumber(p)) {
-                p = Ext.draw.Draw.rad(p);
-                o.rotationRads = p
-            } else {
-                if ("rads" in p) {
-                    o.rotationRads = p.rads
-                } else {
-                    if ("degrees" in p) {
-                        if (Ext.isArray(p.degrees)) {
-                            o.rotationRads = Ext.Array.map(p.degrees, function(i) {
-                                return Ext.draw.Draw.rad(i)
-                            })
-                        } else {
-                            o.rotationRads = Ext.draw.Draw.rad(p.degrees)
-                        }
-                    }
-                }
-                if ("centerX" in p) {
-                    o.rotationCenterX = p.centerX
-                }
-                if ("centerY" in p) {
-                    o.rotationCenterY = p.centerY
-                }
-            }
-        }
-        if (typeof a !== "undefined") {
-            if ("x" in a) {
-                o.translationX = a.x
-            }
-            if ("y" in a) {
-                o.translationY = a.y
-            }
-        }
-        if ("matrix" in f) {
-            m = Ext.draw.Matrix.create(f.matrix);
-            k = m.split();
-            o.matrix = m;
-            o.rotationRads = k.rotation;
-            o.rotationCenterX = 0;
-            o.rotationCenterY = 0;
-            o.scalingX = k.scaleX;
-            o.scalingY = k.scaleY;
-            o.scalingCenterX = 0;
-            o.scalingCenterY = 0;
-            o.translationX = k.translateX;
-            o.translationY = k.translateY
-        }
-        for (b in f) {
-            e = f[b];
-            if (typeof e === "undefined") {
-                continue
-            } else {
-                if (Ext.isArray(e)) {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        o[b] = [];
-                        for (g = 0, h = e.length; g < h; g++) {
-                            l = j[b].call(this, e[g]);
-                            if (typeof l !== "undefined") {
-                                o[b][g] = l
-                            }
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                } else {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        e = j[b].call(this, e);
-                        if (typeof e !== "undefined") {
-                            o[b] = e
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                }
-            }
-        }
-        return o
-    },
-    normalize: function(i, j) {
-        if (!i) {
-            return {}
-        }
-        var f = this.getProcessors(),
-            d = this.getAliases(),
-            a = i.translation || i.translate,
-            k = {},
-            b, e, l, c, h, g;
-        if ("rotation" in i) {
-            l = i.rotation
-        } else {
-            l = ("rotate" in i) ? i.rotate : undefined
-        }
-        if ("scaling" in i) {
-            c = i.scaling
-        } else {
-            c = ("scale" in i) ? i.scale : undefined
-        }
-        if (a) {
-            if ("x" in a) {
-                k.translationX = a.x
-            }
-            if ("y" in a) {
-                k.translationY = a.y
-            }
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                k.scalingX = c;
-                k.scalingY = c
-            } else {
-                if ("x" in c) {
-                    k.scalingX = c.x
-                }
-                if ("y" in c) {
-                    k.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    k.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    k.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof l !== "undefined") {
-            if (Ext.isNumber(l)) {
-                l = Ext.draw.Draw.rad(l);
-                k.rotationRads = l
-            } else {
-                if ("rads" in l) {
-                    k.rotationRads = l.rads
-                } else {
-                    if ("degrees" in l) {
-                        k.rotationRads = Ext.draw.Draw.rad(l.degrees)
-                    }
-                }
-                if ("centerX" in l) {
-                    k.rotationCenterX = l.centerX
-                }
-                if ("centerY" in l) {
-                    k.rotationCenterY = l.centerY
-                }
-            }
-        }
-        if ("matrix" in i) {
-            h = Ext.draw.Matrix.create(i.matrix);
-            g = h.split();
-            k.matrix = h;
-            k.rotationRads = g.rotation;
-            k.rotationCenterX = 0;
-            k.rotationCenterY = 0;
-            k.scalingX = g.scaleX;
-            k.scalingY = g.scaleY;
-            k.scalingCenterX = 0;
-            k.scalingCenterY = 0;
-            k.translationX = g.translateX;
-            k.translationY = g.translateY
-        }
-        for (b in i) {
-            e = i[b];
-            if (typeof e === "undefined") {
-                continue
-            }
-            if (b in d) {
-                b = d[b]
-            }
-            if (b in f) {
-                e = f[b].call(this, e);
-                if (typeof e !== "undefined") {
-                    k[b] = e
-                }
-            } else {
-                if (j) {
-                    k[b] = e
-                }
-            }
-        }
-        return k
-    },
-    setBypassingNormalization: function(a, c, b) {
-        return c.pushDown(a, b)
-    },
-    set: function(a, c, b) {
-        b = this.normalize(b);
-        return this.setBypassingNormalization(a, c, b)
-    }
-});
-Ext.define("Ext.draw.Matrix", {
-    isMatrix: true,
-    statics: {
-        createAffineMatrixFromTwoPair: function(h, t, g, s, k, o, i, j) {
-            var v = g - h,
-                u = s - t,
-                e = i - k,
-                q = j - o,
-                d = 1 / (v * v + u * u),
-                p = v * e + u * q,
-                n = e * u - v * q,
-                m = -p * h - n * t,
-                l = n * h - p * t;
-            return new this(p * d, -n * d, n * d, p * d, m * d + k, l * d + o)
-        },
-        createPanZoomFromTwoPair: function(q, e, p, c, h, s, n, g) {
-            if (arguments.length === 2) {
-                return this.createPanZoomFromTwoPair.apply(this, q.concat(e))
-            }
-            var k = p - q,
-                j = c - e,
-                d = (q + p) * 0.5,
-                b = (e + c) * 0.5,
-                o = n - h,
-                a = g - s,
-                f = (h + n) * 0.5,
-                l = (s + g) * 0.5,
-                m = k * k + j * j,
-                i = o * o + a * a,
-                t = Math.sqrt(i / m);
-            return new this(t, 0, 0, t, f - t * d, l - t * b)
-        },
-        fly: (function() {
-            var a = null,
-                b = function(c) {
-                    a.elements = c;
-                    return a
-                };
-            return function(c) {
-                if (!a) {
-                    a = new Ext.draw.Matrix()
-                }
-                a.elements = c;
-                Ext.draw.Matrix.fly = b;
-                return a
-            }
-        })(),
-        create: function(a) {
-            if (a instanceof this) {
-                return a
-            }
-            return new this(a)
-        }
-    },
-    constructor: function(e, d, a, f, c, b) {
-        if (e && e.length === 6) {
-            this.elements = e.slice()
-        } else {
-            if (e !== undefined) {
-                this.elements = [e, d, a, f, c, b]
-            } else {
-                this.elements = [1, 0, 0, 1, 0, 0]
-            }
-        }
-    },
-    prepend: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + h * j;
-        b[1] = l * d + g * j;
-        b[2] = a * e + h * c;
-        b[3] = l * e + g * c;
-        b[4] = a * i + h * f + m;
-        b[5] = l * i + g * f + k;
-        return this
-    },
-    prependMatrix: function(a) {
-        return this.prepend.apply(this, a.elements)
-    },
-    append: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + l * e;
-        b[1] = a * j + l * c;
-        b[2] = h * d + g * e;
-        b[3] = h * j + g * c;
-        b[4] = m * d + k * e + i;
-        b[5] = m * j + k * c + f;
-        return this
-    },
-    appendMatrix: function(a) {
-        return this.append.apply(this, a.elements)
-    },
-    set: function(f, e, a, g, c, b) {
-        var d = this.elements;
-        d[0] = f;
-        d[1] = e;
-        d[2] = a;
-        d[3] = g;
-        d[4] = c;
-        d[5] = b;
-        return this
-    },
-    inverse: function(i) {
-        var g = this.elements,
-            o = g[0],
-            m = g[1],
-            l = g[2],
-            k = g[3],
-            j = g[4],
-            h = g[5],
-            n = 1 / (o * k - m * l);
-        o *= n;
-        m *= n;
-        l *= n;
-        k *= n;
-        if (i) {
-            i.set(k, -m, -l, o, l * h - k * j, m * j - o * h);
-            return i
-        } else {
-            return new Ext.draw.Matrix(k, -m, -l, o, l * h - k * j, m * j - o * h)
-        }
-    },
-    translate: function(a, c, b) {
-        if (b) {
-            return this.prepend(1, 0, 0, 1, a, c)
-        } else {
-            return this.append(1, 0, 0, 1, a, c)
-        }
-    },
-    scale: function(f, e, c, a, b) {
-        var d = this;
-        if (e == null) {
-            e = f
-        }
-        if (c === undefined) {
-            c = 0
-        }
-        if (a === undefined) {
-            a = 0
-        }
-        if (b) {
-            return d.prepend(f, 0, 0, e, c - c * f, a - a * e)
-        } else {
-            return d.append(f, 0, 0, e, c - c * f, a - a * e)
-        }
-    },
-    rotate: function(g, e, c, b) {
-        var d = this,
-            f = Math.cos(g),
-            a = Math.sin(g);
-        e = e || 0;
-        c = c || 0;
-        if (b) {
-            return d.prepend(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        } else {
-            return d.append(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        }
-    },
-    rotateFromVector: function(a, h, c) {
-        var e = this,
-            g = Math.sqrt(a * a + h * h),
-            f = a / g,
-            b = h / g;
-        if (c) {
-            return e.prepend(f, b, -b, f, 0, 0)
-        } else {
-            return e.append(f, b, -b, f, 0, 0)
-        }
-    },
-    clone: function() {
-        return new Ext.draw.Matrix(this.elements)
-    },
-    flipX: function() {
-        return this.append(-1, 0, 0, 1, 0, 0)
-    },
-    flipY: function() {
-        return this.append(1, 0, 0, -1, 0, 0)
-    },
-    skewX: function(a) {
-        return this.append(1, 0, Math.tan(a), 1, 0, 0)
-    },
-    skewY: function(a) {
-        return this.append(1, Math.tan(a), 0, 1, 0, 0)
-    },
-    shearX: function(a) {
-        return this.append(1, 0, a, 1, 0, 0)
-    },
-    shearY: function(a) {
-        return this.append(1, a, 0, 1, 0, 0)
-    },
-    reset: function() {
-        return this.set(1, 0, 0, 1, 0, 0)
-    },
-    precisionCompensate: function(j, g) {
-        var c = this.elements,
-            f = c[0],
-            e = c[1],
-            i = c[2],
-            h = c[3],
-            d = c[4],
-            b = c[5],
-            a = e * i - f * h;
-        g.b = j * e / f;
-        g.c = j * i / h;
-        g.d = j;
-        g.xx = f / j;
-        g.yy = h / j;
-        g.dx = (b * f * i - d * f * h) / a / j;
-        g.dy = (d * e * h - b * f * h) / a / j
-    },
-    precisionCompensateRect: function(j, g) {
-        var b = this.elements,
-            f = b[0],
-            e = b[1],
-            i = b[2],
-            h = b[3],
-            c = b[4],
-            a = b[5],
-            d = i / f;
-        g.b = j * e / f;
-        g.c = j * d;
-        g.d = j * h / f;
-        g.xx = f / j;
-        g.yy = f / j;
-        g.dx = (a * i - c * h) / (e * d - h) / j;
-        g.dy = -(a * f - c * e) / (e * d - h) / j
-    },
-    x: function(a, c) {
-        var b = this.elements;
-        return a * b[0] + c * b[2] + b[4]
-    },
-    y: function(a, c) {
-        var b = this.elements;
-        return a * b[1] + c * b[3] + b[5]
-    },
-    get: function(b, a) {
-        return +this.elements[b + a * 2].toFixed(4)
-    },
-    transformPoint: function(b) {
-        var c = this.elements,
-            a, d;
-        if (b.isPoint) {
-            a = b.x;
-            d = b.y
-        } else {
-            a = b[0];
-            d = b[1]
-        }
-        return [a * c[0] + d * c[2] + c[4], a * c[1] + d * c[3] + c[5]]
-    },
-    transformBBox: function(q, i, j) {
-        var b = this.elements,
-            d = q.x,
-            r = q.y,
-            g = q.width * 0.5,
-            o = q.height * 0.5,
-            a = b[0],
-            s = b[1],
-            n = b[2],
-            k = b[3],
-            e = d + g,
-            c = r + o,
-            p, f, m;
-        if (i) {
-            g -= i;
-            o -= i;
-            m = [Math.sqrt(b[0] * b[0] + b[2] * b[2]), Math.sqrt(b[1] * b[1] + b[3] * b[3])];
-            p = Math.abs(g * a) + Math.abs(o * n) + Math.abs(m[0] * i);
-            f = Math.abs(g * s) + Math.abs(o * k) + Math.abs(m[1] * i)
-        } else {
-            p = Math.abs(g * a) + Math.abs(o * n);
-            f = Math.abs(g * s) + Math.abs(o * k)
-        }
-        if (!j) {
-            j = {}
-        }
-        j.x = e * a + c * n + b[4] - p;
-        j.y = e * s + c * k + b[5] - f;
-        j.width = p + p;
-        j.height = f + f;
-        return j
-    },
-    transformList: function(e) {
-        var b = this.elements,
-            a = b[0],
-            h = b[2],
-            l = b[4],
-            k = b[1],
-            g = b[3],
-            j = b[5],
-            f = e.length,
-            c, d;
-        for (d = 0; d < f; d++) {
-            c = e[d];
-            e[d] = [c[0] * a + c[1] * h + l, c[0] * k + c[1] * g + j]
-        }
-        return e
-    },
-    isIdentity: function() {
-        var a = this.elements;
-        return a[0] === 1 && a[1] === 0 && a[2] === 0 && a[3] === 1 && a[4] === 0 && a[5] === 0
-    },
-    isEqual: function(a) {
-        var c = a && a.isMatrix ? a.elements : a,
-            b = this.elements;
-        return b[0] === c[0] && b[1] === c[1] && b[2] === c[2] && b[3] === c[3] && b[4] === c[4] && b[5] === c[5]
-    },
-    equals: function(a) {
-        return this.isEqual(a)
-    },
-    toArray: function() {
-        var a = this.elements;
-        return [a[0], a[2], a[4], a[1], a[3], a[5]]
-    },
-    toVerticalArray: function() {
-        return this.elements.slice()
-    },
-    toString: function() {
-        var a = this;
-        return [a.get(0, 0), a.get(0, 1), a.get(1, 0), a.get(1, 1), a.get(2, 0), a.get(2, 1)].join(",")
-    },
-    toContext: function(a) {
-        a.transform.apply(a, this.elements);
-        return this
-    },
-    toSvg: function() {
-        var a = this.elements;
-        return "matrix(" + a[0].toFixed(9) + "," + a[1].toFixed(9) + "," + a[2].toFixed(9) + "," + a[3].toFixed(9) + "," + a[4].toFixed(9) + "," + a[5].toFixed(9) + ")"
-    },
-    getScaleX: function() {
-        var a = this.elements;
-        return Math.sqrt(a[0] * a[0] + a[2] * a[2])
-    },
-    getScaleY: function() {
-        var a = this.elements;
-        return Math.sqrt(a[1] * a[1] + a[3] * a[3])
-    },
-    getXX: function() {
-        return this.elements[0]
-    },
-    getXY: function() {
-        return this.elements[1]
-    },
-    getYX: function() {
-        return this.elements[2]
-    },
-    getYY: function() {
-        return this.elements[3]
-    },
-    getDX: function() {
-        return this.elements[4]
-    },
-    getDY: function() {
-        return this.elements[5]
-    },
-    split: function() {
-        var b = this.elements,
-            d = b[0],
-            c = b[1],
-            e = b[3],
-            a = {
-                translateX: b[4],
-                translateY: b[5]
-            };
-        a.rotate = a.rotation = Math.atan2(c, d);
-        a.scaleX = d / Math.cos(a.rotate);
-        a.scaleY = e / d * a.scaleX;
-        return a
-    }
-}, function() {
-    function b(e, c, d) {
-        e[c] = {
-            get: function() {
-                return this.elements[d]
-            },
-            set: function(f) {
-                this.elements[d] = f
-            }
-        }
-    }
-    if (Object.defineProperties) {
-        var a = {};
-        b(a, "a", 0);
-        b(a, "b", 1);
-        b(a, "c", 2);
-        b(a, "d", 3);
-        b(a, "e", 4);
-        b(a, "f", 5);
-        Object.defineProperties(this.prototype, a)
-    }
-    this.prototype.multiply = this.prototype.appendMatrix
-});
-Ext.define("Ext.draw.modifier.Modifier", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        previous: null,
-        next: null,
-        sprite: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    updateNext: function(a) {
-        if (a) {
-            a.setPrevious(this)
-        }
-    },
-    updatePrevious: function(a) {
-        if (a) {
-            a.setNext(this)
-        }
-    },
-    prepareAttributes: function(a) {
-        if (this._previous) {
-            this._previous.prepareAttributes(a)
-        }
-    },
-    popUp: function(a, b) {
-        if (this._next) {
-            this._next.popUp(a, b)
-        } else {
-            Ext.apply(a, b)
-        }
-    },
-    pushDown: function(a, c) {
-        if (this._previous) {
-            return this._previous.pushDown(a, c)
-        } else {
-            for (var b in c) {
-                if (c[b] === a[b]) {
-                    delete c[b]
-                }
-            }
-            return c
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Target", {
-    requires: ["Ext.draw.Matrix"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.target",
-    statics: {
-        uniqueId: 0
-    },
-    prepareAttributes: function(a) {
-        var b = this.getPrevious();
-        if (b) {
-            b.prepareAttributes(a)
-        }
-        a.attributeId = "attribute-" + Ext.draw.modifier.Target.uniqueId++;
-        if (!a.hasOwnProperty("canvasAttributes")) {
-            a.bbox = {
-                plain: {
-                    dirty: true
-                },
-                transform: {
-                    dirty: true
-                }
-            };
-            a.dirty = true;
-            a.pendingUpdaters = {};
-            a.canvasAttributes = {};
-            a.matrix = new Ext.draw.Matrix();
-            a.inverseMatrix = new Ext.draw.Matrix()
-        }
-    },
-    applyChanges: function(f, k) {
-        Ext.apply(f, k);
-        var l = this.getSprite(),
-            o = f.pendingUpdaters,
-            h = l.self.def.getTriggers(),
-            p, a, m, b, e, n, d, c, g;
-        for (b in k) {
-            e = true;
-            if ((p = h[b])) {
-                l.scheduleUpdaters(f, p, [b])
-            }
-            if (f.template && k.removeFromInstance && k.removeFromInstance[b]) {
-                delete f[b]
-            }
-        }
-        if (!e) {
-            return
-        }
-        if (o.canvas) {
-            n = o.canvas;
-            delete o.canvas;
-            for (d = 0, g = n.length; d < g; d++) {
-                b = n[d];
-                f.canvasAttributes[b] = f[b]
-            }
-        }
-        if (f.hasOwnProperty("children")) {
-            a = f.children;
-            for (d = 0, g = a.length; d < g; d++) {
-                m = a[d];
-                Ext.apply(m.pendingUpdaters, o);
-                if (n) {
-                    for (c = 0; c < n.length; c++) {
-                        b = n[c];
-                        m.canvasAttributes[b] = m[b]
-                    }
-                }
-                l.callUpdaters(m)
-            }
-        }
-        l.setDirty(true);
-        l.callUpdaters(f)
-    },
-    popUp: function(a, b) {
-        this.applyChanges(a, b)
-    },
-    pushDown: function(a, b) {
-        var c = this.getPrevious();
-        if (c) {
-            b = c.pushDown(a, b)
-        }
-        this.applyChanges(a, b);
-        return b
-    }
-});
-Ext.define("Ext.draw.TimingFunctions", function() {
-    var g = Math.pow,
-        j = Math.sin,
-        m = Math.cos,
-        l = Math.sqrt,
-        e = Math.PI,
-        b = ["quad", "cube", "quart", "quint"],
-        c = {
-            pow: function(o, i) {
-                return g(o, i || 6)
-            },
-            expo: function(i) {
-                return g(2, 8 * (i - 1))
-            },
-            circ: function(i) {
-                return 1 - l(1 - i * i)
-            },
-            sine: function(i) {
-                return 1 - j((1 - i) * e / 2)
-            },
-            back: function(i, o) {
-                o = o || 1.616;
-                return i * i * ((o + 1) * i - o)
-            },
-            bounce: function(q) {
-                for (var o = 0, i = 1; 1; o += i, i /= 2) {
-                    if (q >= (7 - 4 * o) / 11) {
-                        return i * i - g((11 - 6 * o - 11 * q) / 4, 2)
-                    }
-                }
-            },
-            elastic: function(o, i) {
-                return g(2, 10 * --o) * m(20 * o * e * (i || 1) / 3)
-            }
-        },
-        k = {},
-        a, f, d;
-
-    function h(i) {
-        return function(o) {
-            return g(o, i)
-        }
-    }
-
-    function n(i, o) {
-        k[i + "In"] = function(p) {
-            return o(p)
-        };
-        k[i + "Out"] = function(p) {
-            return 1 - o(1 - p)
-        };
-        k[i + "InOut"] = function(p) {
-            return (p <= 0.5) ? o(2 * p) / 2 : (2 - o(2 * (1 - p))) / 2
-        }
-    }
-    for (d = 0, f = b.length; d < f; ++d) {
-        c[b[d]] = h(d + 2)
-    }
-    for (a in c) {
-        n(a, c[a])
-    }
-    k.linear = Ext.identityFn;
-    k.easeIn = k.quadIn;
-    k.easeOut = k.quadOut;
-    k.easeInOut = k.quadInOut;
-    return {
-        singleton: true,
-        easingMap: k
-    }
-}, function(a) {
-    Ext.apply(a, a.easingMap)
-});
-Ext.define("Ext.draw.Animator", {
-    uses: ["Ext.draw.Draw"],
-    singleton: true,
-    frameCallbacks: {},
-    frameCallbackId: 0,
-    scheduled: 0,
-    frameStartTimeOffset: Ext.now(),
-    animations: [],
-    running: false,
-    animationTime: function() {
-        return Ext.AnimationQueue.frameStartTime - this.frameStartTimeOffset
-    },
-    add: function(b) {
-        var a = this;
-        if (!a.contains(b)) {
-            a.animations.push(b);
-            a.ignite();
-            if ("fireEvent" in b) {
-                b.fireEvent("animationstart", b)
-            }
-        }
-    },
-    remove: function(d) {
-        var c = this,
-            e = c.animations,
-            b = 0,
-            a = e.length;
-        for (; b < a; ++b) {
-            if (e[b] === d) {
-                e.splice(b, 1);
-                if ("fireEvent" in d) {
-                    d.fireEvent("animationend", d)
-                }
-                return
-            }
-        }
-    },
-    contains: function(a) {
-        return Ext.Array.indexOf(this.animations, a) > -1
-    },
-    empty: function() {
-        return this.animations.length === 0
-    },
-    step: function(d) {
-        var c = this,
-            f = c.animations,
-            e, a = 0,
-            b = f.length;
-        for (; a < b; a++) {
-            e = f[a];
-            e.step(d);
-            if (!e.animating) {
-                f.splice(a, 1);
-                a--;
-                b--;
-                if (e.fireEvent) {
-                    e.fireEvent("animationend", e)
-                }
-            }
-        }
-    },
-    schedule: function(c, a) {
-        a = a || this;
-        var b = "frameCallback" + (this.frameCallbackId++);
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a,
-            once: true
-        };
-        this.scheduled++;
-        Ext.draw.Animator.ignite();
-        return b
-    },
-    scheduleIf: function(e, b) {
-        b = b || this;
-        var c = Ext.draw.Animator.frameCallbacks,
-            a, d;
-        if (Ext.isString(e)) {
-            e = b[e]
-        }
-        for (d in c) {
-            a = c[d];
-            if (a.once && a.fn === e && a.scope === b) {
-                return null
-            }
-        }
-        return this.schedule(e, b)
-    },
-    cancel: function(a) {
-        if (Ext.draw.Animator.frameCallbacks[a] && Ext.draw.Animator.frameCallbacks[a].once) {
-            this.scheduled--;
-            delete Ext.draw.Animator.frameCallbacks[a]
-        }
-    },
-    addFrameCallback: function(c, a) {
-        a = a || this;
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        var b = "frameCallback" + (this.frameCallbackId++);
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a
-        };
-        return b
-    },
-    removeFrameCallback: function(a) {
-        delete Ext.draw.Animator.frameCallbacks[a]
-    },
-    fireFrameCallbacks: function() {
-        var c = this.frameCallbacks,
-            d, b, a;
-        for (d in c) {
-            a = c[d];
-            b = a.fn;
-            if (Ext.isString(b)) {
-                b = a.scope[b]
-            }
-            b.call(a.scope);
-            if (c[d] && a.once) {
-                this.scheduled--;
-                delete c[d]
-            }
-        }
-    },
-    handleFrame: function() {
-        this.step(this.animationTime());
-        this.fireFrameCallbacks();
-        if (!this.scheduled && this.empty()) {
-            Ext.AnimationQueue.stop(this.handleFrame, this);
-            this.running = false;
-            Ext.draw.Draw.endUpdateIOS()
-        }
-    },
-    ignite: function() {
-        if (!this.running) {
-            this.running = true;
-            Ext.AnimationQueue.start(this.handleFrame, this);
-            Ext.draw.Draw.beginUpdateIOS()
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Animation", {
-    requires: ["Ext.draw.TimingFunctions", "Ext.draw.Animator"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.animation",
-    config: {
-        easing: Ext.identityFn,
-        duration: 0,
-        customEasings: {},
-        customDurations: {},
-        customDuration: null
-    },
-    constructor: function(a) {
-        var b = this;
-        b.anyAnimation = b.anySpecialAnimations = false;
-        b.animating = 0;
-        b.animatingPool = [];
-        b.callParent([a])
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("timers")) {
-            a.animating = false;
-            a.timers = {};
-            a.animationOriginal = Ext.Object.chain(a);
-            a.animationOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.animationOriginal)
-        }
-    },
-    updateSprite: function(a) {
-        this.setConfig(a.config.fx)
-    },
-    updateDuration: function(a) {
-        this.anyAnimation = a > 0
-    },
-    applyEasing: function(a) {
-        if (typeof a === "string") {
-            a = Ext.draw.TimingFunctions.easingMap[a]
-        }
-        return a
-    },
-    applyCustomEasings: function(a, e) {
-        e = e || {};
-        var g, d, b, h, c, f;
-        for (d in a) {
-            g = true;
-            h = a[d];
-            b = d.split(",");
-            if (typeof h === "string") {
-                h = Ext.draw.TimingFunctions.easingMap[h]
-            }
-            for (c = 0, f = b.length; c < f; c++) {
-                e[b[c]] = h
-            }
-        }
-        if (g) {
-            this.anySpecialAnimations = g
-        }
-        return e
-    },
-    setEasingOn: function(a, e) {
-        a = Ext.Array.from(a).slice();
-        var c = {},
-            d = a.length,
-            b = 0;
-        for (; b < d; b++) {
-            c[a[b]] = e
-        }
-        this.setCustomEasings(c)
-    },
-    clearEasingOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customEasings[a[b]]
-        }
-    },
-    applyCustomDurations: function(g, h) {
-        h = h || {};
-        var e, c, f, a, b, d;
-        for (c in g) {
-            e = true;
-            f = g[c];
-            a = c.split(",");
-            for (b = 0, d = a.length; b < d; b++) {
-                h[a[b]] = f
-            }
-        }
-        if (e) {
-            this.anySpecialAnimations = e
-        }
-        return h
-    },
-    applyCustomDuration: function(a, b) {
-        if (a) {
-            this.getCustomDurations();
-            this.setCustomDurations(a)
-        }
-    },
-    setDurationOn: function(b, e) {
-        b = Ext.Array.from(b).slice();
-        var a = {},
-            c = 0,
-            d = b.length;
-        for (; c < d; c++) {
-            a[b[c]] = e
-        }
-        this.setCustomDurations(a)
-    },
-    clearDurationOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customDurations[a[b]]
-        }
-    },
-    setAnimating: function(a, b) {
-        var e = this,
-            d = e.animatingPool;
-        if (a.animating !== b) {
-            a.animating = b;
-            if (b) {
-                d.push(a);
-                if (e.animating === 0) {
-                    Ext.draw.Animator.add(e)
-                }
-                e.animating++
-            } else {
-                for (var c = d.length; c--;) {
-                    if (d[c] === a) {
-                        d.splice(c, 1)
-                    }
-                }
-                e.animating = d.length
-            }
-        }
-    },
-    setAttrs: function(r, t) {
-        var s = this,
-            m = r.timers,
-            h = s._sprite.self.def._animationProcessors,
-            f = s._easing,
-            e = s._duration,
-            j = s._customDurations,
-            i = s._customEasings,
-            g = s.anySpecialAnimations,
-            n = s.anyAnimation || g,
-            o = r.animationOriginal,
-            d = false,
-            k, u, l, p, c, q, a;
-        if (!n) {
-            for (u in t) {
-                if (r[u] === t[u]) {
-                    delete t[u]
-                } else {
-                    r[u] = t[u]
-                }
-                delete o[u];
-                delete m[u]
-            }
-            return t
-        } else {
-            for (u in t) {
-                l = t[u];
-                p = r[u];
-                if (l !== p && p !== undefined && p !== null && (c = h[u])) {
-                    q = f;
-                    a = e;
-                    if (g) {
-                        if (u in i) {
-                            q = i[u]
-                        }
-                        if (u in j) {
-                            a = j[u]
-                        }
-                    }
-                    if (p && p.isGradient || l && l.isGradient) {
-                        a = 0
-                    }
-                    if (a) {
-                        if (!m[u]) {
-                            m[u] = {}
-                        }
-                        k = m[u];
-                        k.start = 0;
-                        k.easing = q;
-                        k.duration = a;
-                        k.compute = c.compute;
-                        k.serve = c.serve || Ext.identityFn;
-                        k.remove = t.removeFromInstance && t.removeFromInstance[u];
-                        if (c.parseInitial) {
-                            var b = c.parseInitial(p, l);
-                            k.source = b[0];
-                            k.target = b[1]
-                        } else {
-                            if (c.parse) {
-                                k.source = c.parse(p);
-                                k.target = c.parse(l)
-                            } else {
-                                k.source = p;
-                                k.target = l
-                            }
-                        }
-                        o[u] = l;
-                        delete t[u];
-                        d = true;
-                        continue
-                    } else {
-                        delete o[u]
-                    }
-                } else {
-                    delete o[u]
-                }
-                delete m[u]
-            }
-        }
-        if (d && !r.animating) {
-            s.setAnimating(r, true)
-        }
-        return t
-    },
-    updateAttributes: function(g) {
-        if (!g.animating) {
-            return {}
-        }
-        var h = {},
-            e = false,
-            d = g.timers,
-            f = g.animationOriginal,
-            c = Ext.draw.Animator.animationTime(),
-            a, b, i;
-        if (g.lastUpdate === c) {
-            return null
-        }
-        for (a in d) {
-            b = d[a];
-            if (!b.start) {
-                b.start = c;
-                i = 0
-            } else {
-                i = (c - b.start) / b.duration
-            }
-            if (i >= 1) {
-                h[a] = f[a];
-                delete f[a];
-                if (d[a].remove) {
-                    h.removeFromInstance = h.removeFromInstance || {};
-                    h.removeFromInstance[a] = true
-                }
-                delete d[a]
-            } else {
-                h[a] = b.serve(b.compute(b.source, b.target, b.easing(i), g[a]));
-                e = true
-            }
-        }
-        g.lastUpdate = c;
-        this.setAnimating(g, e);
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.animationOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    },
-    step: function(g) {
-        var f = this,
-            c = f.animatingPool.slice(),
-            e = c.length,
-            b = 0,
-            a, d;
-        for (; b < e; b++) {
-            a = c[b];
-            d = f.updateAttributes(a);
-            if (d && f._next) {
-                f._next.popUp(a, d)
-            }
-        }
-    },
-    stop: function() {
-        this.step();
-        var d = this,
-            b = d.animatingPool,
-            a, c;
-        for (a = 0, c = b.length; a < c; a++) {
-            b[a].animating = false
-        }
-        d.animatingPool.length = 0;
-        d.animating = 0;
-        Ext.draw.Animator.remove(d)
-    },
-    destroy: function() {
-        this.animatingPool.length = 0;
-        this.animating = 0;
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.modifier.Highlight", {
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.highlight",
-    config: {
-        enabled: false,
-        highlightStyle: null
-    },
-    preFx: true,
-    applyHighlightStyle: function(b, a) {
-        a = a || {};
-        if (this.getSprite()) {
-            Ext.apply(a, this.getSprite().self.def.normalize(b))
-        } else {
-            Ext.apply(a, b)
-        }
-        return a
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("highlightOriginal")) {
-            a.highlighted = false;
-            a.highlightOriginal = Ext.Object.chain(a);
-            a.highlightOriginal.prototype = a;
-            a.highlightOriginal.removeFromInstance = {}
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.highlightOriginal)
-        }
-    },
-    updateSprite: function(b, a) {
-        if (b) {
-            if (this.getHighlightStyle()) {
-                this._highlightStyle = b.self.def.normalize(this.getHighlightStyle())
-            }
-            this.setHighlightStyle(b.config.highlight)
-        }
-        b.self.def.setConfig({
-            defaults: {
-                highlighted: false
-            },
-            processors: {
-                highlighted: "bool"
-            }
-        });
-        this.setSprite(b)
-    },
-    filterChanges: function(a, d) {
-        var e = this,
-            f = a.highlightOriginal,
-            c = e.getHighlightStyle(),
-            b;
-        if (a.highlighted) {
-            for (b in d) {
-                if (c.hasOwnProperty(b)) {
-                    f[b] = d[b];
-                    delete d[b]
-                }
-            }
-        }
-        for (b in d) {
-            if (b !== "highlighted" && f[b] === d[b]) {
-                delete d[b]
-            }
-        }
-        return d
-    },
-    pushDown: function(e, g) {
-        var f = this.getHighlightStyle(),
-            c = e.highlightOriginal,
-            i = c.removeFromInstance,
-            d, a, h, b;
-        if (g.hasOwnProperty("highlighted")) {
-            d = g.highlighted;
-            delete g.highlighted;
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g);
-            if (d !== e.highlighted) {
-                if (d) {
-                    for (a in f) {
-                        if (a in g) {
-                            c[a] = g[a]
-                        } else {
-                            h = e.template && e.template.ownAttr;
-                            if (h && !e.prototype.hasOwnProperty(a)) {
-                                i[a] = true;
-                                c[a] = h.animationOriginal[a]
-                            } else {
-                                b = c.timers[a];
-                                if (b && b.remove) {
-                                    i[a] = true
-                                }
-                                c[a] = e[a]
-                            }
-                        }
-                        if (c[a] !== f[a]) {
-                            g[a] = f[a]
-                        }
-                    }
-                } else {
-                    for (a in f) {
-                        if (!(a in g)) {
-                            g[a] = c[a]
-                        }
-                        delete c[a]
-                    }
-                    g.removeFromInstance = g.removeFromInstance || {};
-                    Ext.apply(g.removeFromInstance, i);
-                    c.removeFromInstance = {}
-                }
-                g.highlighted = d
-            }
-        } else {
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g)
-        }
-        return g
-    },
-    popUp: function(a, b) {
-        b = this.filterChanges(a, b);
-        Ext.draw.modifier.Modifier.prototype.popUp.call(this, a, b)
-    }
-});
-Ext.define("Ext.draw.sprite.Sprite", {
-    alias: "sprite.sprite",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.draw.Draw", "Ext.draw.gradient.Gradient", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.modifier.Target", "Ext.draw.modifier.Animation", "Ext.draw.modifier.Highlight"],
-    isSprite: true,
-    statics: {
-        defaultHitTestOptions: {
-            fill: true,
-            stroke: true
-        }
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                strokeStyle: "color",
-                fillStyle: "color",
-                strokeOpacity: "limited01",
-                fillOpacity: "limited01",
-                lineWidth: "number",
-                lineCap: "enums(butt,round,square)",
-                lineJoin: "enums(round,bevel,miter)",
-                lineDash: "data",
-                lineDashOffset: "number",
-                miterLimit: "number",
-                shadowColor: "color",
-                shadowOffsetX: "number",
-                shadowOffsetY: "number",
-                shadowBlur: "number",
-                globalAlpha: "limited01",
-                globalCompositeOperation: "enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",
-                hidden: "bool",
-                transformFillStroke: "bool",
-                zIndex: "number",
-                translationX: "number",
-                translationY: "number",
-                rotationRads: "number",
-                rotationCenterX: "number",
-                rotationCenterY: "number",
-                scalingX: "number",
-                scalingY: "number",
-                scalingCenterX: "number",
-                scalingCenterY: "number",
-                constrainGradients: "bool"
-            },
-            aliases: {
-                stroke: "strokeStyle",
-                fill: "fillStyle",
-                color: "fillStyle",
-                "stroke-width": "lineWidth",
-                "stroke-linecap": "lineCap",
-                "stroke-linejoin": "lineJoin",
-                "stroke-miterlimit": "miterLimit",
-                "text-anchor": "textAlign",
-                opacity: "globalAlpha",
-                translateX: "translationX",
-                translateY: "translationY",
-                rotateRads: "rotationRads",
-                rotateCenterX: "rotationCenterX",
-                rotateCenterY: "rotationCenterY",
-                scaleX: "scalingX",
-                scaleY: "scalingY",
-                scaleCenterX: "scalingCenterX",
-                scaleCenterY: "scalingCenterY"
-            },
-            defaults: {
-                hidden: false,
-                zIndex: 0,
-                strokeStyle: "none",
-                fillStyle: "none",
-                lineWidth: 1,
-                lineDash: [],
-                lineDashOffset: 0,
-                lineCap: "butt",
-                lineJoin: "miter",
-                miterLimit: 10,
-                shadowColor: "none",
-                shadowOffsetX: 0,
-                shadowOffsetY: 0,
-                shadowBlur: 0,
-                globalAlpha: 1,
-                strokeOpacity: 1,
-                fillOpacity: 1,
-                transformFillStroke: false,
-                translationX: 0,
-                translationY: 0,
-                rotationRads: 0,
-                rotationCenterX: null,
-                rotationCenterY: null,
-                scalingX: 1,
-                scalingY: 1,
-                scalingCenterX: null,
-                scalingCenterY: null,
-                constrainGradients: false
-            },
-            triggers: {
-                zIndex: "zIndex",
-                globalAlpha: "canvas",
-                globalCompositeOperation: "canvas",
-                transformFillStroke: "canvas",
-                strokeStyle: "canvas",
-                fillStyle: "canvas",
-                strokeOpacity: "canvas",
-                fillOpacity: "canvas",
-                lineWidth: "canvas",
-                lineCap: "canvas",
-                lineJoin: "canvas",
-                lineDash: "canvas",
-                lineDashOffset: "canvas",
-                miterLimit: "canvas",
-                shadowColor: "canvas",
-                shadowOffsetX: "canvas",
-                shadowOffsetY: "canvas",
-                shadowBlur: "canvas",
-                translationX: "transform",
-                translationY: "transform",
-                rotationRads: "transform",
-                rotationCenterX: "transform",
-                rotationCenterY: "transform",
-                scalingX: "transform",
-                scalingY: "transform",
-                scalingCenterX: "transform",
-                scalingCenterY: "transform",
-                constrainGradients: "canvas"
-            },
-            updaters: {
-                bbox: "bboxUpdater",
-                zIndex: function(a) {
-                    a.dirtyZIndex = true
-                },
-                transform: function(a) {
-                    a.dirtyTransform = true;
-                    a.bbox.transform.dirty = true
-                }
-            }
-        }
-    },
-    config: {
-        parent: null,
-        surface: null
-    },
-    onClassExtended: function(d, c) {
-        var b = d.superclass.self.def.initialConfig,
-            e = c.inheritableStatics && c.inheritableStatics.def,
-            a;
-        if (e) {
-            a = Ext.Object.merge({}, b, e);
-            d.def = new Ext.draw.sprite.AttributeDefinition(a);
-            delete c.inheritableStatics.def
-        } else {
-            d.def = new Ext.draw.sprite.AttributeDefinition(b)
-        }
-        d.def.spriteClass = d
-    },
-    constructor: function(b) {
-        var d = this,
-            c = d.self.def,
-            e = c.getDefaults(),
-            a;
-        b = Ext.isObject(b) ? b : {};
-        d.id = b.id || Ext.id(null, "ext-sprite-");
-        d.attr = {};
-        d.mixins.observable.constructor.apply(d, arguments);
-        a = Ext.Array.from(b.modifiers, true);
-        d.prepareModifiers(a);
-        d.initializeAttributes();
-        d.setAttributes(e, true);
-        d.setAttributes(b)
-    },
-    getDirty: function() {
-        return this.attr.dirty
-    },
-    setDirty: function(b) {
-        this.attr.dirty = b;
-        if (b) {
-            var a = this.getParent();
-            if (a) {
-                a.setDirty(true)
-            }
-        }
-    },
-    addModifier: function(a, b) {
-        var c = this;
-        if (!(a instanceof Ext.draw.modifier.Modifier)) {
-            a = Ext.factory(a, null, null, "modifier")
-        }
-        a.setSprite(c);
-        if (a.preFx || a.config && a.config.preFx) {
-            if (c.fx.getPrevious()) {
-                c.fx.getPrevious().setNext(a)
-            }
-            a.setNext(c.fx)
-        } else {
-            c.topModifier.getPrevious().setNext(a);
-            a.setNext(c.topModifier)
-        }
-        if (b) {
-            c.initializeAttributes()
-        }
-        return a
-    },
-    prepareModifiers: function(d) {
-        var c = this,
-            a, b;
-        c.topModifier = new Ext.draw.modifier.Target({
-            sprite: c
-        });
-        c.fx = new Ext.draw.modifier.Animation({
-            sprite: c
-        });
-        c.fx.setNext(c.topModifier);
-        for (a = 0, b = d.length; a < b; a++) {
-            c.addModifier(d[a], false)
-        }
-    },
-    getAnimation: function() {
-        return this.fx
-    },
-    setAnimation: function(a) {
-        this.fx.setConfig(a)
-    },
-    initializeAttributes: function() {
-        this.topModifier.prepareAttributes(this.attr)
-    },
-    callUpdaters: function(d) {
-        var e = this,
-            h = d.pendingUpdaters,
-            i = e.self.def.getUpdaters(),
-            c = false,
-            a = false,
-            b, g, f;
-        e.callUpdaters = Ext.emptyFn;
-        do {
-            c = false;
-            for (g in h) {
-                c = true;
-                b = h[g];
-                delete h[g];
-                f = i[g];
-                if (typeof f === "string") {
-                    f = e[f]
-                }
-                if (f) {
-                    f.call(e, d, b)
-                }
-            }
-            a = a || c
-        } while (c);
-        delete e.callUpdaters;
-        if (a) {
-            e.setDirty(true)
-        }
-    },
-    scheduleUpdaters: function(a, e, c) {
-        var f;
-        if (c) {
-            for (var b = 0, d = e.length; b < d; b++) {
-                f = e[b];
-                this.scheduleUpdater(a, f, c)
-            }
-        } else {
-            for (f in e) {
-                c = e[f];
-                this.scheduleUpdater(a, f, c)
-            }
-        }
-    },
-    scheduleUpdater: function(a, c, b) {
-        b = b || [];
-        var d = a.pendingUpdaters;
-        if (c in d) {
-            if (b.length) {
-                d[c] = Ext.Array.merge(d[c], b)
-            }
-        } else {
-            d[c] = b
-        }
-    },
-    setAttributes: function(d, g, c) {
-        var a = this.attr,
-            b, e, f;
-        if (g) {
-            if (c) {
-                this.topModifier.pushDown(a, d)
-            } else {
-                f = {};
-                for (b in d) {
-                    e = d[b];
-                    if (e !== a[b]) {
-                        f[b] = e
-                    }
-                }
-                this.topModifier.pushDown(a, f)
-            }
-        } else {
-            this.topModifier.pushDown(a, this.self.def.normalize(d))
-        }
-    },
-    setAttributesBypassingNormalization: function(b, a) {
-        return this.setAttributes(b, true, a)
-    },
-    bboxUpdater: function(b) {
-        var c = b.rotationRads !== 0,
-            a = b.scalingX !== 1 || b.scalingY !== 1,
-            d = b.rotationCenterX === null || b.rotationCenterY === null,
-            e = b.scalingCenterX === null || b.scalingCenterY === null;
-        b.bbox.plain.dirty = true;
-        b.bbox.transform.dirty = true;
-        if (c && d || a && e) {
-            this.scheduleUpdater(b, "transform")
-        }
-    },
-    getBBox: function(d) {
-        var e = this,
-            a = e.attr,
-            f = a.bbox,
-            c = f.plain,
-            b = f.transform;
-        if (c.dirty) {
-            e.updatePlainBBox(c);
-            c.dirty = false
-        }
-        if (!d) {
-            e.applyTransformations();
-            if (b.dirty) {
-                e.updateTransformedBBox(b, c);
-                b.dirty = false
-            }
-            return b
-        }
-        return c
-    },
-    updatePlainBBox: Ext.emptyFn,
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, 0, a)
-    },
-    getBBoxCenter: function(a) {
-        var b = this.getBBox(a);
-        if (b) {
-            return [b.x + b.width * 0.5, b.y + b.height * 0.5]
-        } else {
-            return [0, 0]
-        }
-    },
-    hide: function() {
-        this.attr.hidden = true;
-        this.setDirty(true);
-        return this
-    },
-    show: function() {
-        this.attr.hidden = false;
-        this.setDirty(true);
-        return this
-    },
-    useAttributes: function(i, f) {
-        this.applyTransformations();
-        var d = this.attr,
-            h = d.canvasAttributes,
-            e = h.strokeStyle,
-            g = h.fillStyle,
-            b = h.lineDash,
-            c = h.lineDashOffset,
-            a;
-        if (e) {
-            if (e.isGradient) {
-                i.strokeStyle = "black";
-                i.strokeGradient = e
-            } else {
-                i.strokeGradient = false
-            }
-        }
-        if (g) {
-            if (g.isGradient) {
-                i.fillStyle = "black";
-                i.fillGradient = g
-            } else {
-                i.fillGradient = false
-            }
-        }
-        if (b) {
-            i.setLineDash(b)
-        }
-        if (Ext.isNumber(c + i.lineDashOffset)) {
-            i.lineDashOffset = c
-        }
-        for (a in h) {
-            if (h[a] !== undefined && h[a] !== i[a]) {
-                i[a] = h[a]
-            }
-        }
-        this.setGradientBBox(i, f)
-    },
-    setGradientBBox: function(b, c) {
-        var a = this.attr;
-        if (a.constrainGradients) {
-            b.setGradientBBox({
-                x: c[0],
-                y: c[1],
-                width: c[2],
-                height: c[3]
-            })
-        } else {
-            b.setGradientBBox(this.getBBox(a.transformFillStroke))
-        }
-    },
-    applyTransformations: function(b) {
-        if (!b && !this.attr.dirtyTransform) {
-            return
-        }
-        var r = this,
-            k = r.attr,
-            p = r.getBBoxCenter(true),
-            g = p[0],
-            f = p[1],
-            q = k.translationX,
-            o = k.translationY,
-            j = k.scalingX,
-            i = k.scalingY === null ? k.scalingX : k.scalingY,
-            m = k.scalingCenterX === null ? g : k.scalingCenterX,
-            l = k.scalingCenterY === null ? f : k.scalingCenterY,
-            s = k.rotationRads,
-            e = k.rotationCenterX === null ? g : k.rotationCenterX,
-            d = k.rotationCenterY === null ? f : k.rotationCenterY,
-            c = Math.cos(s),
-            a = Math.sin(s),
-            n, h;
-        if (j === 1 && i === 1) {
-            m = 0;
-            l = 0
-        }
-        if (s === 0) {
-            e = 0;
-            d = 0
-        }
-        n = m * (1 - j) - e;
-        h = l * (1 - i) - d;
-        k.matrix.elements = [c * j, a * j, -a * i, c * i, c * n - a * h + e + q, a * n + c * h + d + o];
-        k.matrix.inverse(k.inverseMatrix);
-        k.dirtyTransform = false;
-        k.bbox.transform.dirty = true
-    },
-    transform: function(b, c) {
-        var a = this.attr,
-            e = a.matrix,
-            d;
-        if (b && b.isMatrix) {
-            d = b.elements
-        } else {
-            d = b
-        }
-        e.prepend.apply(e, d.slice());
-        e.inverse(a.inverseMatrix);
-        if (c) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    updateTransformAttributes: function() {
-        var a = this.attr,
-            b = a.matrix.split();
-        a.rotationRads = b.rotate;
-        a.rotationCenterX = 0;
-        a.rotationCenterY = 0;
-        a.scalingX = b.scaleX;
-        a.scalingY = b.scaleY;
-        a.scalingCenterX = 0;
-        a.scalingCenterY = 0;
-        a.translationX = b.translateX;
-        a.translationY = b.translateY
-    },
-    resetTransform: function(b) {
-        var a = this.attr;
-        a.matrix.reset();
-        a.inverseMatrix.reset();
-        if (!b) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    setTransform: function(a, b) {
-        this.resetTransform(true);
-        this.transform.call(this, a, b);
-        return this
-    },
-    preRender: Ext.emptyFn,
-    render: Ext.emptyFn,
-    hitTest: function(b, c) {
-        if (this.isVisible()) {
-            var a = b[0],
-                f = b[1],
-                e = this.getBBox(),
-                d = e && a >= e.x && a <= (e.x + e.width) && f >= e.y && f <= (e.y + e.height);
-            if (d) {
-                return {
-                    sprite: this
-                }
-            }
-        }
-        return null
-    },
-    isVisible: function() {
-        var e = this.attr,
-            f = this.getParent(),
-            g = f && (f.isSurface || f.isVisible()),
-            d = g && !e.hidden && e.globalAlpha,
-            b = Ext.draw.Color.NONE,
-            a = Ext.draw.Color.RGBA_NONE,
-            c = e.fillOpacity && e.fillStyle !== b && e.fillStyle !== a,
-            i = e.strokeOpacity && e.strokeStyle !== b && e.strokeStyle !== a,
-            h = d && (c || i);
-        return !!h
-    },
-    repaint: function() {
-        var a = this.getSurface();
-        if (a) {
-            a.renderFrame()
-        }
-    },
-    remove: function() {
-        var a = this.getSurface();
-        if (a && a.isSurface) {
-            return a.remove(this)
-        }
-        return null
-    },
-    destroy: function() {
-        var b = this,
-            a = b.topModifier,
-            c;
-        while (a) {
-            c = a;
-            a = a.getPrevious();
-            c.destroy()
-        }
-        delete b.attr;
-        b.remove();
-        if (b.fireEvent("beforedestroy", b) !== false) {
-            b.fireEvent("destroy", b)
-        }
-        b.callParent()
-    }
-}, function() {
-    this.def = new Ext.draw.sprite.AttributeDefinition(this.def);
-    this.def.spriteClass = this
-});
-Ext.define("Ext.draw.Path", {
-    requires: ["Ext.draw.Draw"],
-    statics: {
-        pathRe: /,?([achlmqrstvxz]),?/gi,
-        pathRe2: /-/gi,
-        pathSplitRe: /\s|,/g
-    },
-    svgString: "",
-    constructor: function(a) {
-        var b = this;
-        b.commands = [];
-        b.params = [];
-        b.cursor = null;
-        b.startX = 0;
-        b.startY = 0;
-        if (a) {
-            b.fromSvgString(a)
-        }
-    },
-    clear: function() {
-        var a = this;
-        a.params.length = 0;
-        a.commands.length = 0;
-        a.cursor = null;
-        a.startX = 0;
-        a.startY = 0;
-        a.dirt()
-    },
-    dirt: function() {
-        this.svgString = ""
-    },
-    moveTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c]
-        }
-        b.params.push(a, c);
-        b.commands.push("M");
-        b.startX = a;
-        b.startY = c;
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    lineTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c];
-            b.params.push(a, c);
-            b.commands.push("M")
-        } else {
-            b.params.push(a, c);
-            b.commands.push("L")
-        }
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    bezierCurveTo: function(c, e, b, d, a, g) {
-        var f = this;
-        if (!f.cursor) {
-            f.moveTo(c, e)
-        }
-        f.params.push(c, e, b, d, a, g);
-        f.commands.push("C");
-        f.cursor[0] = a;
-        f.cursor[1] = g;
-        f.dirt()
-    },
-    quadraticCurveTo: function(b, e, a, d) {
-        var c = this;
-        if (!c.cursor) {
-            c.moveTo(b, e)
-        }
-        c.bezierCurveTo((2 * b + c.cursor[0]) / 3, (2 * e + c.cursor[1]) / 3, (2 * b + a) / 3, (2 * e + d) / 3, a, d)
-    },
-    closePath: function() {
-        var a = this;
-        if (a.cursor) {
-            a.cursor = null;
-            a.commands.push("Z");
-            a.dirt()
-        }
-    },
-    arcTo: function(A, f, z, d, j, i, v) {
-        var E = this;
-        if (i === undefined) {
-            i = j
-        }
-        if (v === undefined) {
-            v = 0
-        }
-        if (!E.cursor) {
-            E.moveTo(A, f);
-            return
-        }
-        if (j === 0 || i === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        z -= A;
-        d -= f;
-        var B = E.cursor[0] - A,
-            g = E.cursor[1] - f,
-            C = z * g - d * B,
-            b, a, l, r, k, q, x = Math.sqrt(B * B + g * g),
-            u = Math.sqrt(z * z + d * d),
-            t, e, c;
-        if (C === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        if (i !== j) {
-            b = Math.cos(v);
-            a = Math.sin(v);
-            l = b / j;
-            r = a / i;
-            k = -a / j;
-            q = b / i;
-            var D = l * B + r * g;
-            g = k * B + q * g;
-            B = D;
-            D = l * z + r * d;
-            d = k * z + q * d;
-            z = D
-        } else {
-            B /= j;
-            g /= i;
-            z /= j;
-            d /= i
-        }
-        e = B * u + z * x;
-        c = g * u + d * x;
-        t = 1 / (Math.sin(Math.asin(Math.abs(C) / (x * u)) * 0.5) * Math.sqrt(e * e + c * c));
-        e *= t;
-        c *= t;
-        var o = (e * B + c * g) / (B * B + g * g),
-            m = (e * z + c * d) / (z * z + d * d);
-        var n = B * o - e,
-            p = g * o - c,
-            h = z * m - e,
-            y = d * m - c,
-            w = Math.atan2(p, n),
-            s = Math.atan2(y, h);
-        if (C > 0) {
-            if (s < w) {
-                s += Math.PI * 2
-            }
-        } else {
-            if (w < s) {
-                w += Math.PI * 2
-            }
-        }
-        if (i !== j) {
-            e = b * e * j - a * c * i + A;
-            c = a * c * i + b * c * i + f;
-            E.lineTo(b * j * n - a * i * p + e, a * j * n + b * i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        } else {
-            e = e * j + A;
-            c = c * i + f;
-            E.lineTo(j * n + e, i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        }
-    },
-    ellipse: function(h, f, c, a, q, n, d, e) {
-        var o = this,
-            g = o.params,
-            b = g.length,
-            m, l, k;
-        if (d - n >= Math.PI * 2) {
-            o.ellipse(h, f, c, a, q, n, n + Math.PI, e);
-            o.ellipse(h, f, c, a, q, n + Math.PI, d, e);
-            return
-        }
-        if (!e) {
-            if (d < n) {
-                d += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, n, d)
-        } else {
-            if (n < d) {
-                n += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, d, n);
-            for (l = b, k = g.length - 2; l < k; l += 2, k -= 2) {
-                var p = g[l];
-                g[l] = g[k];
-                g[k] = p;
-                p = g[l + 1];
-                g[l + 1] = g[k + 1];
-                g[k + 1] = p
-            }
-        }
-        if (!o.cursor) {
-            o.cursor = [g[g.length - 2], g[g.length - 1]];
-            o.commands.push("M")
-        } else {
-            o.cursor[0] = g[g.length - 2];
-            o.cursor[1] = g[g.length - 1];
-            o.commands.push("L")
-        }
-        for (l = 2; l < m; l += 6) {
-            o.commands.push("C")
-        }
-        o.dirt()
-    },
-    arc: function(b, f, a, d, c, e) {
-        this.ellipse(b, f, a, a, 0, d, c, e)
-    },
-    rect: function(b, e, c, a) {
-        if (c == 0 || a == 0) {
-            return
-        }
-        var d = this;
-        d.moveTo(b, e);
-        d.lineTo(b + c, e);
-        d.lineTo(b + c, e + a);
-        d.lineTo(b, e + a);
-        d.closePath()
-    },
-    approximateArc: function(s, i, f, o, n, d, x, v) {
-        var e = Math.cos(d),
-            z = Math.sin(d),
-            k = Math.cos(x),
-            l = Math.sin(x),
-            q = e * k * o - z * l * n,
-            y = -e * l * o - z * k * n,
-            p = z * k * o + e * l * n,
-            w = -z * l * o + e * k * n,
-            m = Math.PI / 2,
-            r = 2,
-            j = q,
-            u = y,
-            h = p,
-            t = w,
-            b = 0.547443256150549,
-            C, g, A, a, B, c;
-        v -= x;
-        if (v < 0) {
-            v += Math.PI * 2
-        }
-        s.push(q + i, p + f);
-        while (v >= m) {
-            s.push(j + u * b + i, h + t * b + f, j * b + u + i, h * b + t + f, u + i, t + f);
-            r += 6;
-            v -= m;
-            C = j;
-            j = u;
-            u = -C;
-            C = h;
-            h = t;
-            t = -C
-        }
-        if (v) {
-            g = (0.3294738052815987 + 0.012120855841304373 * v) * v;
-            A = Math.cos(v);
-            a = Math.sin(v);
-            B = A + g * a;
-            c = a - g * A;
-            s.push(j + u * g + i, h + t * g + f, j * B + u * c + i, h * B + t * c + f, j * A + u * a + i, h * A + t * a + f);
-            r += 6
-        }
-        return r
-    },
-    arcSvg: function(j, h, r, m, w, t, c) {
-        if (j < 0) {
-            j = -j
-        }
-        if (h < 0) {
-            h = -h
-        }
-        var x = this,
-            u = x.cursor[0],
-            f = x.cursor[1],
-            a = (u - t) / 2,
-            y = (f - c) / 2,
-            d = Math.cos(r),
-            s = Math.sin(r),
-            o = a * d + y * s,
-            v = -a * s + y * d,
-            i = o / j,
-            g = v / h,
-            p = i * i + g * g,
-            e = (u + t) * 0.5,
-            b = (f + c) * 0.5,
-            l = 0,
-            k = 0;
-        if (p >= 1) {
-            p = Math.sqrt(p);
-            j *= p;
-            h *= p
-        } else {
-            p = Math.sqrt(1 / p - 1);
-            if (m === w) {
-                p = -p
-            }
-            l = p * j * g;
-            k = -p * h * i;
-            e += d * l - s * k;
-            b += s * l + d * k
-        }
-        var q = Math.atan2((v - k) / h, (o - l) / j),
-            n = Math.atan2((-v - k) / h, (-o - l) / j) - q;
-        if (w) {
-            if (n <= 0) {
-                n += Math.PI * 2
-            }
-        } else {
-            if (n >= 0) {
-                n -= Math.PI * 2
-            }
-        }
-        x.ellipse(e, b, j, h, r, q, q + n, 1 - w)
-    },
-    fromSvgString: function(e) {
-        if (!e) {
-            return
-        }
-        var m = this,
-            h, l = {
-                a: 7,
-                c: 6,
-                h: 1,
-                l: 2,
-                m: 2,
-                q: 4,
-                s: 4,
-                t: 2,
-                v: 1,
-                z: 0,
-                A: 7,
-                C: 6,
-                H: 1,
-                L: 2,
-                M: 2,
-                Q: 4,
-                S: 4,
-                T: 2,
-                V: 1,
-                Z: 0
-            },
-            k = "",
-            g, f, c = 0,
-            b = 0,
-            d = false,
-            j, n, a;
-        if (Ext.isString(e)) {
-            h = e.replace(Ext.draw.Path.pathRe, " $1 ").replace(Ext.draw.Path.pathRe2, " -").split(Ext.draw.Path.pathSplitRe)
-        } else {
-            if (Ext.isArray(e)) {
-                h = e.join(",").split(Ext.draw.Path.pathSplitRe)
-            }
-        }
-        for (j = 0, n = 0; j < h.length; j++) {
-            if (h[j] !== "") {
-                h[n++] = h[j]
-            }
-        }
-        h.length = n;
-        m.clear();
-        for (j = 0; j < h.length;) {
-            k = d;
-            d = h[j];
-            a = (d.toUpperCase() !== d);
-            j++;
-            switch (d) {
-                case "M":
-                    m.moveTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "L":
-                    m.lineTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "A":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c = +h[j + 5], b = +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "C":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(+h[j], +h[j + 1], g = +h[j + 2], f = +h[j + 3], c = +h[j + 4], b = +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "Z":
-                    m.closePath();
-                    break;
-                case "m":
-                    m.moveTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "l":
-                    m.lineTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "a":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c += +h[j + 5], b += +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "c":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + (+h[j]), b + (+h[j + 1]), g = c + (+h[j + 2]), f = b + (+h[j + 3]), c += +h[j + 4], b += +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "z":
-                    m.closePath();
-                    break;
-                case "s":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "S":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = +h[j], f = +h[j + 1], c = (+h[j + 2]), b = (+h[j + 3]));
-                        j += 4
-                    }
-                    break;
-                case "q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "Q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = +h[j], f = +h[j + 1], c = +h[j + 2], b = +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "t":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c += +h[j + 1], b += +h[j + 2]);
-                        j += 2
-                    }
-                    break;
-                case "T":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c = (+h[j + 1]), b = (+h[j + 2]));
-                        j += 2
-                    }
-                    break;
-                case "h":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b);
-                        j++
-                    }
-                    break;
-                case "H":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b);
-                        j++
-                    }
-                    break;
-                case "v":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b += +h[j]);
-                        j++
-                    }
-                    break;
-                case "V":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b = +h[j]);
-                        j++
-                    }
-                    break
-            }
-        }
-    },
-    clone: function() {
-        var a = this,
-            b = new Ext.draw.Path();
-        b.params = a.params.slice(0);
-        b.commands = a.commands.slice(0);
-        b.cursor = a.cursor ? a.cursor.slice(0) : null;
-        b.startX = a.startX;
-        b.startY = a.startY;
-        b.svgString = a.svgString;
-        return b
-    },
-    transform: function(j) {
-        if (j.isIdentity()) {
-            return
-        }
-        var a = j.getXX(),
-            f = j.getYX(),
-            m = j.getDX(),
-            l = j.getXY(),
-            e = j.getYY(),
-            k = j.getDY(),
-            b = this.params,
-            c = 0,
-            d = b.length,
-            h, g;
-        for (; c < d; c += 2) {
-            h = b[c];
-            g = b[c + 1];
-            b[c] = h * a + g * f + m;
-            b[c + 1] = h * l + g * e + k
-        }
-        this.dirt()
-    },
-    getDimension: function(f) {
-        if (!f) {
-            f = {}
-        }
-        if (!this.commands || !this.commands.length) {
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var d = 0,
-            c = 0,
-            b = this.commands,
-            g = this.params,
-            e = b.length,
-            a, h;
-        for (; d < e; d++) {
-            switch (b[d]) {
-                case "M":
-                case "L":
-                    a = g[c];
-                    h = g[c + 1];
-                    f.left = Math.min(a, f.left);
-                    f.top = Math.min(h, f.top);
-                    f.right = Math.max(a, f.right);
-                    f.bottom = Math.max(h, f.bottom);
-                    c += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, a, h, g[c], g[c + 1], g[c + 2], g[c + 3], a = g[c + 4], h = g[c + 5]);
-                    c += 6;
-                    break
-            }
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    getDimensionWithTransform: function(n, f) {
-        if (!this.commands || !this.commands.length) {
-            if (!f) {
-                f = {}
-            }
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var a = n.getXX(),
-            k = n.getYX(),
-            q = n.getDX(),
-            p = n.getXY(),
-            h = n.getYY(),
-            o = n.getDY(),
-            e = 0,
-            d = 0,
-            b = this.commands,
-            c = this.params,
-            g = b.length,
-            m, l;
-        for (; e < g; e++) {
-            switch (b[e]) {
-                case "M":
-                case "L":
-                    m = c[d] * a + c[d + 1] * k + q;
-                    l = c[d] * p + c[d + 1] * h + o;
-                    f.left = Math.min(m, f.left);
-                    f.top = Math.min(l, f.top);
-                    f.right = Math.max(m, f.right);
-                    f.bottom = Math.max(l, f.bottom);
-                    d += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, m, l, c[d] * a + c[d + 1] * k + q, c[d] * p + c[d + 1] * h + o, c[d + 2] * a + c[d + 3] * k + q, c[d + 2] * p + c[d + 3] * h + o, m = c[d + 4] * a + c[d + 5] * k + q, l = c[d + 4] * p + c[d + 5] * h + o);
-                    d += 6;
-                    break
-            }
-        }
-        if (!f) {
-            f = {}
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    expandDimension: function(i, d, p, k, g, j, e, c, o) {
-        var m = this,
-            f = i.left,
-            a = i.right,
-            q = i.top,
-            n = i.bottom,
-            h = m.dim || (m.dim = []);
-        m.curveDimension(d, k, j, c, h);
-        f = Math.min(f, h[0]);
-        a = Math.max(a, h[1]);
-        m.curveDimension(p, g, e, o, h);
-        q = Math.min(q, h[0]);
-        n = Math.max(n, h[1]);
-        i.left = f;
-        i.right = a;
-        i.top = q;
-        i.bottom = n
-    },
-    curveDimension: function(p, n, k, j, h) {
-        var i = 3 * (-p + 3 * (n - k) + j),
-            g = 6 * (p - 2 * n + k),
-            f = -3 * (p - n),
-            o, m, e = Math.min(p, j),
-            l = Math.max(p, j),
-            q;
-        if (i === 0) {
-            if (g === 0) {
-                h[0] = e;
-                h[1] = l;
-                return
-            } else {
-                o = -f / g;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-            }
-        } else {
-            q = g * g - 4 * i * f;
-            if (q >= 0) {
-                q = Math.sqrt(q);
-                o = (q - g) / 2 / i;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-                if (q > 0) {
-                    o -= q / i;
-                    if (0 < o && o < 1) {
-                        m = this.interpolate(p, n, k, j, o);
-                        e = Math.min(e, m);
-                        l = Math.max(l, m)
-                    }
-                }
-            }
-        }
-        h[0] = e;
-        h[1] = l
-    },
-    interpolate: function(f, e, j, i, g) {
-        if (g === 0) {
-            return f
-        }
-        if (g === 1) {
-            return i
-        }
-        var h = (1 - g) / g;
-        return g * g * g * (i + h * (3 * j + h * (3 * e + h * f)))
-    },
-    fromStripes: function(g) {
-        var e = this,
-            c = 0,
-            d = g.length,
-            b, a, f;
-        e.clear();
-        for (; c < d; c++) {
-            f = g[c];
-            e.params.push.apply(e.params, f);
-            e.commands.push("M");
-            for (b = 2, a = f.length; b < a; b += 6) {
-                e.commands.push("C")
-            }
-        }
-        if (!e.cursor) {
-            e.cursor = []
-        }
-        e.cursor[0] = e.params[e.params.length - 2];
-        e.cursor[1] = e.params[e.params.length - 1];
-        e.dirt()
-    },
-    toStripes: function(k) {
-        var o = k || [],
-            p, n, m, b, a, h, g, f, e, c = this.commands,
-            d = this.params,
-            l = c.length;
-        for (f = 0, e = 0; f < l; f++) {
-            switch (c[f]) {
-                case "M":
-                    p = [h = b = d[e++], g = a = d[e++]];
-                    o.push(p);
-                    break;
-                case "L":
-                    n = d[e++];
-                    m = d[e++];
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break;
-                case "C":
-                    p.push(d[e++], d[e++], d[e++], d[e++], b = d[e++], a = d[e++]);
-                    break;
-                case "Z":
-                    n = h;
-                    m = g;
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break
-            }
-        }
-        return o
-    },
-    updateSvgString: function() {
-        var b = [],
-            a = this.commands,
-            f = this.params,
-            e = a.length,
-            d = 0,
-            c = 0;
-        for (; d < e; d++) {
-            switch (a[d]) {
-                case "M":
-                    b.push("M" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "L":
-                    b.push("L" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "C":
-                    b.push("C" + f[c] + "," + f[c + 1] + " " + f[c + 2] + "," + f[c + 3] + " " + f[c + 4] + "," + f[c + 5]);
-                    c += 6;
-                    break;
-                case "Z":
-                    b.push("Z");
-                    break
-            }
-        }
-        this.svgString = b.join("")
-    },
-    toString: function() {
-        if (!this.svgString) {
-            this.updateSvgString()
-        }
-        return this.svgString
-    }
-});
-Ext.define("Ext.draw.overrides.Path", {
-    override: "Ext.draw.Path",
-    rayOrigin: {
-        x: -10000,
-        y: -10000
-    },
-    isPointInPath: function(o, n) {
-        var m = this,
-            c = m.commands,
-            q = Ext.draw.PathUtil,
-            p = m.rayOrigin,
-            f = m.params,
-            l = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            k = 0,
-            h, g;
-        for (h = 0, g = 0; h < l; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (q.linesIntersection(b, a, f[g], f[g + 1], p.x, p.y, o, n)) {
-                        k += 1
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    k += q.cubicLineIntersections(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], p.x, p.y, o, n).length;
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    break
-            }
-        }
-        return k % 2 === 1
-    },
-    isPointOnPath: function(n, m) {
-        var l = this,
-            c = l.commands,
-            o = Ext.draw.PathUtil,
-            f = l.params,
-            k = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            h, g;
-        for (h = 0, g = 0; h < k; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (o.pointOnLine(b, a, f[g], f[g + 1], n, m)) {
-                        return true
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    if (o.pointOnCubic(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], n, m)) {
-                        return true
-                    }
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    break
-            }
-        }
-        return false
-    },
-    getSegmentIntersections: function(t, d, s, c, r, b, o, a) {
-        var w = this,
-            g = arguments.length,
-            v = Ext.draw.PathUtil,
-            f = w.commands,
-            u = w.params,
-            k = f.length,
-            m = null,
-            l = null,
-            h = 0,
-            e = 0,
-            x = [],
-            q, n, p;
-        for (q = 0, n = 0; q < k; q++) {
-            switch (f[q]) {
-                case "M":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    m = h = u[n];
-                    l = e = u[n + 1];
-                    n += 2;
-                    break;
-                case "L":
-                    switch (g) {
-                        case 4:
-                            p = v.linesIntersection(h, e, u[n], u[n + 1], t, d, s, c);
-                            if (p) {
-                                x.push(p)
-                            }
-                            break;
-                        case 8:
-                            p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, h, e, u[n], u[n + 1]);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n];
-                    e = u[n + 1];
-                    n += 2;
-                    break;
-                case "C":
-                    switch (g) {
-                        case 4:
-                            p = v.cubicLineIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, d, s, c);
-                            x.push.apply(x, p);
-                            break;
-                        case 8:
-                            p = v.cubicsIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, s, r, o, d, c, b, a);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n + 4];
-                    e = u[n + 5];
-                    n += 6;
-                    break;
-                case "Z":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    break
-            }
-        }
-        return x
-    },
-    getIntersections: function(o) {
-        var m = this,
-            c = m.commands,
-            g = m.params,
-            l = c.length,
-            f = null,
-            e = null,
-            b = 0,
-            a = 0,
-            d = [],
-            k, h, n;
-        for (k = 0, h = 0; k < l; k++) {
-            switch (c[k]) {
-                case "M":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    f = b = g[h];
-                    e = a = g[h + 1];
-                    h += 2;
-                    break;
-                case "L":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1]);
-                    d.push.apply(d, n);
-                    b = g[h];
-                    a = g[h + 1];
-                    h += 2;
-                    break;
-                case "C":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1], g[h + 2], g[h + 3], g[h + 4], g[h + 5]);
-                    d.push.apply(d, n);
-                    b = g[h + 4];
-                    a = g[h + 5];
-                    h += 6;
-                    break;
-                case "Z":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    break
-            }
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.Path", {
-    extend: "Ext.draw.sprite.Sprite",
-    requires: ["Ext.draw.Draw", "Ext.draw.Path"],
-    alias: ["sprite.path", "Ext.draw.Sprite"],
-    type: "path",
-    isPath: true,
-    inheritableStatics: {
-        def: {
-            processors: {
-                path: function(b, a) {
-                    if (!(b instanceof Ext.draw.Path)) {
-                        b = new Ext.draw.Path(b)
-                    }
-                    return b
-                }
-            },
-            aliases: {
-                d: "path"
-            },
-            triggers: {
-                path: "bbox"
-            },
-            updaters: {
-                path: function(a) {
-                    var b = a.path;
-                    if (!b || b.bindAttr !== a) {
-                        b = new Ext.draw.Path();
-                        b.bindAttr = a;
-                        a.path = b
-                    }
-                    b.clear();
-                    this.updatePath(b, a);
-                    this.scheduleUpdater(a, "bbox", ["path"])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimension(a)
-        }
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimensionWithTransform(this.attr.matrix, a)
-        }
-    },
-    render: function(b, c) {
-        var d = this.attr.matrix,
-            a = this.attr;
-        if (!a.path || a.path.params.length === 0) {
-            return
-        }
-        d.toContext(c);
-        c.appendPath(a.path);
-        c.fillStroke(a)
-    },
-    updatePath: function(b, a) {}
-});
-Ext.define("Ext.draw.overrides.sprite.Path", {
-    override: "Ext.draw.sprite.Path",
-    requires: ["Ext.draw.Color"],
-    isPointInPath: function(c, g) {
-        var b = this.attr;
-        if (b.fillStyle === Ext.draw.Color.RGBA_NONE) {
-            return this.isPointOnPath(c, g)
-        }
-        var e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointInPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    isPointOnPath: function(c, g) {
-        var b = this.attr,
-            e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointOnPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    hitTest: function(i, l) {
-        var e = this,
-            c = e.attr,
-            k = c.path,
-            g = c.matrix,
-            h = i[0],
-            f = i[1],
-            d = e.callParent([i, l]),
-            j = null,
-            a, b;
-        if (!d) {
-            return j
-        }
-        l = l || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        if (!g.isIdentity()) {
-            a = k.params.slice(0);
-            k.transform(c.matrix)
-        }
-        if (l.fill && l.stroke) {
-            b = c.fillStyle !== Ext.draw.Color.NONE && c.fillStyle !== Ext.draw.Color.RGBA_NONE;
-            if (b) {
-                if (k.isPointInPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (k.isPointInPath(h, f) || k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            }
-        } else {
-            if (l.stroke && !l.fill) {
-                if (k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (l.fill && !l.stroke) {
-                    if (k.isPointInPath(h, f)) {
-                        j = {
-                            sprite: e
-                        }
-                    }
-                }
-            }
-        }
-        if (a) {
-            k.params = a
-        }
-        return j
-    },
-    getIntersections: function(j) {
-        if (!(j.isSprite && j.isPath)) {
-            return []
-        }
-        var e = this.attr,
-            d = j.attr,
-            i = e.path,
-            h = d.path,
-            g = e.matrix,
-            a = d.matrix,
-            c, f, b;
-        if (!g.isIdentity()) {
-            c = i.params.slice(0);
-            i.transform(e.matrix)
-        }
-        if (!a.isIdentity()) {
-            f = h.params.slice(0);
-            h.transform(d.matrix)
-        }
-        b = i.getIntersections(h);
-        if (c) {
-            i.params = c
-        }
-        if (f) {
-            h.params = f
-        }
-        return b
-    }
-});
-Ext.define("Ext.draw.sprite.Circle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.circle",
-    type: "circle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                r: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                r: 4
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                r: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            e = b.cy,
-            d = b.r;
-        c.x = a - d;
-        c.y = e - d;
-        c.width = d + d;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var g = this.attr,
-            f = g.cx,
-            e = g.cy,
-            a = g.r,
-            h = g.matrix,
-            j = h.getScaleX(),
-            i = h.getScaleY(),
-            c, b;
-        c = j * a;
-        b = i * a;
-        d.x = h.x(f, e) - c;
-        d.y = h.y(f, e) - b;
-        d.width = c + c;
-        d.height = b + b
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.Arc", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "sprite.arc",
-    type: "arc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Arrow", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.arrow",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.5,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c * 0.7, ",", e - c * 0.4, "l", [c * 0.6, 0, 0, -c * 0.4, c, c * 0.8, -c, c * 0.8, 0, -c * 0.4, -c * 0.6, 0], "z"))
-    }
-});
-Ext.define("Ext.draw.sprite.Composite", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.composite",
-    type: "composite",
-    isComposite: true,
-    config: {
-        sprites: []
-    },
-    constructor: function() {
-        this.sprites = [];
-        this.sprites.map = {};
-        this.callParent(arguments)
-    },
-    add: function(c) {
-        if (!c) {
-            return null
-        }
-        if (!c.isSprite) {
-            c = Ext.create("sprite." + c.type, c);
-            c.setParent(this);
-            c.setSurface(this.getSurface())
-        }
-        var d = this,
-            a = d.attr,
-            b = c.applyTransformations;
-        c.applyTransformations = function() {
-            if (c.attr.dirtyTransform) {
-                a.dirtyTransform = true;
-                a.bbox.plain.dirty = true;
-                a.bbox.transform.dirty = true
-            }
-            b.call(c)
-        };
-        d.sprites.push(c);
-        d.sprites.map[c.id] = c.getId();
-        a.bbox.plain.dirty = true;
-        a.bbox.transform.dirty = true;
-        return c
-    },
-    updateSurface: function(a) {
-        for (var b = 0, c = this.sprites.length; b < c; b++) {
-            this.sprites[b].setSurface(a)
-        }
-    },
-    addAll: function(b) {
-        if (b.isSprite || b.type) {
-            this.add(b)
-        } else {
-            if (Ext.isArray(b)) {
-                var a = 0;
-                while (a < b.length) {
-                    this.add(b[a++])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(g) {
-        var e = this,
-            b = Infinity,
-            h = -Infinity,
-            f = Infinity,
-            a = -Infinity,
-            j, k, c, d;
-        for (c = 0, d = e.sprites.length; c < d; c++) {
-            j = e.sprites[c];
-            j.applyTransformations();
-            k = j.getBBox();
-            if (b > k.x) {
-                b = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (f > k.y) {
-                f = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        g.x = b;
-        g.y = f;
-        g.width = h - b;
-        g.height = a - f
-    },
-    render: function(a, b, f) {
-        var d = this.attr.matrix,
-            c, e;
-        d.toContext(b);
-        for (c = 0, e = this.sprites.length; c < e; c++) {
-            a.renderSprite(this.sprites[c], f)
-        }
-    },
-    destroy: function() {
-        var c = this,
-            d = c.sprites,
-            b = d.length,
-            a;
-        c.callParent();
-        for (a = 0; a < b; a++) {
-            d[a].destroy()
-        }
-        d.length = 0
-    }
-});
-Ext.define("Ext.draw.sprite.Cross", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.cross",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.7,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c, ",", e, "l", [-c, -c, c, -c, c, c, c, -c, c, c, -c, c, c, c, -c, c, -c, -c, -c, c, -c, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Diamond", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.diamond",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.25,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString(["M", a, e - c, "l", c, c, -c, c, -c, -c, c, -c, "z"])
-    }
-});
-Ext.define("Ext.draw.sprite.Ellipse", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.ellipse",
-    type: "ellipse",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                rx: "number",
-                ry: "number",
-                axisRotation: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy",
-                radiusX: "rx",
-                radiusY: "ry"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                rx: 1,
-                ry: 1,
-                axisRotation: 0
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                rx: "path",
-                ry: "path",
-                axisRotation: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            f = b.cy,
-            e = b.rx,
-            d = b.ry;
-        c.x = a - e;
-        c.y = f - d;
-        c.width = e + e;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var i = this.attr,
-            f = i.cx,
-            e = i.cy,
-            c = i.rx,
-            b = i.ry,
-            l = b / c,
-            m = i.matrix.clone(),
-            a, q, k, j, p, o, n, g;
-        m.append(1, 0, 0, l, 0, e * (1 - l));
-        a = m.getXX();
-        k = m.getYX();
-        p = m.getDX();
-        q = m.getXY();
-        j = m.getYY();
-        o = m.getDY();
-        n = Math.sqrt(a * a + k * k) * c;
-        g = Math.sqrt(q * q + j * j) * c;
-        d.x = f * a + e * k + p - n;
-        d.y = f * q + e * j + o - g;
-        d.width = n + n;
-        d.height = g + g
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.EllipticalArc", {
-    extend: "Ext.draw.sprite.Ellipse",
-    alias: "sprite.ellipticalArc",
-    type: "ellipticalArc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Rect", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.rect",
-    type: "rect",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                radius: "number"
-            },
-            aliases: {},
-            triggers: {
-                x: "path",
-                y: "path",
-                width: "path",
-                height: "path",
-                radius: "path"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                radius: 0
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.x;
-        b.y = a.y;
-        b.width = a.width;
-        b.height = a.height
-    },
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, this.attr.radius, a)
-    },
-    updatePath: function(f, d) {
-        var c = d.x,
-            g = d.y,
-            e = d.width,
-            b = d.height,
-            a = Math.min(d.radius, Math.abs(d.height) * 0.5, Math.abs(d.width) * 0.5);
-        if (a === 0) {
-            f.rect(c, g, e, b)
-        } else {
-            f.moveTo(c + a, g);
-            f.arcTo(c + e, g, c + e, g + b, a);
-            f.arcTo(c + e, g + b, c, g + b, a);
-            f.arcTo(c, g + b, c, g, a);
-            f.arcTo(c, g, c + a, g, a)
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Image", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.image",
-    type: "image",
-    statics: {
-        imageLoaders: {}
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                src: "string"
-            },
-            defaults: {
-                src: "",
-                width: null,
-                height: null
-            }
-        }
-    },
-    render: function(c, o) {
-        var j = this,
-            h = j.attr,
-            n = h.matrix,
-            a = h.src,
-            l = h.x,
-            k = h.y,
-            b = h.width,
-            m = h.height,
-            g = Ext.draw.sprite.Image.imageLoaders[a],
-            f, d, e;
-        if (g && g.done) {
-            n.toContext(o);
-            d = g.image;
-            o.drawImage(d, l, k, b || (d.naturalWidth || d.width) / c.devicePixelRatio, m || (d.naturalHeight || d.height) / c.devicePixelRatio)
-        } else {
-            if (!g) {
-                f = new Image();
-                g = Ext.draw.sprite.Image.imageLoaders[a] = {
-                    image: f,
-                    done: false,
-                    pendingSprites: [j],
-                    pendingSurfaces: [c]
-                };
-                f.width = b;
-                f.height = m;
-                f.onload = function() {
-                    if (!g.done) {
-                        g.done = true;
-                        for (e = 0; e < g.pendingSprites.length; e++) {
-                            g.pendingSprites[e].setDirty(true)
-                        }
-                        for (e in g.pendingSurfaces) {
-                            g.pendingSurfaces[e].renderFrame()
-                        }
-                    }
-                };
-                f.src = a
-            } else {
-                Ext.Array.include(g.pendingSprites, j);
-                Ext.Array.include(g.pendingSurfaces, c)
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Instancing", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.instancing",
-    type: "instancing",
-    isInstancing: true,
-    config: {
-        template: null
-    },
-    instances: null,
-    applyTemplate: function(a) {
-        if (!a.isSprite) {
-            if (!a.xclass && !a.type) {
-                a.type = "circle"
-            }
-            a = Ext.create(a.xclass || "sprite." + a.type, a)
-        }
-        a.setParent(this);
-        return a
-    },
-    updateTemplate: function(a, b) {
-        if (b) {
-            delete b.ownAttr
-        }
-        a.setSurface(this.getSurface());
-        a.ownAttr = a.attr;
-        this.clearAll()
-    },
-    updateSurface: function(a) {
-        var b = this.getTemplate();
-        if (b) {
-            b.setSurface(a)
-        }
-    },
-    get: function(a) {
-        return this.instances[a]
-    },
-    getCount: function() {
-        return this.instances.length
-    },
-    clearAll: function() {
-        var a = this.getTemplate();
-        a.attr.children = this.instances = [];
-        this.position = 0
-    },
-    createInstance: function(d, f, c) {
-        var e = this.getTemplate(),
-            b = e.attr,
-            a = Ext.Object.chain(b);
-        e.topModifier.prepareAttributes(a);
-        e.attr = a;
-        e.setAttributes(d, f, c);
-        a.template = e;
-        this.instances.push(a);
-        e.attr = b;
-        this.position++;
-        return a
-    },
-    getBBox: function() {
-        return null
-    },
-    getBBoxFor: function(b, d) {
-        var c = this.getTemplate(),
-            a = c.attr,
-            e;
-        c.attr = this.instances[b];
-        e = c.getBBox(d);
-        c.attr = a;
-        return e
-    },
-    isVisible: function() {
-        var b = this.attr,
-            c = this.getParent(),
-            a;
-        a = c && c.isSurface && !b.hidden && b.globalAlpha;
-        return !!a
-    },
-    isInstanceVisible: function(c) {
-        var e = this,
-            d = e.getTemplate(),
-            b = d.attr,
-            f = e.instances,
-            a = false;
-        if (!Ext.isNumber(c) || c < 0 || c >= f.length || !e.isVisible()) {
-            return a
-        }
-        d.attr = f[c];
-        a = d.isVisible(point, options);
-        d.attr = b;
-        return a
-    },
-    render: function(b, l, d, h) {
-        var g = this,
-            j = g.getTemplate(),
-            k = g.attr.matrix,
-            c = j.attr,
-            a = g.instances,
-            e, f = g.position;
-        k.toContext(l);
-        j.preRender(b, l, d, h);
-        j.useAttributes(l, h);
-        for (e = 0; e < f; e++) {
-            if (a[e].dirtyZIndex) {
-                break
-            }
-        }
-        for (e = 0; e < f; e++) {
-            if (a[e].hidden) {
-                continue
-            }
-            l.save();
-            j.attr = a[e];
-            j.useAttributes(l, h);
-            j.render(b, l, d, h);
-            l.restore()
-        }
-        j.attr = c
-    },
-    setAttributesFor: function(c, e, f) {
-        var d = this.getTemplate(),
-            b = d.attr,
-            a = this.instances[c];
-        if (!a) {
-            return
-        }
-        d.attr = a;
-        if (f) {
-            e = Ext.apply({}, e)
-        } else {
-            e = d.self.def.normalize(e)
-        }
-        d.topModifier.pushDown(a, e);
-        d.attr = b
-    },
-    destroy: function() {
-        var b = this,
-            a = b.getTemplate();
-        b.instances = null;
-        if (a) {
-            a.destroy()
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.sprite.Instancing", {
-    override: "Ext.draw.sprite.Instancing",
-    hitTest: function(f, j) {
-        var e = this,
-            g = e.getTemplate(),
-            b = g.attr,
-            a = e.instances,
-            d = a.length,
-            c = 0,
-            h = null;
-        if (!e.isVisible()) {
-            return h
-        }
-        for (; c < d; c++) {
-            g.attr = a[c];
-            h = g.hitTest(f, j);
-            if (h) {
-                h.isInstance = true;
-                h.template = h.sprite;
-                h.sprite = this;
-                h.instance = a[c];
-                h.index = c;
-                return h
-            }
-        }
-        g.attr = b;
-        return h
-    }
-});
-Ext.define("Ext.draw.sprite.Line", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.line",
-    type: "line",
-    inheritableStatics: {
-        def: {
-            processors: {
-                fromX: "number",
-                fromY: "number",
-                toX: "number",
-                toY: "number"
-            },
-            defaults: {
-                fromX: 0,
-                fromY: 0,
-                toX: 1,
-                toY: 1,
-                strokeStyle: "black"
-            },
-            aliases: {
-                x1: "fromX",
-                y1: "fromY",
-                x2: "toX",
-                y2: "toY"
-            }
-        }
-    },
-    updateLineBBox: function(b, i, s, g, r, f) {
-        var o = this.attr,
-            q = o.matrix,
-            h = o.lineWidth / 2,
-            m, l, d, c, k, j, n;
-        if (i) {
-            n = q.transformPoint([s, g]);
-            s = n[0];
-            g = n[1];
-            n = q.transformPoint([r, f]);
-            r = n[0];
-            f = n[1]
-        }
-        m = Math.min(s, r);
-        d = Math.max(s, r);
-        l = Math.min(g, f);
-        c = Math.max(g, f);
-        var t = Math.atan2(d - m, c - l),
-            a = Math.sin(t),
-            e = Math.cos(t),
-            k = h * e,
-            j = h * a;
-        m -= k;
-        l -= j;
-        d += k;
-        c += j;
-        b.x = m;
-        b.y = l;
-        b.width = d - m;
-        b.height = c - l
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        this.updateLineBBox(b, false, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    updateTransformedBBox: function(b, c) {
-        var a = this.attr;
-        this.updateLineBBox(b, true, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    render: function(b, c) {
-        var a = this.attr,
-            d = this.attr.matrix;
-        d.toContext(c);
-        c.beginPath();
-        c.moveTo(a.fromX, a.fromY);
-        c.lineTo(a.toX, a.toY);
-        c.stroke()
-    }
-});
-Ext.define("Ext.draw.sprite.Plus", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.plus",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.3,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c / 2, ",", e - c / 2, "l", [0, -c, c, 0, 0, c, c, 0, 0, c, -c, 0, 0, c, -c, 0, 0, -c, -c, 0, 0, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Sector", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.sector",
-    type: "sector",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,bbox",
-                endAngle: "path,bbox",
-                startRho: "path,bbox",
-                endRho: "path,bbox",
-                margin: "path,bbox"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: 0,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                path: "M 0,0"
-            }
-        }
-    },
-    getMidAngle: function() {
-        return this.midAngle || 0
-    },
-    updatePath: function(j, h) {
-        var g = Math.min(h.startAngle, h.endAngle),
-            c = Math.max(h.startAngle, h.endAngle),
-            b = this.midAngle = (g + c) * 0.5,
-            d = h.margin,
-            f = h.centerX,
-            e = h.centerY,
-            i = Math.min(h.startRho, h.endRho),
-            a = Math.max(h.startRho, h.endRho);
-        if (d) {
-            f += d * Math.cos(b);
-            e += d * Math.sin(b)
-        }
-        j.moveTo(f + i * Math.cos(g), e + i * Math.sin(g));
-        j.lineTo(f + a * Math.cos(g), e + a * Math.sin(g));
-        j.arc(f, e, a, g, c, false);
-        j.lineTo(f + i * Math.cos(c), e + i * Math.sin(c));
-        j.arc(f, e, i, c, g, true)
-    }
-});
-Ext.define("Ext.draw.sprite.Square", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.square",
-    inheritableStatics: {
-        def: {
-            processors: {
-                size: "number"
-            },
-            defaults: {
-                size: 4
-            },
-            triggers: {
-                size: "size"
-            },
-            updaters: {
-                size: function(a) {
-                    var c = a.size,
-                        b = a.lineWidth / 2;
-                    this.setAttributes({
-                        x: a.x - c - b,
-                        y: a.y - c,
-                        height: 2 * c,
-                        width: 2 * c
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.TextMeasurer", {
-    singleton: true,
-    requires: ["Ext.util.TextMetrics"],
-    measureDiv: null,
-    measureCache: {},
-    precise: Ext.isIE8,
-    measureDivTpl: {
-        tag: "div",
-        style: {
-            overflow: "hidden",
-            position: "relative",
-            "float": "left",
-            width: 0,
-            height: 0
-        },
-        children: {
-            tag: "div",
-            style: {
-                display: "block",
-                position: "absolute",
-                x: -100000,
-                y: -100000,
-                padding: 0,
-                margin: 0,
-                "z-index": -100000,
-                "white-space": "nowrap"
-            }
-        }
-    },
-    actualMeasureText: function(g, b) {
-        var e = Ext.draw.TextMeasurer,
-            f = e.measureDiv,
-            a = 100000,
-            c;
-        if (!f) {
-            var d = Ext.Element.create({
-                style: {
-                    overflow: "hidden",
-                    position: "relative",
-                    "float": "left",
-                    width: 0,
-                    height: 0
-                }
-            });
-            e.measureDiv = f = Ext.Element.create({
-                style: {
-                    position: "absolute",
-                    x: a,
-                    y: a,
-                    "z-index": -a,
-                    "white-space": "nowrap",
-                    display: "block",
-                    padding: 0,
-                    margin: 0
-                }
-            });
-            Ext.getBody().appendChild(d);
-            d.appendChild(f)
-        }
-        if (b) {
-            f.setStyle({
-                font: b,
-                lineHeight: "normal"
-            })
-        }
-        f.setText("(" + g + ")");
-        c = f.getSize();
-        f.setText("()");
-        c.width -= f.getSize().width;
-        return c
-    },
-    measureTextSingleLine: function(h, d) {
-        if (this.precise) {
-            return this.preciseMeasureTextSingleLine(h, d)
-        }
-        h = h.toString();
-        var a = this.measureCache,
-            g = h.split(""),
-            c = 0,
-            j = 0,
-            l, b, e, f, k;
-        if (!a[d]) {
-            a[d] = {}
-        }
-        a = a[d];
-        if (a[h]) {
-            return a[h]
-        }
-        for (e = 0, f = g.length; e < f; e++) {
-            b = g[e];
-            if (!(l = a[b])) {
-                k = this.actualMeasureText(b, d);
-                l = a[b] = k
-            }
-            c += l.width;
-            j = Math.max(j, l.height)
-        }
-        return a[h] = {
-            width: c,
-            height: j
-        }
-    },
-    preciseMeasureTextSingleLine: function(c, a) {
-        c = c.toString();
-        var b = this.measureDiv || (this.measureDiv = Ext.getBody().createChild(this.measureDivTpl).down("div"));
-        b.setStyle({
-            font: a || ""
-        });
-        return Ext.util.TextMetrics.measure(b, c)
-    },
-    measureText: function(e, b) {
-        var h = e.split("\n"),
-            d = h.length,
-            f = 0,
-            a = 0,
-            j, c, g;
-        if (d === 1) {
-            return this.measureTextSingleLine(e, b)
-        }
-        g = [];
-        for (c = 0; c < d; c++) {
-            j = this.measureTextSingleLine(h[c], b);
-            g.push(j);
-            f += j.height;
-            a = Math.max(a, j.width)
-        }
-        return {
-            width: a,
-            height: f,
-            sizes: g
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Text", function() {
-    var d = {
-        "xx-small": true,
-        "x-small": true,
-        small: true,
-        medium: true,
-        large: true,
-        "x-large": true,
-        "xx-large": true
-    };
-    var b = {
-        normal: true,
-        bold: true,
-        bolder: true,
-        lighter: true,
-        100: true,
-        200: true,
-        300: true,
-        400: true,
-        500: true,
-        600: true,
-        700: true,
-        800: true,
-        900: true
-    };
-    var a = {
-        start: "start",
-        left: "start",
-        center: "center",
-        middle: "center",
-        end: "end",
-        right: "end"
-    };
-    var c = {
-        top: "top",
-        hanging: "hanging",
-        middle: "middle",
-        center: "middle",
-        alphabetic: "alphabetic",
-        ideographic: "ideographic",
-        bottom: "bottom"
-    };
-    return {
-        extend: "Ext.draw.sprite.Sprite",
-        requires: ["Ext.draw.TextMeasurer", "Ext.draw.Color"],
-        alias: "sprite.text",
-        type: "text",
-        lineBreakRe: /\r?\n/g,
-        inheritableStatics: {
-            def: {
-                animationProcessors: {
-                    text: "text"
-                },
-                processors: {
-                    x: "number",
-                    y: "number",
-                    text: "string",
-                    fontSize: function(e) {
-                        if (Ext.isNumber(+e)) {
-                            return e + "px"
-                        } else {
-                            if (e.match(Ext.dom.Element.unitRe)) {
-                                return e
-                            } else {
-                                if (e in d) {
-                                    return e
-                                }
-                            }
-                        }
-                    },
-                    fontStyle: "enums(,italic,oblique)",
-                    fontVariant: "enums(,small-caps)",
-                    fontWeight: function(e) {
-                        if (e in b) {
-                            return String(e)
-                        } else {
-                            return ""
-                        }
-                    },
-                    fontFamily: "string",
-                    textAlign: function(e) {
-                        return a[e] || "center"
-                    },
-                    textBaseline: function(e) {
-                        return c[e] || "alphabetic"
-                    },
-                    font: "string"
-                },
-                aliases: {
-                    "font-size": "fontSize",
-                    "font-family": "fontFamily",
-                    "font-weight": "fontWeight",
-                    "font-variant": "fontVariant",
-                    "text-anchor": "textAlign"
-                },
-                defaults: {
-                    fontStyle: "",
-                    fontVariant: "",
-                    fontWeight: "",
-                    fontSize: "10px",
-                    fontFamily: "sans-serif",
-                    font: "10px sans-serif",
-                    textBaseline: "alphabetic",
-                    textAlign: "start",
-                    strokeStyle: "rgba(0, 0, 0, 0)",
-                    fillStyle: "#000",
-                    x: 0,
-                    y: 0,
-                    text: ""
-                },
-                triggers: {
-                    fontStyle: "fontX,bbox",
-                    fontVariant: "fontX,bbox",
-                    fontWeight: "fontX,bbox",
-                    fontSize: "fontX,bbox",
-                    fontFamily: "fontX,bbox",
-                    font: "font,bbox,canvas",
-                    textBaseline: "bbox",
-                    textAlign: "bbox",
-                    x: "bbox",
-                    y: "bbox",
-                    text: "bbox"
-                },
-                updaters: {
-                    fontX: "makeFontShorthand",
-                    font: "parseFontShorthand"
-                }
-            }
-        },
-        constructor: function(e) {
-            if (e && e.font) {
-                e = Ext.clone(e);
-                for (var f in e) {
-                    if (f !== "font" && f.indexOf("font") === 0) {
-                        delete e[f]
-                    }
-                }
-            }
-            Ext.draw.sprite.Sprite.prototype.constructor.call(this, e)
-        },
-        fontValuesMap: {
-            italic: "fontStyle",
-            oblique: "fontStyle",
-            "small-caps": "fontVariant",
-            bold: "fontWeight",
-            bolder: "fontWeight",
-            lighter: "fontWeight",
-            "100": "fontWeight",
-            "200": "fontWeight",
-            "300": "fontWeight",
-            "400": "fontWeight",
-            "500": "fontWeight",
-            "600": "fontWeight",
-            "700": "fontWeight",
-            "800": "fontWeight",
-            "900": "fontWeight",
-            "xx-small": "fontSize",
-            "x-small": "fontSize",
-            small: "fontSize",
-            medium: "fontSize",
-            large: "fontSize",
-            "x-large": "fontSize",
-            "xx-large": "fontSize"
-        },
-        makeFontShorthand: function(e) {
-            var f = [];
-            if (e.fontStyle) {
-                f.push(e.fontStyle)
-            }
-            if (e.fontVariant) {
-                f.push(e.fontVariant)
-            }
-            if (e.fontWeight) {
-                f.push(e.fontWeight)
-            }
-            if (e.fontSize) {
-                f.push(e.fontSize)
-            }
-            if (e.fontFamily) {
-                f.push(e.fontFamily)
-            }
-            this.setAttributes({
-                font: f.join(" ")
-            }, true)
-        },
-        parseFontShorthand: function(j) {
-            var m = j.font,
-                k = m.length,
-                l = {},
-                n = this.fontValuesMap,
-                e = 0,
-                i, g, f, h;
-            while (e < k && i !== -1) {
-                i = m.indexOf(" ", e);
-                if (i < 0) {
-                    f = m.substr(e)
-                } else {
-                    if (i > e) {
-                        f = m.substr(e, i - e)
-                    } else {
-                        continue
-                    }
-                }
-                g = f.indexOf("/");
-                if (g > 0) {
-                    f = f.substr(0, g)
-                } else {
-                    if (g === 0) {
-                        continue
-                    }
-                }
-                if (f !== "normal" && f !== "inherit") {
-                    h = n[f];
-                    if (h) {
-                        l[h] = f
-                    } else {
-                        if (f.match(Ext.dom.Element.unitRe)) {
-                            l.fontSize = f
-                        } else {
-                            l.fontFamily = m.substr(e);
-                            break
-                        }
-                    }
-                }
-                e = i + 1
-            }
-            if (!l.fontStyle) {
-                l.fontStyle = ""
-            }
-            if (!l.fontVariant) {
-                l.fontVariant = ""
-            }
-            if (!l.fontWeight) {
-                l.fontWeight = ""
-            }
-            this.setAttributes(l, true)
-        },
-        fontProperties: {
-            fontStyle: true,
-            fontVariant: true,
-            fontWeight: true,
-            fontSize: true,
-            fontFamily: true
-        },
-        setAttributes: function(g, i, e) {
-            var f, h;
-            if (g && g.font) {
-                h = {};
-                for (f in g) {
-                    if (!(f in this.fontProperties)) {
-                        h[f] = g[f]
-                    }
-                }
-                g = h
-            }
-            this.callParent([g, i, e])
-        },
-        getBBox: function(g) {
-            var h = this,
-                f = h.attr.bbox.plain,
-                e = h.getSurface();
-            if (f.dirty) {
-                h.updatePlainBBox(f);
-                f.dirty = false
-            }
-            if (e.getInherited().rtl && e.getFlipRtlText()) {
-                h.updatePlainBBox(f, true)
-            }
-            return h.callParent([g])
-        },
-        rtlAlignments: {
-            start: "end",
-            center: "center",
-            end: "start"
-        },
-        updatePlainBBox: function(k, B) {
-            var C = this,
-                w = C.attr,
-                o = w.x,
-                n = w.y,
-                q = [],
-                t = w.font,
-                r = w.text,
-                s = w.textBaseline,
-                l = w.textAlign,
-                u = (B && C.oldSize) ? C.oldSize : (C.oldSize = Ext.draw.TextMeasurer.measureText(r, t)),
-                z = C.getSurface(),
-                p = z.getInherited().rtl,
-                v = p && z.getFlipRtlText(),
-                h = z.getRect(),
-                f = u.sizes,
-                g = u.height,
-                j = u.width,
-                m = f ? f.length : 0,
-                e, A = 0;
-            switch (s) {
-                case "hanging":
-                case "top":
-                    break;
-                case "ideographic":
-                case "bottom":
-                    n -= g;
-                    break;
-                case "alphabetic":
-                    n -= g * 0.8;
-                    break;
-                case "middle":
-                    n -= g * 0.5;
-                    break
-            }
-            if (v) {
-                o = h[2] - h[0] - o;
-                l = C.rtlAlignments[l]
-            }
-            switch (l) {
-                case "start":
-                    if (p) {
-                        for (; A < m; A++) {
-                            e = f[A].width;
-                            q.push(-(j - e))
-                        }
-                    }
-                    break;
-                case "end":
-                    o -= j;
-                    if (p) {
-                        break
-                    }
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push(j - e)
-                    }
-                    break;
-                case "center":
-                    o -= j * 0.5;
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push((p ? -1 : 1) * (j - e) * 0.5)
-                    }
-                    break
-            }
-            w.textAlignOffsets = q;
-            k.x = o;
-            k.y = n;
-            k.width = j;
-            k.height = g
-        },
-        setText: function(e) {
-            this.setAttributes({
-                text: e
-            }, true)
-        },
-        render: function(e, q, k) {
-            var h = this,
-                g = h.attr,
-                p = Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),
-                o = h.getBBox(true),
-                s = g.textAlignOffsets,
-                m = Ext.draw.Color.RGBA_NONE,
-                l, j, f, r, n;
-            if (g.text.length === 0) {
-                return
-            }
-            r = g.text.split(h.lineBreakRe);
-            n = o.height / r.length;
-            l = g.bbox.plain.x;
-            j = g.bbox.plain.y + n * 0.78;
-            p.toContext(q);
-            if (e.getInherited().rtl) {
-                l += g.bbox.plain.width
-            }
-            for (f = 0; f < r.length; f++) {
-                if (q.fillStyle !== m) {
-                    q.fillText(r[f], l + (s[f] || 0), j + n * f)
-                }
-                if (q.strokeStyle !== m) {
-                    q.strokeText(r[f], l + (s[f] || 0), j + n * f)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Tick", {
-    extend: "Ext.draw.sprite.Line",
-    alias: "sprite.tick",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "tick",
-                y: "tick",
-                size: "tick"
-            },
-            updaters: {
-                tick: function(b) {
-                    var d = b.size * 1.5,
-                        c = b.lineWidth / 2,
-                        a = b.x,
-                        e = b.y;
-                    this.setAttributes({
-                        fromX: a - c,
-                        fromY: e - d,
-                        toX: a - c,
-                        toY: e + d
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Triangle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.triangle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 2.2,
-            a = b.x,
-            e = b.y;
-        d.fromSvgString("M".concat(a, ",", e, "m0-", c * 0.58, "l", c * 0.5, ",", c * 0.87, "-", c, ",0z"))
-    }
-});
-Ext.define("Ext.draw.gradient.Linear", {
-    extend: "Ext.draw.gradient.Gradient",
-    requires: ["Ext.draw.Color"],
-    type: "linear",
-    config: {
-        degrees: 0,
-        radians: 0
-    },
-    applyRadians: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    applyDegrees: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    updateRadians: function(a) {
-        this.setDegrees(Ext.draw.Draw.degrees(a))
-    },
-    updateDegrees: function(a) {
-        this.setRadians(Ext.draw.Draw.rad(a))
-    },
-    generateGradient: function(q, o) {
-        var c = this.getRadians(),
-            p = Math.cos(c),
-            j = Math.sin(c),
-            m = o.width,
-            f = o.height,
-            d = o.x + m * 0.5,
-            b = o.y + f * 0.5,
-            n = this.getStops(),
-            g = n.length,
-            k, a, e;
-        if (Ext.isNumber(d + b) && f > 0 && m > 0) {
-            a = (Math.sqrt(f * f + m * m) * Math.abs(Math.cos(c - Math.atan(f / m)))) / 2;
-            k = q.createLinearGradient(d + p * a, b + j * a, d - p * a, b - j * a);
-            for (e = 0; e < g; e++) {
-                k.addColorStop(n[e].offset, n[e].color)
-            }
-            return k
-        }
-        return Ext.draw.Color.NONE
-    }
-});
-Ext.define("Ext.draw.gradient.Radial", {
-    extend: "Ext.draw.gradient.Gradient",
-    type: "radial",
-    config: {
-        start: {
-            x: 0,
-            y: 0,
-            r: 0
-        },
-        end: {
-            x: 0,
-            y: 0,
-            r: 1
-        }
-    },
-    applyStart: function(a, b) {
-        if (!b) {
-            return a
-        }
-        var c = {
-            x: b.x,
-            y: b.y,
-            r: b.r
-        };
-        if ("x" in a) {
-            c.x = a.x
-        } else {
-            if ("centerX" in a) {
-                c.x = a.centerX
-            }
-        }
-        if ("y" in a) {
-            c.y = a.y
-        } else {
-            if ("centerY" in a) {
-                c.y = a.centerY
-            }
-        }
-        if ("r" in a) {
-            c.r = a.r
-        } else {
-            if ("radius" in a) {
-                c.r = a.radius
-            }
-        }
-        return c
-    },
-    applyEnd: function(b, a) {
-        if (!a) {
-            return b
-        }
-        var c = {
-            x: a.x,
-            y: a.y,
-            r: a.r
-        };
-        if ("x" in b) {
-            c.x = b.x
-        } else {
-            if ("centerX" in b) {
-                c.x = b.centerX
-            }
-        }
-        if ("y" in b) {
-            c.y = b.y
-        } else {
-            if ("centerY" in b) {
-                c.y = b.centerY
-            }
-        }
-        if ("r" in b) {
-            c.r = b.r
-        } else {
-            if ("radius" in b) {
-                c.r = b.radius
-            }
-        }
-        return c
-    },
-    generateGradient: function(n, m) {
-        var a = this.getStart(),
-            b = this.getEnd(),
-            k = m.width * 0.5,
-            d = m.height * 0.5,
-            j = m.x + k,
-            f = m.y + d,
-            g = n.createRadialGradient(j + a.x * k, f + a.y * d, a.r * Math.max(k, d), j + b.x * k, f + b.y * d, b.r * Math.max(k, d)),
-            l = this.getStops(),
-            e = l.length,
-            c;
-        for (c = 0; c < e; c++) {
-            g.addColorStop(l[c].offset, l[c].color)
-        }
-        return g
-    }
-});
-Ext.define("Ext.draw.Surface", {
-    extend: "Ext.draw.SurfaceBase",
-    xtype: "surface",
-    requires: ["Ext.draw.sprite.*", "Ext.draw.gradient.*", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.Matrix", "Ext.draw.Draw"],
-    uses: ["Ext.draw.engine.Canvas"],
-    devicePixelRatio: window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI,
-    deprecated: {
-        "5.1.0": {
-            statics: {
-                methods: {
-                    stableSort: function(a) {
-                        return Ext.Array.sort(a, function(d, c) {
-                            return d.attr.zIndex - c.attr.zIndex
-                        })
-                    }
-                }
-            }
-        }
-    },
-    config: {
-        cls: Ext.baseCSSPrefix + "surface",
-        rect: null,
-        background: null,
-        items: [],
-        dirty: false,
-        flipRtlText: false
-    },
-    isSurface: true,
-    isPendingRenderFrame: false,
-    dirtyPredecessorCount: 0,
-    constructor: function(a) {
-        var b = this;
-        b.predecessors = [];
-        b.successors = [];
-        b.map = {};
-        b.callParent([a]);
-        b.matrix = new Ext.draw.Matrix();
-        b.inverseMatrix = b.matrix.inverse()
-    },
-    roundPixel: function(a) {
-        return Math.round(this.devicePixelRatio * a) / this.devicePixelRatio
-    },
-    waitFor: function(a) {
-        var b = this,
-            c = b.predecessors;
-        if (!Ext.Array.contains(c, a)) {
-            c.push(a);
-            a.successors.push(b);
-            if (a.getDirty()) {
-                b.dirtyPredecessorCount++
-            }
-        }
-    },
-    updateDirty: function(d) {
-        var c = this.successors,
-            e = c.length,
-            b = 0,
-            a;
-        for (; b < e; b++) {
-            a = c[b];
-            if (d) {
-                a.dirtyPredecessorCount++;
-                a.setDirty(true)
-            } else {
-                a.dirtyPredecessorCount--;
-                if (a.dirtyPredecessorCount === 0 && a.isPendingRenderFrame) {
-                    a.renderFrame()
-                }
-            }
-        }
-    },
-    applyBackground: function(a, b) {
-        this.setDirty(true);
-        if (Ext.isString(a)) {
-            a = {
-                fillStyle: a
-            }
-        }
-        return Ext.factory(a, Ext.draw.sprite.Rect, b)
-    },
-    applyRect: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return
-        }
-        if (Ext.isArray(a)) {
-            return [a[0], a[1], a[2], a[3]]
-        } else {
-            if (Ext.isObject(a)) {
-                return [a.x || a.left, a.y || a.top, a.width || (a.right - a.left), a.height || (a.bottom - a.top)]
-            }
-        }
-    },
-    updateRect: function(i) {
-        var h = this,
-            c = i[0],
-            f = i[1],
-            g = c + i[2],
-            a = f + i[3],
-            e = h.getBackground(),
-            d = h.element;
-        d.setLocalXY(Math.floor(c), Math.floor(f));
-        d.setSize(Math.ceil(g - Math.floor(c)), Math.ceil(a - Math.floor(f)));
-        if (e) {
-            e.setAttributes({
-                x: 0,
-                y: 0,
-                width: Math.ceil(g - Math.floor(c)),
-                height: Math.ceil(a - Math.floor(f))
-            })
-        }
-        h.setDirty(true)
-    },
-    resetTransform: function() {
-        this.matrix.set(1, 0, 0, 1, 0, 0);
-        this.inverseMatrix.set(1, 0, 0, 1, 0, 0);
-        this.setDirty(true)
-    },
-    get: function(a) {
-        return this.map[a] || this.getItems()[a]
-    },
-    add: function() {
-        var g = this,
-            e = Array.prototype.slice.call(arguments),
-            j = Ext.isArray(e[0]),
-            a = g.map,
-            c = [],
-            f, k, h, b, d;
-        f = Ext.Array.clean(j ? e[0] : e);
-        if (!f.length) {
-            return c
-        }
-        for (b = 0, d = f.length; b < d; b++) {
-            k = f[b];
-            h = null;
-            if (k.isSprite && !a[k.getId()]) {
-                h = k
-            } else {
-                if (!a[k.id]) {
-                    h = this.createItem(k)
-                }
-            }
-            if (h) {
-                a[h.getId()] = h;
-                c.push(h);
-                h.setParent(g);
-                h.setSurface(g);
-                g.onAdd(h)
-            }
-        }
-        f = g.getItems();
-        if (f) {
-            f.push.apply(f, c)
-        }
-        g.dirtyZIndex = true;
-        g.setDirty(true);
-        if (!j && c.length === 1) {
-            return c[0]
-        } else {
-            return c
-        }
-    },
-    onAdd: Ext.emptyFn,
-    remove: function(a, c) {
-        var b = this,
-            e, d;
-        if (a) {
-            if (a.charAt) {
-                a = b.map[a]
-            }
-            if (!a || !a.isSprite) {
-                return null
-            }
-            if (a.isDestroyed || a.isDestroying) {
-                return a
-            }
-            e = a.getId();
-            d = b.map[e];
-            delete b.map[e];
-            if (c) {
-                a.destroy()
-            }
-            if (!d) {
-                return a
-            }
-            a.setParent(null);
-            a.setSurface(null);
-            Ext.Array.remove(b.getItems(), a);
-            b.dirtyZIndex = true;
-            b.setDirty(true)
-        }
-        return a || null
-    },
-    removeAll: function(d) {
-        var a = this.getItems(),
-            b = a.length - 1,
-            c;
-        if (d) {
-            for (; b >= 0; b--) {
-                a[b].destroy()
-            }
-        } else {
-            for (; b >= 0; b--) {
-                c = a[b];
-                c.setParent(null);
-                c.setSurface(null)
-            }
-        }
-        a.length = 0;
-        this.map = {};
-        this.dirtyZIndex = true
-    },
-    applyItems: function(a) {
-        if (this.getItems()) {
-            this.removeAll(true)
-        }
-        return Ext.Array.from(this.add(a))
-    },
-    createItem: function(a) {
-        return Ext.create(a.xclass || "sprite." + a.type, a)
-    },
-    getBBox: function(f, b) {
-        var f = Ext.Array.from(f),
-            c = Infinity,
-            h = -Infinity,
-            g = Infinity,
-            a = -Infinity,
-            j, k, d, e;
-        for (d = 0, e = f.length; d < e; d++) {
-            j = f[d];
-            k = j.getBBox(b);
-            if (c > k.x) {
-                c = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (g > k.y) {
-                g = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        return {
-            x: c,
-            y: g,
-            width: h - c,
-            height: a - g
-        }
-    },
-    emptyRect: [0, 0, 0, 0],
-    getEventXY: function(d) {
-        var g = this,
-            f = g.getInherited().rtl,
-            c = d.getXY(),
-            a = g.getOwnerBody(),
-            i = a.getXY(),
-            h = g.getRect() || g.emptyRect,
-            j = [],
-            b;
-        if (f) {
-            b = a.getWidth();
-            j[0] = i[0] - c[0] - h[0] + b
-        } else {
-            j[0] = c[0] - i[0] - h[0]
-        }
-        j[1] = c[1] - i[1] - h[1];
-        return j
-    },
-    clear: Ext.emptyFn,
-    orderByZIndex: function() {
-        var d = this,
-            a = d.getItems(),
-            e = false,
-            b, c;
-        if (d.getDirty()) {
-            for (b = 0, c = a.length; b < c; b++) {
-                if (a[b].attr.dirtyZIndex) {
-                    e = true;
-                    break
-                }
-            }
-            if (e) {
-                Ext.Array.sort(a, function(g, f) {
-                    return g.attr.zIndex - f.attr.zIndex
-                });
-                this.setDirty(true)
-            }
-            for (b = 0, c = a.length; b < c; b++) {
-                a[b].attr.dirtyZIndex = false
-            }
-        }
-    },
-    repaint: function() {
-        var a = this;
-        a.repaint = Ext.emptyFn;
-        Ext.defer(function() {
-            delete a.repaint;
-            a.element.repaint()
-        }, 1)
-    },
-    renderFrame: function() {
-        var g = this;
-        if (!g.element) {
-            return
-        }
-        if (g.dirtyPredecessorCount > 0) {
-            g.isPendingRenderFrame = true;
-            return
-        }
-        var f = g.getRect(),
-            c = g.getBackground(),
-            a = g.getItems(),
-            e, b, d;
-        if (!f) {
-            return
-        }
-        g.orderByZIndex();
-        if (g.getDirty()) {
-            g.clear();
-            g.clearTransform();
-            if (c) {
-                g.renderSprite(c)
-            }
-            for (b = 0, d = a.length; b < d; b++) {
-                e = a[b];
-                if (g.renderSprite(e) === false) {
-                    return
-                }
-                e.attr.textPositionCount = g.textPosition
-            }
-            g.setDirty(false)
-        }
-    },
-    renderSprite: Ext.emptyFn,
-    clearTransform: Ext.emptyFn,
-    destroy: function() {
-        var a = this;
-        a.removeAll(true);
-        a.predecessors = null;
-        a.successors = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.Surface", {
-    override: "Ext.draw.Surface",
-    hitTest: function(b, c) {
-        var f = this,
-            g = f.getItems(),
-            e, d, a;
-        c = c || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        for (e = g.length - 1; e >= 0; e--) {
-            d = g[e];
-            if (d.hitTest) {
-                a = d.hitTest(b, c);
-                if (a) {
-                    return a
-                }
-            }
-        }
-        return null
-    },
-    hitTestEvent: function(b, a) {
-        var c = this.getEventXY(b);
-        return this.hitTest(c, a)
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext", {
-    requires: ["Ext.draw.Color"],
-    toSave: ["strokeOpacity", "strokeStyle", "fillOpacity", "fillStyle", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "lineDash", "lineDashOffset", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "globalCompositeOperation", "position", "fillGradient", "strokeGradient"],
-    strokeOpacity: 1,
-    strokeStyle: "none",
-    fillOpacity: 1,
-    fillStyle: "none",
-    lineDash: [],
-    lineDashOffset: 0,
-    globalAlpha: 1,
-    lineWidth: 1,
-    lineCap: "butt",
-    lineJoin: "miter",
-    miterLimit: 10,
-    shadowOffsetX: 0,
-    shadowOffsetY: 0,
-    shadowBlur: 0,
-    shadowColor: "none",
-    globalCompositeOperation: "src",
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    constructor: function(a) {
-        this.surface = a;
-        this.state = [];
-        this.matrix = new Ext.draw.Matrix();
-        this.path = null;
-        this.clear()
-    },
-    clear: function() {
-        this.group = this.surface.mainGroup;
-        this.position = 0;
-        this.path = null
-    },
-    getElement: function(a) {
-        return this.surface.getSvgElement(this.group, a, this.position++)
-    },
-    removeElement: function(d) {
-        var d = Ext.fly(d),
-            h, g, b, f, a, e, c;
-        if (!d) {
-            return
-        }
-        if (d.dom.tagName === "g") {
-            a = d.dom.gradients;
-            for (c in a) {
-                a[c].destroy()
-            }
-        } else {
-            h = d.getAttribute("fill");
-            g = d.getAttribute("stroke");
-            b = h && h.match(this.urlStringRe);
-            f = g && g.match(this.urlStringRe);
-            if (b && b[1]) {
-                e = Ext.fly(b[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-            if (f && f[1]) {
-                e = Ext.fly(f[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-        }
-        d.destroy()
-    },
-    save: function() {
-        var c = this.toSave,
-            e = {},
-            d = this.getElement("g"),
-            b, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            if (b in this) {
-                e[b] = this[b]
-            }
-        }
-        this.position = 0;
-        e.matrix = this.matrix.clone();
-        this.state.push(e);
-        this.group = d;
-        return d
-    },
-    restore: function() {
-        var d = this.toSave,
-            e = this.state.pop(),
-            c = this.group.dom.childNodes,
-            b, a;
-        while (c.length > this.position) {
-            this.removeElement(c[c.length - 1])
-        }
-        for (a = 0; a < d.length; a++) {
-            b = d[a];
-            if (b in e) {
-                this[b] = e[b]
-            } else {
-                delete this[b]
-            }
-        }
-        this.setTransform.apply(this, e.matrix.elements);
-        this.group = this.group.getParent()
-    },
-    transform: function(f, b, e, g, d, c) {
-        if (this.path) {
-            var a = Ext.draw.Matrix.fly([f, b, e, g, d, c]).inverse();
-            this.path.transform(a)
-        }
-        this.matrix.append(f, b, e, g, d, c)
-    },
-    setTransform: function(e, a, d, f, c, b) {
-        if (this.path) {
-            this.path.transform(this.matrix)
-        }
-        this.matrix.reset();
-        this.transform(e, a, d, f, c, b)
-    },
-    scale: function(a, b) {
-        this.transform(a, 0, 0, b, 0, 0)
-    },
-    rotate: function(d) {
-        var c = Math.cos(d),
-            a = Math.sin(d),
-            b = -Math.sin(d),
-            e = Math.cos(d);
-        this.transform(c, a, b, e, 0, 0)
-    },
-    translate: function(a, b) {
-        this.transform(1, 0, 0, 1, a, b)
-    },
-    setGradientBBox: function(a) {
-        this.bbox = a
-    },
-    beginPath: function() {
-        this.path = new Ext.draw.Path()
-    },
-    moveTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.moveTo(a, b);
-        this.path.element = null
-    },
-    lineTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.lineTo(a, b);
-        this.path.element = null
-    },
-    rect: function(b, d, c, a) {
-        this.moveTo(b, d);
-        this.lineTo(b + c, d);
-        this.lineTo(b + c, d + a);
-        this.lineTo(b, d + a);
-        this.closePath()
-    },
-    strokeRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.stroke()
-    },
-    fillRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.fill()
-    },
-    closePath: function() {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.closePath();
-        this.path.element = null
-    },
-    arcSvg: function(d, a, f, g, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcSvg(d, a, f, g, c, b, e);
-        this.path.element = null
-    },
-    arc: function(b, f, a, d, c, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arc(b, f, a, d, c, e);
-        this.path.element = null
-    },
-    ellipse: function(a, h, g, f, d, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.ellipse(a, h, g, f, d, c, b, e);
-        this.path.element = null
-    },
-    arcTo: function(b, e, a, d, g, f, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcTo(b, e, a, d, g, f, c);
-        this.path.element = null
-    },
-    bezierCurveTo: function(d, f, b, e, a, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.bezierCurveTo(d, f, b, e, a, c);
-        this.path.element = null
-    },
-    strokeText: function(d, a, e) {
-        d = String(d);
-        if (this.strokeStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                stroke: this.strokeStyle,
-                fill: "none",
-                opacity: this.globalAlpha,
-                "stroke-opacity": this.strokeOpacity,
-                style: "font: " + this.font,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(b, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    fillText: function(d, a, e) {
-        d = String(d);
-        if (this.fillStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                fill: this.fillStyle,
-                opacity: this.globalAlpha,
-                "fill-opacity": this.fillOpacity,
-                style: "font: " + this.font
-            });
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    drawImage: function(c, k, i, l, e, p, n, a, g) {
-        var f = this,
-            d = f.getElement("image"),
-            j = k,
-            h = i,
-            b = typeof l === "undefined" ? c.width : l,
-            m = typeof e === "undefined" ? c.height : e,
-            o = null;
-        if (typeof g !== "undefined") {
-            o = k + " " + i + " " + l + " " + e;
-            j = p;
-            h = n;
-            b = a;
-            m = g
-        }
-        d.dom.setAttributeNS("http://www.w3.org/1999/xlink", "href", c.src);
-        f.surface.setElementAttributes(d, {
-            viewBox: o,
-            x: j,
-            y: h,
-            width: b,
-            height: m,
-            opacity: f.globalAlpha,
-            transform: f.matrix.toSvg()
-        })
-    },
-    fill: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.fillStyle) {
-            var c, a = this.fillGradient,
-                d = this.bbox,
-                b = this.path.element;
-            if (!b) {
-                c = this.path.toString();
-                b = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(b, {
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(b, {
-                fill: a && d ? a.generateGradient(this, d) : this.fillStyle,
-                "fill-opacity": this.fillOpacity * this.globalAlpha
-            })
-        }
-    },
-    stroke: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.strokeStyle) {
-            var c, b = this.strokeGradient,
-                d = this.bbox,
-                a = this.path.element;
-            if (!a || !this.path.svgString) {
-                c = this.path.toString();
-                if (!c) {
-                    return
-                }
-                a = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(a, {
-                    fill: "none",
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(a, {
-                stroke: b && d ? b.generateGradient(this, d) : this.strokeStyle,
-                "stroke-linecap": this.lineCap,
-                "stroke-linejoin": this.lineJoin,
-                "stroke-width": this.lineWidth,
-                "stroke-opacity": this.strokeOpacity * this.globalAlpha,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(a, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-        }
-    },
-    fillStroke: function(a, e) {
-        var b = this,
-            d = b.fillStyle,
-            g = b.strokeStyle,
-            c = b.fillOpacity,
-            f = b.strokeOpacity;
-        if (e === undefined) {
-            e = a.transformFillStroke
-        }
-        if (!e) {
-            a.inverseMatrix.toContext(b)
-        }
-        if (d && c !== 0) {
-            b.fill()
-        }
-        if (g && f !== 0) {
-            b.stroke()
-        }
-    },
-    appendPath: function(a) {
-        this.path = a.clone()
-    },
-    setLineDash: function(a) {
-        this.lineDash = a
-    },
-    getLineDash: function() {
-        return this.lineDash
-    },
-    createLinearGradient: function(d, g, b, e) {
-        var f = this,
-            c = f.surface.getNextDef("linearGradient"),
-            a = f.group.dom.gradients || (f.group.dom.gradients = {}),
-            h;
-        f.surface.setElementAttributes(c, {
-            x1: d,
-            y1: g,
-            x2: b,
-            y2: e,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(f, f.surface, c);
-        a[c.dom.id] = h;
-        return h
-    },
-    createRadialGradient: function(b, j, d, a, i, c) {
-        var g = this,
-            e = g.surface.getNextDef("radialGradient"),
-            f = g.group.dom.gradients || (g.group.dom.gradients = {}),
-            h;
-        g.surface.setElementAttributes(e, {
-            fx: b,
-            fy: j,
-            cx: a,
-            cy: i,
-            r: c,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(g, g.surface, e, d / c);
-        f[e.dom.id] = h;
-        return h
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext.Gradient", {
-    statics: {
-        map: {}
-    },
-    constructor: function(c, a, d, b) {
-        var f = this.statics().map,
-            e;
-        e = f[d.dom.id];
-        if (e) {
-            e.element = null
-        }
-        f[d.dom.id] = this;
-        this.ctx = c;
-        this.surface = a;
-        this.element = d;
-        this.position = 0;
-        this.compression = b || 0
-    },
-    addColorStop: function(d, b) {
-        var c = this.surface.getSvgElement(this.element, "stop", this.position++),
-            a = this.compression;
-        this.surface.setElementAttributes(c, {
-            offset: (((1 - a) * d + a) * 100).toFixed(2) + "%",
-            "stop-color": b,
-            "stop-opacity": Ext.draw.Color.fly(b).a.toFixed(15)
-        })
-    },
-    toString: function() {
-        var a = this.element.dom.childNodes;
-        while (a.length > this.position) {
-            Ext.fly(a[a.length - 1]).destroy()
-        }
-        return "url(#" + this.element.getId() + ")"
-    },
-    destroy: function() {
-        var b = this.statics().map,
-            a = this.element;
-        if (a && a.dom) {
-            delete b[a.dom.id];
-            a.destroy()
-        }
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.engine.Svg", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.SvgContext"],
-    statics: {
-        BBoxTextCache: {}
-    },
-    config: {
-        highPrecision: false
-    },
-    getElementConfig: function() {
-        return {
-            reference: "element",
-            style: {
-                position: "absolute"
-            },
-            children: [{
-                reference: "innerElement",
-                style: {
-                    width: "100%",
-                    height: "100%",
-                    position: "relative"
-                },
-                children: [{
-                    tag: "svg",
-                    reference: "svgElement",
-                    namespace: "http://www.w3.org/2000/svg",
-                    width: "100%",
-                    height: "100%",
-                    version: 1.1
-                }]
-            }]
-        }
-    },
-    constructor: function(a) {
-        var b = this;
-        b.callParent([a]);
-        b.mainGroup = b.createSvgNode("g");
-        b.defElement = b.createSvgNode("defs");
-        b.svgElement.appendChild(b.mainGroup);
-        b.svgElement.appendChild(b.defElement);
-        b.ctx = new Ext.draw.engine.SvgContext(b)
-    },
-    createSvgNode: function(a) {
-        var b = document.createElementNS("http://www.w3.org/2000/svg", a);
-        return Ext.get(b)
-    },
-    getSvgElement: function(d, b, a) {
-        var c;
-        if (d.dom.childNodes.length > a) {
-            c = d.dom.childNodes[a];
-            if (c.tagName === b) {
-                return Ext.get(c)
-            } else {
-                Ext.destroy(c)
-            }
-        }
-        c = Ext.get(this.createSvgNode(b));
-        if (a === 0) {
-            d.insertFirst(c)
-        } else {
-            c.insertAfter(Ext.fly(d.dom.childNodes[a - 1]))
-        }
-        c.cache = {};
-        return c
-    },
-    setElementAttributes: function(d, b) {
-        var f = d.dom,
-            a = d.cache,
-            c, e;
-        for (c in b) {
-            e = b[c];
-            if (a[c] !== e) {
-                a[c] = e;
-                f.setAttribute(c, e)
-            }
-        }
-    },
-    getNextDef: function(a) {
-        return this.getSvgElement(this.defElement, a, this.defPosition++)
-    },
-    clearTransform: function() {
-        var a = this;
-        a.mainGroup.set({
-            transform: a.matrix.toSvg()
-        })
-    },
-    clear: function() {
-        this.ctx.clear();
-        this.defPosition = 0
-    },
-    renderSprite: function(b) {
-        var d = this,
-            c = d.getRect(),
-            a = d.ctx;
-        if (b.attr.hidden || b.attr.globalAlpha === 0) {
-            a.save();
-            a.restore();
-            return
-        }
-        b.element = a.save();
-        b.preRender(this);
-        b.useAttributes(a, c);
-        if (false === b.render(this, a, [0, 0, c[2], c[3]])) {
-            return false
-        }
-        b.setDirty(false);
-        a.restore()
-    },
-    flatten: function(e, b) {
-        var c = '<?xml version="1.0" standalone="yes"?>',
-            f = Ext.getClassName(this),
-            a, g, d;
-        c += '<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="' + e.width + '" height="' + e.height + '">';
-        for (d = 0; d < b.length; d++) {
-            a = b[d];
-            if (Ext.getClassName(a) !== f) {
-                continue
-            }
-            g = a.getRect();
-            c += '<g transform="translate(' + g[0] + "," + g[1] + ')">';
-            c += this.serializeNode(a.svgElement.dom);
-            c += "</g>"
-        }
-        c += "</svg>";
-        return {
-            data: "data:image/svg+xml;utf8," + encodeURIComponent(c),
-            type: "svg"
-        }
-    },
-    serializeNode: function(d) {
-        var b = "",
-            c, f, a, e;
-        if (d.nodeType === document.TEXT_NODE) {
-            return d.nodeValue
-        }
-        b += "<" + d.nodeName;
-        if (d.attributes.length) {
-            for (c = 0, f = d.attributes.length; c < f; c++) {
-                a = d.attributes[c];
-                b += " " + a.name + '="' + a.value + '"'
-            }
-        }
-        b += ">";
-        if (d.childNodes && d.childNodes.length) {
-            for (c = 0, f = d.childNodes.length; c < f; c++) {
-                e = d.childNodes[c];
-                b += this.serializeNode(e)
-            }
-        }
-        b += "</" + d.nodeName + ">";
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.ctx.destroy();
-        a.mainGroup.destroy();
-        delete a.mainGroup;
-        delete a.ctx;
-        a.callParent()
-    },
-    remove: function(a, b) {
-        if (a && a.element) {
-            if (this.ctx) {
-                this.ctx.removeElement(a.element)
-            } else {
-                a.element.destroy()
-            }
-            a.element = null
-        }
-        this.callParent(arguments)
-    }
-});
-Ext.draw || (Ext.draw = {});
-Ext.draw.engine || (Ext.draw.engine = {});
-Ext.draw.engine.excanvas = true;
-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) {
-            Ext.onReady(function() {
-                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.lineDash = j.lineDash;
-            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.lineDash = [];
-            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(an, j) {
-            var ah, Z, aj, ar, al, ak, ao, av;
-            var ai = an.runtimeStyle.width;
-            var am = an.runtimeStyle.height;
-            an.runtimeStyle.width = "auto";
-            an.runtimeStyle.height = "auto";
-            var ag = an.width;
-            var aq = an.height;
-            an.runtimeStyle.width = ai;
-            an.runtimeStyle.height = am;
-            if (arguments.length == 3) {
-                ah = arguments[1];
-                Z = arguments[2];
-                al = ak = 0;
-                ao = aj = ag;
-                av = ar = aq
-            } else {
-                if (arguments.length == 5) {
-                    ah = arguments[1];
-                    Z = arguments[2];
-                    aj = arguments[3];
-                    ar = arguments[4];
-                    al = ak = 0;
-                    ao = ag;
-                    av = aq
-                } else {
-                    if (arguments.length == 9) {
-                        al = arguments[1];
-                        ak = arguments[2];
-                        ao = arguments[3];
-                        av = arguments[4];
-                        ah = arguments[5];
-                        Z = arguments[6];
-                        aj = arguments[7];
-                        ar = arguments[8]
-                    } else {
-                        throw Error("Invalid number of arguments")
-                    }
-                }
-            }
-            var au = V(this, ah, Z);
-            var at = [];
-            var i = 10;
-            var p = 10;
-            var ap = this.m_;
-            at.push(" <g_vml_:group", ' coordsize="', d * i, ",", d * p, '"', ' coordorigin="0,0"', ' style="width:', n(i * ap[0][0]), "px;height:", n(p * ap[1][1]), "px;position:absolute;", "top:", n(au.y / d), "px;left:", n(au.x / d), "px; rotation:", n(Math.atan(ap[0][1] / ap[1][1]) * 180 / Math.PI), ";");
-            at.push('" >', '<g_vml_:image src="', an.src, '"', ' style="width:', d * aj, "px;", " height:", d * ar, 'px"', ' cropleft="', al / ag, '"', ' croptop="', ak / aq, '"', ' cropright="', (ag - al - ao) / ag, '"', ' cropbottom="', (aq - ak - av) / aq, '"', " />", "</g_vml_:group>");
-            this.element_.insertAdjacentHTML("BeforeEnd", at.join(""))
-        };
-        q.setLineDash = function(i) {
-            if (i.length === 1) {
-                i = i.slice();
-                i[1] = i[0]
-            }
-            this.lineDash = i
-        };
-        q.getLineDash = function() {
-            return this.lineDash
-        };
-        q.stroke = function(ak) {
-            var ai = [];
-            var m = 10;
-            var al = 10;
-            ai.push("<g_vml_:shape", ' filled="', !!ak, '"', ' style="position:absolute;width:', m, "px;height:", al, 'px;left:0px;top:0px;"', ' coordorigin="0,0"', ' coordsize="', d * m, ",", d * al, '"', ' stroked="', !ak, '"', ' path="');
-            var Z = {
-                x: null,
-                y: null
-            };
-            var aj = {
-                x: null,
-                y: null
-            };
-            for (var ag = 0; ag < this.currentPath_.length; ag++) {
-                var j = this.currentPath_[ag];
-                var ah;
-                switch (j.type) {
-                    case "moveTo":
-                        ah = j;
-                        ai.push(" m ", n(j.x), ",", n(j.y));
-                        break;
-                    case "lineTo":
-                        ai.push(" l ", n(j.x), ",", n(j.y));
-                        break;
-                    case "close":
-                        ai.push(" x ");
-                        j = null;
-                        break;
-                    case "bezierCurveTo":
-                        ai.push(" c ", n(j.cp1x), ",", n(j.cp1y), ",", n(j.cp2x), ",", n(j.cp2y), ",", n(j.x), ",", n(j.y));
-                        break;
-                    case "at":
-                    case "wa":
-                        ai.push(" ", j.type, " ", n(j.x - this.arcScaleX_ * j.radius), ",", n(j.y - this.arcScaleY_ * j.radius), " ", n(j.x + this.arcScaleX_ * j.radius), ",", n(j.y + this.arcScaleY_ * j.radius), " ", n(j.xStart), ",", n(j.yStart), " ", n(j.xEnd), ",", n(j.yEnd));
-                        break
-                }
-                if (j) {
-                    if (Z.x == null || j.x < Z.x) {
-                        Z.x = j.x
-                    }
-                    if (aj.x == null || j.x > aj.x) {
-                        aj.x = j.x
-                    }
-                    if (Z.y == null || j.y < Z.y) {
-                        Z.y = j.y
-                    }
-                    if (aj.y == null || j.y > aj.y) {
-                        aj.y = j.y
-                    }
-                }
-            }
-            ai.push(' ">');
-            if (!ak) {
-                w(this, ai)
-            } else {
-                G(this, ai, Z, aj)
-            }
-            ai.push("</g_vml_:shape>");
-            this.element_.insertAdjacentHTML("beforeEnd", ai.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, '"', ' dashstyle="', m.lineDash.join(" "), '"', ' 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 / 3;
-                    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;left:0px;top:0px;">');
-            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
-    })()
-}
-Ext.define("Ext.draw.engine.Canvas", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.excanvas", "Ext.draw.Animator", "Ext.draw.Color"],
-    config: {
-        highPrecision: false
-    },
-    statics: {
-        contextOverrides: {
-            setGradientBBox: function(a) {
-                this.bbox = a
-            },
-            fill: function() {
-                var c = this.fillStyle,
-                    a = this.fillGradient,
-                    b = this.fillOpacity,
-                    d = this.globalAlpha,
-                    e = this.bbox;
-                if (c !== Ext.draw.Color.RGBA_NONE && b !== 0) {
-                    if (a && e) {
-                        this.fillStyle = a.generateGradient(this, e)
-                    }
-                    if (b !== 1) {
-                        this.globalAlpha = d * b
-                    }
-                    this.$fill();
-                    if (b !== 1) {
-                        this.globalAlpha = d
-                    }
-                    if (a && e) {
-                        this.fillStyle = c
-                    }
-                }
-            },
-            stroke: function() {
-                var e = this.strokeStyle,
-                    c = this.strokeGradient,
-                    a = this.strokeOpacity,
-                    b = this.globalAlpha,
-                    d = this.bbox;
-                if (e !== Ext.draw.Color.RGBA_NONE && a !== 0) {
-                    if (c && d) {
-                        this.strokeStyle = c.generateGradient(this, d)
-                    }
-                    if (a !== 1) {
-                        this.globalAlpha = b * a
-                    }
-                    this.$stroke();
-                    if (a !== 1) {
-                        this.globalAlpha = b
-                    }
-                    if (c && d) {
-                        this.strokeStyle = e
-                    }
-                }
-            },
-            fillStroke: function(d, e) {
-                var j = this,
-                    i = this.fillStyle,
-                    h = this.fillOpacity,
-                    f = this.strokeStyle,
-                    c = this.strokeOpacity,
-                    b = j.shadowColor,
-                    a = j.shadowBlur,
-                    g = Ext.draw.Color.RGBA_NONE;
-                if (e === undefined) {
-                    e = d.transformFillStroke
-                }
-                if (!e) {
-                    d.inverseMatrix.toContext(j)
-                }
-                if (i !== g && h !== 0) {
-                    j.fill();
-                    j.shadowColor = g;
-                    j.shadowBlur = 0
-                }
-                if (f !== g && c !== 0) {
-                    j.stroke()
-                }
-                j.shadowColor = b;
-                j.shadowBlur = a
-            },
-            setLineDash: function(a) {
-                if (this.$setLineDash) {
-                    this.$setLineDash(a)
-                }
-            },
-            getLineDash: function() {
-                if (this.$getLineDash) {
-                    return this.$getLineDash()
-                }
-            },
-            ellipse: function(g, e, c, a, j, b, f, d) {
-                var i = Math.cos(j),
-                    h = Math.sin(j);
-                this.transform(i * c, h * c, -h * a, i * a, g, e);
-                this.arc(0, 0, 1, b, f, d);
-                this.transform(i / c, -h / a, h / c, i / a, -(i * g + h * e) / c, (h * g - i * e) / a)
-            },
-            appendPath: function(f) {
-                var e = this,
-                    c = 0,
-                    b = 0,
-                    a = f.commands,
-                    g = f.params,
-                    d = a.length;
-                e.beginPath();
-                for (; c < d; c++) {
-                    switch (a[c]) {
-                        case "M":
-                            e.moveTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "L":
-                            e.lineTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "C":
-                            e.bezierCurveTo(g[b], g[b + 1], g[b + 2], g[b + 3], g[b + 4], g[b + 5]);
-                            b += 6;
-                            break;
-                        case "Z":
-                            e.closePath();
-                            break
-                    }
-                }
-            },
-            save: function() {
-                var c = this.toSave,
-                    d = c.length,
-                    e = d && {},
-                    b = 0,
-                    a;
-                for (; b < d; b++) {
-                    a = c[b];
-                    if (a in this) {
-                        e[a] = this[a]
-                    }
-                }
-                this.state.push(e);
-                this.$save()
-            },
-            restore: function() {
-                var b = this.state.pop(),
-                    a;
-                if (b) {
-                    for (a in b) {
-                        this[a] = b[a]
-                    }
-                }
-                this.$restore()
-            }
-        }
-    },
-    splitThreshold: 3000,
-    toSave: ["fillGradient", "strokeGradient"],
-    element: {
-        reference: "element",
-        style: {
-            position: "absolute"
-        },
-        children: [{
-            reference: "innerElement",
-            style: {
-                width: "100%",
-                height: "100%",
-                position: "relative"
-            }
-        }]
-    },
-    createCanvas: function() {
-        var c = Ext.Element.create({
-            tag: "canvas",
-            cls: Ext.baseCSSPrefix + "surface-canvas"
-        });
-        window.G_vmlCanvasManager && G_vmlCanvasManager.initElement(c.dom);
-        var d = Ext.draw.engine.Canvas.contextOverrides,
-            a = c.dom.getContext("2d"),
-            b;
-        if (a.ellipse) {
-            delete d.ellipse
-        }
-        a.state = [];
-        a.toSave = this.toSave;
-        for (b in d) {
-            a["$" + b] = a[b]
-        }
-        Ext.apply(a, d);
-        if (this.getHighPrecision()) {
-            this.enablePrecisionCompensation(a)
-        } else {
-            this.disablePrecisionCompensation(a)
-        }
-        this.innerElement.appendChild(c);
-        this.canvases.push(c);
-        this.contexts.push(a)
-    },
-    updateHighPrecision: function(d) {
-        var e = this.contexts,
-            c = e.length,
-            b, a;
-        for (b = 0; b < c; b++) {
-            a = e[b];
-            if (d) {
-                this.enablePrecisionCompensation(a)
-            } else {
-                this.disablePrecisionCompensation(a)
-            }
-        }
-    },
-    precisionNames: ["rect", "fillRect", "strokeRect", "clearRect", "moveTo", "lineTo", "arc", "arcTo", "save", "restore", "updatePrecisionCompensate", "setTransform", "transform", "scale", "translate", "rotate", "quadraticCurveTo", "bezierCurveTo", "createLinearGradient", "createRadialGradient", "fillText", "strokeText", "drawImage"],
-    disablePrecisionCompensation: function(b) {
-        var a = Ext.draw.engine.Canvas.contextOverrides,
-            f = this.precisionNames,
-            e = f.length,
-            d, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            if (!(c in a)) {
-                delete b[c]
-            }
-        }
-        this.setDirty(true)
-    },
-    enablePrecisionCompensation: function(j) {
-        var c = this,
-            a = 1,
-            g = 1,
-            l = 0,
-            k = 0,
-            i = new Ext.draw.Matrix(),
-            b = [],
-            e = {},
-            d = Ext.draw.engine.Canvas.contextOverrides,
-            h = j.constructor.prototype;
-        var f = {
-            toSave: c.toSave,
-            rect: function(m, p, n, o) {
-                return h.rect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            fillRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.fillRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            strokeRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.strokeRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            clearRect: function(m, p, n, o) {
-                return h.clearRect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            moveTo: function(m, n) {
-                return h.moveTo.call(this, m * a + l, n * g + k)
-            },
-            lineTo: function(m, n) {
-                return h.lineTo.call(this, m * a + l, n * g + k)
-            },
-            arc: function(n, r, m, p, o, q) {
-                this.updatePrecisionCompensateRect();
-                h.arc.call(this, n * a + l, r * a + k, m * a, p, o, q);
-                this.updatePrecisionCompensate()
-            },
-            arcTo: function(o, q, n, p, m) {
-                this.updatePrecisionCompensateRect();
-                h.arcTo.call(this, o * a + l, q * g + k, n * a + l, p * g + k, m * a);
-                this.updatePrecisionCompensate()
-            },
-            save: function() {
-                b.push(i);
-                i = i.clone();
-                d.save.call(this);
-                h.save.call(this)
-            },
-            restore: function() {
-                i = b.pop();
-                d.restore.call(this);
-                h.restore.call(this);
-                this.updatePrecisionCompensate()
-            },
-            updatePrecisionCompensate: function() {
-                i.precisionCompensate(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            updatePrecisionCompensateRect: function() {
-                i.precisionCompensateRect(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            setTransform: function(q, o, n, m, r, p) {
-                i.set(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            transform: function(q, o, n, m, r, p) {
-                i.append(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            scale: function(n, m) {
-                this.transform(n, 0, 0, m, 0, 0)
-            },
-            translate: function(n, m) {
-                this.transform(1, 0, 0, 1, n, m)
-            },
-            rotate: function(o) {
-                var n = Math.cos(o),
-                    m = Math.sin(o);
-                this.transform(n, m, -m, n, 0, 0)
-            },
-            quadraticCurveTo: function(n, p, m, o) {
-                h.quadraticCurveTo.call(this, n * a + l, p * g + k, m * a + l, o * g + k)
-            },
-            bezierCurveTo: function(r, p, o, n, m, q) {
-                h.bezierCurveTo.call(this, r * a + l, p * g + k, o * a + l, n * g + k, m * a + l, q * g + k)
-            },
-            createLinearGradient: function(n, p, m, o) {
-                this.updatePrecisionCompensateRect();
-                var q = h.createLinearGradient.call(this, n * a + l, p * g + k, m * a + l, o * g + k);
-                this.updatePrecisionCompensate();
-                return q
-            },
-            createRadialGradient: function(p, r, o, n, q, m) {
-                this.updatePrecisionCompensateRect();
-                var s = h.createLinearGradient.call(this, p * a + l, r * a + k, o * a, n * a + l, q * a + k, m * a);
-                this.updatePrecisionCompensate();
-                return s
-            },
-            fillText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.fillText.call(this, o, m, p)
-                } else {
-                    h.fillText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            strokeText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.strokeText.call(this, o, m, p)
-                } else {
-                    h.strokeText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            fill: function() {
-                var m = this.fillGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.fillStyle = m.generateGradient(this, n)
-                }
-                h.fill.call(this);
-                this.updatePrecisionCompensate()
-            },
-            stroke: function() {
-                var m = this.strokeGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.strokeStyle = m.generateGradient(this, n)
-                }
-                h.stroke.call(this);
-                this.updatePrecisionCompensate()
-            },
-            drawImage: function(u, s, r, q, p, o, n, m, t) {
-                switch (arguments.length) {
-                    case 3:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k);
-                    case 5:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k, q * a, p * g);
-                    case 9:
-                        return h.drawImage.call(this, u, s, r, q, p, o * a + l, n * g * k, m * a, t * g)
-                }
-            }
-        };
-        Ext.apply(j, f);
-        this.setDirty(true)
-    },
-    updateRect: function(a) {
-        this.callParent([a]);
-        var C = this,
-            p = Math.floor(a[0]),
-            e = Math.floor(a[1]),
-            g = Math.ceil(a[0] + a[2]),
-            B = Math.ceil(a[1] + a[3]),
-            u = C.devicePixelRatio,
-            D = C.canvases,
-            d = g - p,
-            y = B - e,
-            n = Math.round(C.splitThreshold / u),
-            c = C.xSplits = Math.ceil(d / n),
-            f = C.ySplits = Math.ceil(y / n),
-            v, s, q, A, z, x, o, m;
-        for (s = 0, z = 0; s < f; s++, z += n) {
-            for (v = 0, A = 0; v < c; v++, A += n) {
-                q = s * c + v;
-                if (q >= D.length) {
-                    C.createCanvas()
-                }
-                x = D[q].dom;
-                x.style.left = A + "px";
-                x.style.top = z + "px";
-                m = Math.min(n, y - z);
-                if (m * u !== x.height) {
-                    x.height = m * u;
-                    x.style.height = m + "px"
-                }
-                o = Math.min(n, d - A);
-                if (o * u !== x.width) {
-                    x.width = o * u;
-                    x.style.width = o + "px"
-                }
-                C.applyDefaults(C.contexts[q])
-            }
-        }
-        for (q += 1; q < D.length; q++) {
-            D[q].destroy()
-        }
-        C.activeCanvases = c * f;
-        D.length = C.activeCanvases;
-        C.clear()
-    },
-    clearTransform: function() {
-        var f = this,
-            a = f.xSplits,
-            g = f.ySplits,
-            d = f.contexts,
-            h = f.splitThreshold,
-            l = f.devicePixelRatio,
-            e, c, b, m;
-        for (e = 0; e < a; e++) {
-            for (c = 0; c < g; c++) {
-                b = c * a + e;
-                m = d[b];
-                m.translate(-h * e, -h * c);
-                m.scale(l, l);
-                f.matrix.toContext(m)
-            }
-        }
-    },
-    renderSprite: function(q) {
-        var C = this,
-            b = C.getRect(),
-            e = C.matrix,
-            g = q.getParent(),
-            v = Ext.draw.Matrix.fly([1, 0, 0, 1, 0, 0]),
-            p = C.splitThreshold / C.devicePixelRatio,
-            c = C.xSplits,
-            m = C.ySplits,
-            A, z, s, a, r, o, d = 0,
-            B, n = 0,
-            f, l = b[2],
-            y = b[3],
-            x, u, t;
-        while (g && (g !== C)) {
-            v.prependMatrix(g.matrix || g.attr && g.attr.matrix);
-            g = g.getParent()
-        }
-        v.prependMatrix(e);
-        a = q.getBBox();
-        if (a) {
-            a = v.transformBBox(a)
-        }
-        q.preRender(C);
-        if (q.attr.hidden || q.attr.globalAlpha === 0) {
-            q.setDirty(false);
-            return
-        }
-        for (u = 0, z = 0; u < m; u++, z += p) {
-            for (x = 0, A = 0; x < c; x++, A += p) {
-                t = u * c + x;
-                s = C.contexts[t];
-                r = Math.min(p, l - A);
-                o = Math.min(p, y - z);
-                d = A;
-                B = d + r;
-                n = z;
-                f = n + o;
-                if (a) {
-                    if (a.x > B || a.x + a.width < d || a.y > f || a.y + a.height < n) {
-                        continue
-                    }
-                }
-                s.save();
-                q.useAttributes(s, b);
-                if (false === q.render(C, s, [d, n, r, o], b)) {
-                    return false
-                }
-                s.restore()
-            }
-        }
-        q.setDirty(false)
-    },
-    flatten: function(n, a) {
-        var k = document.createElement("canvas"),
-            f = Ext.getClassName(this),
-            g = this.devicePixelRatio,
-            l = k.getContext("2d"),
-            b, c, h, e, d, m;
-        k.width = Math.ceil(n.width * g);
-        k.height = Math.ceil(n.height * g);
-        for (e = 0; e < a.length; e++) {
-            b = a[e];
-            if (Ext.getClassName(b) !== f) {
-                continue
-            }
-            h = b.getRect();
-            for (d = 0; d < b.canvases.length; d++) {
-                c = b.canvases[d];
-                m = c.getOffsetsTo(c.getParent());
-                l.drawImage(c.dom, (h[0] + m[0]) * g, (h[1] + m[1]) * g)
-            }
-        }
-        return {
-            data: k.toDataURL(),
-            type: "png"
-        }
-    },
-    applyDefaults: function(a) {
-        var b = Ext.draw.Color.RGBA_NONE;
-        a.strokeStyle = b;
-        a.fillStyle = b;
-        a.textAlign = "start";
-        a.textBaseline = "alphabetic";
-        a.miterLimit = 1
-    },
-    clear: function() {
-        var d = this,
-            e = d.activeCanvases,
-            c, b, a;
-        for (c = 0; c < e; c++) {
-            b = d.canvases[c].dom;
-            a = d.contexts[c];
-            a.setTransform(1, 0, 0, 1, 0, 0);
-            a.clearRect(0, 0, b.width, b.height)
-        }
-        d.setDirty(true)
-    },
-    destroy: function() {
-        var c = this,
-            a, b = c.canvases.length;
-        for (a = 0; a < b; a++) {
-            c.contexts[a] = null;
-            c.canvases[a].destroy();
-            c.canvases[a] = null
-        }
-        delete c.contexts;
-        delete c.canvases;
-        c.callParent()
-    },
-    privates: {
-        initElement: function() {
-            var a = this;
-            a.callParent();
-            a.canvases = [];
-            a.contexts = [];
-            a.activeCanvases = (a.xSplits = 0) * (a.ySplits = 0)
-        }
-    }
-}, function() {
-    var c = this,
-        b = c.prototype,
-        a = 10000000000;
-    if (Ext.os.is.Android4 && Ext.browser.is.Chrome) {
-        a = 3000
-    } else {
-        if (Ext.is.iOS) {
-            a = 2200
-        }
-    }
-    b.splitThreshold = a
-});
-Ext.define("Ext.draw.Container", {
-    extend: "Ext.draw.ContainerBase",
-    alternateClassName: "Ext.draw.Component",
-    xtype: "draw",
-    defaultType: "surface",
-    isDrawContainer: true,
-    requires: ["Ext.draw.Surface", "Ext.draw.engine.Svg", "Ext.draw.engine.Canvas", "Ext.draw.gradient.GradientDefinition"],
-    engine: "Ext.draw.engine.Canvas",
-    config: {
-        cls: Ext.baseCSSPrefix + "draw-container",
-        resizeHandler: null,
-        sprites: null,
-        gradients: []
-    },
-    defaultDownloadServerUrl: "http://svg.sencha.io",
-    supportedFormats: ["png", "pdf", "jpeg", "gif"],
-    supportedOptions: {
-        version: Ext.isNumber,
-        data: Ext.isString,
-        format: function(a) {
-            return Ext.Array.indexOf(this.supportedFormats, a) >= 0
-        },
-        filename: Ext.isString,
-        width: Ext.isNumber,
-        height: Ext.isNumber,
-        scale: Ext.isNumber,
-        pdf: Ext.isObject,
-        jpeg: Ext.isObject
-    },
-    initAnimator: function() {
-        this.frameCallbackId = Ext.draw.Animator.addFrameCallback("renderFrame", this)
-    },
-    applyGradients: function(b) {
-        var a = [],
-            c, f, d, e;
-        if (!Ext.isArray(b)) {
-            return a
-        }
-        for (c = 0, f = b.length; c < f; c++) {
-            d = b[c];
-            if (!Ext.isObject(d)) {
-                continue
-            }
-            if (typeof d.type !== "string") {
-                d.type = "linear"
-            }
-            if (d.angle) {
-                d.degrees = d.angle;
-                delete d.angle
-            }
-            if (Ext.isObject(d.stops)) {
-                d.stops = (function(i) {
-                    var g = [],
-                        h;
-                    for (e in i) {
-                        h = i[e];
-                        h.offset = e / 100;
-                        g.push(h)
-                    }
-                    return g
-                })(d.stops)
-            }
-            a.push(d)
-        }
-        Ext.draw.gradient.GradientDefinition.add(a);
-        return a
-    },
-    applySprites: function(f) {
-        if (!f) {
-            return
-        }
-        f = Ext.Array.from(f);
-        var e = f.length,
-            b = [],
-            d, a, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            a = c.surface;
-            if (!(a && a.isSurface)) {
-                if (Ext.isString(a)) {
-                    a = this.getSurface(a)
-                } else {
-                    a = this.getSurface("main")
-                }
-            }
-            c = a.add(c);
-            b.push(c)
-        }
-        return b
-    },
-    onBodyResize: function() {
-        var b = this.element,
-            a;
-        if (!b) {
-            return
-        }
-        a = b.getSize();
-        if (a.width && a.height) {
-            this.setBodySize(a)
-        }
-    },
-    setBodySize: function(c) {
-        var d = this,
-            b = d.getResizeHandler() || d.defaultResizeHandler,
-            a;
-        d.fireEvent("bodyresize", d, c);
-        a = b.call(d, c);
-        if (a !== false) {
-            d.renderFrame()
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.getItems().each(function(b) {
-            b.setRect([0, 0, a.width, a.height])
-        })
-    },
-    getSurface: function(d) {
-        d = this.getId() + "-" + (d || "main");
-        var c = this,
-            b = c.getItems(),
-            a = b.get(d);
-        if (!a) {
-            a = c.add({
-                xclass: c.engine,
-                id: d
-            });
-            c.onBodyResize()
-        }
-        return a
-    },
-    renderFrame: function() {
-        var e = this,
-            a = e.getItems(),
-            b, d, c;
-        for (b = 0, d = a.length; b < d; b++) {
-            c = a.items[b];
-            if (c.isSurface) {
-                c.renderFrame()
-            }
-        }
-    },
-    getImage: function(k) {
-        var l = this.innerElement.getSize(),
-            a = Array.prototype.slice.call(this.items.items),
-            d, g, c = this.surfaceZIndexes,
-            f, e, b, h;
-        for (e = 1; e < a.length; e++) {
-            b = a[e];
-            h = c[b.type];
-            f = e - 1;
-            while (f >= 0 && c[a[f].type] > h) {
-                a[f + 1] = a[f];
-                f--
-            }
-            a[f + 1] = b
-        }
-        d = a[0].flatten(l, a);
-        if (k === "image") {
-            g = new Image();
-            g.src = d.data;
-            d.data = g;
-            return d
-        }
-        if (k === "stream") {
-            d.data = d.data.replace(/^data:image\/[^;]+/, "data:application/octet-stream");
-            return d
-        }
-        return d
-    },
-    download: function(d) {
-        var e = this,
-            a = [],
-            b, c, f;
-        d = Ext.apply({
-            version: 2,
-            data: e.getImage().data
-        }, d);
-        for (c in d) {
-            if (d.hasOwnProperty(c)) {
-                f = d[c];
-                if (c in e.supportedOptions) {
-                    if (e.supportedOptions[c].call(e, f)) {
-                        a.push({
-                            tag: "input",
-                            type: "hidden",
-                            name: c,
-                            value: Ext.String.htmlEncode(Ext.isObject(f) ? Ext.JSON.encode(f) : f)
-                        })
-                    }
-                }
-            }
-        }
-        b = Ext.dom.Helper.markup({
-            tag: "html",
-            children: [{
-                tag: "head"
-            }, {
-                tag: "body",
-                children: [{
-                    tag: "form",
-                    method: "POST",
-                    action: d.url || e.defaultDownloadServerUrl,
-                    children: a
-                }, {
-                    tag: "script",
-                    type: "text/javascript",
-                    children: 'document.getElementsByTagName("form")[0].submit();'
-                }]
-            }]
-        });
-        window.open("", "ImageDownload_" + Date.now()).document.write(b)
-    },
-    destroy: function() {
-        var a = this.frameCallbackId;
-        if (a) {
-            Ext.draw.Animator.removeFrameCallback(a)
-        }
-        this.callParent()
-    }
-}, function() {
-    if (location.search.match("svg")) {
-        Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-    } else {
-        if ((Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) || (Ext.browser.is.AndroidStock4 && (Ext.os.version.getMinor() === 1 || Ext.os.version.getMinor() === 2 || Ext.os.version.getMinor() === 3))) {
-            Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Base", {
-    mixins: {
-        factoryable: "Ext.mixin.Factoryable"
-    },
-    requires: ["Ext.draw.Color"],
-    factoryConfig: {
-        type: "chart.theme"
-    },
-    isTheme: true,
-    config: {
-        baseColor: null,
-        colors: undefined,
-        gradients: null,
-        chart: {
-            defaults: {
-                background: "white"
-            }
-        },
-        axis: {
-            defaults: {
-                label: {
-                    x: 0,
-                    y: 0,
-                    textBaseline: "middle",
-                    textAlign: "center",
-                    fontSize: "default",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fillStyle: "black"
-                },
-                title: {
-                    fillStyle: "black",
-                    fontSize: "default*1.23",
-                    fontFamily: "default",
-                    fontWeight: "default"
-                },
-                style: {
-                    strokeStyle: "black"
-                },
-                grid: {
-                    strokeStyle: "rgb(221, 221, 221)"
-                }
-            },
-            top: {
-                style: {
-                    textPadding: 5
-                }
-            },
-            bottom: {
-                style: {
-                    textPadding: 5
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "black",
-                    strokeStyle: "none",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fontSize: "default*1.077",
-                    textBaseline: "middle",
-                    textAlign: "center"
-                },
-                labelOverflowPadding: 5
-            }
-        },
-        sprites: {
-            text: {
-                fontSize: "default",
-                fontWeight: "default",
-                fontFamily: "default",
-                fillStyle: "black"
-            }
-        },
-        seriesThemes: undefined,
-        markerThemes: {
-            type: ["circle", "cross", "plus", "square", "triangle", "diamond"]
-        },
-        useGradients: false,
-        background: null
-    },
-    colorDefaults: ["#94ae0a", "#115fa6", "#a61120", "#ff8809", "#ffd13e", "#a61187", "#24ad9a", "#7c7474", "#a66111"],
-    constructor: function(a) {
-        this.initConfig(a);
-        this.resolveDefaults()
-    },
-    defaultRegEx: /^default([+\-/\*]\d+(?:\.\d+)?)?$/,
-    defaultOperators: {
-        "*": function(b, a) {
-            return b * a
-        },
-        "+": function(b, a) {
-            return b + a
-        },
-        "-": function(b, a) {
-            return b - a
-        }
-    },
-    resolveDefaults: function() {
-        var a = this;
-        Ext.onReady(function() {
-            var f = Ext.clone(a.getSprites()),
-                e = Ext.clone(a.getAxis()),
-                d = Ext.clone(a.getSeries()),
-                g, c, b;
-            if (!a.superclass.defaults) {
-                g = Ext.getBody().createChild({
-                    tag: "div",
-                    cls: "x-component"
-                });
-                a.superclass.defaults = {
-                    fontFamily: g.getStyle("fontFamily"),
-                    fontWeight: g.getStyle("fontWeight"),
-                    fontSize: parseFloat(g.getStyle("fontSize")),
-                    fontVariant: g.getStyle("fontVariant"),
-                    fontStyle: g.getStyle("fontStyle")
-                };
-                g.destroy()
-            }
-            a.replaceDefaults(f.text);
-            a.setSprites(f);
-            for (c in e) {
-                b = e[c];
-                a.replaceDefaults(b.label);
-                a.replaceDefaults(b.title)
-            }
-            a.setAxis(e);
-            for (c in d) {
-                b = d[c];
-                a.replaceDefaults(b.label)
-            }
-            a.setSeries(d)
-        })
-    },
-    replaceDefaults: function(h) {
-        var e = this,
-            g = e.superclass.defaults,
-            a = e.defaultRegEx,
-            d, f, c, b;
-        if (Ext.isObject(h)) {
-            for (d in g) {
-                c = a.exec(h[d]);
-                if (c) {
-                    f = g[d];
-                    c = c[1];
-                    if (c) {
-                        b = e.defaultOperators[c.charAt(0)];
-                        f = Math.round(b(f, parseFloat(c.substr(1))))
-                    }
-                    h[d] = f
-                }
-            }
-        }
-    },
-    applyBaseColor: function(c) {
-        var a, b;
-        if (c) {
-            a = c.isColor ? c : Ext.draw.Color.fromString(c);
-            b = a.getHSL()[2];
-            if (b < 0.15) {
-                a = a.createLighter(0.3)
-            } else {
-                if (b < 0.3) {
-                    a = a.createLighter(0.15)
-                } else {
-                    if (b > 0.85) {
-                        a = a.createDarker(0.3)
-                    } else {
-                        if (b > 0.7) {
-                            a = a.createDarker(0.15)
-                        }
-                    }
-                }
-            }
-            this.setColors([a.createDarker(0.3).toString(), a.createDarker(0.15).toString(), a.toString(), a.createLighter(0.12).toString(), a.createLighter(0.24).toString(), a.createLighter(0.31).toString()])
-        }
-        return c
-    },
-    applyColors: function(a) {
-        return a || this.colorDefaults
-    },
-    updateUseGradients: function(a) {
-        if (a) {
-            this.updateGradients({
-                type: "linear",
-                degrees: 90
-            })
-        }
-    },
-    updateBackground: function(a) {
-        if (a) {
-            var b = this.getChart();
-            b.defaults.background = a;
-            this.setChart(b)
-        }
-    },
-    updateGradients: function(a) {
-        var c = this.getColors(),
-            e = [],
-            h, b, d, f, g;
-        if (Ext.isObject(a)) {
-            for (f = 0, g = c && c.length || 0; f < g; f++) {
-                b = Ext.draw.Color.fromString(c[f]);
-                if (b) {
-                    d = b.createLighter(0.15).toString();
-                    h = Ext.apply(Ext.Object.chain(a), {
-                        stops: [{
-                            offset: 1,
-                            color: b.toString()
-                        }, {
-                            offset: 0,
-                            color: d.toString()
-                        }]
-                    });
-                    e.push(h)
-                }
-            }
-            this.setColors(e)
-        }
-    },
-    applySeriesThemes: function(a) {
-        this.getBaseColor();
-        this.getUseGradients();
-        this.getGradients();
-        var b = this.getColors();
-        if (!a) {
-            a = {
-                fillStyle: Ext.Array.clone(b),
-                strokeStyle: Ext.Array.map(b, function(d) {
-                    var c = Ext.draw.Color.fromString(d.stops ? d.stops[0].color : d);
-                    return c.createDarker(0.15).toString()
-                })
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.theme.Default", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default", "chart.theme.Base"]
-});
-Ext.define("Ext.chart.Markers", {
-    extend: "Ext.draw.sprite.Instancing",
-    isMarkers: true,
-    defaultCategory: "default",
-    constructor: function() {
-        this.callParent(arguments);
-        this.categories = {};
-        this.revisions = {}
-    },
-    destroy: function() {
-        this.categories = null;
-        this.revisions = null;
-        this.callParent()
-    },
-    getMarkerFor: function(b, a) {
-        if (b in this.categories) {
-            var c = this.categories[b];
-            if (a in c) {
-                return this.get(c[a])
-            }
-        }
-    },
-    clear: function(a) {
-        a = a || this.defaultCategory;
-        if (!(a in this.revisions)) {
-            this.revisions[a] = 1
-        } else {
-            this.revisions[a]++
-        }
-    },
-    putMarkerFor: function(e, b, c, h, f) {
-        e = e || this.defaultCategory;
-        var d = this,
-            g = d.categories[e] || (d.categories[e] = {}),
-            a;
-        if (c in g) {
-            d.setAttributesFor(g[c], b, h)
-        } else {
-            g[c] = d.getCount();
-            d.createInstance(b, h)
-        }
-        a = d.get(g[c]);
-        if (a) {
-            a.category = e;
-            if (!f) {
-                a.revision = d.revisions[e] || (d.revisions[e] = 1)
-            }
-        }
-    },
-    getMarkerBBoxFor: function(c, a, b) {
-        if (c in this.categories) {
-            var d = this.categories[c];
-            if (a in d) {
-                return this.getBBoxFor(d[a], b)
-            }
-        }
-    },
-    getBBox: function() {
-        return null
-    },
-    render: function(a, l, b) {
-        var f = this,
-            k = f.revisions,
-            j = f.attr.matrix,
-            h = f.getTemplate(),
-            d = h.attr,
-            g, c, e;
-        j.toContext(l);
-        h.preRender(a, l, b);
-        h.useAttributes(l, b);
-        for (c = 0, e = f.instances.length; c < e; c++) {
-            g = f.get(c);
-            if (g.hidden || g.revision !== k[g.category]) {
-                continue
-            }
-            l.save();
-            h.attr = g;
-            h.useAttributes(l, b);
-            h.render(a, l, b);
-            l.restore()
-        }
-        h.attr = d
-    }
-});
-Ext.define("Ext.chart.label.Callout", {
-    extend: "Ext.draw.modifier.Modifier",
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("calloutOriginal")) {
-            a.calloutOriginal = Ext.Object.chain(a);
-            a.calloutOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.calloutOriginal)
-        }
-    },
-    setAttrs: function(e, h) {
-        var d = e.callout,
-            i = e.calloutOriginal,
-            l = e.bbox.plain,
-            c = (l.width || 0) + e.labelOverflowPadding,
-            m = (l.height || 0) + e.labelOverflowPadding,
-            p, o;
-        if ("callout" in h) {
-            d = h.callout
-        }
-        if ("callout" in h || "calloutPlaceX" in h || "calloutPlaceY" in h || "x" in h || "y" in h) {
-            var n = "rotationRads" in h ? i.rotationRads = h.rotationRads : i.rotationRads,
-                g = "x" in h ? (i.x = h.x) : i.x,
-                f = "y" in h ? (i.y = h.y) : i.y,
-                b = "calloutPlaceX" in h ? h.calloutPlaceX : e.calloutPlaceX,
-                a = "calloutPlaceY" in h ? h.calloutPlaceY : e.calloutPlaceY,
-                k = "calloutVertical" in h ? h.calloutVertical : e.calloutVertical,
-                j;
-            n %= Math.PI * 2;
-            if (Math.cos(n) < 0) {
-                n = (n + Math.PI) % (Math.PI * 2)
-            }
-            if (n > Math.PI) {
-                n -= Math.PI * 2
-            }
-            if (k) {
-                n = n * (1 - d) - Math.PI / 2 * d;
-                j = c;
-                c = m;
-                m = j
-            } else {
-                n = n * (1 - d)
-            }
-            h.rotationRads = n;
-            h.x = g * (1 - d) + b * d;
-            h.y = f * (1 - d) + a * d;
-            p = b - g;
-            o = a - f;
-            if (Math.abs(o * c) > Math.abs(p * m)) {
-                if (o > 0) {
-                    h.calloutEndX = h.x - (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y - (m / 2) * d
-                } else {
-                    h.calloutEndX = h.x + (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y + (m / 2) * d
-                }
-            } else {
-                if (p > 0) {
-                    h.calloutEndX = h.x - c / 2;
-                    h.calloutEndY = h.y - (c / 2) * (o / p) * d
-                } else {
-                    h.calloutEndX = h.x + c / 2;
-                    h.calloutEndY = h.y + (c / 2) * (o / p) * d
-                }
-            }
-            if (h.calloutStartX && h.calloutStartY) {
-                h.calloutHasLine = (p > 0 && h.calloutStartX < h.calloutEndX) || (p <= 0 && h.calloutStartX > h.calloutEndX) || (o > 0 && h.calloutStartY < h.calloutEndY) || (o <= 0 && h.calloutStartY > h.calloutEndY)
-            } else {
-                h.calloutHasLine = true
-            }
-        }
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.calloutOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    }
-});
-Ext.define("Ext.chart.label.Label", {
-    extend: "Ext.draw.sprite.Text",
-    requires: ["Ext.chart.label.Callout"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                callout: "limited01",
-                calloutHasLine: "bool",
-                calloutPlaceX: "number",
-                calloutPlaceY: "number",
-                calloutStartX: "number",
-                calloutStartY: "number",
-                calloutEndX: "number",
-                calloutEndY: "number",
-                calloutColor: "color",
-                calloutWidth: "number",
-                calloutVertical: "bool",
-                labelOverflowPadding: "number",
-                display: "enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",
-                orientation: "enums(horizontal,vertical)",
-                renderer: "default"
-            },
-            defaults: {
-                callout: 0,
-                calloutHasLine: true,
-                calloutPlaceX: 0,
-                calloutPlaceY: 0,
-                calloutStartX: 0,
-                calloutStartY: 0,
-                calloutEndX: 0,
-                calloutEndY: 0,
-                calloutWidth: 1,
-                calloutVertical: false,
-                calloutColor: "black",
-                labelOverflowPadding: 5,
-                display: "none",
-                orientation: "",
-                renderer: null
-            },
-            triggers: {
-                callout: "transform",
-                calloutPlaceX: "transform",
-                calloutPlaceY: "transform",
-                labelOverflowPadding: "transform",
-                calloutRotation: "transform",
-                display: "hidden"
-            },
-            updaters: {
-                hidden: function(a) {
-                    a.hidden = a.display === "none"
-                }
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                callout: 200
-            }
-        },
-        field: null,
-        calloutLine: true
-    },
-    applyCalloutLine: function(a) {
-        if (a) {
-            return Ext.apply({}, a)
-        }
-    },
-    prepareModifiers: function() {
-        this.callParent(arguments);
-        this.calloutModifier = new Ext.chart.label.Callout({
-            sprite: this
-        });
-        this.fx.setNext(this.calloutModifier);
-        this.calloutModifier.setNext(this.topModifier)
-    },
-    render: function(b, c) {
-        var e = this,
-            a = e.attr,
-            d = a.calloutColor;
-        c.save();
-        c.globalAlpha *= a.callout;
-        if (c.globalAlpha > 0 && a.calloutHasLine) {
-            if (d && d.isGradient) {
-                d = d.getStops()[0].color
-            }
-            c.strokeStyle = d;
-            c.fillStyle = d;
-            c.lineWidth = a.calloutWidth;
-            c.beginPath();
-            c.moveTo(e.attr.calloutStartX, e.attr.calloutStartY);
-            c.lineTo(e.attr.calloutEndX, e.attr.calloutEndY);
-            c.stroke();
-            c.beginPath();
-            c.arc(e.attr.calloutStartX, e.attr.calloutStartY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill();
-            c.beginPath();
-            c.arc(e.attr.calloutEndX, e.attr.calloutEndY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill()
-        }
-        c.restore();
-        Ext.draw.sprite.Text.prototype.render.apply(e, arguments)
-    }
-});
-Ext.define("Ext.chart.series.Series", {
-    requires: ["Ext.chart.Markers", "Ext.chart.label.Label", "Ext.tip.ToolTip"],
-    mixins: ["Ext.mixin.Observable", "Ext.mixin.Bindable"],
-    isSeries: true,
-    defaultBindProperty: "store",
-    type: null,
-    seriesType: "sprite",
-    identifiablePrefix: "ext-line-",
-    observableType: "series",
-    darkerStrokeRatio: 0.15,
-    config: {
-        chart: null,
-        title: null,
-        renderer: null,
-        showInLegend: true,
-        triggerAfterDraw: false,
-        style: {},
-        subStyle: {},
-        themeStyle: {},
-        colors: null,
-        useDarkerStrokeColor: true,
-        store: null,
-        label: {},
-        labelOverflowPadding: null,
-        showMarkers: true,
-        marker: null,
-        markerSubStyle: null,
-        itemInstancing: null,
-        background: null,
-        highlightItem: null,
-        surface: null,
-        overlaySurface: null,
-        hidden: false,
-        highlight: false,
-        highlightCfg: {
-            merge: function(a) {
-                return a
-            },
-            $value: {
-                fillStyle: "yellow",
-                strokeStyle: "red"
-            }
-        },
-        animation: null,
-        tooltip: null
-    },
-    directions: [],
-    sprites: null,
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 0
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        var a = this.getChart();
-        if (a && a.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    updateTitle: function(a) {
-        var j = this,
-            g = j.getChart();
-        if (!g || g.isInitializing) {
-            return
-        }
-        a = Ext.Array.from(a);
-        var c = g.getSeries(),
-            b = Ext.Array.indexOf(c, j),
-            e = g.getLegendStore(),
-            h = j.getYField(),
-            d, l, k, f;
-        if (e.getCount() && b !== -1) {
-            f = h ? Math.min(a.length, h.length) : a.length;
-            for (d = 0; d < f; d++) {
-                k = a[d];
-                l = e.getAt(b + d);
-                if (k && l) {
-                    l.set("name", k)
-                }
-            }
-        }
-    },
-    applyHighlight: function(a, b) {
-        if (Ext.isObject(a)) {
-            a = Ext.merge({}, this.config.highlightCfg, a)
-        } else {
-            if (a === true) {
-                a = this.config.highlightCfg
-            }
-        }
-        return Ext.apply(b || {}, a)
-    },
-    updateHighlight: function(a) {
-        this.getStyle();
-        if (!Ext.Object.isEmpty(a)) {
-            this.addItemHighlight()
-        }
-    },
-    updateHighlightCfg: function(a) {
-        if (!Ext.Object.equals(a, this.defaultConfig.highlightCfg)) {
-            this.addItemHighlight()
-        }
-    },
-    applyItemInstancing: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    setAttributesForItem: function(c, d) {
-        var b = c && c.sprite,
-            a;
-        if (b) {
-            if (b.itemsMarker && c.category === "items") {
-                b.putMarker(c.category, d, c.index, false, true)
-            }
-            if (b.isMarkerHolder && c.category === "markers") {
-                b.putMarker(c.category, d, c.index, false, true)
-            } else {
-                if (b.isInstancing) {
-                    b.setAttributesFor(c.index, d)
-                } else {
-                    if (Ext.isArray(b)) {
-                        for (a = 0; a < b.length; a++) {
-                            b[a].setAttributes(d)
-                        }
-                    } else {
-                        b.setAttributes(d)
-                    }
-                }
-            }
-        }
-    },
-    getBBoxForItem: function(a) {
-        if (a && a.sprite) {
-            if (a.sprite.itemsMarker && a.category === "items") {
-                return a.sprite.getMarkerBBox(a.category, a.index)
-            } else {
-                if (a.sprite instanceof Ext.draw.sprite.Instancing) {
-                    return a.sprite.getBBoxFor(a.index)
-                } else {
-                    return a.sprite.getBBox()
-                }
-            }
-        }
-        return null
-    },
-    applyHighlightItem: function(d, a) {
-        if (d === a) {
-            return
-        }
-        if (Ext.isObject(d) && Ext.isObject(a)) {
-            var c = d.sprite === a.sprite,
-                b = d.index === a.index;
-            if (c && b) {
-                return
-            }
-        }
-        return d
-    },
-    updateHighlightItem: function(b, a) {
-        this.setAttributesForItem(a, {
-            highlighted: false
-        });
-        this.setAttributesForItem(b, {
-            highlighted: true
-        })
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if (a.tips) {
-            a = Ext.apply({
-                tooltip: a.tips
-            }, a)
-        }
-        if (a.highlightCfg) {
-            a = Ext.apply({
-                highlight: a.highlightCfg
-            }, a)
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.sprites = [];
-        b.dataRange = [];
-        b.mixins.observable.constructor.call(b, a);
-        b.initBindable()
-    },
-    lookupViewModel: function(a) {
-        var b = this.getChart();
-        return b ? b.lookupViewModel(a) : null
-    },
-    applyTooltip: function(c, b) {
-        var a = Ext.apply({
-            xtype: "tooltip",
-            renderer: Ext.emptyFn,
-            constrainPosition: true,
-            shrinkWrapDock: true,
-            autoHide: true,
-            offsetX: 10,
-            offsetY: 10
-        }, c);
-        return Ext.create(a)
-    },
-    updateTooltip: function() {
-        this.addItemHighlight()
-    },
-    addItemHighlight: function() {
-        var d = this.getChart();
-        if (!d) {
-            return
-        }
-        var e = d.getInteractions(),
-            c, a, b;
-        for (c = 0; c < e.length; c++) {
-            a = e[c];
-            if (a.isItemHighlight || a.isItemEdit) {
-                b = true;
-                break
-            }
-        }
-        if (!b) {
-            e.push("itemhighlight");
-            d.setInteractions(e)
-        }
-    },
-    showTooltip: function(l, m) {
-        var d = this,
-            n = d.getTooltip(),
-            j, a, i, f, h, k, g, e, b, c;
-        if (!n) {
-            return
-        }
-        clearTimeout(d.tooltipTimeout);
-        b = n.config;
-        if (n.trackMouse) {
-            m[0] += b.offsetX;
-            m[1] += b.offsetY
-        } else {
-            j = l.sprite;
-            a = j.getSurface();
-            i = Ext.get(a.getId());
-            if (i) {
-                k = l.series.getBBoxForItem(l);
-                g = k.x + k.width / 2;
-                e = k.y + k.height / 2;
-                h = a.matrix.transformPoint([g, e]);
-                f = i.getXY();
-                c = a.getInherited().rtl;
-                g = c ? f[0] + i.getWidth() - h[0] : f[0] + h[0];
-                e = f[1] + h[1];
-                m = [g, e]
-            }
-        }
-        Ext.callback(n.renderer, n.scope, [n, l.record, l], 0, d);
-        n.show(m)
-    },
-    hideTooltip: function(b) {
-        var a = this,
-            c = a.getTooltip();
-        if (!c) {
-            return
-        }
-        clearTimeout(a.tooltipTimeout);
-        a.tooltipTimeout = Ext.defer(function() {
-            c.hide()
-        }, 1)
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    getStore: function() {
-        return this._store || this.getChart() && this.getChart().getStore()
-    },
-    updateStore: function(b, a) {
-        var h = this,
-            g = h.getChart(),
-            c = g && g.getStore(),
-            f, j, e, d;
-        a = a || c;
-        if (a && a !== b) {
-            a.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            })
-        }
-        if (b) {
-            b.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            });
-            f = h.getSprites();
-            for (d = 0, e = f.length; d < e; d++) {
-                j = f[d];
-                if (j.setStore) {
-                    j.setStore(b)
-                }
-            }
-            h.onDataChanged()
-        }
-        h.fireEvent("storechange", h, b, a)
-    },
-    onStoreChange: function(b, a, c) {
-        if (!this._store) {
-            this.updateStore(a, c)
-        }
-    },
-    coordinate: function(o, m, e) {
-        var l = this,
-            p = l.getStore(),
-            h = l.getHidden(),
-            k = p.getData().items,
-            b = l["get" + o + "Axis"](),
-            f = {
-                min: Infinity,
-                max: -Infinity
-            },
-            q = l["fieldCategory" + o] || [o],
-            g = l.getFields(q),
-            d, n, c, a = {},
-            j = l.getSprites();
-        if (j.length > 0) {
-            if (!Ext.isBoolean(h) || !h) {
-                for (d = 0; d < q.length; d++) {
-                    n = g[d];
-                    c = l.coordinateData(k, n, b);
-                    l.getRangeOfData(c, f);
-                    a["data" + q[d]] = c
-                }
-            }
-            l.dataRange[m] = f.min;
-            l.dataRange[m + e] = f.max;
-            a["dataMin" + o] = f.min;
-            a["dataMax" + o] = f.max;
-            if (b) {
-                b.range = null;
-                a["range" + o] = b.getRange()
-            }
-            for (d = 0; d < j.length; d++) {
-                j[d].setAttributes(a)
-            }
-        }
-    },
-    coordinateData: function(b, h, d) {
-        var g = [],
-            f = b.length,
-            e = d && d.getLayout(),
-            c, a;
-        for (c = 0; c < f; c++) {
-            a = b[c].data[h];
-            if (!Ext.isEmpty(a, true)) {
-                if (e) {
-                    g[c] = e.getCoordFor(a, h, c, b)
-                } else {
-                    g[c] = +a
-                }
-            } else {
-                g[c] = a
-            }
-        }
-        return g
-    },
-    getRangeOfData: function(g, b) {
-        var e = g.length,
-            d = b.min,
-            a = b.max,
-            c, f;
-        for (c = 0; c < e; c++) {
-            f = g[c];
-            if (f < d) {
-                d = f
-            }
-            if (f > a) {
-                a = f
-            }
-        }
-        b.min = d;
-        b.max = a
-    },
-    updateLabelData: function() {
-        var h = this,
-            l = h.getStore(),
-            g = l.getData().items,
-            f = h.getSprites(),
-            a = h.getLabel().getTemplate(),
-            n = Ext.Array.from(a.getField()),
-            c, b, e, d, m, k;
-        if (!f.length || !n.length) {
-            return
-        }
-        for (c = 0; c < f.length; c++) {
-            d = [];
-            m = f[c];
-            k = m.getField();
-            if (Ext.Array.indexOf(n, k) < 0) {
-                k = n[c]
-            }
-            for (b = 0, e = g.length; b < e; b++) {
-                d.push(g[b].get(k))
-            }
-            m.setAttributes({
-                labels: d
-            })
-        }
-    },
-    processData: function() {
-        if (!this.getStore()) {
-            return
-        }
-        var d = this,
-            f = this.directions,
-            a, c = f.length,
-            e, b;
-        for (a = 0; a < c; a++) {
-            e = f[a];
-            b = d["get" + e + "Axis"]();
-            if (b) {
-                b.processData(d);
-                continue
-            }
-            if (d["coordinate" + e]) {
-                d["coordinate" + e]()
-            }
-        }
-        d.updateLabelData()
-    },
-    applyBackground: function(a) {
-        if (this.getChart()) {
-            this.getSurface().setBackground(a);
-            return this.getSurface().getBackground()
-        } else {
-            return a
-        }
-    },
-    updateChart: function(d, a) {
-        var c = this,
-            b = c._store;
-        if (a) {
-            a.un("axeschange", "onAxesChange", c);
-            c.clearSprites();
-            c.setSurface(null);
-            c.setOverlaySurface(null);
-            a.unregister(c);
-            c.onChartDetached(a);
-            if (!b) {
-                c.updateStore(null)
-            }
-        }
-        if (d) {
-            c.setSurface(d.getSurface("series"));
-            c.setOverlaySurface(d.getSurface("overlay"));
-            d.on("axeschange", "onAxesChange", c);
-            if (d.getAxes()) {
-                c.onAxesChange(d)
-            }
-            c.onChartAttached(d);
-            d.register(c);
-            if (!b) {
-                c.updateStore(d.getStore())
-            }
-        }
-    },
-    onAxesChange: function(h) {
-        var k = this,
-            g = h.getAxes(),
-            c, a = {},
-            b = {},
-            e = false,
-            j = this.directions,
-            l, d, f;
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            b[l] = k.getFields(k["fieldCategory" + l])
-        }
-        for (d = 0, f = g.length; d < f; d++) {
-            c = g[d];
-            if (!a[c.getDirection()]) {
-                a[c.getDirection()] = [c]
-            } else {
-                a[c.getDirection()].push(c)
-            }
-        }
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            if (k["get" + l + "Axis"]()) {
-                continue
-            }
-            if (a[l]) {
-                c = k.findMatchingAxis(a[l], b[l]);
-                if (c) {
-                    k["set" + l + "Axis"](c);
-                    if (c.getNeedHighPrecision()) {
-                        e = true
-                    }
-                }
-            }
-        }
-        this.getSurface().setHighPrecision(e)
-    },
-    findMatchingAxis: function(f, e) {
-        var d, c, b, a;
-        for (b = 0; b < f.length; b++) {
-            d = f[b];
-            c = d.getFields();
-            if (!c.length) {
-                return d
-            } else {
-                if (e) {
-                    for (a = 0; a < e.length; a++) {
-                        if (Ext.Array.indexOf(c, e[a]) >= 0) {
-                            return d
-                        }
-                    }
-                }
-            }
-        }
-    },
-    onChartDetached: function(a) {
-        var b = this;
-        b.fireEvent("chartdetached", a, b);
-        a.un("storechange", "onStoreChange", b)
-    },
-    onChartAttached: function(a) {
-        var b = this;
-        b.setBackground(b.getBackground());
-        b.fireEvent("chartattached", a, b);
-        a.on("storechange", "onStoreChange", b);
-        b.processData()
-    },
-    updateOverlaySurface: function(a) {
-        var b = this;
-        if (a) {
-            if (b.getLabel()) {
-                b.getOverlaySurface().add(b.getLabel())
-            }
-        }
-    },
-    applyLabel: function(a, b) {
-        if (!b) {
-            b = new Ext.chart.Markers({
-                zIndex: 10
-            });
-            b.setTemplate(new Ext.chart.label.Label(a))
-        } else {
-            b.getTemplate().setAttributes(a)
-        }
-        return b
-    },
-    createItemInstancingSprite: function(c, b) {
-        var e = this,
-            f = new Ext.chart.Markers(),
-            a, d;
-        f.setAttributes({
-            zIndex: Number.MAX_VALUE
-        });
-        a = Ext.apply({}, b);
-        if (e.getHighlight()) {
-            a.highlight = e.getHighlight();
-            a.modifiers = ["highlight"]
-        }
-        f.setTemplate(a);
-        d = f.getTemplate();
-        d.setAttributes(e.getStyle());
-        d.fx.on("animationstart", "onSpriteAnimationStart", this);
-        d.fx.on("animationend", "onSpriteAnimationEnd", this);
-        c.bindMarker("items", f);
-        e.getSurface().add(f);
-        return f
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer()
-        }
-    },
-    updateRenderer: function(c) {
-        var b = this,
-            a = b.getChart(),
-            d;
-        if (a && a.isInitializing) {
-            return
-        }
-        d = b.getSprites();
-        if (d.length) {
-            d[0].setAttributes({
-                renderer: c || null
-            });
-            if (a && !a.isInitializing) {
-                a.redraw()
-            }
-        }
-    },
-    updateShowMarkers: function(a) {
-        var d = this.getSprites(),
-            b = d && d[0],
-            c = b && b.getMarker("markers");
-        if (c) {
-            c.getTemplate().setAttributes({
-                hidden: !a
-            })
-        }
-    },
-    createSprite: function() {
-        var f = this,
-            a = f.getSurface(),
-            e = f.getItemInstancing(),
-            d = a.add(f.getDefaultSpriteConfig()),
-            b = f.getMarker(),
-            g, c;
-        d.setAttributes(f.getStyle());
-        d.setSeries(f);
-        if (e) {
-            d.itemsMarker = f.createItemInstancingSprite(d, e)
-        }
-        if (d.bindMarker) {
-            if (b) {
-                g = new Ext.chart.Markers();
-                c = Ext.Object.merge({}, b);
-                if (f.getHighlight()) {
-                    c.highlight = f.getHighlight();
-                    c.modifiers = ["highlight"]
-                }
-                g.setTemplate(c);
-                g.getTemplate().fx.setCustomDurations({
-                    translationX: 0,
-                    translationY: 0
-                });
-                d.dataMarker = g;
-                d.bindMarker("markers", g);
-                f.getOverlaySurface().add(g)
-            }
-            if (f.getLabel().getTemplate().getField()) {
-                d.bindMarker("labels", f.getLabel())
-            }
-        }
-        if (d.setStore) {
-            d.setStore(f.getStore())
-        }
-        d.fx.on("animationstart", "onSpriteAnimationStart", f);
-        d.fx.on("animationend", "onSpriteAnimationEnd", f);
-        f.sprites.push(d);
-        return d
-    },
-    getSprites: Ext.emptyFn,
-    onDataChanged: function() {
-        var d = this,
-            c = d.getChart(),
-            b = c && c.getStore(),
-            a = d.getStore();
-        if (a !== b) {
-            d.processData()
-        }
-    },
-    isXType: function(a) {
-        return a === "series"
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    applyThemeStyle: function(e, a) {
-        var b = this,
-            d, c;
-        d = e && e.subStyle && e.subStyle.fillStyle;
-        c = d && e.subStyle.strokeStyle;
-        if (d && !c) {
-            e.subStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        d = e && e.markerSubStyle && e.markerSubStyle.fillStyle;
-        c = d && e.markerSubStyle.strokeStyle;
-        if (d && !c) {
-            e.markerSubStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        return Ext.apply(a || {}, e)
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        return Ext.apply({}, c, b)
-    },
-    applySubStyle: function(b, c) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            b = a.def.batchedNormalize(b, true)
-        }
-        return Ext.merge({}, c, b)
-    },
-    applyMarker: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.normalize(Ext.isObject(c) ? c : {}, true);
-            c.type = d
-        }
-        return Ext.merge(a || {}, c)
-    },
-    applyMarkerSubStyle: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.batchedNormalize(c, true)
-        }
-        return Ext.merge(a || {}, c)
-    },
-    updateHidden: function(b) {
-        var a = this;
-        a.getColors();
-        a.getSubStyle();
-        a.setSubStyle({
-            hidden: b
-        });
-        a.processData();
-        a.doUpdateStyles();
-        if (!Ext.isArray(b)) {
-            a.updateLegendStore(b)
-        }
-    },
-    updateLegendStore: function(f, b) {
-        var e = this,
-            d = e.getChart(),
-            c = d.getLegendStore(),
-            g = e.getId(),
-            a;
-        if (c) {
-            if (arguments.length > 1) {
-                a = c.findBy(function(h) {
-                    return h.get("series") === g && h.get("index") === b
-                });
-                if (a !== -1) {
-                    a = c.getAt(a)
-                }
-            } else {
-                a = c.findRecord("series", g)
-            }
-            if (a && a.get("disabled") !== f) {
-                a.set("disabled", f)
-            }
-        }
-    },
-    setHiddenByIndex: function(a, c) {
-        var b = this;
-        if (Ext.isArray(b.getHidden())) {
-            b.getHidden()[a] = c;
-            b.updateHidden(b.getHidden());
-            b.updateLegendStore(c, a)
-        } else {
-            b.setHidden(c)
-        }
-    },
-    getStrokeColorsFromFillColors: function(a) {
-        var c = this,
-            e = c.getUseDarkerStrokeColor(),
-            b = (Ext.isNumber(e) ? e : c.darkerStrokeRatio),
-            d;
-        if (e) {
-            d = Ext.Array.map(a, function(f) {
-                f = Ext.isString(f) ? f : f.stops[0].color;
-                f = Ext.draw.Color.fromString(f);
-                return f.createDarker(b).toString()
-            })
-        } else {
-            d = Ext.Array.clone(a)
-        }
-        return d
-    },
-    updateThemeColors: function(b) {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = Ext.Array.clone(b),
-            f = c.getStrokeColorsFromFillColors(b),
-            e = {
-                fillStyle: a,
-                strokeStyle: f
-            };
-        d.subStyle = Ext.apply(d.subStyle || {}, e);
-        d.markerSubStyle = Ext.apply(d.markerSubStyle || {}, e);
-        c.doUpdateStyles()
-    },
-    themeOnlyIfConfigured: {},
-    updateTheme: function(d) {
-        var h = this,
-            a = d.getSeries(),
-            n = h.getInitialConfig(),
-            c = h.defaultConfig,
-            f = h.getConfigurator().configs,
-            j = a.defaults,
-            k = a[h.type],
-            g = h.themeOnlyIfConfigured,
-            l, i, o, b, m, e;
-        a = Ext.merge({}, j, k);
-        for (l in a) {
-            i = a[l];
-            e = f[l];
-            if (i !== null && i !== undefined && e) {
-                m = n[l];
-                o = Ext.isObject(i);
-                b = m === c[l];
-                if (o) {
-                    if (b && g[l]) {
-                        continue
-                    }
-                    i = Ext.merge({}, i, m)
-                }
-                if (b || o) {
-                    h[e.names.set](i)
-                }
-            }
-        }
-    },
-    updateChartColors: function(a) {
-        var b = this;
-        if (!b.getColors()) {
-            b.updateThemeColors(a)
-        }
-    },
-    updateColors: function(a) {
-        this.updateThemeColors(a)
-    },
-    updateStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateSubStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateThemeStyle: function() {
-        this.doUpdateStyles()
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.sprites,
-            d = g.getItemInstancing(),
-            c = 0,
-            f = h && h.length,
-            a = g.getConfig("showMarkers", true),
-            b = g.getMarker(),
-            e;
-        for (; c < f; c++) {
-            e = g.getStyleByIndex(c);
-            if (d) {
-                h[c].itemsMarker.getTemplate().setAttributes(e)
-            }
-            h[c].setAttributes(e);
-            if (b && h[c].dataMarker) {
-                h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))
-            }
-        }
-    },
-    getStyleWithTheme: function() {
-        var b = this,
-            c = b.getThemeStyle(),
-            d = (c && c.style) || {},
-            a = Ext.applyIf(Ext.apply({}, b.getStyle()), d);
-        return a
-    },
-    getSubStyleWithTheme: function() {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = (d && d.subStyle) || {},
-            b = Ext.applyIf(Ext.apply({}, c.getSubStyle()), a);
-        return b
-    },
-    getStyleByIndex: function(b) {
-        var e = this,
-            h = e.getThemeStyle(),
-            d, g, c, f, a = {};
-        d = e.getStyle();
-        g = (h && h.style) || {};
-        c = e.styleDataForIndex(e.getSubStyle(), b);
-        f = e.styleDataForIndex((h && h.subStyle), b);
-        Ext.apply(a, g);
-        Ext.apply(a, f);
-        Ext.apply(a, d);
-        Ext.apply(a, c);
-        return a
-    },
-    getMarkerStyleByIndex: function(d) {
-        var g = this,
-            c = g.getThemeStyle(),
-            a, e, k, j, b, l, h, f, m = {};
-        a = g.getStyle();
-        e = (c && c.style) || {};
-        k = g.styleDataForIndex(g.getSubStyle(), d);
-        if (k.hasOwnProperty("hidden")) {
-            k.hidden = k.hidden || !this.getConfig("showMarkers", true)
-        }
-        j = g.styleDataForIndex((c && c.subStyle), d);
-        b = g.getMarker();
-        l = (c && c.marker) || {};
-        h = g.getMarkerSubStyle();
-        f = g.styleDataForIndex((c && c.markerSubStyle), d);
-        Ext.apply(m, e);
-        Ext.apply(m, j);
-        Ext.apply(m, l);
-        Ext.apply(m, f);
-        Ext.apply(m, a);
-        Ext.apply(m, k);
-        Ext.apply(m, b);
-        Ext.apply(m, h);
-        return m
-    },
-    styleDataForIndex: function(d, c) {
-        var e, b, a = {};
-        if (d) {
-            for (b in d) {
-                e = d[b];
-                if (Ext.isArray(e)) {
-                    a[b] = e[c % e.length]
-                } else {
-                    a[b] = e
-                }
-            }
-        }
-        return a
-    },
-    getItemForPoint: Ext.emptyFn,
-    getItemByIndex: function(a, e) {
-        var d = this,
-            f = d.getSprites(),
-            b = f && f[0],
-            c;
-        if (!b) {
-            return
-        }
-        if (e === undefined && b.isMarkerHolder) {
-            e = d.getItemInstancing() ? "items" : "markers"
-        } else {
-            if (!e || e === "" || e === "sprites") {
-                b = f[a]
-            }
-        }
-        if (b) {
-            c = {
-                series: d,
-                category: e,
-                index: a,
-                record: d.getStore().getData().items[a],
-                field: d.getYField(),
-                sprite: b
-            };
-            return c
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.fireEvent("animationstart", this, a)
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.fireEvent("animationend", this, a)
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    provideLegendInfo: function(a) {
-        a.push({
-            name: this.getTitle() || this.getId(),
-            mark: "black",
-            disabled: this.getHidden(),
-            series: this.getId(),
-            index: 0
-        })
-    },
-    clearSprites: function() {
-        var d = this.sprites,
-            b, a, c;
-        for (a = 0, c = d.length; a < c; a++) {
-            b = d[a];
-            if (b && b.isSprite) {
-                b.destroy()
-            }
-        }
-        this.sprites = []
-    },
-    destroy: function() {
-        var b = this,
-            a = b._store,
-            c = b.getConfig("tooltip", true);
-        if (a && a.getAutoDestroy()) {
-            Ext.destroy(a)
-        }
-        b.setChart(null);
-        b.clearListeners();
-        if (c) {
-            Ext.destroy(c);
-            clearTimeout(b.tooltipTimeout)
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Abstract", {
-    xtype: "interaction",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        gestures: {
-            tap: "onGesture"
-        },
-        chart: null,
-        enabled: true
-    },
-    throttleGap: 0,
-    stopAnimationBeforeSync: false,
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.call(b, a)
-    },
-    initialize: Ext.emptyFn,
-    updateChart: function(c, a) {
-        var b = this;
-        if (a === c) {
-            return
-        }
-        if (a) {
-            a.unregister(b);
-            b.removeChartListener(a)
-        }
-        if (c) {
-            c.register(b);
-            b.addChartListener()
-        }
-    },
-    updateEnabled: function(a) {
-        var c = this,
-            b = c.getChart();
-        if (b) {
-            if (a) {
-                c.addChartListener()
-            } else {
-                c.removeChartListener(b)
-            }
-        }
-    },
-    onGesture: Ext.emptyFn,
-    getItemForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemForPoint(c[0], c[1])
-    },
-    getItemsForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemsForPoint(c[0], c[1])
-    },
-    addChartListener: function() {
-        var c = this,
-            b = c.getChart(),
-            e = c.getGestures(),
-            a;
-        if (!c.getEnabled()) {
-            return
-        }
-
-        function d(f, g) {
-            b.addElementListener(f, c.listeners[f] = function(j) {
-                var i = c.getLocks(),
-                    h;
-                if (c.getEnabled() && (!(f in i) || i[f] === c)) {
-                    h = (Ext.isFunction(g) ? g : c[g]).apply(this, arguments);
-                    if (h === false && j && j.stopPropagation) {
-                        j.stopPropagation()
-                    }
-                    return h
-                }
-            }, c)
-        }
-        c.listeners = c.listeners || {};
-        for (a in e) {
-            d(a, e[a])
-        }
-    },
-    removeChartListener: function(c) {
-        var d = this,
-            e = d.getGestures(),
-            b;
-
-        function a(f) {
-            var g = d.listeners[f];
-            if (g) {
-                c.removeElementListener(f, g);
-                delete d.listeners[f]
-            }
-        }
-        if (d.listeners) {
-            for (b in e) {
-                a(b)
-            }
-        }
-    },
-    lockEvents: function() {
-        var d = this,
-            c = d.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            c[a[b]] = d
-        }
-    },
-    unlockEvents: function() {
-        var c = this.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            delete c[a[b]]
-        }
-    },
-    getLocks: function() {
-        var a = this.getChart();
-        return a.lockedEvents || (a.lockedEvents = {})
-    },
-    isMultiTouch: function() {
-        if (Ext.browser.is.IE10) {
-            return true
-        }
-        return !Ext.os.is.Desktop
-    },
-    initializeDefaults: Ext.emptyFn,
-    doSync: function() {
-        var b = this,
-            a = b.getChart();
-        if (b.syncTimer) {
-            clearTimeout(b.syncTimer);
-            b.syncTimer = null
-        }
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount++
-        }
-        a.redraw();
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount--
-        }
-        b.syncThrottle = Date.now() + b.throttleGap
-    },
-    sync: function() {
-        var a = this;
-        if (a.throttleGap && Ext.frameStartTime < a.syncThrottle) {
-            if (a.syncTimer) {
-                return
-            }
-            a.syncTimer = Ext.defer(function() {
-                a.doSync()
-            }, a.throttleGap)
-        } else {
-            a.doSync()
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    isXType: function(a) {
-        return a === "interaction"
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        delete a.listeners;
-        a.callParent()
-    }
-}, function() {
-    if (Ext.os.is.Android4) {
-        this.prototype.throttleGap = 40
-    }
-});
-Ext.define("Ext.chart.MarkerHolder", {
-    extend: "Ext.Mixin",
-    mixinConfig: {
-        id: "markerHolder",
-        after: {
-            constructor: "constructor",
-            preRender: "preRender"
-        },
-        before: {
-            destroy: "destroy"
-        }
-    },
-    isMarkerHolder: true,
-    surfaceMatrix: null,
-    inverseSurfaceMatrix: null,
-    deprecated: {
-        6: {
-            methods: {
-                getBoundMarker: {
-                    message: "Please use the 'getMarker' method instead.",
-                    fn: function(b) {
-                        var a = this.boundMarkers[b];
-                        return a ? [a] : a
-                    }
-                }
-            }
-        }
-    },
-    constructor: function() {
-        this.boundMarkers = {};
-        this.cleanRedraw = false
-    },
-    bindMarker: function(b, a) {
-        var c = this,
-            d = c.boundMarkers;
-        if (a && a.isMarkers) {
-            c.releaseMarker(b);
-            d[b] = a;
-            a.on("destroy", c.onMarkerDestroy, c)
-        }
-    },
-    onMarkerDestroy: function(a) {
-        this.releaseMarker(a)
-    },
-    releaseMarker: function(a) {
-        var c = this.boundMarkers,
-            b;
-        if (a && a.isMarkers) {
-            for (b in c) {
-                if (c[b] === a) {
-                    delete c[b];
-                    break
-                }
-            }
-        } else {
-            b = a;
-            a = c[b];
-            delete c[b]
-        }
-        return a || null
-    },
-    getMarker: function(a) {
-        return this.boundMarkers[a] || null
-    },
-    preRender: function() {
-        var f = this,
-            g = f.getId(),
-            d = f.boundMarkers,
-            e = f.getParent(),
-            c, a, b;
-        if (f.surfaceMatrix) {
-            b = f.surfaceMatrix.set(1, 0, 0, 1, 0, 0)
-        } else {
-            b = f.surfaceMatrix = new Ext.draw.Matrix()
-        }
-        f.cleanRedraw = !f.attr.dirty;
-        if (!f.cleanRedraw) {
-            for (c in d) {
-                a = d[c];
-                if (a) {
-                    a.clear(g)
-                }
-            }
-        }
-        while (e && e.attr && e.attr.matrix) {
-            b.prependMatrix(e.attr.matrix);
-            e = e.getParent()
-        }
-        b.prependMatrix(e.matrix);
-        f.surfaceMatrix = b;
-        f.inverseSurfaceMatrix = b.inverse(f.inverseSurfaceMatrix)
-    },
-    putMarker: function(d, a, c, g, e) {
-        var b = this.boundMarkers[d],
-            f = this.getId();
-        if (b) {
-            b.putMarkerFor(f, a, c, g, e)
-        }
-    },
-    getMarkerBBox: function(c, b, d) {
-        var a = this.boundMarkers[c],
-            e = this.getId();
-        if (a) {
-            return a.getMarkerBBoxFor(e, b, d)
-        }
-    },
-    destroy: function() {
-        var c = this.boundMarkers,
-            b, a;
-        for (b in c) {
-            a = c[b];
-            a.destroy()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.axis",
-    type: "axis",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    requires: ["Ext.draw.sprite.Text"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                grid: "bool",
-                axisLine: "bool",
-                minorTicks: "bool",
-                minorTickSize: "number",
-                majorTicks: "bool",
-                majorTickSize: "number",
-                length: "number",
-                startGap: "number",
-                endGap: "number",
-                dataMin: "number",
-                dataMax: "number",
-                visibleMin: "number",
-                visibleMax: "number",
-                position: "enums(left,right,top,bottom,angular,radial,gauge)",
-                minStepSize: "number",
-                estStepSize: "number",
-                titleOffset: "number",
-                textPadding: "number",
-                min: "number",
-                max: "number",
-                centerX: "number",
-                centerY: "number",
-                radius: "number",
-                totalAngle: "number",
-                baseRotation: "number",
-                data: "default",
-                enlargeEstStepSizeByText: "bool"
-            },
-            defaults: {
-                grid: false,
-                axisLine: true,
-                minorTicks: false,
-                minorTickSize: 3,
-                majorTicks: true,
-                majorTickSize: 5,
-                length: 0,
-                startGap: 0,
-                endGap: 0,
-                visibleMin: 0,
-                visibleMax: 1,
-                dataMin: 0,
-                dataMax: 1,
-                position: "",
-                minStepSize: 0,
-                estStepSize: 20,
-                min: 0,
-                max: 1,
-                centerX: 0,
-                centerY: 0,
-                radius: 1,
-                baseRotation: 0,
-                data: null,
-                titleOffset: 0,
-                textPadding: 0,
-                scalingCenterY: 0,
-                scalingCenterX: 0,
-                strokeStyle: "black",
-                enlargeEstStepSizeByText: false
-            },
-            triggers: {
-                minorTickSize: "bbox",
-                majorTickSize: "bbox",
-                position: "bbox,layout",
-                axisLine: "bbox,layout",
-                min: "layout",
-                max: "layout",
-                length: "layout",
-                minStepSize: "layout",
-                estStepSize: "layout",
-                data: "layout",
-                dataMin: "layout",
-                dataMax: "layout",
-                visibleMin: "layout",
-                visibleMax: "layout",
-                enlargeEstStepSizeByText: "layout"
-            },
-            updaters: {
-                layout: "layoutUpdater"
-            }
-        }
-    },
-    config: {
-        label: null,
-        layout: null,
-        segmenter: null,
-        renderer: null,
-        layoutContext: null,
-        axis: null
-    },
-    thickness: 0,
-    stepSize: 0,
-    getBBox: function() {
-        return null
-    },
-    defaultRenderer: function(a) {
-        return this.segmenter.renderer(a, this)
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            c = e.position,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (c === "left" || c === "right") {
-            e.translationX = 0;
-            e.translationY = i * e.length / (i - b);
-            e.scalingX = 1;
-            e.scalingY = -e.length / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (c === "top" || c === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * e.length / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    iterate: function(e, j) {
-        var c, g, a, b, h, d, k = Ext.Array.some,
-            m = Math.abs,
-            f;
-        if (e.getLabel) {
-            if (e.min < e.from) {
-                j.call(this, e.min, e.getLabel(e.min), -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                j.call(this, e.get(c), e.getLabel(c), c, e)
-            }
-            if (e.max > e.to) {
-                j.call(this, e.max, e.getLabel(e.max), e.steps + 1, e)
-            }
-        } else {
-            b = this.getAxis();
-            h = b.floatingAxes;
-            d = [];
-            f = (e.to - e.from) / (e.steps + 1);
-            if (b.getFloating()) {
-                for (a in h) {
-                    d.push(h[a])
-                }
-            }
-
-            function l(i) {
-                return !d.length || k(d, function(n) {
-                    return m(n - i) > f
-                })
-            }
-            if (e.min < e.from && l(e.min)) {
-                j.call(this, e.min, e.min, -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                g = e.get(c);
-                if (l(g)) {
-                    j.call(this, g, g, c, e)
-                }
-            }
-            if (e.max > e.to && l(e.max)) {
-                j.call(this, e.max, e.max, e.steps + 1, e)
-            }
-        }
-    },
-    renderTicks: function(l, m, s, p) {
-        var v = this,
-            k = v.attr,
-            u = k.position,
-            n = k.matrix,
-            e = 0.5 * k.lineWidth,
-            f = n.getXX(),
-            i = n.getDX(),
-            j = n.getYY(),
-            h = n.getDY(),
-            o = s.majorTicks,
-            d = k.majorTickSize,
-            a = s.minorTicks,
-            r = k.minorTickSize;
-        if (o) {
-            switch (u) {
-                case "right":
-                    function q(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(0, x);
-                            m.lineTo(w, x)
-                        }
-                    }
-                    v.iterate(o, q(d));
-                    a && v.iterate(a, q(r));
-                    break;
-                case "left":
-                    function t(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(p[2] - w, x);
-                            m.lineTo(p[2], x)
-                        }
-                    }
-                    v.iterate(o, t(d));
-                    a && v.iterate(a, t(r));
-                    break;
-                case "bottom":
-                    function c(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, 0);
-                            m.lineTo(x, w)
-                        }
-                    }
-                    v.iterate(o, c(d));
-                    a && v.iterate(a, c(r));
-                    break;
-                case "top":
-                    function b(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, p[3]);
-                            m.lineTo(x, p[3] - w)
-                        }
-                    }
-                    v.iterate(o, b(d));
-                    a && v.iterate(a, b(r));
-                    break;
-                case "angular":
-                    v.iterate(o, function(w, y, x) {
-                        w = w / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break;
-                case "gauge":
-                    var g = v.getGaugeAngles();
-                    v.iterate(o, function(w, y, x) {
-                        w = (w - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + g.start;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break
-            }
-        }
-    },
-    renderLabels: function(E, q, D, K) {
-        var o = this,
-            k = o.attr,
-            i = 0.5 * k.lineWidth,
-            u = k.position,
-            y = k.matrix,
-            A = k.textPadding,
-            x = y.getXX(),
-            d = y.getDX(),
-            g = y.getYY(),
-            c = y.getDY(),
-            n = 0,
-            I = D.majorTicks,
-            G = Math.max(k.majorTickSize, k.minorTickSize) + k.lineWidth,
-            f = Ext.draw.Draw.isBBoxIntersect,
-            F = o.getLabel(),
-            J, s, r = null,
-            w = 0,
-            b = 0,
-            m = D.segmenter,
-            B = o.getRenderer(),
-            t = o.getAxis(),
-            z = t.getTitle(),
-            a = z && z.attr.text !== "" && z.getBBox(),
-            l, h = null,
-            p, C, v, e, H;
-        if (I && F && !F.attr.hidden) {
-            J = F.attr.font;
-            if (q.font !== J) {
-                q.font = J
-            }
-            F.setAttributes({
-                translationX: 0,
-                translationY: 0
-            }, true);
-            F.applyTransformations();
-            l = F.attr.inverseMatrix.elements.slice(0);
-            switch (u) {
-                case "left":
-                    e = a ? a.x + a.width : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(e + d) - i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - G + d) - i;
-                            break;
-                        default:
-                            H = E.roundPixel(e + (K[2] - e - G) / 2 + d) - i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "right":
-                    e = a ? K[2] - a.x : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(G + d) + i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - e + d) + i;
-                            break;
-                        default:
-                            H = E.roundPixel(G + (K[2] - G - e) / 2 + d) + i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "top":
-                    e = a ? a.y + a.height : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(e + (K[3] - e - G) / 2) - i
-                    }, true);
-                    break;
-                case "bottom":
-                    e = a ? K[3] - a.y : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(G + (K[3] - G - e) / 2) + i
-                    }, true);
-                    break;
-                case "radial":
-                    F.setAttributes({
-                        translationX: k.centerX
-                    }, true);
-                    break;
-                case "angular":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break;
-                case "gauge":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break
-            }
-            if (u === "left" || u === "right") {
-                o.iterate(I, function(L, N, M) {
-                    if (N === undefined) {
-                        return
-                    }
-                    if (B) {
-                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                    } else {
-                        v = m.renderer(N, D, r)
-                    }
-                    r = N;
-                    F.setAttributes({
-                        text: String(v),
-                        translationY: E.roundPixel(L * g + c)
-                    }, true);
-                    F.applyTransformations();
-                    n = Math.max(n, F.getBBox().width + G);
-                    if (n <= o.thickness) {
-                        C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                        p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                        if (h && !f(p, h, A)) {
-                            return
-                        }
-                        E.renderSprite(F);
-                        h = p;
-                        w += p.height;
-                        b++
-                    }
-                })
-            } else {
-                if (u === "top" || u === "bottom") {
-                    o.iterate(I, function(L, N, M) {
-                        if (N === undefined) {
-                            return
-                        }
-                        if (B) {
-                            v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                        } else {
-                            v = m.renderer(N, D, r)
-                        }
-                        r = N;
-                        F.setAttributes({
-                            text: String(v),
-                            translationX: E.roundPixel(L * x + d)
-                        }, true);
-                        F.applyTransformations();
-                        n = Math.max(n, F.getBBox().height + G);
-                        if (n <= o.thickness) {
-                            C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                            p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                            if (h && !f(p, h, A)) {
-                                return
-                            }
-                            E.renderSprite(F);
-                            h = p;
-                            w += p.width;
-                            b++
-                        }
-                    })
-                } else {
-                    if (u === "radial") {
-                        o.iterate(I, function(L, N, M) {
-                            if (N === undefined) {
-                                return
-                            }
-                            if (B) {
-                                v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                            } else {
-                                v = m.renderer(N, D, r)
-                            }
-                            r = N;
-                            if (typeof v !== "undefined") {
-                                F.setAttributes({
-                                    text: String(v),
-                                    translationX: k.centerX - E.roundPixel(L) / k.max * k.length * Math.cos(k.baseRotation + Math.PI / 2),
-                                    translationY: k.centerY - E.roundPixel(L) / k.max * k.length * Math.sin(k.baseRotation + Math.PI / 2)
-                                }, true);
-                                F.applyTransformations();
-                                p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                if (h && !f(p, h)) {
-                                    return
-                                }
-                                E.renderSprite(F);
-                                h = p;
-                                w += p.width;
-                                b++
-                            }
-                        })
-                    } else {
-                        if (u === "angular") {
-                            s = k.majorTickSize + k.lineWidth * 0.5 + (parseInt(F.attr.fontSize, 10) || 10) / 2;
-                            o.iterate(I, function(L, N, M) {
-                                if (N === undefined) {
-                                    return
-                                }
-                                if (B) {
-                                    v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                } else {
-                                    v = m.renderer(N, D, r)
-                                }
-                                r = N;
-                                n = Math.max(n, Math.max(k.majorTickSize, k.minorTickSize) + (k.lineCap !== "butt" ? k.lineWidth * 0.5 : 0));
-                                if (typeof v !== "undefined") {
-                                    var O = L / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                                    F.setAttributes({
-                                        text: String(v),
-                                        translationX: k.centerX + (k.length + s) * Math.cos(O),
-                                        translationY: k.centerY + (k.length + s) * Math.sin(O)
-                                    }, true);
-                                    F.applyTransformations();
-                                    p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                    if (h && !f(p, h)) {
-                                        return
-                                    }
-                                    E.renderSprite(F);
-                                    h = p;
-                                    w += p.width;
-                                    b++
-                                }
-                            })
-                        } else {
-                            if (u === "gauge") {
-                                var j = o.getGaugeAngles();
-                                o.iterate(I, function(L, N, M) {
-                                    if (N === undefined) {
-                                        return
-                                    }
-                                    if (B) {
-                                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                    } else {
-                                        v = m.renderer(N, D, r)
-                                    }
-                                    r = N;
-                                    if (typeof v !== "undefined") {
-                                        var O = (L - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + j.start;
-                                        F.setAttributes({
-                                            text: String(v),
-                                            translationX: k.centerX + (k.length + 10) * Math.cos(O),
-                                            translationY: k.centerY + (k.length + 10) * Math.sin(O)
-                                        }, true);
-                                        F.applyTransformations();
-                                        p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                        if (h && !f(p, h)) {
-                                            return
-                                        }
-                                        E.renderSprite(F);
-                                        h = p;
-                                        w += p.width;
-                                        b++
-                                    }
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-            if (k.enlargeEstStepSizeByText && b) {
-                w /= b;
-                w += G;
-                w *= 2;
-                if (k.estStepSize < w) {
-                    k.estStepSize = w
-                }
-            }
-            if (Math.abs(o.thickness - (n)) > 1) {
-                o.thickness = n;
-                k.bbox.plain.dirty = true;
-                k.bbox.transform.dirty = true;
-                o.doThicknessChanged();
-                return false
-            }
-        }
-    },
-    renderAxisLine: function(a, i, e, c) {
-        var h = this,
-            g = h.attr,
-            b = g.lineWidth * 0.5,
-            j = g.position,
-            d, f;
-        if (g.axisLine && g.length) {
-            switch (j) {
-                case "left":
-                    d = a.roundPixel(c[2]) - b;
-                    i.moveTo(d, -g.endGap);
-                    i.lineTo(d, g.length + g.startGap + 1);
-                    break;
-                case "right":
-                    i.moveTo(b, -g.endGap);
-                    i.lineTo(b, g.length + g.startGap + 1);
-                    break;
-                case "bottom":
-                    i.moveTo(-g.startGap, b);
-                    i.lineTo(g.length + g.endGap, b);
-                    break;
-                case "top":
-                    d = a.roundPixel(c[3]) - b;
-                    i.moveTo(-g.startGap, d);
-                    i.lineTo(g.length + g.endGap, d);
-                    break;
-                case "angular":
-                    i.moveTo(g.centerX + g.length, g.centerY);
-                    i.arc(g.centerX, g.centerY, g.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    f = h.getGaugeAngles();
-                    i.moveTo(g.centerX + Math.cos(f.start) * g.length, g.centerY + Math.sin(f.start) * g.length);
-                    i.arc(g.centerX, g.centerY, g.length, f.start, f.end, true);
-                    break
-            }
-        }
-    },
-    getGaugeAngles: function() {
-        var a = this,
-            c = a.attr.totalAngle,
-            b;
-        if (c <= Math.PI) {
-            b = (Math.PI - c) * 0.5
-        } else {
-            b = -(Math.PI * 2 - c) * 0.5
-        }
-        b = Math.PI * 2 - b;
-        return {
-            start: b,
-            end: b - c
-        }
-    },
-    renderGridLines: function(m, n, s, r) {
-        var t = this,
-            b = t.getAxis(),
-            l = t.attr,
-            p = l.matrix,
-            d = l.startGap,
-            a = l.endGap,
-            c = p.getXX(),
-            k = p.getYY(),
-            h = p.getDX(),
-            g = p.getDY(),
-            u = l.position,
-            f = b.getGridAlignment(),
-            q = s.majorTicks,
-            e, o, i;
-        if (l.grid) {
-            if (q) {
-                if (u === "left" || u === "right") {
-                    i = l.min * k + g + a + d;
-                    t.iterate(q, function(j, w, v) {
-                        e = j * k + g + a;
-                        t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                            y: e,
-                            height: i - e
-                        }, o = v, true);
-                        i = e
-                    });
-                    o++;
-                    e = 0;
-                    t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                        y: e,
-                        height: i - e
-                    }, o, true)
-                } else {
-                    if (u === "top" || u === "bottom") {
-                        i = l.min * c + h + d;
-                        if (d) {
-                            t.putMarker(f + "-even", {
-                                x: 0,
-                                width: i
-                            }, -1, true)
-                        }
-                        t.iterate(q, function(j, w, v) {
-                            e = j * c + h + d;
-                            t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                x: e,
-                                width: i - e
-                            }, o = v, true);
-                            i = e
-                        });
-                        o++;
-                        e = l.length + l.startGap + l.endGap;
-                        t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                            x: e,
-                            width: i - e
-                        }, o, true)
-                    } else {
-                        if (u === "radial") {
-                            t.iterate(q, function(j, w, v) {
-                                if (!j) {
-                                    return
-                                }
-                                e = j / l.max * l.length;
-                                t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                    scalingX: e,
-                                    scalingY: e
-                                }, v, true);
-                                i = e
-                            })
-                        } else {
-                            if (u === "angular") {
-                                t.iterate(q, function(j, w, v) {
-                                    if (!l.length) {
-                                        return
-                                    }
-                                    e = j / (l.max + 1) * Math.PI * 2 + l.baseRotation;
-                                    t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                        rotationRads: e,
-                                        rotationCenterX: 0,
-                                        rotationCenterY: 0,
-                                        scalingX: l.length,
-                                        scalingY: l.length
-                                    }, v, true);
-                                    i = e
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    renderLimits: function(o) {
-        var t = this,
-            a = t.getAxis(),
-            h = a.getChart(),
-            p = h.getInnerPadding(),
-            d = Ext.Array.from(a.getLimits());
-        if (!d.length) {
-            return
-        }
-        var r = a.limits.surface.getRect(),
-            m = t.attr,
-            n = m.matrix,
-            u = m.position,
-            k = Ext.Object.chain,
-            v = a.limits.titles,
-            c, j, b, s, l, q, f, g, e;
-        v.instances = [];
-        v.position = 0;
-        if (u === "left" || u === "right") {
-            for (q = 0, f = d.length; q < f; q++) {
-                s = k(d[q]);
-                !s.line && (s.line = {});
-                l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                l = l * n.getYY() + n.getDY();
-                s.line.y = l + p.top;
-                s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                t.putMarker("horizontal-limit-lines", s.line, q, true);
-                if (s.line.title) {
-                    v.createInstance(s.line.title);
-                    c = v.getBBoxFor(v.position - 1);
-                    j = s.line.title.position || (u === "left" ? "start" : "end");
-                    switch (j) {
-                        case "start":
-                            g = 10;
-                            break;
-                        case "end":
-                            g = r[2] - 10;
-                            break;
-                        case "middle":
-                            g = r[2] / 2;
-                            break
-                    }
-                    v.setAttributesFor(v.position - 1, {
-                        x: g,
-                        y: s.line.y - c.height / 2,
-                        textAlign: j,
-                        fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                    })
-                }
-            }
-        } else {
-            if (u === "top" || u === "bottom") {
-                for (q = 0, f = d.length; q < f; q++) {
-                    s = k(d[q]);
-                    !s.line && (s.line = {});
-                    l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                    l = l * n.getXX() + n.getDX();
-                    s.line.x = l + p.left;
-                    s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                    t.putMarker("vertical-limit-lines", s.line, q, true);
-                    if (s.line.title) {
-                        v.createInstance(s.line.title);
-                        c = v.getBBoxFor(v.position - 1);
-                        j = s.line.title.position || (u === "top" ? "end" : "start");
-                        switch (j) {
-                            case "start":
-                                e = r[3] - c.width / 2 - 10;
-                                break;
-                            case "end":
-                                e = c.width / 2 + 10;
-                                break;
-                            case "middle":
-                                e = r[3] / 2;
-                                break
-                        }
-                        v.setAttributesFor(v.position - 1, {
-                            x: s.line.x + c.height / 2,
-                            y: e,
-                            fillStyle: s.line.title.fillStyle || s.line.strokeStyle,
-                            rotationRads: Math.PI / 2
-                        })
-                    }
-                }
-            } else {
-                if (u === "radial") {
-                    for (q = 0, f = d.length; q < f; q++) {
-                        s = k(d[q]);
-                        !s.line && (s.line = {});
-                        l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                        if (l > m.max) {
-                            continue
-                        }
-                        l = l / m.max * m.length;
-                        s.line.cx = m.centerX;
-                        s.line.cy = m.centerY;
-                        s.line.scalingX = l;
-                        s.line.scalingY = l;
-                        s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                        t.putMarker("circular-limit-lines", s.line, q, true);
-                        if (s.line.title) {
-                            v.createInstance(s.line.title);
-                            c = v.getBBoxFor(v.position - 1);
-                            v.setAttributesFor(v.position - 1, {
-                                x: m.centerX,
-                                y: m.centerY - l - c.height / 2,
-                                fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                            })
-                        }
-                    }
-                } else {
-                    if (u === "angular") {
-                        for (q = 0, f = d.length; q < f; q++) {
-                            s = k(d[q]);
-                            !s.line && (s.line = {});
-                            l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                            l = l / (m.max + 1) * Math.PI * 2 + m.baseRotation;
-                            s.line.translationX = m.centerX;
-                            s.line.translationY = m.centerY;
-                            s.line.rotationRads = l;
-                            s.line.rotationCenterX = 0;
-                            s.line.rotationCenterY = 0;
-                            s.line.scalingX = m.length;
-                            s.line.scalingY = m.length;
-                            s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                            t.putMarker("radial-limit-lines", s.line, q, true);
-                            if (s.line.title) {
-                                v.createInstance(s.line.title);
-                                c = v.getBBoxFor(v.position - 1);
-                                b = ((l > -0.5 * Math.PI && l < 0.5 * Math.PI) || (l > 1.5 * Math.PI && l < 2 * Math.PI)) ? 1 : -1;
-                                v.setAttributesFor(v.position - 1, {
-                                    x: m.centerX + 0.5 * m.length * Math.cos(l) + b * c.height / 2 * Math.sin(l),
-                                    y: m.centerY + 0.5 * m.length * Math.sin(l) - b * c.height / 2 * Math.cos(l),
-                                    rotationRads: b === 1 ? l : l - Math.PI,
-                                    fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                                })
-                            }
-                        }
-                    } else {
-                        if (u === "gauge") {}
-                    }
-                }
-            }
-        }
-    },
-    doThicknessChanged: function() {
-        var a = this.getAxis();
-        if (a) {
-            a.onThicknessChanged()
-        }
-    },
-    render: function(a, c, d) {
-        var e = this,
-            b = e.getLayoutContext();
-        if (b) {
-            if (false === e.renderLabels(a, c, b, d)) {
-                return false
-            }
-            c.beginPath();
-            e.renderTicks(a, c, b, d);
-            e.renderAxisLine(a, c, b, d);
-            e.renderGridLines(a, c, b, d);
-            e.renderLimits(d);
-            c.stroke()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Segmenter", {
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    renderer: function(b, a) {
-        return String(b)
-    },
-    from: function(a) {
-        return a
-    },
-    diff: Ext.emptyFn,
-    align: Ext.emptyFn,
-    add: Ext.emptyFn,
-    preferredStep: Ext.emptyFn
-});
-Ext.define("Ext.chart.axis.segmenter.Names", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.names",
-    renderer: function(b, a) {
-        return b
-    },
-    diff: function(b, a, c) {
-        return Math.floor(a - b)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c)
-    },
-    add: function(c, b, a) {
-        return c + b
-    },
-    preferredStep: function(c, a, b, d) {
-        return {
-            unit: 1,
-            step: 1
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Numeric", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.numeric",
-    isNumeric: true,
-    renderer: function(b, a) {
-        return b.toFixed(Math.max(0, a.majorTicks.unit.fixes))
-    },
-    diff: function(b, a, c) {
-        return Math.floor((a - b) / c.scale)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c / (a.scale * b)) * a.scale * b
-    },
-    add: function(c, b, a) {
-        return c + b * a.scale
-    },
-    preferredStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        b /= d;
-        if (b < 2) {
-            b = 2
-        } else {
-            if (b < 5) {
-                b = 5
-            } else {
-                if (b < 10) {
-                    b = 10;
-                    a++
-                }
-            }
-        }
-        return {
-            unit: {
-                fixes: -a,
-                scale: d
-            },
-            step: b
-        }
-    },
-    exactStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        return {
-            unit: {
-                fixes: -a + (b % d === 0 ? 0 : 1),
-                scale: 1
-            },
-            step: b
-        }
-    },
-    adjustByMajorUnit: function(e, g, c) {
-        var d = c[0],
-            b = c[1],
-            a = e * g,
-            f = d % a;
-        if (f !== 0) {
-            c[0] = d - f + (d < 0 ? -a : 0)
-        }
-        f = b % a;
-        if (f !== 0) {
-            c[1] = b - f + (b > 0 ? a : 0)
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Time", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.time",
-    config: {
-        step: null
-    },
-    renderer: function(c, b) {
-        var a = Ext.Date;
-        switch (b.majorTicks.unit) {
-            case "y":
-                return a.format(c, "Y");
-            case "mo":
-                return a.format(c, "Y-m");
-            case "d":
-                return a.format(c, "Y-m-d")
-        }
-        return a.format(c, "Y-m-d\nH:i:s")
-    },
-    from: function(a) {
-        return new Date(a)
-    },
-    diff: function(b, a, c) {
-        if (isFinite(b)) {
-            b = new Date(b)
-        }
-        if (isFinite(a)) {
-            a = new Date(a)
-        }
-        return Ext.Date.diff(b, a, c)
-    },
-    align: function(a, c, b) {
-        if (b === "d" && c >= 7) {
-            a = Ext.Date.align(a, "d", c);
-            a.setDate(a.getDate() - a.getDay() + 1);
-            return a
-        } else {
-            return Ext.Date.align(a, b, c)
-        }
-    },
-    add: function(c, b, a) {
-        return Ext.Date.add(new Date(c), a, b)
-    },
-    stepUnits: [
-        [Ext.Date.YEAR, 1, 2, 5, 10, 20, 50, 100, 200, 500],
-        [Ext.Date.MONTH, 1, 3, 6],
-        [Ext.Date.DAY, 1, 7, 14],
-        [Ext.Date.HOUR, 1, 6, 12],
-        [Ext.Date.MINUTE, 1, 5, 15, 30],
-        [Ext.Date.SECOND, 1, 5, 15, 30],
-        [Ext.Date.MILLI, 1, 2, 5, 10, 20, 50, 100, 200, 500]
-    ],
-    preferredStep: function(b, e) {
-        if (this.getStep()) {
-            return this.getStep()
-        }
-        var f = new Date(+b),
-            g = new Date(+b + Math.ceil(e)),
-            d = this.stepUnits,
-            l, k, h, c, a;
-        for (c = 0; c < d.length; c++) {
-            k = d[c][0];
-            h = this.diff(f, g, k);
-            if (h > 0) {
-                for (a = 1; a < d[c].length; a++) {
-                    if (h <= d[c][a]) {
-                        l = {
-                            unit: k,
-                            step: d[c][a]
-                        };
-                        break
-                    }
-                }
-                if (!l) {
-                    c--;
-                    l = {
-                        unit: d[c][0],
-                        step: 1
-                    }
-                }
-                break
-            }
-        }
-        if (!l) {
-            l = {
-                unit: Ext.Date.DAY,
-                step: 1
-            }
-        }
-        return l
-    }
-});
-Ext.define("Ext.chart.axis.layout.Layout", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    processData: function(b) {
-        var e = this,
-            c = e.getAxis(),
-            f = c.getDirection(),
-            g = c.boundSeries,
-            a, d;
-        if (b) {
-            b["coordinate" + f]()
-        } else {
-            for (a = 0, d = g.length; a < d; a++) {
-                g[a]["coordinate" + f]()
-            }
-        }
-    },
-    calculateMajorTicks: function(a) {
-        var f = this,
-            e = a.attr,
-            d = e.max - e.min,
-            i = d / Math.max(1, e.length) * (e.visibleMax - e.visibleMin),
-            h = e.min + d * e.visibleMin,
-            b = e.min + d * e.visibleMax,
-            g = e.estStepSize * i,
-            c = f.snapEnds(a, e.min, e.max, g);
-        if (c) {
-            f.trimByRange(a, c, h, b);
-            a.majorTicks = c
-        }
-    },
-    calculateMinorTicks: function(a) {
-        if (this.snapMinorEnds) {
-            a.minorTicks = this.snapMinorEnds(a)
-        }
-    },
-    calculateLayout: function(b) {
-        var c = this,
-            a = b.attr;
-        if (a.length === 0) {
-            return null
-        }
-        if (a.majorTicks) {
-            c.calculateMajorTicks(b);
-            if (a.minorTicks) {
-                c.calculateMinorTicks(b)
-            }
-        }
-    },
-    snapEnds: Ext.emptyFn,
-    trimByRange: function(b, f, i, a) {
-        var g = b.segmenter,
-            j = f.unit,
-            h = g.diff(f.from, i, j),
-            d = g.diff(f.from, a, j),
-            c = Math.max(0, Math.ceil(h / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = g.add(f.from, e * f.step, j)
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < i) {
-            f.from = g.add(f.from, c * f.step, j);
-            while (f.from < i) {
-                c++;
-                f.from = g.add(f.from, f.step, j)
-            }
-        }
-        if (f.min < i) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    }
-});
-Ext.define("Ext.chart.axis.layout.Discrete", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.discrete",
-    isDiscrete: true,
-    processData: function() {
-        var f = this,
-            d = f.getAxis(),
-            c = d.boundSeries,
-            g = d.getDirection(),
-            b, e, a;
-        f.labels = [];
-        f.labelMap = {};
-        for (b = 0, e = c.length; b < e; b++) {
-            a = c[b];
-            if (a["get" + g + "Axis"]() === d) {
-                a["coordinate" + g]()
-            }
-        }
-        d.getSprites()[0].setAttributes({
-            data: f.labels
-        });
-        f.fireEvent("datachange", f.labels)
-    },
-    calculateLayout: function(a) {
-        a.data = this.labels;
-        this.callParent([a])
-    },
-    calculateMajorTicks: function(a) {
-        var g = this,
-            f = a.attr,
-            d = a.data,
-            e = f.max - f.min,
-            j = e / Math.max(1, f.length) * (f.visibleMax - f.visibleMin),
-            i = f.min + e * f.visibleMin,
-            b = f.min + e * f.visibleMax,
-            h = f.estStepSize * j;
-        var c = g.snapEnds(a, Math.max(0, f.min), Math.min(f.max, d.length - 1), h);
-        if (c) {
-            g.trimByRange(a, c, i, b);
-            a.majorTicks = c
-        }
-    },
-    snapEnds: function(e, d, a, b) {
-        b = Math.ceil(b);
-        var c = Math.floor((a - d) / b),
-            f = e.data;
-        return {
-            min: d,
-            max: a,
-            from: d,
-            to: c * b + d,
-            step: b,
-            steps: c,
-            unit: 1,
-            getLabel: function(g) {
-                return f[this.from + this.step * g]
-            },
-            get: function(g) {
-                return this.from + this.step * g
-            }
-        }
-    },
-    trimByRange: function(b, f, h, a) {
-        var i = f.unit,
-            g = Math.ceil((h - f.from) / i) * i,
-            d = Math.floor((a - f.from) / i) * i,
-            c = Math.max(0, Math.ceil(g / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = e
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < h && f.step > 0) {
-            f.from = f.from + c * f.step * i;
-            while (f.from < h) {
-                c++;
-                f.from += f.step * i
-            }
-        }
-        if (f.min < h) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    },
-    getCoordFor: function(c, d, a, b) {
-        this.labels.push(c);
-        return this.labels.length - 1
-    }
-});
-Ext.define("Ext.chart.axis.layout.CombineDuplicate", {
-    extend: "Ext.chart.axis.layout.Discrete",
-    alias: "axisLayout.combineDuplicate",
-    getCoordFor: function(d, e, b, c) {
-        if (!(d in this.labelMap)) {
-            var a = this.labelMap[d] = this.labels.length;
-            this.labels.push(d);
-            return a
-        }
-        return this.labelMap[d]
-    }
-});
-Ext.define("Ext.chart.axis.layout.Continuous", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.continuous",
-    isContinuous: true,
-    config: {
-        adjustMinimumByMajorUnit: false,
-        adjustMaximumByMajorUnit: false
-    },
-    getCoordFor: function(c, d, a, b) {
-        return +c
-    },
-    snapEnds: function(a, d, i, h) {
-        var f = a.segmenter,
-            c = this.getAxis(),
-            l = c.getMajorTickSteps(),
-            e = l && f.exactStep ? f.exactStep(d, (i - d) / l) : f.preferredStep(d, h),
-            k = e.unit,
-            b = e.step,
-            j = f.align(d, b, k),
-            g = (l || f.diff(d, i, k)) + 1;
-        return {
-            min: f.from(d),
-            max: f.from(i),
-            from: j,
-            to: f.add(j, g * b, k),
-            step: b,
-            steps: g,
-            unit: k,
-            get: function(m) {
-                return f.add(this.from, this.step * m, k)
-            }
-        }
-    },
-    snapMinorEnds: function(a) {
-        var e = a.majorTicks,
-            m = this.getAxis().getMinorTickSteps(),
-            f = a.segmenter,
-            d = e.min,
-            i = e.max,
-            k = e.from,
-            l = e.unit,
-            b = e.step / m,
-            n = b * l.scale,
-            j = k - d,
-            c = Math.floor(j / n),
-            h = c + Math.floor((i - e.to) / n) + 1,
-            g = e.steps * m + h;
-        return {
-            min: d,
-            max: i,
-            from: d + j % n,
-            to: f.add(k, g * b, l),
-            step: b,
-            steps: g,
-            unit: l,
-            get: function(o) {
-                return (o % m + c + 1 !== 0) ? f.add(this.from, this.step * o, l) : null
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis", {
-    xtype: "axis",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.chart.axis.sprite.Axis", "Ext.chart.axis.segmenter.*", "Ext.chart.axis.layout.*"],
-    isAxis: true,
-    config: {
-        position: "bottom",
-        fields: [],
-        label: undefined,
-        grid: false,
-        limits: null,
-        renderer: null,
-        chart: null,
-        style: null,
-        margin: 0,
-        titleMargin: 4,
-        background: null,
-        minimum: NaN,
-        maximum: NaN,
-        reconcileRange: false,
-        minZoom: 1,
-        maxZoom: 10000,
-        layout: "continuous",
-        segmenter: "numeric",
-        hidden: false,
-        majorTickSteps: 0,
-        minorTickSteps: 0,
-        adjustByMajorUnit: true,
-        title: null,
-        increment: 0.5,
-        length: 0,
-        center: null,
-        radius: null,
-        totalAngle: Math.PI,
-        rotation: null,
-        labelInSpan: null,
-        visibleRange: [0, 1],
-        needHighPrecision: false,
-        linkedTo: null,
-        floating: null
-    },
-    titleOffset: 0,
-    spriteAnimationCount: 0,
-    prevMin: 0,
-    prevMax: 1,
-    boundSeries: [],
-    sprites: null,
-    surface: null,
-    range: null,
-    xValues: [],
-    yValues: [],
-    masterAxis: null,
-    applyRotation: function(b) {
-        var a = Math.PI * 2;
-        return (b % a + Math.PI) % a - Math.PI
-    },
-    updateRotation: function(b) {
-        var c = this.getSprites(),
-            a = this.getPosition();
-        if (!this.getHidden() && a === "angular" && c[0]) {
-            c[0].setAttributes({
-                baseRotation: b
-            })
-        }
-    },
-    applyTitle: function(c, b) {
-        var a;
-        if (Ext.isString(c)) {
-            c = {
-                text: c
-            }
-        }
-        if (!b) {
-            b = Ext.create("sprite.text", c);
-            if ((a = this.getSurface())) {
-                a.add(b)
-            }
-        } else {
-            b.setAttributes(c)
-        }
-        return b
-    },
-    applyFloating: function(b, a) {
-        if (b === null) {
-            b = {
-                value: null,
-                alongAxis: null
-            }
-        } else {
-            if (Ext.isNumber(b)) {
-                b = {
-                    value: b,
-                    alongAxis: null
-                }
-            }
-        }
-        if (Ext.isObject(b)) {
-            if (a && a.alongAxis) {
-                delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]
-            }
-            return b
-        }
-        return a
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        b.sprites = [];
-        b.labels = [];
-        b.floatingAxes = {};
-        a = a || {};
-        if (a.position === "angular") {
-            a.style = a.style || {};
-            a.style.estStepSize = 1
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.apply(b, arguments)
-    },
-    getAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "vertical";
-            case "top":
-            case "bottom":
-                return "horizontal";
-            case "radial":
-                return "radial";
-            case "angular":
-                return "angular"
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal";
-            case "top":
-            case "bottom":
-                return "vertical";
-            case "radial":
-                return "circular";
-            case "angular":
-                return "radial"
-        }
-    },
-    getSurface: function() {
-        var e = this,
-            d = e.getChart();
-        if (d && !e.surface) {
-            var b = e.surface = d.getSurface(e.getId(), "axis"),
-                c = e.gridSurface = d.getSurface("main"),
-                a = e.getSprites()[0],
-                f = e.getGridAlignment();
-            c.waitFor(b);
-            e.getGrid();
-            if (e.getLimits() && f) {
-                f = f.replace("3d", "");
-                e.limits = {
-                    surface: d.getSurface("overlay"),
-                    lines: new Ext.chart.Markers(),
-                    titles: new Ext.draw.sprite.Instancing()
-                };
-                e.limits.lines.setTemplate({
-                    xclass: "grid." + f
-                });
-                e.limits.lines.getTemplate().setAttributes({
-                    strokeStyle: "black"
-                }, true);
-                e.limits.surface.add(e.limits.lines);
-                a.bindMarker(f + "-limit-lines", e.limits.lines);
-                e.limitTitleTpl = new Ext.draw.sprite.Text();
-                e.limits.titles.setTemplate(e.limitTitleTpl);
-                e.limits.surface.add(e.limits.titles);
-                d.on("redraw", e.renderLimits, e)
-            }
-        }
-        return e.surface
-    },
-    applyGrid: function(a) {
-        if (a === true) {
-            return {}
-        }
-        return a
-    },
-    updateGrid: function(b) {
-        var e = this,
-            d = e.getChart();
-        if (!d) {
-            e.on({
-                chartattached: Ext.bind(e.updateGrid, e, [b]),
-                single: true
-            });
-            return
-        }
-        var c = e.gridSurface,
-            a = e.getSprites()[0],
-            f = e.getGridAlignment(),
-            g;
-        if (b) {
-            g = e.gridSpriteEven;
-            if (!g) {
-                g = e.gridSpriteEven = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-even", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.even)) {
-                    g.getTemplate().setAttributes(b.even)
-                }
-            }
-            g = e.gridSpriteOdd;
-            if (!g) {
-                g = e.gridSpriteOdd = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-odd", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.odd)) {
-                    g.getTemplate().setAttributes(b.odd)
-                }
-            }
-        }
-    },
-    renderLimits: function() {
-        this.getSprites()[0].renderLimits()
-    },
-    getCoordFor: function(c, d, a, b) {
-        return this.getLayout().getCoordFor(c, d, a, b)
-    },
-    applyPosition: function(a) {
-        return a.toLowerCase()
-    },
-    applyLength: function(b, a) {
-        return b > 0 ? b : a
-    },
-    applyLabel: function(b, a) {
-        if (!a) {
-            a = new Ext.draw.sprite.Text({})
-        }
-        if (this.limitTitleTpl) {
-            this.limitTitleTpl.setAttributes(b)
-        }
-        a.setAttributes(b);
-        return a
-    },
-    applyLayout: function(b, a) {
-        b = Ext.factory(b, null, a, "axisLayout");
-        b.setAxis(this);
-        return b
-    },
-    applySegmenter: function(a, b) {
-        a = Ext.factory(a, null, b, "segmenter");
-        a.setAxis(this);
-        return a
-    },
-    updateMinimum: function() {
-        this.range = null
-    },
-    updateMaximum: function() {
-        this.range = null
-    },
-    hideLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: true
-        })
-    },
-    showLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: false
-        })
-    },
-    renderFrame: function() {
-        this.getSurface().renderFrame()
-    },
-    updateChart: function(d, b) {
-        var c = this,
-            a;
-        if (b) {
-            b.unregister(c);
-            b.un("serieschange", c.onSeriesChange, c);
-            b.un("redraw", c.renderLimits, c);
-            c.linkAxis();
-            c.fireEvent("chartdetached", b, c)
-        }
-        if (d) {
-            d.on("serieschange", c.onSeriesChange, c);
-            c.surface = null;
-            a = c.getSurface();
-            c.getLabel().setSurface(a);
-            a.add(c.getSprites());
-            a.add(c.getTitle());
-            d.register(c);
-            c.fireEvent("chartattached", d, c)
-        }
-    },
-    applyBackground: function(a) {
-        var b = Ext.ClassManager.getByAlias("sprite.rect");
-        return b.def.normalize(a)
-    },
-    processData: function() {
-        this.getLayout().processData();
-        this.range = null
-    },
-    getDirection: function() {
-        return this.getChart().getDirectionForAxis(this.getPosition())
-    },
-    isSide: function() {
-        var a = this.getPosition();
-        return a === "left" || a === "right"
-    },
-    applyFields: function(a) {
-        return Ext.Array.from(a)
-    },
-    applyVisibleRange: function(a, c) {
-        this.getChart();
-        if (a[0] > a[1]) {
-            var b = a[0];
-            a[0] = a[1];
-            a[0] = b
-        }
-        if (a[1] === a[0]) {
-            a[1] += 1 / this.getMaxZoom()
-        }
-        if (a[1] > a[0] + 1) {
-            a[0] = 0;
-            a[1] = 1
-        } else {
-            if (a[0] < 0) {
-                a[1] -= a[0];
-                a[0] = 0
-            } else {
-                if (a[1] > 1) {
-                    a[0] -= a[1] - 1;
-                    a[1] = 1
-                }
-            }
-        }
-        if (c && a[0] === c[0] && a[1] === c[1]) {
-            return undefined
-        }
-        return a
-    },
-    updateVisibleRange: function(a) {
-        this.fireEvent("visiblerangechange", this, a)
-    },
-    onSeriesChange: function(e) {
-        var f = this,
-            b = e.getSeries(),
-            j = "get" + f.getDirection() + "Axis",
-            g = [],
-            c, d = b.length,
-            a, h;
-        for (c = 0; c < d; c++) {
-            if (this === b[c][j]()) {
-                g.push(b[c])
-            }
-        }
-        f.boundSeries = g;
-        a = f.getLinkedTo();
-        h = !Ext.isEmpty(a) && e.getAxis(a);
-        if (h) {
-            f.linkAxis(h)
-        } else {
-            f.getLayout().processData()
-        }
-    },
-    linkAxis: function(a) {
-        var c = this;
-
-        function b(f, d, e) {
-            e.getLayout()[f]("datachange", "onDataChange", d);
-            e[f]("rangechange", "onMasterAxisRangeChange", d)
-        }
-        if (c.masterAxis) {
-            b("un", c, c.masterAxis);
-            c.masterAxis = null
-        }
-        if (a) {
-            if (a.type !== this.type) {
-                Ext.Error.raise("Linked axes must be of the same type.")
-            }
-            b("on", c, a);
-            c.onDataChange(a.getLayout().labels);
-            c.onMasterAxisRangeChange(a, a.range);
-            c.setStyle(Ext.apply({}, c.config.style, a.config.style));
-            c.setTitle(Ext.apply({}, c.config.title, a.config.title));
-            c.setLabel(Ext.apply({}, c.config.label, a.config.label));
-            c.masterAxis = a
-        }
-    },
-    onDataChange: function(a) {
-        this.getLayout().labels = a
-    },
-    onMasterAxisRangeChange: function(b, a) {
-        this.range = a
-    },
-    applyRange: function(a) {
-        if (!a) {
-            return this.dataRange.slice(0)
-        } else {
-            return [a[0] === null ? this.dataRange[0] : a[0], a[1] === null ? this.dataRange[1] : a[1]]
-        }
-    },
-    getRange: function() {
-        var m = this;
-        if (m.range) {
-            return m.range
-        } else {
-            if (m.masterAxis) {
-                return m.masterAxis.range
-            }
-        }
-        if (Ext.isNumber(m.getMinimum() + m.getMaximum())) {
-            return m.range = [m.getMinimum(), m.getMaximum()]
-        }
-        var d = Infinity,
-            n = -Infinity,
-            o = m.boundSeries,
-            h = m.getLayout(),
-            l = m.getSegmenter(),
-            p = m.getVisibleRange(),
-            b = "get" + m.getDirection() + "Range",
-            a, j, g, f, e, k;
-        for (e = 0, k = o.length; e < k; e++) {
-            f = o[e];
-            var c = f[b]();
-            if (c) {
-                if (c[0] < d) {
-                    d = c[0]
-                }
-                if (c[1] > n) {
-                    n = c[1]
-                }
-            }
-        }
-        if (!isFinite(n)) {
-            n = m.prevMax
-        }
-        if (!isFinite(d)) {
-            d = m.prevMin
-        }
-        if (m.getLabelInSpan() || d === n) {
-            n += m.getIncrement();
-            d -= m.getIncrement()
-        }
-        if (Ext.isNumber(m.getMinimum())) {
-            d = m.getMinimum()
-        } else {
-            m.prevMin = d
-        }
-        if (Ext.isNumber(m.getMaximum())) {
-            n = m.getMaximum()
-        } else {
-            m.prevMax = n
-        }
-        m.range = [Ext.Number.correctFloat(d), Ext.Number.correctFloat(n)];
-        if (m.getReconcileRange()) {
-            m.reconcileRange()
-        }
-        if (m.getAdjustByMajorUnit() && l.adjustByMajorUnit && !m.getMajorTickSteps()) {
-            j = Ext.Object.chain(m.getSprites()[0].attr);
-            j.min = m.range[0];
-            j.max = m.range[1];
-            j.visibleMin = p[0];
-            j.visibleMax = p[1];
-            a = {
-                attr: j,
-                segmenter: l
-            };
-            h.calculateLayout(a);
-            g = a.majorTicks;
-            if (g) {
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range);
-                j.min = m.range[0];
-                j.max = m.range[1];
-                delete a.majorTicks;
-                h.calculateLayout(a);
-                g = a.majorTicks;
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range)
-            } else {
-                if (!m.hasClearRangePending) {
-                    m.hasClearRangePending = true;
-                    m.getChart().on("layout", "clearRange", m)
-                }
-            }
-        }
-        if (!Ext.Array.equals(m.range, m.oldRange || [])) {
-            m.fireEvent("rangechange", m, m.range);
-            m.oldRange = m.range
-        }
-        return m.range
-    },
-    clearRange: function() {
-        delete this.hasClearRangePending;
-        this.range = null
-    },
-    reconcileRange: function() {
-        var e = this,
-            g = e.getChart().getAxes(),
-            f = e.getDirection(),
-            b, d, c, a;
-        if (!g) {
-            return
-        }
-        for (b = 0, d = g.length; b < d; b++) {
-            c = g[b];
-            a = c.getRange();
-            if (c === e || c.getDirection() !== f || !a || !c.getReconcileRange()) {
-                continue
-            }
-            if (a[0] < e.range[0]) {
-                e.range[0] = a[0]
-            }
-            if (a[1] > e.range[1]) {
-                e.range[1] = a[1]
-            }
-        }
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.getByAlias("sprite." + this.seriesType);
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        b = Ext.apply(b || {}, c);
-        return b
-    },
-    themeOnlyIfConfigured: {
-        grid: true
-    },
-    updateTheme: function(d) {
-        var i = this,
-            k = d.getAxis(),
-            e = i.getPosition(),
-            o = i.getInitialConfig(),
-            c = i.defaultConfig,
-            g = i.getConfigurator().configs,
-            a = k.defaults,
-            n = k[e],
-            h = i.themeOnlyIfConfigured,
-            l, j, p, b, m, f;
-        k = Ext.merge({}, a, n);
-        for (l in k) {
-            j = k[l];
-            f = g[l];
-            if (j !== null && j !== undefined && f) {
-                m = o[l];
-                p = Ext.isObject(j);
-                b = m === c[l];
-                if (p) {
-                    if (b && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (b || p) {
-                    i[f.names.set](j)
-                }
-            }
-        }
-    },
-    updateCenter: function(b) {
-        var e = this.getSprites(),
-            a = e[0],
-            d = b[0],
-            c = b[1];
-        if (a) {
-            a.setAttributes({
-                centerX: d,
-                centerY: c
-            })
-        }
-        if (this.gridSpriteEven) {
-            this.gridSpriteEven.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-        if (this.gridSpriteOdd) {
-            this.gridSpriteOdd.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-    },
-    getSprites: function() {
-        if (!this.getChart()) {
-            return
-        }
-        var i = this,
-            e = i.getRange(),
-            f = i.getPosition(),
-            g = i.getChart(),
-            c = g.getAnimation(),
-            d, a, b = i.getLength(),
-            h = i.superclass;
-        if (c === false) {
-            c = {
-                duration: 0
-            }
-        }
-        if (e) {
-            a = Ext.applyIf({
-                position: f,
-                axis: i,
-                min: e[0],
-                max: e[1],
-                length: b,
-                grid: i.getGrid(),
-                hidden: i.getHidden(),
-                titleOffset: i.titleOffset,
-                layout: i.getLayout(),
-                segmenter: i.getSegmenter(),
-                totalAngle: i.getTotalAngle(),
-                label: i.getLabel()
-            }, i.getStyle());
-            if (!i.sprites.length) {
-                while (!h.xtype) {
-                    h = h.superclass
-                }
-                d = Ext.create("sprite." + h.xtype, a);
-                d.fx.setCustomDurations({
-                    baseRotation: 0
-                });
-                d.fx.on("animationstart", "onAnimationStart", i);
-                d.fx.on("animationend", "onAnimationEnd", i);
-                d.setLayout(i.getLayout());
-                d.setSegmenter(i.getSegmenter());
-                d.setLabel(i.getLabel());
-                i.sprites.push(d);
-                i.updateTitleSprite()
-            } else {
-                d = i.sprites[0];
-                d.setAnimation(c);
-                d.setAttributes(a)
-            }
-            if (i.getRenderer()) {
-                d.setRenderer(i.getRenderer())
-            }
-        }
-        return i.sprites
-    },
-    updateTitleSprite: function() {
-        var f = this,
-            b = f.getLength();
-        if (!f.sprites[0] || !Ext.isNumber(b)) {
-            return
-        }
-        var h = this.sprites[0].thickness,
-            a = f.getSurface(),
-            g = f.getTitle(),
-            e = f.getPosition(),
-            c = f.getMargin(),
-            i = f.getTitleMargin(),
-            d = a.roundPixel(b / 2);
-        if (g) {
-            switch (e) {
-                case "top":
-                    g.setAttributes({
-                        x: d,
-                        y: c + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "bottom":
-                    g.setAttributes({
-                        x: d,
-                        y: h + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "left":
-                    g.setAttributes({
-                        x: c + i / 2,
-                        y: d,
-                        textBaseline: "top",
-                        textAlign: "center",
-                        rotationCenterX: c + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: -Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break;
-                case "right":
-                    g.setAttributes({
-                        x: h - c + i / 2,
-                        y: d,
-                        textBaseline: "bottom",
-                        textAlign: "center",
-                        rotationCenterX: h + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        this.getChart().onThicknessChanged()
-    },
-    getThickness: function() {
-        if (this.getHidden()) {
-            return 0
-        }
-        return (this.sprites[0] && this.sprites[0].thickness || 1) + this.titleOffset + this.getMargin()
-    },
-    onAnimationStart: function() {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart", this)
-        }
-    },
-    onAnimationEnd: function() {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend", this)
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    getAncestorIds: function() {
-        return [this.getChart().getId()]
-    },
-    isXType: function(a) {
-        return a === "axis"
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        a.surface.destroy();
-        a.surface = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.chart.LegendBase", {
-    extend: "Ext.view.View",
-    config: {
-        tpl: ['<div class="', Ext.baseCSSPrefix, 'legend-container">', '<tpl for=".">', '<div class="', Ext.baseCSSPrefix, 'legend-item">', "<span ", 'class="', Ext.baseCSSPrefix, "legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ", 'style="background:{mark};">', "</span>{name}", "</div>", "</tpl>", "</div>"],
-        nodeContainerSelector: "div." + Ext.baseCSSPrefix + "legend-container",
-        itemSelector: "div." + Ext.baseCSSPrefix + "legend-item",
-        docked: "bottom"
-    },
-    setDocked: function(d) {
-        var c = this,
-            a = c.ownerCt,
-            b;
-        c.docked = d;
-        switch (d) {
-            case "top":
-            case "bottom":
-                c.addCls(Ext.baseCSSPrefix + "horizontal");
-                b = "hbox";
-                break;
-            case "left":
-            case "right":
-                c.removeCls(Ext.baseCSSPrefix + "horizontal");
-                b = "vbox";
-                break
-        }
-        if (a) {
-            a.setDocked(d)
-        }
-    },
-    setStore: function(a) {
-        this.bindStore(a)
-    },
-    clearViewEl: function() {
-        this.callParent(arguments);
-        Ext.removeNode(this.getNodeContainer())
-    },
-    onItemClick: function(a, c, b, d) {
-        this.callParent(arguments);
-        this.toggleItem(b)
-    }
-});
-Ext.define("Ext.chart.Legend", {
-    xtype: "legend",
-    extend: "Ext.chart.LegendBase",
-    config: {
-        baseCls: Ext.baseCSSPrefix + "legend",
-        padding: 5,
-        rect: null,
-        disableSelection: true,
-        toggleable: true
-    },
-    toggleItem: function(c) {
-        if (!this.getToggleable()) {
-            return
-        }
-        var b = this.getStore(),
-            h = 0,
-            e, g = true,
-            d, f, a;
-        if (b) {
-            f = b.getCount();
-            for (d = 0; d < f; d++) {
-                a = b.getAt(d);
-                if (a.get("disabled")) {
-                    h++
-                }
-            }
-            g = f - h > 1;
-            a = b.getAt(c);
-            if (a) {
-                e = a.get("disabled");
-                if (e || g) {
-                    a.set("disabled", !e)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.AbstractChart", {
-    extend: "Ext.draw.Container",
-    requires: ["Ext.chart.theme.Default", "Ext.chart.series.Series", "Ext.chart.interactions.Abstract", "Ext.chart.axis.Axis", "Ext.data.StoreManager", "Ext.chart.Legend", "Ext.data.Store"],
-    isChart: true,
-    defaultBindProperty: "store",
-    config: {
-        store: "ext-empty-store",
-        theme: "default",
-        style: null,
-        animation: !Ext.isIE8,
-        series: [],
-        axes: [],
-        legend: null,
-        colors: null,
-        insetPadding: {
-            top: 10,
-            left: 10,
-            right: 10,
-            bottom: 10
-        },
-        background: null,
-        interactions: [],
-        mainRect: null,
-        resizeHandler: null,
-        highlightItem: null
-    },
-    animationSuspendCount: 0,
-    chartLayoutSuspendCount: 0,
-    axisThicknessSuspendCount: 0,
-    isThicknessChanged: false,
-    surfaceZIndexes: {
-        background: 0,
-        main: 1,
-        grid: 2,
-        series: 3,
-        axis: 4,
-        chart: 5,
-        overlay: 6,
-        events: 7
-    },
-    constructor: function(a) {
-        var b = this;
-        b.itemListeners = {};
-        b.surfaceMap = {};
-        b.chartComponents = {};
-        b.isInitializing = true;
-        b.suspendChartLayout();
-        b.animationSuspendCount++;
-        b.callParent(arguments);
-        delete b.isInitializing;
-        b.getSurface("main");
-        b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);
-        b.getSurface("overlay").waitFor(b.getSurface("series"));
-        b.animationSuspendCount--;
-        b.resumeChartLayout()
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        if (this.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    applyInsetPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    suspendAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            e = c.length,
-            b = -1,
-            a;
-        d.animationSuspendCount++;
-        if (d.animationSuspendCount === 1) {
-            while (++b < e) {
-                a = c[b];
-                a.setAnimation(a.getAnimation())
-            }
-        }
-    },
-    resumeAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            f = c.length,
-            b = -1,
-            a, e;
-        d.animationSuspendCount--;
-        if (d.animationSuspendCount === 0) {
-            while (++b < f) {
-                a = c[b];
-                e = a.getAnimation();
-                a.setAnimation(e.duration && e || d.getAnimation())
-            }
-        }
-    },
-    suspendChartLayout: function() {
-        this.chartLayoutSuspendCount++;
-        if (this.chartLayoutSuspendCount === 1) {
-            if (this.scheduledLayoutId) {
-                this.layoutInSuspension = true;
-                this.cancelChartLayout()
-            } else {
-                this.layoutInSuspension = false
-            }
-        }
-    },
-    resumeChartLayout: function() {
-        this.chartLayoutSuspendCount--;
-        if (this.chartLayoutSuspendCount === 0) {
-            if (this.layoutInSuspension) {
-                this.scheduleLayout()
-            }
-        }
-    },
-    cancelChartLayout: function() {
-        if (this.scheduledLayoutId) {
-            Ext.draw.Animator.cancel(this.scheduledLayoutId);
-            this.scheduledLayoutId = null
-        }
-    },
-    scheduleLayout: function() {
-        var a = this;
-        if (a.allowSchedule() && !a.scheduledLayoutId) {
-            a.scheduledLayoutId = Ext.draw.Animator.schedule("doScheduleLayout", a)
-        }
-    },
-    allowSchedule: function() {
-        return true
-    },
-    doScheduleLayout: function() {
-        if (this.chartLayoutSuspendCount) {
-            this.layoutInSuspension = true
-        } else {
-            this.performLayout()
-        }
-    },
-    suspendThicknessChanged: function() {
-        this.axisThicknessSuspendCount++
-    },
-    resumeThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount > 0) {
-            this.axisThicknessSuspendCount--;
-            if (this.axisThicknessSuspendCount === 0 && this.isThicknessChanged) {
-                this.onThicknessChanged()
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount === 0) {
-            this.isThicknessChanged = false;
-            this.performLayout()
-        } else {
-            this.isThicknessChanged = true
-        }
-    },
-    applySprites: function(b) {
-        var a = this.getSurface("chart");
-        b = Ext.Array.from(b);
-        a.removeAll(true);
-        a.add(b);
-        return b
-    },
-    initItems: function() {
-        var a = this.items,
-            b, d, c;
-        if (a && !a.isMixedCollection) {
-            this.items = [];
-            a = Ext.Array.from(a);
-            for (b = 0, d = a.length; b < d; b++) {
-                c = a[b];
-                if (c.type) {
-                    Ext.raise("To add custom sprites to the chart use the 'sprites' config.")
-                } else {
-                    this.items.push(c)
-                }
-            }
-        }
-        this.callParent()
-    },
-    applyBackground: function(c, e) {
-        var b = this.getSurface("background"),
-            d, a, f;
-        if (c) {
-            if (e) {
-                d = e.attr.width;
-                a = e.attr.height;
-                f = e.type === (c.type || "rect")
-            }
-            if (c.isSprite) {
-                e = c
-            } else {
-                if (c.type === "image" && Ext.isString(c.src)) {
-                    if (f) {
-                        e.setAttributes({
-                            src: c.src
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add(c)
-                    }
-                } else {
-                    if (f) {
-                        e.setAttributes({
-                            fillStyle: c
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add({
-                            type: "rect",
-                            fillStyle: c,
-                            fx: {
-                                customDurations: {
-                                    x: 0,
-                                    y: 0,
-                                    width: 0,
-                                    height: 0
-                                }
-                            }
-                        })
-                    }
-                }
-            }
-        }
-        if (d && a) {
-            e.setAttributes({
-                width: d,
-                height: a
-            })
-        }
-        e.setAnimation(this.getAnimation());
-        return e
-    },
-    getLegendStore: function() {
-        return this.legendStore
-    },
-    refreshLegendStore: function() {
-        if (this.getLegendStore()) {
-            var d, e, c = this.getSeries(),
-                b, a = [];
-            if (c) {
-                for (d = 0, e = c.length; d < e; d++) {
-                    b = c[d];
-                    if (b.getShowInLegend()) {
-                        b.provideLegendInfo(a)
-                    }
-                }
-            }
-            this.getLegendStore().setData(a)
-        }
-    },
-    resetLegendStore: function() {
-        var c = this.getLegendStore(),
-            e, d, a, b;
-        if (c) {
-            e = this.getLegendStore().getData().items;
-            for (d = 0, a = e.length; d < a; d++) {
-                b = e[d];
-                b.beginEdit();
-                b.set("disabled", false);
-                b.commit()
-            }
-        }
-    },
-    onUpdateLegendStore: function(b, a) {
-        var d = this.getSeries(),
-            c;
-        if (a && d) {
-            c = d.map[a.get("series")];
-            if (c) {
-                c.setHiddenByIndex(a.get("index"), a.get("disabled"));
-                this.redraw()
-            }
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.scheduleLayout();
-        return false
-    },
-    applyMainRect: function(a, b) {
-        if (!b) {
-            return a
-        }
-        this.getSeries();
-        this.getAxes();
-        if (a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return b
-        } else {
-            return a
-        }
-    },
-    register: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        b[c] = a
-    },
-    unregister: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        delete b[c]
-    },
-    get: function(a) {
-        return this.chartComponents[a]
-    },
-    getAxis: function(a) {
-        if (a instanceof Ext.chart.axis.Axis) {
-            return a
-        } else {
-            if (Ext.isNumber(a)) {
-                return this.getAxes()[a]
-            } else {
-                if (Ext.isString(a)) {
-                    return this.get(a)
-                }
-            }
-        }
-    },
-    getSurface: function(b, c) {
-        b = b || "main";
-        c = c || b;
-        var d = this,
-            a = this.callParent([b]),
-            f = d.surfaceZIndexes,
-            e = d.surfaceMap;
-        if (c in f) {
-            a.element.setStyle("zIndex", f[c])
-        }
-        if (!e[c]) {
-            e[c] = []
-        }
-        if (Ext.Array.indexOf(e[c], a) < 0) {
-            a.type = c;
-            e[c].push(a);
-            a.on("destroy", d.forgetSurface, d)
-        }
-        return a
-    },
-    forgetSurface: function(a) {
-        var d = this.surfaceMap;
-        if (!d || this.isDestroying) {
-            return
-        }
-        var c = d[a.type],
-            b = c ? Ext.Array.indexOf(c, a) : -1;
-        if (b >= 0) {
-            c.splice(b, 1)
-        }
-    },
-    applyAxes: function(b, k) {
-        var l = this,
-            g = {
-                left: "right",
-                right: "left"
-            },
-            m = [],
-            c, d, e, a, f, h, j;
-        l.animationSuspendCount++;
-        l.getStore();
-        if (!k) {
-            k = [];
-            k.map = {}
-        }
-        j = k.map;
-        m.map = {};
-        b = Ext.Array.from(b, true);
-        for (f = 0, h = b.length; f < h; f++) {
-            c = b[f];
-            if (!c) {
-                continue
-            }
-            if (c instanceof Ext.chart.axis.Axis) {
-                d = j[c.getId()];
-                c.setChart(l)
-            } else {
-                c = Ext.Object.chain(c);
-                e = c.linkedTo;
-                a = c.id;
-                if (Ext.isNumber(e)) {
-                    c = Ext.merge({}, b[e], c)
-                } else {
-                    if (Ext.isString(e)) {
-                        Ext.Array.each(b, function(i) {
-                            if (i.id === c.linkedTo) {
-                                c = Ext.merge({}, i, c);
-                                return false
-                            }
-                        })
-                    }
-                }
-                c.id = a;
-                c.chart = l;
-                if (l.getInherited().rtl) {
-                    c.position = g[c.position] || c.position
-                }
-                a = c.getId && c.getId() || c.id;
-                c = Ext.factory(c, null, d = j[a], "axis")
-            }
-            if (c) {
-                m.push(c);
-                m.map[c.getId()] = c;
-                if (!d) {
-                    c.on("animationstart", "onAnimationStart", l);
-                    c.on("animationend", "onAnimationEnd", l)
-                }
-            }
-        }
-        for (f in j) {
-            if (!m.map[f]) {
-                j[f].destroy()
-            }
-        }
-        l.animationSuspendCount--;
-        return m
-    },
-    updateAxes: function() {
-        if (!this.isDestroying) {
-            this.scheduleLayout()
-        }
-    },
-    circularCopyArray: function(e, f, d) {
-        var c = [],
-            b, a = e && e.length;
-        if (a) {
-            for (b = 0; b < d; b++) {
-                c.push(e[(f + b) % a])
-            }
-        }
-        return c
-    },
-    circularCopyObject: function(f, g, d) {
-        var c = this,
-            b, e, a = {};
-        if (d) {
-            for (b in f) {
-                if (f.hasOwnProperty(b)) {
-                    e = f[b];
-                    if (Ext.isArray(e)) {
-                        a[b] = c.circularCopyArray(e, g, d)
-                    } else {
-                        a[b] = e
-                    }
-                }
-            }
-        }
-        return a
-    },
-    getColors: function() {
-        var b = this,
-            a = b.config.colors,
-            c = b.getTheme();
-        if (Ext.isArray(a) && a.length > 0) {
-            a = b.applyColors(a)
-        }
-        return a || (c && c.getColors())
-    },
-    applyColors: function(a) {
-        a = Ext.Array.map(a, function(b) {
-            if (Ext.isString(b)) {
-                return b
-            } else {
-                return b.toString()
-            }
-        });
-        return a
-    },
-    updateColors: function(c) {
-        var k = this,
-            e = k.getTheme(),
-            a = c || (e && e.getColors()),
-            l = 0,
-            f = k.getSeries(),
-            d = f && f.length,
-            g, j, b, h;
-        if (a.length) {
-            for (g = 0; g < d; g++) {
-                j = f[g];
-                h = j.themeColorCount();
-                b = k.circularCopyArray(a, l, h);
-                l += h;
-                j.updateChartColors(b)
-            }
-        }
-        k.refreshLegendStore()
-    },
-    applyTheme: function(a) {
-        if (a && a.isTheme) {
-            return a
-        }
-        return Ext.Factory.chartTheme(a)
-    },
-    updateTheme: function(g) {
-        var e = this,
-            f = e.getAxes(),
-            d = e.getSeries(),
-            a = e.getColors(),
-            c, b;
-        e.updateChartTheme(g);
-        for (b = 0; b < f.length; b++) {
-            f[b].updateTheme(g)
-        }
-        for (b = 0; b < d.length; b++) {
-            c = d[b];
-            c.updateTheme(g)
-        }
-        e.updateSpriteTheme(g);
-        e.updateColors(a);
-        e.redraw()
-    },
-    themeOnlyIfConfigured: {},
-    updateChartTheme: function(c) {
-        var i = this,
-            k = c.getChart(),
-            n = i.getInitialConfig(),
-            b = i.defaultConfig,
-            e = i.getConfigurator().configs,
-            f = k.defaults,
-            g = k[i.xtype],
-            h = i.themeOnlyIfConfigured,
-            l, j, o, a, m, d;
-        k = Ext.merge({}, f, g);
-        for (l in k) {
-            j = k[l];
-            d = e[l];
-            if (j !== null && j !== undefined && d) {
-                m = n[l];
-                o = Ext.isObject(j);
-                a = m === b[l];
-                if (o) {
-                    if (a && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (a || o) {
-                    i[d.names.set](j)
-                }
-            }
-        }
-    },
-    updateSpriteTheme: function(c) {
-        this.getSprites();
-        var j = this,
-            e = j.getSurface("chart"),
-            h = e.getItems(),
-            m = c.getSprites(),
-            k, a, l, f, d, b, g;
-        for (b = 0, g = h.length; b < g; b++) {
-            k = h[b];
-            a = m[k.type];
-            if (a) {
-                f = {};
-                d = k.type === "text";
-                for (l in a) {
-                    if (!(l in k.config)) {
-                        if (!(d && l.indexOf("font") === 0 && k.config.font)) {
-                            f[l] = a[l]
-                        }
-                    }
-                }
-                k.setAttributes(f)
-            }
-        }
-    },
-    addSeries: function(b) {
-        var a = this.getSeries();
-        Ext.Array.push(a, b);
-        this.setSeries(a)
-    },
-    removeSeries: function(d) {
-        d = Ext.Array.from(d);
-        var b = this.getSeries(),
-            f = [],
-            a = d.length,
-            g = {},
-            c, e;
-        for (c = 0; c < a; c++) {
-            e = d[c];
-            if (typeof e !== "string") {
-                e = e.getId()
-            }
-            g[e] = true
-        }
-        for (c = 0, a = b.length; c < a; c++) {
-            if (!g[b[c].getId()]) {
-                f.push(b[c])
-            }
-        }
-        this.setSeries(f)
-    },
-    applySeries: function(e, d) {
-        var g = this,
-            j = [],
-            h, a, c, f, b;
-        g.animationSuspendCount++;
-        g.getAxes();
-        if (d) {
-            h = d.map
-        } else {
-            d = [];
-            h = d.map = {}
-        }
-        j.map = {};
-        e = Ext.Array.from(e, true);
-        for (c = 0, f = e.length; c < f; c++) {
-            b = e[c];
-            if (!b) {
-                continue
-            }
-            a = h[b.getId && b.getId() || b.id];
-            if (b instanceof Ext.chart.series.Series) {
-                if (a && a !== b) {
-                    a.destroy()
-                }
-                b.setChart(g)
-            } else {
-                if (Ext.isObject(b)) {
-                    if (a) {
-                        a.setConfig(b);
-                        b = a
-                    } else {
-                        if (Ext.isString(b)) {
-                            b = {
-                                type: b
-                            }
-                        }
-                        b.chart = g;
-                        b = Ext.create(b.xclass || ("series." + b.type), b);
-                        b.on("animationstart", "onAnimationStart", g);
-                        b.on("animationend", "onAnimationEnd", g)
-                    }
-                }
-            }
-            j.push(b);
-            j.map[b.getId()] = b
-        }
-        for (c in h) {
-            if (!j.map[h[c].getId()]) {
-                h[c].destroy()
-            }
-        }
-        g.animationSuspendCount--;
-        return j
-    },
-    applyLegend: function(b, a) {
-        return Ext.factory(b, Ext.chart.Legend, a)
-    },
-    updateLegend: function(b, a) {
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            this.getItems();
-            this.legendStore = new Ext.data.Store({
-                autoDestroy: true,
-                fields: ["id", "name", "mark", "disabled", "series", "index"]
-            });
-            b.setStore(this.legendStore);
-            this.refreshLegendStore();
-            this.legendStore.on("update", "onUpdateLegendStore", this)
-        }
-    },
-    updateSeries: function(b, a) {
-        var c = this;
-        if (c.isDestroying) {
-            return
-        }
-        c.animationSuspendCount++;
-        c.fireEvent("serieschange", c, b, a);
-        c.refreshLegendStore();
-        if (!Ext.isEmpty(b)) {
-            c.updateTheme(c.getTheme())
-        }
-        c.scheduleLayout();
-        c.animationSuspendCount--
-    },
-    applyInteractions: function(h, d) {
-        if (!d) {
-            d = [];
-            d.map = {}
-        }
-        var g = this,
-            a = [],
-            c = d.map,
-            e, f, b;
-        a.map = {};
-        h = Ext.Array.from(h, true);
-        for (e = 0, f = h.length; e < f; e++) {
-            b = h[e];
-            if (!b) {
-                continue
-            }
-            b = Ext.factory(b, null, c[b.getId && b.getId() || b.id], "interaction");
-            if (b) {
-                b.setChart(g);
-                a.push(b);
-                a.map[b.getId()] = b
-            }
-        }
-        for (e in c) {
-            if (!a.map[e]) {
-                c[e].destroy()
-            }
-        }
-        return a
-    },
-    getInteraction: function(e) {
-        var f = this.getInteractions(),
-            a = f && f.length,
-            c = null,
-            b, d;
-        if (a) {
-            for (d = 0; d < a; ++d) {
-                b = f[d];
-                if (b.type === e) {
-                    c = b;
-                    break
-                }
-            }
-        }
-        return c
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    updateStore: function(a, c) {
-        var b = this;
-        if (c) {
-            c.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            });
-            if (c.autoDestroy) {
-                c.destroy()
-            }
-        }
-        if (a) {
-            a.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            })
-        }
-        b.fireEvent("storechange", b, a, c);
-        b.onDataChanged()
-    },
-    redraw: function() {
-        this.fireEvent("redraw", this)
-    },
-    performLayout: function() {
-        var d = this,
-            b = d.getChartSize(true),
-            c = [0, 0, b.width, b.height],
-            a = d.getBackground();
-        d.hasFirstLayout = true;
-        d.fireEvent("layout", d);
-        d.cancelChartLayout();
-        d.getSurface("background").setRect(c);
-        d.getSurface("chart").setRect(c);
-        a.setAttributes({
-            width: b.width,
-            height: b.height
-        })
-    },
-    getChartSize: function(b) {
-        var a = this;
-        if (b) {
-            a.chartSize = null
-        }
-        return a.chartSize || (a.chartSize = a.innerElement.getSize())
-    },
-    getEventXY: function(a) {
-        return this.getSurface().getEventXY(a)
-    },
-    getItemForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            e = f.getMainRect(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            c, j;
-        if (!(e && h >= 0 && h <= e[2] && g >= 0 && g <= e[3])) {
-            return null
-        }
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                return j
-            }
-        }
-        return null
-    },
-    getItemsForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            e = [],
-            c, j;
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                e.push(j)
-            }
-        }
-        return e
-    },
-    onAnimationStart: function() {
-        this.fireEvent("animationstart", this)
-    },
-    onAnimationEnd: function() {
-        this.fireEvent("animationend", this)
-    },
-    onDataChanged: function() {
-        var d = this;
-        if (d.isInitializing) {
-            return
-        }
-        var c = d.getMainRect(),
-            a = d.getStore(),
-            b = d.getSeries(),
-            e = d.getAxes();
-        if (!a || !e || !b) {
-            return
-        }
-        if (!c) {
-            d.on({
-                redraw: d.onDataChanged,
-                scope: d,
-                single: true
-            });
-            return
-        }
-        d.processData();
-        d.redraw()
-    },
-    recordCount: 0,
-    processData: function() {
-        var g = this,
-            e = g.getStore().getCount(),
-            c = g.getSeries(),
-            f = c.length,
-            d = false,
-            b = 0,
-            a;
-        for (; b < f; b++) {
-            a = c[b];
-            a.processData();
-            if (!d && a.isStoreDependantColorCount) {
-                d = true
-            }
-        }
-        if (d && e > g.recordCount) {
-            g.updateColors(g.getColors());
-            g.recordCount = e
-        }
-    },
-    bindStore: function(a) {
-        this.setStore(a)
-    },
-    applyHighlightItem: function(f, a) {
-        if (f === a) {
-            return
-        }
-        if (Ext.isObject(f) && Ext.isObject(a)) {
-            var e = f,
-                d = a,
-                c = e.sprite && (e.sprite[0] || e.sprite),
-                b = d.sprite && (d.sprite[0] || d.sprite);
-            if (c === b && e.index === d.index) {
-                return
-            }
-        }
-        return f
-    },
-    updateHighlightItem: function(b, a) {
-        if (a) {
-            a.series.setAttributesForItem(a, {
-                highlighted: false
-            })
-        }
-        if (b) {
-            b.series.setAttributesForItem(b, {
-                highlighted: true
-            });
-            this.fireEvent("itemhighlight", this, b, a)
-        }
-        this.fireEvent("itemhighlightchange", this, b, a)
-    },
-    destroyChart: function() {
-        var f = this,
-            d = f.getLegend(),
-            g = f.getAxes(),
-            c = f.getSeries(),
-            h = f.getInteractions(),
-            b = [],
-            a, e;
-        f.surfaceMap = null;
-        for (a = 0, e = h.length; a < e; a++) {
-            h[a].destroy()
-        }
-        for (a = 0, e = g.length; a < e; a++) {
-            g[a].destroy()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            c[a].destroy()
-        }
-        f.setInteractions(b);
-        f.setAxes(b);
-        f.setSeries(b);
-        if (d) {
-            d.destroy();
-            f.setLegend(null)
-        }
-        f.legendStore = null;
-        f.setStore(null);
-        f.cancelChartLayout()
-    },
-    getRefItems: function(b) {
-        var g = this,
-            e = g.getSeries(),
-            h = g.getAxes(),
-            a = g.getInteractions(),
-            c = [],
-            d, f;
-        for (d = 0, f = e.length; d < f; d++) {
-            c.push(e[d]);
-            if (e[d].getRefItems) {
-                c.push.apply(c, e[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = h.length; d < f; d++) {
-            c.push(h[d]);
-            if (h[d].getRefItems) {
-                c.push.apply(c, h[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = a.length; d < f; d++) {
-            c.push(a[d]);
-            if (a[d].getRefItems) {
-                c.push.apply(c, a[d].getRefItems(b))
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.overrides.AbstractChart", {
-    override: "Ext.chart.AbstractChart",
-    updateLegend: function(b, a) {
-        var c;
-        this.callParent([b, a]);
-        if (b) {
-            c = b.docked;
-            this.addDocked({
-                dock: c,
-                xtype: "panel",
-                shrinkWrap: true,
-                scrollable: true,
-                layout: {
-                    type: c === "top" || c === "bottom" ? "hbox" : "vbox",
-                    pack: "center"
-                },
-                items: b,
-                cls: Ext.baseCSSPrefix + "legend-panel"
-            })
-        }
-    },
-    performLayout: function() {
-        if (this.isVisible(true)) {
-            return this.callParent()
-        }
-        this.cancelChartLayout();
-        return false
-    },
-    afterComponentLayout: function(c, a, b, d) {
-        this.callParent([c, a, b, d]);
-        this.scheduleLayout()
-    },
-    allowSchedule: function() {
-        return this.rendered
-    },
-    onDestroy: function() {
-        this.destroyChart();
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.horizontal",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(b, c, e) {
-        var a = this.attr,
-            f = b.roundPixel(a.y),
-            d = c.lineWidth * 0.5;
-        c.beginPath();
-        c.rect(e[0] - b.matrix.getDX(), f + d, +e[2], a.height);
-        c.fill();
-        c.beginPath();
-        c.moveTo(e[0] - b.matrix.getDX(), f + d);
-        c.lineTo(e[0] + e[2] - b.matrix.getDX(), f + d);
-        c.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.vertical",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    }
-});
-Ext.define("Ext.chart.CartesianChart", {
-    extend: "Ext.chart.AbstractChart",
-    alternateClassName: "Ext.chart.Chart",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid"],
-    xtype: ["cartesian", "chart"],
-    isCartesian: true,
-    config: {
-        flipXY: false,
-        innerRect: [0, 0, 1, 1],
-        innerPadding: {
-            top: 0,
-            left: 0,
-            right: 0,
-            bottom: 0
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    getDirectionForAxis: function(a) {
-        var b = this.getFlipXY();
-        if (a === "left" || a === "right") {
-            if (b) {
-                return "X"
-            } else {
-                return "Y"
-            }
-        } else {
-            if (b) {
-                return "Y"
-            } else {
-                return "X"
-            }
-        }
-    },
-    performLayout: function() {
-        var A = this;
-        A.animationSuspendCount++;
-        if (A.callParent() === false) {
-            --A.animationSuspendCount;
-            return
-        }
-        A.suspendThicknessChanged();
-        var d = A.getSurface("chart").getRect(),
-            o = d[2],
-            n = d[3],
-            z = A.getAxes(),
-            b, q = A.getSeries(),
-            h, l, a, f = A.getInsetPadding(),
-            v = A.getInnerPadding(),
-            r, c, e = Ext.apply({}, f),
-            u, p, s, k, m, y, t, x, g, j = A.getInherited().rtl,
-            w = A.getFlipXY();
-        if (o <= 0 || n <= 0) {
-            return
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            m = b.getFloating();
-            y = m ? m.value : null;
-            a = b.getThickness();
-            switch (b.getPosition()) {
-                case "top":
-                    l.setRect([0, e.top + 1, o, a]);
-                    break;
-                case "bottom":
-                    l.setRect([0, n - (e.bottom + a), o, a]);
-                    break;
-                case "left":
-                    l.setRect([e.left, 0, a, n]);
-                    break;
-                case "right":
-                    l.setRect([o - (e.right + a), 0, a, n]);
-                    break
-            }
-            if (y === null) {
-                e[b.getPosition()] += a
-            }
-        }
-        o -= e.left + e.right;
-        n -= e.top + e.bottom;
-        u = [e.left, e.top, o, n];
-        e.left += v.left;
-        e.top += v.top;
-        e.right += v.right;
-        e.bottom += v.bottom;
-        p = o - v.left - v.right;
-        s = n - v.top - v.bottom;
-        A.setInnerRect([e.left, e.top, p, s]);
-        if (p <= 0 || s <= 0) {
-            return
-        }
-        A.setMainRect(u);
-        A.getSurface().setRect(u);
-        for (x = 0, g = A.surfaceMap.grid && A.surfaceMap.grid.length; x < g; x++) {
-            c = A.surfaceMap.grid[x];
-            c.setRect(u);
-            c.matrix.set(1, 0, 0, 1, v.left, v.top);
-            c.matrix.inverse(c.inverseMatrix)
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            t = l.matrix;
-            k = t.elements;
-            switch (b.getPosition()) {
-                case "top":
-                case "bottom":
-                    k[4] = e.left;
-                    b.setLength(p);
-                    break;
-                case "left":
-                case "right":
-                    k[5] = e.top;
-                    b.setLength(s);
-                    break
-            }
-            b.updateTitleSprite();
-            t.inverse(l.inverseMatrix)
-        }
-        for (x = 0, g = q.length; x < g; x++) {
-            h = q[x];
-            r = h.getSurface();
-            r.setRect(u);
-            if (w) {
-                if (j) {
-                    r.matrix.set(0, -1, -1, 0, v.left + p, v.top + s)
-                } else {
-                    r.matrix.set(0, -1, 1, 0, v.left, v.top + s)
-                }
-            } else {
-                r.matrix.set(1, 0, 0, -1, v.left, v.top + s)
-            }
-            r.matrix.inverse(r.inverseMatrix);
-            h.getOverlaySurface().setRect(u)
-        }
-        A.redraw();
-        A.animationSuspendCount--;
-        A.resumeThicknessChanged()
-    },
-    refloatAxes: function() {
-        var h = this,
-            g = h.getAxes(),
-            o = (g && g.length) || 0,
-            c, d, n, f, l, b, k, r = h.getChartSize(),
-            q = h.getInsetPadding(),
-            p = h.getInnerPadding(),
-            a = r.width - q.left - q.right,
-            m = r.height - q.top - q.bottom,
-            j, e;
-        for (e = 0; e < o; e++) {
-            c = g[e];
-            f = c.getFloating();
-            l = f ? f.value : null;
-            if (l === null) {
-                delete c.floatingAtCoord;
-                continue
-            }
-            d = c.getSurface();
-            n = d.getRect();
-            if (!n) {
-                continue
-            }
-            n = n.slice();
-            b = h.getAxis(f.alongAxis);
-            if (b) {
-                j = b.getAlignment() === "horizontal";
-                if (Ext.isString(l)) {
-                    l = b.getCoordFor(l)
-                }
-                b.floatingAxes[c.getId()] = l;
-                k = b.getSprites()[0].attr.matrix;
-                if (j) {
-                    l = l * k.getXX() + k.getDX();
-                    c.floatingAtCoord = l + p.left + p.right
-                } else {
-                    l = l * k.getYY() + k.getDY();
-                    c.floatingAtCoord = l + p.top + p.bottom
-                }
-            } else {
-                j = c.getAlignment() === "horizontal";
-                if (j) {
-                    c.floatingAtCoord = l + p.top + p.bottom
-                } else {
-                    c.floatingAtCoord = l + p.left + p.right
-                }
-                l = d.roundPixel(0.01 * l * (j ? m : a))
-            }
-            switch (c.getPosition()) {
-                case "top":
-                    n[1] = q.top + p.top + l - n[3] + 1;
-                    break;
-                case "bottom":
-                    n[1] = q.top + p.top + (b ? l : m - l);
-                    break;
-                case "left":
-                    n[0] = q.left + p.left + l - n[2];
-                    break;
-                case "right":
-                    n[0] = q.left + p.left + (b ? l : a - l) - 1;
-                    break
-            }
-            d.setRect(n)
-        }
-    },
-    redraw: function() {
-        var C = this,
-            r = C.getSeries(),
-            z = C.getAxes(),
-            b = C.getMainRect(),
-            p, t, w = C.getInnerPadding(),
-            f, l, s, e, q, A, v, g, d, c, a, k, n, y = C.getFlipXY(),
-            x = 1000,
-            m, u, h, o, B;
-        if (!b) {
-            return
-        }
-        p = b[2] - w.left - w.right;
-        t = b[3] - w.top - w.bottom;
-        for (A = 0; A < r.length; A++) {
-            h = r[A];
-            if ((c = h.getXAxis())) {
-                n = c.getVisibleRange();
-                l = c.getRange();
-                l = [l[0] + (l[1] - l[0]) * n[0], l[0] + (l[1] - l[0]) * n[1]]
-            } else {
-                l = h.getXRange()
-            }
-            if ((a = h.getYAxis())) {
-                n = a.getVisibleRange();
-                s = a.getRange();
-                s = [s[0] + (s[1] - s[0]) * n[0], s[0] + (s[1] - s[0]) * n[1]]
-            } else {
-                s = h.getYRange()
-            }
-            q = {
-                visibleMinX: l[0],
-                visibleMaxX: l[1],
-                visibleMinY: s[0],
-                visibleMaxY: s[1],
-                innerWidth: p,
-                innerHeight: t,
-                flipXY: y
-            };
-            f = h.getSprites();
-            for (v = 0, g = f.length; v < g; v++) {
-                o = f[v];
-                m = o.attr.zIndex;
-                if (m < x) {
-                    m += (A + 1) * 100 + x;
-                    o.attr.zIndex = m;
-                    B = o.getMarker("items");
-                    if (B) {
-                        u = B.attr.zIndex;
-                        if (u === Number.MAX_VALUE) {
-                            B.attr.zIndex = m
-                        } else {
-                            if (u < x) {
-                                B.attr.zIndex = m + u
-                            }
-                        }
-                    }
-                }
-                o.setAttributes(q, true)
-            }
-        }
-        for (A = 0; A < z.length; A++) {
-            d = z[A];
-            e = d.isSide();
-            f = d.getSprites();
-            k = d.getRange();
-            n = d.getVisibleRange();
-            q = {
-                dataMin: k[0],
-                dataMax: k[1],
-                visibleMin: n[0],
-                visibleMax: n[1]
-            };
-            if (e) {
-                q.length = t;
-                q.startGap = w.bottom;
-                q.endGap = w.top
-            } else {
-                q.length = p;
-                q.startGap = w.left;
-                q.endGap = w.right
-            }
-            for (v = 0, g = f.length; v < g; v++) {
-                f[v].setAttributes(q, true)
-            }
-        }
-        C.renderFrame();
-        C.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.grid.CircularGrid", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "grid.circular",
-    inheritableStatics: {
-        def: {
-            defaults: {
-                r: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.grid.RadialGrid", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "grid.radial",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startRadius: "number",
-                endRadius: "number"
-            },
-            defaults: {
-                startRadius: 0,
-                endRadius: 1,
-                scalingCenterX: 0,
-                scalingCenterY: 0,
-                strokeStyle: "#DDD"
-            },
-            triggers: {
-                startRadius: "path,bbox",
-                endRadius: "path,bbox"
-            }
-        }
-    },
-    render: function() {
-        this.callParent(arguments)
-    },
-    updatePath: function(d, a) {
-        var b = a.startRadius,
-            c = a.endRadius;
-        d.moveTo(b, 0);
-        d.lineTo(c, 0)
-    }
-});
-Ext.define("Ext.chart.PolarChart", {
-    extend: "Ext.chart.AbstractChart",
-    requires: ["Ext.chart.grid.CircularGrid", "Ext.chart.grid.RadialGrid"],
-    xtype: "polar",
-    isPolar: true,
-    config: {
-        center: [0, 0],
-        radius: 0,
-        innerPadding: 0
-    },
-    getDirectionForAxis: function(a) {
-        return a === "radial" ? "Y" : "X"
-    },
-    applyCenter: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1]) {
-            return
-        }
-        return [+a[0], +a[1]]
-    },
-    updateCenter: function(a) {
-        var g = this,
-            h = g.getAxes(),
-            d = g.getSeries(),
-            c, f, e, b;
-        for (c = 0, f = h.length; c < f; c++) {
-            e = h[c];
-            e.setCenter(a)
-        }
-        for (c = 0, f = d.length; c < f; c++) {
-            b = d[c];
-            b.setCenter(a)
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        return Ext.isNumber(b) ? b : a
-    },
-    doSetSurfaceRect: function(b, c) {
-        var a = this.getMainRect();
-        b.setRect(c);
-        b.matrix.set(1, 0, 0, 1, a[0] - c[0], a[1] - c[1]);
-        b.inverseMatrix.set(1, 0, 0, 1, c[0] - a[0], c[1] - a[1])
-    },
-    applyAxes: function(f, h) {
-        var e = this,
-            g = Ext.Array.from(e.config.series)[0],
-            b, d, c, a;
-        if (g.type === "radar" && f && f.length) {
-            for (b = 0, d = f.length; b < d; b++) {
-                c = f[b];
-                if (c.position === "angular") {
-                    a = true;
-                    break
-                }
-            }
-            if (!a) {
-                f.push({
-                    type: "category",
-                    position: "angular",
-                    fields: g.xField || g.angleField,
-                    style: {
-                        estStepSize: 1
-                    },
-                    grid: true
-                })
-            }
-        }
-        return this.callParent(arguments)
-    },
-    performLayout: function() {
-        var F = this,
-            g = true;
-        try {
-            F.animationSuspendCount++;
-            if (this.callParent() === false) {
-                g = false;
-                return
-            }
-            F.suspendThicknessChanged();
-            var h = F.getSurface("chart").getRect(),
-                v = F.getInsetPadding(),
-                G = F.getInnerPadding(),
-                l = Ext.apply({}, v),
-                d, s = h[2] - v.left - v.right,
-                r = h[3] - v.top - v.bottom,
-                x = [v.left, v.top, s, r],
-                u = F.getSeries(),
-                p, t = s - G * 2,
-                w = r - G * 2,
-                D = [t * 0.5 + G, w * 0.5 + G],
-                j = Math.min(t, w) * 0.5,
-                A = F.getAxes(),
-                f, a, k, m = [],
-                o = [],
-                E = j - G,
-                z, n, b, q, y, c, C;
-            F.setMainRect(x);
-            F.doSetSurfaceRect(F.getSurface(), x);
-            for (z = 0, n = F.surfaceMap.grid && F.surfaceMap.grid.length; z < n; z++) {
-                F.doSetSurfaceRect(F.surfaceMap.grid[z], h)
-            }
-            for (z = 0, n = A.length; z < n; z++) {
-                f = A[z];
-                switch (f.getPosition()) {
-                    case "angular":
-                        m.push(f);
-                        break;
-                    case "radial":
-                        o.push(f);
-                        break
-                }
-            }
-            for (z = 0, n = m.length; z < n; z++) {
-                f = m[z];
-                q = f.getFloating();
-                y = q ? q.value : null;
-                F.doSetSurfaceRect(f.getSurface(), h);
-                a = f.getThickness();
-                for (d in l) {
-                    l[d] += a
-                }
-                s = h[2] - l.left - l.right;
-                r = h[3] - l.top - l.bottom;
-                b = Math.min(s, r) * 0.5;
-                if (z === 0) {
-                    E = b - G
-                }
-                f.setMinimum(0);
-                f.setLength(b);
-                f.getSprites();
-                k = f.sprites[0].attr.lineWidth * 0.5;
-                for (d in l) {
-                    l[d] += k
-                }
-            }
-            for (z = 0, n = o.length; z < n; z++) {
-                f = o[z];
-                F.doSetSurfaceRect(f.getSurface(), h);
-                f.setMinimum(0);
-                f.setLength(E);
-                f.getSprites()
-            }
-            for (z = 0, n = u.length; z < n; z++) {
-                p = u[z];
-                if (p.type === "gauge" && !c) {
-                    c = p
-                } else {
-                    p.setRadius(E)
-                }
-                F.doSetSurfaceRect(p.getSurface(), x)
-            }
-            F.doSetSurfaceRect(F.getSurface("overlay"), h);
-            if (c) {
-                c.setRect(x);
-                C = c.getRadius() - G;
-                F.setRadius(C);
-                F.setCenter(c.getCenter());
-                c.setRadius(C);
-                if (A.length && A[0].getPosition() === "gauge") {
-                    f = A[0];
-                    F.doSetSurfaceRect(f.getSurface(), h);
-                    f.setTotalAngle(c.getTotalAngle());
-                    f.setLength(C)
-                }
-            } else {
-                F.setRadius(j);
-                F.setCenter(D)
-            }
-            F.redraw()
-        } catch (B) {
-            throw B
-        } finally {
-            F.animationSuspendCount--;
-            if (g) {
-                F.resumeThicknessChanged()
-            }
-        }
-    },
-    refloatAxes: function() {
-        var j = this,
-            g = j.getAxes(),
-            h = j.getMainRect(),
-            f, k, b, d, a, c, e;
-        if (!h) {
-            return
-        }
-        e = 0.5 * Math.min(h[2], h[3]);
-        for (d = 0, a = g.length; d < a; d++) {
-            c = g[d];
-            f = c.getFloating();
-            k = f ? f.value : null;
-            if (k !== null) {
-                b = j.getAxis(f.alongAxis);
-                if (c.getPosition() === "angular") {
-                    if (b) {
-                        k = b.getLength() * k / b.getRange()[1]
-                    } else {
-                        k = 0.01 * k * e
-                    }
-                    c.sprites[0].setAttributes({
-                        length: k
-                    }, true)
-                } else {
-                    if (b) {
-                        if (Ext.isString(k)) {
-                            k = b.getCoordFor(k)
-                        }
-                        k = k / (b.getRange()[1] + 1) * Math.PI * 2 - Math.PI * 1.5 + c.getRotation()
-                    } else {
-                        k = Ext.draw.Draw.rad(k)
-                    }
-                    c.sprites[0].setAttributes({
-                        baseRotation: k
-                    }, true)
-                }
-            }
-        }
-    },
-    redraw: function() {
-        var f = this,
-            g = f.getAxes(),
-            d, c = f.getSeries(),
-            b, a, e;
-        for (a = 0, e = g.length; a < e; a++) {
-            d = g[a];
-            d.getSprites()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        f.renderFrame();
-        f.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.SpaceFillingChart", {
-    extend: "Ext.chart.AbstractChart",
-    xtype: "spacefilling",
-    config: {},
-    performLayout: function() {
-        var j = this;
-        try {
-            j.animationSuspendCount++;
-            if (j.callParent() === false) {
-                return
-            }
-            var k = j.getSurface("chart").getRect(),
-                l = j.getInsetPadding(),
-                a = k[2] - l.left - l.right,
-                m = k[3] - l.top - l.bottom,
-                h = [l.left, l.top, a, m],
-                b = j.getSeries(),
-                d, c, g;
-            j.getSurface().setRect(h);
-            j.setMainRect(h);
-            for (c = 0, g = b.length; c < g; c++) {
-                d = b[c];
-                d.getSurface().setRect(h);
-                if (d.setRect) {
-                    d.setRect(h)
-                }
-                d.getOverlaySurface().setRect(k)
-            }
-            j.redraw()
-        } catch (f) {
-            throw f
-        } finally {
-            j.animationSuspendCount--
-        }
-    },
-    redraw: function() {
-        var e = this,
-            c = e.getSeries(),
-            b, a, d;
-        for (a = 0, d = c.length; a < d; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        e.renderFrame();
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis3D", {
-    extend: "Ext.chart.axis.sprite.Axis",
-    alias: "sprite.axis3d",
-    type: "axis3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            },
-            triggers: {
-                depth: "layout"
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                depth: 0
-            }
-        }
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            c = d.isDiscrete ? 0 : e.depth,
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (e.position === "left" || e.position === "right") {
-            e.translationX = 0;
-            e.translationY = i * (e.length - c) / (i - b) + c;
-            e.scalingX = 1;
-            e.scalingY = (-e.length + c) / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (e.position === "top" || e.position === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * (e.length - c) / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    renderAxisLine: function(a, j, f, c) {
-        var i = this,
-            h = i.attr,
-            b = h.lineWidth * 0.5,
-            f = i.getLayout(),
-            d = f.isDiscrete ? 0 : h.depth,
-            k = h.position,
-            e, g;
-        if (h.axisLine && h.length) {
-            switch (k) {
-                case "left":
-                    e = a.roundPixel(c[2]) - b;
-                    j.moveTo(e, -h.endGap + d);
-                    j.lineTo(e, h.length + h.startGap);
-                    break;
-                case "right":
-                    j.moveTo(b, -h.endGap);
-                    j.lineTo(b, h.length + h.startGap);
-                    break;
-                case "bottom":
-                    j.moveTo(-h.startGap, b);
-                    j.lineTo(h.length - d + h.endGap, b);
-                    break;
-                case "top":
-                    e = a.roundPixel(c[3]) - b;
-                    j.moveTo(-h.startGap, e);
-                    j.lineTo(h.length + h.endGap, e);
-                    break;
-                case "angular":
-                    j.moveTo(h.centerX + h.length, h.centerY);
-                    j.arc(h.centerX, h.centerY, h.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    g = i.getGaugeAngles();
-                    j.moveTo(h.centerX + Math.cos(g.start) * h.length, h.centerY + Math.sin(g.start) * h.length);
-                    j.arc(h.centerX, h.centerY, h.length, g.start, g.end, true);
-                    break
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis3D", {
-    extend: "Ext.chart.axis.Axis",
-    xtype: "axis3d",
-    requires: ["Ext.chart.axis.sprite.Axis3D"],
-    config: {
-        depth: 0
-    },
-    onSeriesChange: function(e) {
-        var g = this,
-            b = "depthchange",
-            f = "onSeriesDepthChange",
-            d, c;
-
-        function a(h) {
-            var i = g.boundSeries;
-            for (d = 0; d < i.length; d++) {
-                c = i[d];
-                c[h](b, f, g)
-            }
-        }
-        a("un");
-        g.callParent(arguments);
-        a("on")
-    },
-    onSeriesDepthChange: function(b, f) {
-        var d = this,
-            g = f,
-            e = d.boundSeries,
-            a, c;
-        if (f > d.getDepth()) {
-            g = f
-        } else {
-            for (a = 0; a < e.length; a++) {
-                c = e[a];
-                if (c !== b && c.getDepth) {
-                    f = c.getDepth();
-                    if (f > g) {
-                        g = f
-                    }
-                }
-            }
-        }
-        d.setDepth(g)
-    },
-    updateDepth: function(d) {
-        var b = this,
-            c = b.getSprites(),
-            a = {
-                depth: d
-            };
-        if (c && c.length) {
-            c[0].setAttributes(a)
-        }
-        if (b.gridSpriteEven && b.gridSpriteOdd) {
-            b.gridSpriteEven.getTemplate().setAttributes(a);
-            b.gridSpriteOdd.getTemplate().setAttributes(a)
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal3d";
-            case "top":
-            case "bottom":
-                return "vertical3d"
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Category", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis",
-    alias: "axis.category",
-    type: "category",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Category3D", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis3D",
-    alias: "axis.category3d",
-    type: "category3d",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric", {
-    extend: "Ext.chart.axis.Axis",
-    type: "numeric",
-    alias: ["axis.numeric", "axis.radial"],
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric3D", {
-    extend: "Ext.chart.axis.Axis3D",
-    alias: ["axis.numeric3d"],
-    type: "numeric3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Time", {
-    extend: "Ext.chart.axis.Numeric",
-    alias: "axis.time",
-    type: "time",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.axis.Time3D", {
-    extend: "Ext.chart.axis.Numeric3D",
-    alias: "axis.time3d",
-    type: "time3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid3D", {
-    extend: "Ext.chart.grid.HorizontalGrid",
-    alias: "grid.horizontal3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render: function(a, k, d) {
-        var f = this.attr,
-            i = a.roundPixel(f.x),
-            h = a.roundPixel(f.y),
-            l = a.matrix.getDX(),
-            c = k.lineWidth * 0.5,
-            j = f.height,
-            e = f.depth,
-            b, g;
-        if (h <= d[1]) {
-            return
-        }
-        b = d[0] + e - l;
-        g = h + c - e;
-        k.beginPath();
-        k.rect(b, g, d[2], j);
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + d[2], g);
-        k.stroke();
-        b = d[0] + i - l;
-        g = h + c;
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.lineTo(b + e, g - e + j);
-        k.lineTo(b, g + j);
-        k.closePath();
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid3D", {
-    extend: "Ext.chart.grid.VerticalGrid",
-    alias: "grid.vertical3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render_: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    },
-    render: function(b, j, e) {
-        var g = this.attr,
-            i = b.roundPixel(g.x),
-            k = b.matrix.getDY(),
-            d = j.lineWidth * 0.5,
-            a = g.width,
-            f = g.depth,
-            c, h;
-        if (i >= e[2]) {
-            return
-        }
-        c = i - d + f;
-        h = e[1] - f - k;
-        j.beginPath();
-        j.rect(c, h, a, e[3]);
-        j.fill();
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c, h + e[3]);
-        j.stroke();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.lineTo(c + f + a, h - f);
-        j.lineTo(c + a, h);
-        j.closePath();
-        j.fill();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.stroke()
-    }
-});
-Ext.define("Ext.chart.interactions.CrossZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "crosszoom",
-    alias: "interaction.crosszoom",
-    isCrossZoom: true,
-    config: {
-        axes: true,
-        gestures: {
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd",
-            dblclick: "onDoubleTap"
-        },
-        undoButton: {}
-    },
-    stopAnimationBeforeSync: false,
-    zoomAnimationInProgress: false,
-    constructor: function() {
-        this.callParent(arguments);
-        this.zoomHistory = []
-    },
-    applyAxes: function(b) {
-        var a = {};
-        if (b === true) {
-            return {
-                top: {},
-                right: {},
-                bottom: {},
-                left: {}
-            }
-        } else {
-            if (Ext.isArray(b)) {
-                a = {};
-                Ext.each(b, function(c) {
-                    a[c] = {}
-                })
-            } else {
-                if (Ext.isObject(b)) {
-                    Ext.iterate(b, function(c, d) {
-                        if (d === true) {
-                            a[c] = {}
-                        } else {
-                            if (d !== false) {
-                                a[c] = d
-                            }
-                        }
-                    })
-                }
-            }
-        }
-        return a
-    },
-    applyUndoButton: function(b, a) {
-        var c = this;
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            return Ext.create("Ext.Button", Ext.apply({
-                cls: [],
-                text: "Undo Zoom",
-                disabled: true,
-                handler: function() {
-                    c.undoZoom()
-                }
-            }, b))
-        }
-    },
-    getSurface: function() {
-        return this.getChart() && this.getChart().getSurface("main")
-    },
-    setSeriesOpacity: function(b) {
-        var a = this.getChart() && this.getChart().getSurface("series");
-        if (a) {
-            a.element.setStyle("opacity", b)
-        }
-    },
-    onGestureStart: function(h) {
-        var j = this,
-            i = j.getChart(),
-            d = j.getSurface(),
-            l = i.getInnerRect(),
-            c = i.getInnerPadding(),
-            g = c.left,
-            b = g + l[2],
-            f = c.top,
-            a = f + l[3],
-            n = i.getEventXY(h),
-            m = n[0],
-            k = n[1];
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (m > g && m < b && k > f && k < a) {
-            j.gestureEvent = "drag";
-            j.lockEvents(j.gestureEvent);
-            j.startX = m;
-            j.startY = k;
-            j.selectionRect = d.add({
-                type: "rect",
-                globalAlpha: 0.5,
-                fillStyle: "rgba(80,80,140,0.5)",
-                strokeStyle: "rgba(80,80,140,1)",
-                lineWidth: 2,
-                x: m,
-                y: k,
-                width: 0,
-                height: 0,
-                zIndex: 10000
-            });
-            j.setSeriesOpacity(0.8);
-            return false
-        }
-    },
-    onGesture: function(h) {
-        var j = this;
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (j.getLocks()[j.gestureEvent] === j) {
-            var i = j.getChart(),
-                d = j.getSurface(),
-                l = i.getInnerRect(),
-                c = i.getInnerPadding(),
-                g = c.left,
-                b = g + l[2],
-                f = c.top,
-                a = f + l[3],
-                n = i.getEventXY(h),
-                m = n[0],
-                k = n[1];
-            if (m < g) {
-                m = g
-            } else {
-                if (m > b) {
-                    m = b
-                }
-            }
-            if (k < f) {
-                k = f
-            } else {
-                if (k > a) {
-                    k = a
-                }
-            }
-            j.selectionRect.setAttributes({
-                width: m - j.startX,
-                height: k - j.startY
-            });
-            if (Math.abs(j.startX - m) < 11 || Math.abs(j.startY - k) < 11) {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 0.5
-                })
-            } else {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 1
-                })
-            }
-            d.renderFrame();
-            return false
-        }
-    },
-    onGestureEnd: function(i) {
-        var l = this;
-        if (l.zoomAnimationInProgress) {
-            return
-        }
-        if (l.getLocks()[l.gestureEvent] === l) {
-            var k = l.getChart(),
-                d = l.getSurface(),
-                n = k.getInnerRect(),
-                c = k.getInnerPadding(),
-                g = c.left,
-                b = g + n[2],
-                f = c.top,
-                a = f + n[3],
-                h = n[2],
-                j = n[3],
-                p = k.getEventXY(i),
-                o = p[0],
-                m = p[1];
-            if (o < g) {
-                o = g
-            } else {
-                if (o > b) {
-                    o = b
-                }
-            }
-            if (m < f) {
-                m = f
-            } else {
-                if (m > a) {
-                    m = a
-                }
-            }
-            if (Math.abs(l.startX - o) < 11 || Math.abs(l.startY - m) < 11) {
-                d.remove(l.selectionRect)
-            } else {
-                l.zoomBy([Math.min(l.startX, o) / h, 1 - Math.max(l.startY, m) / j, Math.max(l.startX, o) / h, 1 - Math.min(l.startY, m) / j]);
-                l.selectionRect.setAttributes({
-                    x: Math.min(l.startX, o),
-                    y: Math.min(l.startY, m),
-                    width: Math.abs(l.startX - o),
-                    height: Math.abs(l.startY - m)
-                });
-                l.selectionRect.setAnimation(k.getAnimation() || {
-                    duration: 0
-                });
-                l.selectionRect.setAttributes({
-                    globalAlpha: 0,
-                    x: 0,
-                    y: 0,
-                    width: h,
-                    height: j
-                });
-                l.zoomAnimationInProgress = true;
-                k.suspendThicknessChanged();
-                l.selectionRect.fx.on("animationend", function() {
-                    k.resumeThicknessChanged();
-                    d.remove(l.selectionRect);
-                    l.selectionRect = null;
-                    l.zoomAnimationInProgress = false
-                })
-            }
-            d.renderFrame();
-            l.sync();
-            l.unlockEvents(l.gestureEvent);
-            l.setSeriesOpacity(1);
-            if (!l.zoomAnimationInProgress) {
-                d.remove(l.selectionRect);
-                l.selectionRect = null
-            }
-        }
-    },
-    zoomBy: function(o) {
-        var n = this,
-            a = n.getAxes(),
-            k = n.getChart(),
-            j = k.getAxes(),
-            l = k.getInherited().rtl,
-            f, d = {},
-            c, b;
-        if (l) {
-            o = o.slice();
-            c = 1 - o[0];
-            b = 1 - o[2];
-            o[0] = Math.min(c, b);
-            o[2] = Math.max(c, b)
-        }
-        for (var h = 0; h < j.length; h++) {
-            var g = j[h];
-            f = a[g.getPosition()];
-            if (f && f.allowZoom !== false) {
-                var e = g.isSide(),
-                    m = g.getVisibleRange();
-                d[g.getId()] = m.slice(0);
-                if (!e) {
-                    g.setVisibleRange([(m[1] - m[0]) * o[0] + m[0], (m[1] - m[0]) * o[2] + m[0]])
-                } else {
-                    g.setVisibleRange([(m[1] - m[0]) * o[1] + m[0], (m[1] - m[0]) * o[3] + m[0]])
-                }
-            }
-        }
-        n.zoomHistory.push(d);
-        n.getUndoButton().setDisabled(false)
-    },
-    undoZoom: function() {
-        var c = this.zoomHistory.pop(),
-            d = this.getChart().getAxes();
-        if (c) {
-            for (var a = 0; a < d.length; a++) {
-                var b = d[a];
-                if (c[b.getId()]) {
-                    b.setVisibleRange(c[b.getId()])
-                }
-            }
-        }
-        this.getUndoButton().setDisabled(this.zoomHistory.length === 0);
-        this.sync()
-    },
-    onDoubleTap: function(a) {
-        this.undoZoom()
-    },
-    destroy: function() {
-        this.setUndoButton(null);
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.interactions.Crosshair", {
-    extend: "Ext.chart.interactions.Abstract",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid", "Ext.chart.CartesianChart", "Ext.chart.axis.layout.Discrete"],
-    type: "crosshair",
-    alias: "interaction.crosshair",
-    config: {
-        axes: {
-            top: {
-                label: {},
-                rect: {}
-            },
-            right: {
-                label: {},
-                rect: {}
-            },
-            bottom: {
-                label: {},
-                rect: {}
-            },
-            left: {
-                label: {},
-                rect: {}
-            }
-        },
-        lines: {
-            horizontal: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            },
-            vertical: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            }
-        },
-        gesture: "drag"
-    },
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyLines: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    updateChart: function(a) {
-        if (a && !a.isCartesian) {
-            Ext.raise("Crosshair interaction can only be used on cartesian charts.")
-        }
-        this.callParent(arguments)
-    },
-    getGestures: function() {
-        var a = this,
-            b = {};
-        b[a.getGesture()] = "onGesture";
-        b[a.getGesture() + "start"] = "onGestureStart";
-        b[a.getGesture() + "end"] = "onGestureEnd";
-        return b
-    },
-    onGestureStart: function(N) {
-        var m = this,
-            O = m.getChart(),
-            B = O.getTheme().getAxis(),
-            A, F = O.getSurface("overlay"),
-            s = O.getInnerRect(),
-            n = s[2],
-            M = s[3],
-            r = O.getEventXY(N),
-            D = r[0],
-            C = r[1],
-            E = O.getAxes(),
-            u = m.getAxes(),
-            h = m.getLines(),
-            q, v, b, d, k, z, G, L, J, o, I, w, l, f, p, j, t, a, g, H, c, K;
-        if (D > 0 && D < n && C > 0 && C < M) {
-            m.lockEvents(m.getGesture());
-            H = Ext.apply({
-                xclass: "Ext.chart.grid.HorizontalGrid",
-                x: 0,
-                y: C,
-                width: n
-            }, h.horizontal);
-            c = Ext.apply({
-                xclass: "Ext.chart.grid.VerticalGrid",
-                x: D,
-                y: 0,
-                height: M
-            }, h.vertical);
-            m.axesLabels = m.axesLabels || {};
-            for (K = 0; K < E.length; K++) {
-                q = E[K];
-                v = q.getSurface();
-                b = v.getRect();
-                w = q.getSprites()[0];
-                d = b[2];
-                k = b[3];
-                z = q.getPosition();
-                G = q.getAlignment();
-                t = q.getTitle();
-                a = t && t.attr.text !== "" && t.getBBox();
-                l = w.attr;
-                f = w.thickness;
-                p = l.axisLine ? l.lineWidth : 0;
-                j = p / 2;
-                I = Math.max(l.majorTickSize, l.minorTickSize) + p;
-                L = m.axesLabels[z] = v.add({
-                    type: "composite"
-                });
-                L.labelRect = L.add(Ext.apply({
-                    type: "rect",
-                    fillStyle: "white",
-                    x: z === "right" ? p : 0,
-                    y: z === "bottom" ? p : 0,
-                    width: d - p - (G === "vertical" && a ? a.width : 0),
-                    height: k - p - (G === "horizontal" && a ? a.height : 0),
-                    translationX: z === "left" && a ? a.width : 0,
-                    translationY: z === "top" && a ? a.height : 0
-                }, u.rect || u[z].rect));
-                if (G === "vertical" && !c.strokeStyle) {
-                    c.strokeStyle = l.strokeStyle
-                }
-                if (G === "horizontal" && !H.strokeStyle) {
-                    H.strokeStyle = l.strokeStyle
-                }
-                A = Ext.merge({}, B.defaults, B[z]);
-                J = Ext.apply({}, q.config.label, A.label);
-                o = u.label || u[z].label;
-                L.labelText = L.add(Ext.apply(J, o, {
-                    type: "text",
-                    x: (function() {
-                        switch (z) {
-                            case "left":
-                                g = a ? a.x + a.width : 0;
-                                return g + (d - g - I) / 2 - j;
-                            case "right":
-                                g = a ? d - a.x : 0;
-                                return I + (d - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })(),
-                    y: (function() {
-                        switch (z) {
-                            case "top":
-                                g = a ? a.y + a.height : 0;
-                                return g + (k - g - I) / 2 - j;
-                            case "bottom":
-                                g = a ? k - a.y : 0;
-                                return I + (k - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })()
-                }))
-            }
-            m.horizontalLine = F.add(H);
-            m.verticalLine = F.add(c);
-            return false
-        }
-    },
-    onGesture: function(G) {
-        var K = this;
-        if (K.getLocks()[K.getGesture()] !== K) {
-            return
-        }
-        var u = K.getChart(),
-            z = u.getSurface("overlay"),
-            a = Ext.Array.slice(u.getInnerRect()),
-            r = u.getInnerPadding(),
-            t = r.left,
-            q = r.top,
-            E = a[2],
-            f = a[3],
-            d = u.getEventXY(G),
-            k = d[0],
-            j = d[1],
-            D = u.getAxes(),
-            c, h, m, p, J, w, I, H, s, b, C, g, v, n, l, A, F, o, B;
-        if (k < 0) {
-            k = 0
-        } else {
-            if (k > E) {
-                k = E
-            }
-        }
-        if (j < 0) {
-            j = 0
-        } else {
-            if (j > f) {
-                j = f
-            }
-        }
-        k += t;
-        j += q;
-        for (B = 0; B < D.length; B++) {
-            c = D[B];
-            h = c.getPosition();
-            m = c.getAlignment();
-            p = c.getSurface();
-            J = c.getSprites()[0];
-            w = J.attr.matrix;
-            C = J.attr.textPadding * 2;
-            s = K.axesLabels[h];
-            I = J.getLayoutContext();
-            H = c.getSegmenter();
-            if (s) {
-                if (m === "vertical") {
-                    v = w.getYY();
-                    l = w.getDY();
-                    F = (j - l - q) / v;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        j = Math.round(F) * v + l + q;
-                        F = H.from(Math.round(F));
-                        F = J.attr.data[F]
-                    } else {
-                        F = H.from(F)
-                    }
-                    o = H.renderer(F, I);
-                    s.setAttributes({
-                        translationY: j - q
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        height: b.height + C,
-                        y: -(b.height + C) / 2
-                    });
-                    p.renderFrame()
-                } else {
-                    g = w.getXX();
-                    n = w.getDX();
-                    A = (k - n - t) / g;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        k = Math.round(A) * g + n + t;
-                        A = H.from(Math.round(A));
-                        A = J.attr.data[A]
-                    } else {
-                        A = H.from(A)
-                    }
-                    o = H.renderer(A, I);
-                    s.setAttributes({
-                        translationX: k - t
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        width: b.width + C,
-                        x: -(b.width + C) / 2
-                    });
-                    p.renderFrame()
-                }
-            }
-        }
-        K.horizontalLine.setAttributes({
-            y: j,
-            strokeStyle: J.attr.strokeStyle
-        });
-        K.verticalLine.setAttributes({
-            x: k,
-            strokeStyle: J.attr.strokeStyle
-        });
-        z.renderFrame();
-        return false
-    },
-    onGestureEnd: function(h) {
-        var l = this,
-            k = l.getChart(),
-            a = k.getSurface("overlay"),
-            j = k.getAxes(),
-            c, g, d, b, f;
-        a.remove(l.verticalLine);
-        a.remove(l.horizontalLine);
-        for (f = 0; f < j.length; f++) {
-            c = j[f];
-            g = c.getPosition();
-            d = c.getSurface();
-            b = l.axesLabels[g];
-            if (b) {
-                delete l.axesLabels[g];
-                d.remove(b)
-            }
-            d.renderFrame()
-        }
-        a.renderFrame();
-        l.unlockEvents(l.getGesture())
-    }
-});
-Ext.define("Ext.chart.interactions.ItemHighlight", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "itemhighlight",
-    alias: "interaction.itemhighlight",
-    isItemHighlight: true,
-    config: {
-        gestures: {
-            tap: "onTapGesture",
-            mousemove: "onMouseMoveGesture",
-            mousedown: "onMouseDownGesture",
-            mouseup: "onMouseUpGesture",
-            mouseleave: "onMouseUpGesture"
-        },
-        sticky: false
-    },
-    stickyHighlightItem: null,
-    onMouseMoveGesture: function(g) {
-        var d = this,
-            h = d.tipItem,
-            a = g.pointerType === "mouse",
-            c, f, b;
-        if (d.getSticky()) {
-            return true
-        }
-        if (d.isDragging) {
-            if (h && a) {
-                h.series.hideTooltip(h);
-                d.tipItem = null
-            }
-        } else {
-            if (!d.stickyHighlightItem) {
-                c = d.getItemForEvent(g);
-                b = d.getChart();
-                if (c !== b.getHighlightItem()) {
-                    d.highlight(c);
-                    d.sync()
-                }
-                if (a) {
-                    if (h && (!c || h.field !== c.field || h.record !== c.record)) {
-                        h.series.hideTooltip(h);
-                        d.tipItem = h = null
-                    }
-                    if (c && (f = c.series.getTooltip())) {
-                        if (f.trackMouse || !h) {
-                            c.series.showTooltip(c, g.getXY())
-                        }
-                        d.tipItem = c
-                    }
-                }
-                return false
-            }
-        }
-    },
-    highlight: function(a) {
-        this.getChart().setHighlightItem(a)
-    },
-    showTooltip: function(b, a) {
-        a.series.showTooltip(a, b.getXY());
-        this.tipItem = a
-    },
-    onMouseDownGesture: function() {
-        this.isDragging = true
-    },
-    onMouseUpGesture: function() {
-        this.isDragging = false
-    },
-    onTapGesture: function(c) {
-        var b = this;
-        if (c.pointerType === "mouse" && !b.getSticky()) {
-            return
-        }
-        var a = b.getItemForEvent(c);
-        if (b.stickyHighlightItem && a && (b.stickyHighlightItem.index === a.index)) {
-            a = null
-        }
-        b.stickyHighlightItem = a;
-        b.highlight(a)
-    }
-});
-Ext.define("Ext.chart.interactions.ItemEdit", {
-    extend: "Ext.chart.interactions.ItemHighlight",
-    requires: ["Ext.tip.ToolTip"],
-    type: "itemedit",
-    alias: "interaction.itemedit",
-    isItemEdit: true,
-    config: {
-        style: null,
-        renderer: null,
-        tooltip: true,
-        gestures: {
-            dragstart: "onDragStart",
-            drag: "onDrag",
-            dragend: "onDragEnd"
-        },
-        cursors: {
-            ewResize: "ew-resize",
-            nsResize: "ns-resize",
-            move: "move"
-        }
-    },
-    item: null,
-    applyTooltip: function(b) {
-        if (b) {
-            var a = Ext.apply({}, b, {
-                renderer: this.defaultTooltipRenderer,
-                constrainPosition: true,
-                shrinkWrapDock: true,
-                autoHide: true,
-                offsetX: 10,
-                offsetY: 10
-            });
-            b = new Ext.tip.ToolTip(a)
-        }
-        return b
-    },
-    defaultTooltipRenderer: function(b, a, f, d) {
-        var c = [];
-        if (f.xField) {
-            c.push(f.xField + ": " + f.xValue)
-        }
-        if (f.yField) {
-            c.push(f.yField + ": " + f.yValue)
-        }
-        b.setHtml(c.join("<br>"))
-    },
-    onDragStart: function(d) {
-        var c = this,
-            a = c.getChart(),
-            b = a.getHighlightItem();
-        if (b) {
-            a.fireEvent("beginitemedit", a, c, c.item = b);
-            return false
-        }
-    },
-    onDrag: function(f) {
-        var d = this,
-            b = d.getChart(),
-            c = b.getHighlightItem(),
-            a = c && c.sprite.type;
-        if (c) {
-            switch (a) {
-                case "barSeries":
-                    return d.onDragBar(f);
-                    break;
-                case "scatterSeries":
-                    return d.onDragScatter(f);
-                    break
-            }
-        }
-    },
-    highlight: function(f) {
-        var e = this,
-            d = e.getChart(),
-            a = d.getFlipXY(),
-            g = e.getCursors(),
-            c = f && f.sprite.type,
-            b = d.el.dom.style;
-        e.callParent([f]);
-        if (f) {
-            switch (c) {
-                case "barSeries":
-                    if (a) {
-                        b.cursor = g.ewResize
-                    } else {
-                        b.cursor = g.nsResize
-                    }
-                    break;
-                case "scatterSeries":
-                    b.cursor = g.move;
-                    break
-            }
-        } else {
-            d.el.dom.style.cursor = "default"
-        }
-    },
-    onDragBar: function(i) {
-        var m = this,
-            k = m.getChart(),
-            l = k.getInherited().rtl,
-            f = k.isCartesian && k.getFlipXY(),
-            q = k.getHighlightItem(),
-            g = q.sprite.getMarker("items"),
-            p = g.getMarkerFor(q.sprite.getId(), q.index),
-            b = q.sprite.getSurface(),
-            c = b.getRect(),
-            r = b.getEventXY(i),
-            o = q.sprite.attr.matrix,
-            j = m.getRenderer(),
-            a, n, d, h;
-        if (f) {
-            h = l ? c[2] - r[0] : r[0]
-        } else {
-            h = c[3] - r[1]
-        }
-        a = {
-            x: p.x,
-            y: h,
-            width: p.width,
-            height: p.height + (p.y - h),
-            radius: p.radius,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(a, m.getStyle());
-        if (Ext.isArray(q.series.getYField())) {
-            h = h - p.y - p.height
-        }
-        m.target = {
-            index: q.index,
-            yField: q.field,
-            yValue: (h - o.getDY()) / o.getYY()
-        };
-        d = [k, {
-            target: m.target,
-            style: a,
-            item: q
-        }];
-        n = Ext.callback(j, null, d, 0, k);
-        if (n) {
-            Ext.apply(a, n)
-        }
-        q.sprite.putMarker("items", a, "itemedit");
-        m.showTooltip(i, m.target, q);
-        b.renderFrame()
-    },
-    onDragScatter: function(n) {
-        var t = this,
-            g = t.getChart(),
-            d = g.getInherited().rtl,
-            l = g.isCartesian && g.getFlipXY(),
-            o = g.getHighlightItem(),
-            b = o.sprite.getMarker("items"),
-            p = b.getMarkerFor(o.sprite.getId(), o.index),
-            j = o.sprite.getSurface(),
-            h = j.getRect(),
-            a = j.getEventXY(n),
-            k = o.sprite.attr.matrix,
-            c = o.series.getXAxis(),
-            f = c && c.getLayout().isContinuous,
-            i = t.getRenderer(),
-            m, u, q, s, r;
-        if (l) {
-            r = d ? h[2] - a[0] : a[0]
-        } else {
-            r = h[3] - a[1]
-        }
-        if (f) {
-            if (l) {
-                s = h[3] - a[1]
-            } else {
-                s = a[0]
-            }
-        } else {
-            s = p.translationX
-        }
-        m = {
-            translationX: s,
-            translationY: r,
-            scalingX: p.scalingX,
-            scalingY: p.scalingY,
-            r: p.r,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(m, t.getStyle());
-        t.target = {
-            index: o.index,
-            yField: o.field,
-            yValue: (r - k.getDY()) / k.getYY()
-        };
-        if (f) {
-            Ext.apply(t.target, {
-                xField: o.series.getXField(),
-                xValue: (s - k.getDX()) / k.getXX()
-            })
-        }
-        q = [g, {
-            target: t.target,
-            style: m,
-            item: o
-        }];
-        u = Ext.callback(i, null, q, 0, g);
-        if (u) {
-            Ext.apply(m, u)
-        }
-        o.sprite.putMarker("items", m, "itemedit");
-        t.showTooltip(n, t.target, o);
-        j.renderFrame()
-    },
-    showTooltip: function(g, f, c) {
-        var d = this.getTooltip(),
-            a, b;
-        if (d && Ext.toolkit !== "modern") {
-            a = d.config;
-            b = this.getChart();
-            Ext.callback(a.renderer, null, [d, c, f, g], 0, b);
-            d.show([g.x + a.offsetX, g.y + a.offsetY])
-        }
-    },
-    hideTooltip: function() {
-        var a = this.getTooltip();
-        if (a && Ext.toolkit !== "modern") {
-            a.hide()
-        }
-    },
-    onDragEnd: function(g) {
-        var d = this,
-            f = d.target,
-            c = d.getChart(),
-            b = c.getStore(),
-            a;
-        if (f) {
-            a = b.getAt(f.index);
-            if (f.yField) {
-                a.set(f.yField, f.yValue, {
-                    convert: false
-                })
-            }
-            if (f.xField) {
-                a.set(f.xField, f.xValue, {
-                    convert: false
-                })
-            }
-            if (f.yField || f.xField) {
-                d.getChart().onDataChanged()
-            }
-            d.target = null
-        }
-        d.hideTooltip();
-        if (d.item) {
-            c.fireEvent("enditemedit", c, d, d.item, f)
-        }
-        d.highlight(d.item = null)
-    },
-    destroy: function() {
-        var a = this.getConfig("tooltip", true);
-        Ext.destroy(a);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.PanZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "panzoom",
-    alias: "interaction.panzoom",
-    requires: ["Ext.draw.Animator"],
-    config: {
-        axes: {
-            top: {},
-            right: {},
-            bottom: {},
-            left: {}
-        },
-        minZoom: null,
-        maxZoom: null,
-        showOverflowArrows: true,
-        panGesture: "drag",
-        zoomGesture: "pinch",
-        zoomOnPanGesture: false,
-        modeToggleButton: {
-            xtype: "segmentedbutton",
-            width: 200,
-            defaults: {
-                ui: "default-toolbar"
-            },
-            cls: Ext.baseCSSPrefix + "panzoom-toggle",
-            items: [{
-                text: "Pan"
-            }, {
-                text: "Zoom"
-            }]
-        },
-        hideLabelInGesture: false
-    },
-    stopAnimationBeforeSync: true,
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyZoomOnPanGesture: function(a) {
-        this.getChart();
-        if (this.isMultiTouch()) {
-            return false
-        }
-        return a
-    },
-    updateZoomOnPanGesture: function(b) {
-        var a = this.getModeToggleButton();
-        if (!this.isMultiTouch()) {
-            a.show();
-            a.setValue(b ? 1 : 0)
-        } else {
-            a.hide()
-        }
-    },
-    toggleMode: function() {
-        var a = this;
-        if (!a.isMultiTouch()) {
-            a.setZoomOnPanGesture(!a.getZoomOnPanGesture())
-        }
-    },
-    applyModeToggleButton: function(c, b) {
-        var d = this,
-            a = Ext.factory(c, "Ext.button.Segmented", b);
-        if (!a && b) {
-            b.destroy()
-        }
-        if (a && !b) {
-            a.addListener("toggle", function(e) {
-                d.setZoomOnPanGesture(e.getValue() === 1)
-            })
-        }
-        return a
-    },
-    getGestures: function() {
-        var c = this,
-            e = {},
-            d = c.getPanGesture(),
-            b = c.getZoomGesture(),
-            a = Ext.supports.Touch;
-        e[b] = "onZoomGestureMove";
-        e[b + "start"] = "onZoomGestureStart";
-        e[b + "end"] = "onZoomGestureEnd";
-        e[d] = "onPanGestureMove";
-        e[d + "start"] = "onPanGestureStart";
-        e[d + "end"] = "onPanGestureEnd";
-        e.doubletap = "onDoubleTap";
-        return e
-    },
-    onDoubleTap: function(h) {
-        var f = this,
-            c = f.getChart(),
-            g = c.getAxes(),
-            b, a, d;
-        for (a = 0, d = g.length; a < d; a++) {
-            b = g[a];
-            b.setVisibleRange([0, 1])
-        }
-        c.redraw()
-    },
-    onPanGestureStart: function(d) {
-        if (!d || !d.touches || d.touches.length < 2) {
-            var b = this,
-                a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            b.startX = d.getX() - c[0] - a[0];
-            b.startY = d.getY() - c[1] - a[1];
-            b.oldVisibleRanges = null;
-            b.hideLabels();
-            b.getChart().suspendThicknessChanged();
-            b.lockEvents(b.getPanGesture());
-            return false
-        }
-    },
-    onPanGestureMove: function(d) {
-        var b = this;
-        if (b.getLocks()[b.getPanGesture()] === b) {
-            var a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            if (b.getZoomOnPanGesture()) {
-                b.transformAxesBy(b.getZoomableAxes(d), 0, 0, (d.getX() - c[0] - a[0]) / b.startX, b.startY / (d.getY() - c[1] - a[1]))
-            } else {
-                b.transformAxesBy(b.getPannableAxes(d), d.getX() - c[0] - a[0] - b.startX, d.getY() - c[1] - a[1] - b.startY, 1, 1)
-            }
-            b.sync();
-            return false
-        }
-    },
-    onPanGestureEnd: function(b) {
-        var a = this,
-            c = a.getPanGesture();
-        if (a.getLocks()[c] === a) {
-            a.getChart().resumeThicknessChanged();
-            a.showLabels();
-            a.sync();
-            a.unlockEvents(c);
-            return false
-        }
-    },
-    onZoomGestureStart: function(b) {
-        if (b.touches && b.touches.length === 2) {
-            var c = this,
-                i = c.getChart().element.getXY(),
-                f = c.getChart().getInnerRect(),
-                h = i[0] + f[0],
-                d = i[1] + f[1],
-                j = [b.touches[0].point.x - h, b.touches[0].point.y - d, b.touches[1].point.x - h, b.touches[1].point.y - d],
-                g = Math.max(44, Math.abs(j[2] - j[0])),
-                a = Math.max(44, Math.abs(j[3] - j[1]));
-            c.getChart().suspendThicknessChanged();
-            c.lastZoomDistances = [g, a];
-            c.lastPoints = j;
-            c.oldVisibleRanges = null;
-            c.hideLabels();
-            c.lockEvents(c.getZoomGesture());
-            return false
-        }
-    },
-    onZoomGestureMove: function(d) {
-        var f = this;
-        if (f.getLocks()[f.getZoomGesture()] === f) {
-            var i = f.getChart().getInnerRect(),
-                n = f.getChart().element.getXY(),
-                k = n[0] + i[0],
-                h = n[1] + i[1],
-                o = Math.abs,
-                c = f.lastPoints,
-                m = [d.touches[0].point.x - k, d.touches[0].point.y - h, d.touches[1].point.x - k, d.touches[1].point.y - h],
-                g = Math.max(44, o(m[2] - m[0])),
-                b = Math.max(44, o(m[3] - m[1])),
-                a = this.lastZoomDistances || [g, b],
-                l = g / a[0],
-                j = b / a[1];
-            f.transformAxesBy(f.getZoomableAxes(d), i[2] * (l - 1) / 2 + m[2] - c[2] * l, i[3] * (j - 1) / 2 + m[3] - c[3] * j, l, j);
-            f.sync();
-            return false
-        }
-    },
-    onZoomGestureEnd: function(c) {
-        var b = this,
-            a = b.getZoomGesture();
-        if (b.getLocks()[a] === b) {
-            b.getChart().resumeThicknessChanged();
-            b.showLabels();
-            b.sync();
-            b.unlockEvents(a);
-            return false
-        }
-    },
-    hideLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.hideLabels()
-            })
-        }
-    },
-    showLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.showLabels()
-            })
-        }
-    },
-    isEventOnAxis: function(c, a) {
-        var b = a.getSurface().getRect();
-        return b[0] <= c.getX() && c.getX() <= b[0] + b[2] && b[1] <= c.getY() && c.getY() <= b[1] + b[3]
-    },
-    getPannableAxes: function(d) {
-        var h = this,
-            a = h.getAxes(),
-            f = h.getChart().getAxes(),
-            c, g = f.length,
-            k = [],
-            j = false,
-            b;
-        if (d) {
-            for (c = 0; c < g; c++) {
-                if (this.isEventOnAxis(d, f[c])) {
-                    j = true;
-                    break
-                }
-            }
-        }
-        for (c = 0; c < g; c++) {
-            b = a[f[c].getPosition()];
-            if (b && b.allowPan !== false && (!j || this.isEventOnAxis(d, f[c]))) {
-                k.push(f[c])
-            }
-        }
-        return k
-    },
-    getZoomableAxes: function(f) {
-        var j = this,
-            a = j.getAxes(),
-            g = j.getChart().getAxes(),
-            l = [],
-            d, h = g.length,
-            c, k = false,
-            b;
-        if (f) {
-            for (d = 0; d < h; d++) {
-                if (this.isEventOnAxis(f, g[d])) {
-                    k = true;
-                    break
-                }
-            }
-        }
-        for (d = 0; d < h; d++) {
-            c = g[d];
-            b = a[c.getPosition()];
-            if (b && b.allowZoom !== false && (!k || this.isEventOnAxis(f, c))) {
-                l.push(c)
-            }
-        }
-        return l
-    },
-    eachInteractiveAxes: function(c) {
-        var d = this,
-            b = d.getAxes(),
-            e = d.getChart().getAxes();
-        for (var a = 0; a < e.length; a++) {
-            if (b[e[a].getPosition()]) {
-                if (false === c.call(this, e[a])) {
-                    return
-                }
-            }
-        }
-    },
-    transformAxesBy: function(d, j, g, h, e) {
-        var f = this.getChart().getInnerRect(),
-            a = this.getAxes(),
-            k, b = this.oldVisibleRanges,
-            l = false;
-        if (!b) {
-            this.oldVisibleRanges = b = {};
-            this.eachInteractiveAxes(function(i) {
-                b[i.getId()] = i.getVisibleRange()
-            })
-        }
-        if (!f) {
-            return
-        }
-        for (var c = 0; c < d.length; c++) {
-            k = a[d[c].getPosition()];
-            l = this.transformAxisBy(d[c], b[d[c].getId()], j, g, h, e, this.minZoom || k.minZoom, this.maxZoom || k.maxZoom) || l
-        }
-        return l
-    },
-    transformAxisBy: function(c, o, r, q, k, i, h, m) {
-        var s = this,
-            b = o[1] - o[0],
-            l = c.getVisibleRange(),
-            g = h || s.getMinZoom() || c.config.minZoom,
-            j = m || s.getMaxZoom() || c.config.maxZoom,
-            a = s.getChart().getInnerRect(),
-            f, p;
-        if (!a) {
-            return
-        }
-        var d = c.isSide(),
-            e = d ? a[3] : a[2],
-            n = d ? -q : r;
-        b /= d ? i : k;
-        if (b < 0) {
-            b = -b
-        }
-        if (b * g > 1) {
-            b = 1
-        }
-        if (b * j < 1) {
-            b = 1 / j
-        }
-        f = o[0];
-        p = o[1];
-        l = l[1] - l[0];
-        if (b === l && l === 1) {
-            return
-        }
-        c.setVisibleRange([(o[0] + o[1] - b) * 0.5 - n / e * b, (o[0] + o[1] + b) * 0.5 - n / e * b]);
-        return (Math.abs(f - c.getVisibleRange()[0]) > 1e-10 || Math.abs(p - c.getVisibleRange()[1]) > 1e-10)
-    },
-    destroy: function() {
-        this.setModeToggleButton(null);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Rotate", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "rotate",
-    alias: "interaction.rotate",
-    config: {
-        gesture: "rotate",
-        gestures: {
-            rotate: "onRotate",
-            rotateend: "onRotate",
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd"
-        },
-        rotation: 0
-    },
-    oldRotations: null,
-    getAngle: function(f) {
-        var c = this,
-            b = c.getChart(),
-            d = b.getEventXY(f),
-            a = b.getCenter();
-        return Math.atan2(d[1] - a[1], d[0] - a[0])
-    },
-    getRadius: function(a) {
-        return this.getChart().getRadius()
-    },
-    getEventRadius: function(h) {
-        var f = this,
-            d = f.getChart(),
-            g = d.getEventXY(h),
-            a = d.getCenter(),
-            c = g[0] - a[0],
-            b = g[1] - a[1];
-        return Math.sqrt(c * c + b * b)
-    },
-    onGestureStart: function(d) {
-        var c = this,
-            b = c.getRadius(d),
-            a = c.getEventRadius(d);
-        if (b >= a) {
-            c.lockEvents("drag");
-            c.angle = c.getAngle(d);
-            c.oldRotations = {};
-            return false
-        }
-    },
-    onGesture: function(b) {
-        var a = this,
-            c = a.getAngle(b) - a.angle;
-        if (a.getLocks().drag === a) {
-            a.doRotateTo(c, true);
-            return false
-        }
-    },
-    doRotateTo: function(d, a, b) {
-        var n = this,
-            l = n.getChart(),
-            k = l.getAxes(),
-            f = l.getSeries(),
-            m = n.oldRotations,
-            c, j, g, e, h;
-        if (!b) {
-            l.suspendAnimation()
-        }
-        for (e = 0, h = k.length; e < h; e++) {
-            c = k[e];
-            g = m[c.getId()] || (m[c.getId()] = c.getRotation());
-            c.setRotation(d + (a ? g : 0))
-        }
-        for (e = 0, h = f.length; e < h; e++) {
-            j = f[e];
-            g = m[j.getId()] || (m[j.getId()] = j.getRotation());
-            j.setRotation(d + (a ? g : 0))
-        }
-        n.setRotation(d + (a ? g : 0));
-        n.fireEvent("rotate", n, n.getRotation());
-        n.sync();
-        if (!b) {
-            l.resumeAnimation()
-        }
-    },
-    rotateTo: function(c, b, a) {
-        this.doRotateTo(c, b, a);
-        this.oldRotations = {}
-    },
-    onGestureEnd: function(b) {
-        var a = this;
-        if (a.getLocks().drag === a) {
-            a.onGesture(b);
-            a.unlockEvents("drag");
-            a.fireEvent("rotationEnd", a, a.getRotation());
-            return false
-        }
-    },
-    onRotate: function(a) {}
-});
-Ext.define("Ext.chart.interactions.RotatePie3D", {
-    extend: "Ext.chart.interactions.Rotate",
-    type: "rotatePie3d",
-    alias: "interaction.rotatePie3d",
-    getAngle: function(g) {
-        var a = this.getChart(),
-            f = a.getInherited().rtl,
-            d = f ? -1 : 1,
-            h = g.getXY(),
-            c = a.element.getXY(),
-            b = a.getMainRect();
-        return d * Math.atan2(h[1] - c[1] - b[3] * 0.5, h[0] - c[0] - b[2] * 0.5)
-    },
-    getRadius: function(j) {
-        var f = this.getChart(),
-            a = f.getRadius(),
-            d = f.getSeries(),
-            h = d.length,
-            c = 0,
-            b, g;
-        for (; c < h; c++) {
-            b = d[c];
-            if (b.isPie3D) {
-                g = b.getRadius();
-                if (g > a) {
-                    a = g
-                }
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.plugin.ItemEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.chartitemevents",
-    moveEvents: false,
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    itemMouseMoveEvents: {
-        itemmousemove: true,
-        itemmouseover: true,
-        itemmouseout: true
-    },
-    init: function(b) {
-        var a = "handleEvent";
-        this.chart = b;
-        b.addElementListener({
-            click: a,
-            dblclick: a,
-            mousedown: a,
-            mousemove: a,
-            mouseup: a,
-            mouseover: a,
-            mouseout: a,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasItemMouseMoveListeners: function() {
-        var b = this.chart.hasListeners,
-            a;
-        for (a in this.itemMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    handleEvent: function(g) {
-        var d = this,
-            a = d.chart,
-            h = g.type in d.mouseMoveEvents,
-            c = d.lastItem,
-            f, b;
-        if (h && !d.hasItemMouseMoveListeners() && !d.moveEvents) {
-            return
-        }
-        f = a.getEventXY(g);
-        b = a.getItemForPoint(f[0], f[1]);
-        if (h && !Ext.Object.equals(b, c)) {
-            if (c) {
-                a.fireEvent("itemmouseout", a, c, g);
-                c.series.fireEvent("itemmouseout", c.series, c, g)
-            }
-            if (b) {
-                a.fireEvent("itemmouseover", a, b, g);
-                b.series.fireEvent("itemmouseover", b.series, b, g)
-            }
-        }
-        if (b) {
-            a.fireEvent("item" + g.type, a, b, g);
-            b.series.fireEvent("item" + g.type, b.series, b, g)
-        }
-        d.lastItem = b
-    }
-});
-Ext.define("Ext.chart.series.Cartesian", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        xField: null,
-        yField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    updateXAxis: function(a) {
-        a.processData(this)
-    },
-    updateYAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    getItemForPoint: function(a, g) {
-        if (this.getSprites()) {
-            var f = this,
-                d = f.getSprites()[0],
-                b = f.getStore(),
-                e, c;
-            if (f.getHidden()) {
-                return null
-            }
-            if (d) {
-                c = d.getIndexNearPoint(a, g);
-                if (c !== -1) {
-                    e = {
-                        series: f,
-                        category: f.getItemInstancing() ? "items" : "markers",
-                        index: c,
-                        record: b.getData().items[c],
-                        field: f.getYField(),
-                        sprite: d
-                    };
-                    return e
-                }
-            }
-        }
-    },
-    createSprite: function() {
-        var c = this,
-            a = c.callParent(),
-            b = c.getChart(),
-            d = c.getXAxis();
-        a.setAttributes({
-            flipXY: b.getFlipXY(),
-            xAxis: d
-        });
-        if (a.setAggregator && d && d.getAggregator) {
-            if (d.getAggregator) {
-                a.setAggregator({
-                    strategy: d.getAggregator()
-                })
-            } else {
-                a.setAggregator({})
-            }
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = this.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.getItemInstancing(),
-            f = d.sprites,
-            a;
-        if (!c) {
-            return []
-        }
-        if (!f.length) {
-            a = d.createSprite()
-        } else {
-            a = f[0]
-        }
-        if (e) {
-            if (b) {
-                a.itemsMarker.getTemplate().setAnimation(e)
-            }
-            a.setAnimation(e)
-        }
-        return f
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    }
-});
-Ext.define("Ext.chart.series.StackedCartesian", {
-    extend: "Ext.chart.series.Cartesian",
-    config: {
-        stacked: true,
-        splitStacks: true,
-        fullStack: false,
-        fullStackTotal: 100,
-        hidden: []
-    },
-    spriteAnimationCount: 0,
-    themeColorCount: function() {
-        var b = this,
-            a = b.getYField();
-        return Ext.isArray(a) ? a.length : 1
-    },
-    updateStacked: function() {
-        this.processData()
-    },
-    updateSplitStacks: function() {
-        this.processData()
-    },
-    coordinateY: function() {
-        return this.coordinateStacked("Y", 1, 2)
-    },
-    coordinateStacked: function(D, e, m) {
-        var F = this,
-            f = F.getStore(),
-            r = f.getData().items,
-            B = r.length,
-            c = F["get" + D + "Axis"](),
-            x = F.getHidden(),
-            a = F.getSplitStacks(),
-            z = F.getFullStack(),
-            l = F.getFullStackTotal(),
-            p = {
-                min: 0,
-                max: 0
-            },
-            n = F["fieldCategory" + D],
-            C = [],
-            o = [],
-            E = [],
-            h, A = F.getStacked(),
-            g = F.getSprites(),
-            q = [],
-            w, v, u, s, H, y, b, d, G, t;
-        if (!g.length) {
-            return
-        }
-        for (w = 0; w < n.length; w++) {
-            d = n[w];
-            s = F.getFields([d]);
-            H = s.length;
-            for (v = 0; v < B; v++) {
-                C[v] = 0;
-                o[v] = 0;
-                E[v] = 0
-            }
-            for (v = 0; v < H; v++) {
-                if (!x[v]) {
-                    q[v] = F.coordinateData(r, s[v], c)
-                }
-            }
-            if (A && z) {
-                y = [];
-                if (a) {
-                    b = []
-                }
-                for (v = 0; v < B; v++) {
-                    y[v] = 0;
-                    if (a) {
-                        b[v] = 0
-                    }
-                    for (u = 0; u < H; u++) {
-                        G = q[u];
-                        if (!G) {
-                            continue
-                        }
-                        G = G[v];
-                        if (G >= 0 || !a) {
-                            y[v] += G
-                        } else {
-                            if (G < 0) {
-                                b[v] += G
-                            }
-                        }
-                    }
-                }
-            }
-            for (v = 0; v < H; v++) {
-                t = {};
-                if (x[v]) {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = C;
-                    g[v].setAttributes(t);
-                    continue
-                }
-                G = q[v];
-                if (A) {
-                    h = [];
-                    for (u = 0; u < B; u++) {
-                        if (!G[u]) {
-                            G[u] = 0
-                        }
-                        if (G[u] >= 0 || !a) {
-                            if (z && y[u]) {
-                                G[u] *= l / y[u]
-                            }
-                            C[u] = o[u];
-                            o[u] += G[u];
-                            h[u] = o[u]
-                        } else {
-                            if (z && b[u]) {
-                                G[u] *= l / b[u]
-                            }
-                            C[u] = E[u];
-                            E[u] += G[u];
-                            h[u] = E[u]
-                        }
-                    }
-                    t["dataStart" + d] = C;
-                    t["data" + d] = h;
-                    F.getRangeOfData(C, p);
-                    F.getRangeOfData(h, p)
-                } else {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = G;
-                    F.getRangeOfData(G, p)
-                }
-                g[v].setAttributes(t)
-            }
-        }
-        F.dataRange[e] = p.min;
-        F.dataRange[e + m] = p.max;
-        t = {};
-        t["dataMin" + D] = p.min;
-        t["dataMax" + D] = p.max;
-        for (w = 0; w < g.length; w++) {
-            g[w].setAttributes(t)
-        }
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    updateLabelOverflowPadding: function(a) {
-        this.getLabel().setAttributes({
-            labelOverflowPadding: a
-        })
-    },
-    getSprites: function() {
-        var k = this,
-            j = k.getChart(),
-            c = k.getAnimation() || j && j.getAnimation(),
-            f = k.getFields(k.fieldCategoryY),
-            b = k.getItemInstancing(),
-            h = k.sprites,
-            l, e = k.getHidden(),
-            g = false,
-            d, a = f.length;
-        if (!j) {
-            return []
-        }
-        for (d = 0; d < a; d++) {
-            l = h[d];
-            if (!l) {
-                l = k.createSprite();
-                l.setAttributes({
-                    zIndex: -d
-                });
-                l.setField(f[d]);
-                g = true;
-                e.push(false);
-                if (b) {
-                    l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))
-                } else {
-                    l.setAttributes(k.getStyleByIndex(d))
-                }
-            }
-            if (c) {
-                if (b) {
-                    l.itemsMarker.getTemplate().setAnimation(c)
-                }
-                l.setAnimation(c)
-            }
-        }
-        if (g) {
-            k.updateHidden(e)
-        }
-        return h
-    },
-    getItemForPoint: function(k, j) {
-        if (this.getSprites()) {
-            var h = this,
-                b, g, m, a = h.getItemInstancing(),
-                f = h.getSprites(),
-                l = h.getStore(),
-                c = h.getHidden(),
-                n, d, e;
-            for (b = 0, g = f.length; b < g; b++) {
-                if (!c[b]) {
-                    m = f[b];
-                    d = m.getIndexNearPoint(k, j);
-                    if (d !== -1) {
-                        e = h.getYField();
-                        n = {
-                            series: h,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: l.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: m
-                        };
-                        return n
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(e) {
-        var g = this,
-            f = g.getSprites(),
-            h = g.getTitle(),
-            j = g.getYField(),
-            d = g.getHidden(),
-            k = f.length === 1,
-            b, l, c, a;
-        for (c = 0; c < f.length; c++) {
-            b = g.getStyleByIndex(c);
-            l = b.fillStyle;
-            if (h) {
-                if (Ext.isArray(h)) {
-                    a = h[c]
-                } else {
-                    if (k) {
-                        a = h
-                    }
-                }
-            } else {
-                if (Ext.isArray(j)) {
-                    a = j[c]
-                } else {
-                    a = g.getId()
-                }
-            }
-            e.push({
-                name: a,
-                mark: (Ext.isObject(l) ? l.stops && l.stops[0].color : l) || b.strokeStyle || "black",
-                disabled: d[c],
-                series: g.getId(),
-                index: c
-            })
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart")
-        }
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend")
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Series", {
-    extend: "Ext.draw.sprite.Sprite",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataMinX: "number",
-                dataMaxX: "number",
-                dataMinY: "number",
-                dataMaxY: "number",
-                rangeX: "data",
-                rangeY: "data",
-                dataX: "data",
-                dataY: "data"
-            },
-            defaults: {
-                dataMinX: 0,
-                dataMaxX: 1,
-                dataMinY: 0,
-                dataMaxY: 1,
-                rangeX: null,
-                rangeY: null,
-                dataX: null,
-                dataY: null
-            },
-            triggers: {
-                dataX: "bbox",
-                dataY: "bbox",
-                dataMinX: "bbox",
-                dataMaxX: "bbox",
-                dataMinY: "bbox",
-                dataMaxY: "bbox"
-            }
-        }
-    },
-    config: {
-        store: null,
-        series: null,
-        field: null
-    }
-});
-Ext.define("Ext.chart.series.sprite.Cartesian", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                labels: "default",
-                labelOverflowPadding: "number",
-                selectionTolerance: "number",
-                flipXY: "bool",
-                renderer: "default",
-                visibleMinX: "number",
-                visibleMinY: "number",
-                visibleMaxX: "number",
-                visibleMaxY: "number",
-                innerWidth: "number",
-                innerHeight: "number"
-            },
-            defaults: {
-                labels: null,
-                labelOverflowPadding: 10,
-                selectionTolerance: 20,
-                flipXY: false,
-                renderer: null,
-                transformFillStroke: false,
-                visibleMinX: 0,
-                visibleMinY: 0,
-                visibleMaxX: 1,
-                visibleMaxY: 1,
-                innerWidth: 1,
-                innerHeight: 1
-            },
-            triggers: {
-                dataX: "dataX,bbox",
-                dataY: "dataY,bbox",
-                visibleMinX: "panzoom",
-                visibleMinY: "panzoom",
-                visibleMaxX: "panzoom",
-                visibleMaxY: "panzoom",
-                innerWidth: "panzoom",
-                innerHeight: "panzoom"
-            },
-            updaters: {
-                dataX: function(a) {
-                    this.processDataX();
-                    this.scheduleUpdater(a, "dataY", ["dataY"])
-                },
-                dataY: function() {
-                    this.processDataY()
-                },
-                panzoom: function(c) {
-                    var e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        g = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = this.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * g / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = g / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    this.applyTransformations(true)
-                }
-            }
-        }
-    },
-    processDataY: Ext.emptyFn,
-    processDataX: Ext.emptyFn,
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.dataMinX;
-        b.y = a.dataMinY;
-        b.width = a.dataMaxX - a.dataMinX;
-        b.height = a.dataMaxY - a.dataMinY
-    },
-    binarySearch: function(d) {
-        var b = this.attr.dataX,
-            f = 0,
-            a = b.length;
-        if (d <= b[0]) {
-            return f
-        }
-        if (d >= b[a - 1]) {
-            return a - 1
-        }
-        while (f + 1 < a) {
-            var c = (f + a) >> 1,
-                e = b[c];
-            if (e === d) {
-                return c
-            } else {
-                if (e < d) {
-                    f = c
-                } else {
-                    a = c
-                }
-            }
-        }
-        return f
-    },
-    render: function(b, c, g) {
-        var f = this,
-            a = f.attr,
-            e = a.inverseMatrix.clone();
-        e.appendMatrix(b.inverseMatrix);
-        if (a.dataX === null || a.dataX === undefined) {
-            return
-        }
-        if (a.dataY === null || a.dataY === undefined) {
-            return
-        }
-        if (e.getXX() * e.getYX() || e.getXY() * e.getYY()) {
-            console.log("Cartesian Series sprite does not support rotation/sheering");
-            return
-        }
-        var d = e.transformList([
-            [g[0] - 1, g[3] + 1],
-            [g[0] + g[2] + 1, -1]
-        ]);
-        d = d[0].concat(d[1]);
-        f.renderClipped(b, c, d, g)
-    },
-    renderClipped: Ext.emptyFn,
-    getIndexNearPoint: function(f, e) {
-        var w = this,
-            q = w.attr.matrix,
-            h = w.attr.dataX,
-            g = w.attr.dataY,
-            k = w.attr.selectionTolerance,
-            t, r, c = -1,
-            j = q.clone().prependMatrix(w.surfaceMatrix).inverse(),
-            u = j.transformPoint([f, e]),
-            b = j.transformPoint([f - k, e - k]),
-            n = j.transformPoint([f + k, e + k]),
-            a = Math.min(b[0], n[0]),
-            s = Math.max(b[0], n[0]),
-            l = Math.min(b[1], n[1]),
-            d = Math.max(b[1], n[1]),
-            m, v, o, p;
-        for (o = 0, p = h.length; o < p; o++) {
-            m = h[o];
-            v = g[o];
-            if (m > a && m < s && v > l && v < d) {
-                if (c === -1 || (Math.abs(m - u[0]) < t) && (Math.abs(v - u[1]) < r)) {
-                    t = Math.abs(m - u[0]);
-                    r = Math.abs(v - u[1]);
-                    c = o
-                }
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.series.sprite.StackedCartesian", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                groupCount: "number",
-                groupOffset: "number",
-                dataStartY: "data"
-            },
-            defaults: {
-                selectionTolerance: 20,
-                groupCount: 1,
-                groupOffset: 0,
-                dataStartY: null
-            },
-            triggers: {
-                dataStartY: "dataY,bbox"
-            }
-        }
-    },
-    getIndexNearPoint: function(e, d) {
-        var o = this,
-            q = o.attr.matrix,
-            h = o.attr.dataX,
-            f = o.attr.dataY,
-            u = o.attr.dataStartY,
-            l = o.attr.selectionTolerance,
-            s = 0.5,
-            r = Infinity,
-            b = -1,
-            k = q.clone().prependMatrix(this.surfaceMatrix).inverse(),
-            t = k.transformPoint([e, d]),
-            a = k.transformPoint([e - l, d - l]),
-            n = k.transformPoint([e + l, d + l]),
-            m = Math.min(a[1], n[1]),
-            c = Math.max(a[1], n[1]),
-            j, g;
-        for (var p = 0; p < h.length; p++) {
-            if (Math.min(u[p], f[p]) <= c && m <= Math.max(u[p], f[p])) {
-                j = Math.abs(h[p] - t[0]);
-                g = Math.max(-Math.min(f[p] - t[1], t[1] - u[p]), 0);
-                if (j < s && g <= r) {
-                    s = j;
-                    r = g;
-                    b = p
-                }
-            }
-        }
-        return b
-    }
-});
-Ext.define("Ext.chart.series.sprite.Area", {
-    alias: "sprite.areaSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                step: "bool"
-            },
-            defaults: {
-                step: false
-            }
-        }
-    },
-    renderClipped: function(q, s, A) {
-        var B = this,
-            p = B.attr,
-            l = p.dataX,
-            j = p.dataY,
-            C = p.dataStartY,
-            t = p.matrix,
-            h, g, v, f, d, z, w, e = t.elements[0],
-            m = t.elements[4],
-            o = t.elements[3],
-            k = t.elements[5],
-            c = B.surfaceMatrix,
-            n = {},
-            r = Math.min(A[0], A[2]),
-            u = Math.max(A[0], A[2]),
-            b = Math.max(0, this.binarySearch(r)),
-            a = Math.min(l.length - 1, this.binarySearch(u) + 1);
-        s.beginPath();
-        z = l[b] * e + m;
-        w = j[b] * o + k;
-        s.moveTo(z, w);
-        if (p.step) {
-            d = w;
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g)
-            }
-        }
-        if (C) {
-            if (p.step) {
-                f = l[a] * e + m;
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(f, g);
-                    s.lineTo(f = h, g)
-                }
-            } else {
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(h, g)
-                }
-            }
-        } else {
-            s.lineTo(l[a] * e + m, g);
-            s.lineTo(l[a] * e + m, k);
-            s.lineTo(z, k);
-            s.lineTo(z, j[v] * o + k)
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.fill();
-        if (p.transformFillStroke) {
-            p.inverseMatrix.toContext(s)
-        }
-        s.beginPath();
-        s.moveTo(z, w);
-        if (p.step) {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.stroke()
-    }
-});
-Ext.define("Ext.chart.series.Area", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.area",
-    type: "area",
-    seriesType: "areaSeries",
-    requires: ["Ext.chart.series.sprite.Area"],
-    config: {
-        splitStacks: false
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar", {
-    alias: "sprite.barSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                minBarWidth: "number",
-                maxBarWidth: "number",
-                minGapWidth: "number",
-                radius: "number",
-                inGroupGapWidth: "number"
-            },
-            defaults: {
-                minBarWidth: 2,
-                maxBarWidth: 100,
-                minGapWidth: 5,
-                inGroupGapWidth: 3,
-                radius: 0
-            }
-        }
-    },
-    drawLabel: function(k, i, s, h, o) {
-        var q = this,
-            n = q.attr,
-            f = q.getMarker("labels"),
-            d = f.getTemplate(),
-            l = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            j = n.labelOverflowPadding,
-            b = d.attr.display,
-            m = d.attr.orientation,
-            g, e, a, r, t, p;
-        l.x = c.x(i, h);
-        l.y = c.y(i, h);
-        if (!n.flipXY) {
-            l.rotationRads = -Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        l.calloutVertical = !n.flipXY;
-        switch (m) {
-            case "horizontal":
-                l.rotationRads = 0;
-                l.calloutVertical = false;
-                break;
-            case "vertical":
-                l.rotationRads = -Math.PI * 0.5;
-                l.calloutVertical = true;
-                break
-        }
-        l.text = k;
-        if (d.attr.renderer) {
-            p = [k, f, l, {
-                store: q.getStore()
-            }, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                l.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        l.text = r.text
-                    }
-                    t = true
-                }
-            }
-        }
-        a = q.getMarkerBBox("labels", o, true);
-        if (!a) {
-            q.putMarker("labels", l, o);
-            a = q.getMarkerBBox("labels", o, true)
-        }
-        e = (a.width / 2 + j);
-        if (s > h) {
-            e = -e
-        }
-        if ((m === "horizontal" && n.flipXY) || (m === "vertical" && !n.flipXY) || !m) {
-            g = (b === "insideStart") ? s + e : h - e
-        } else {
-            g = (b === "insideStart") ? s + j * 2 : h - j * 2
-        }
-        l.x = c.x(i, g);
-        l.y = c.y(i, g);
-        g = (b === "insideStart") ? s - e : h + e;
-        l.calloutPlaceX = c.x(i, g);
-        l.calloutPlaceY = c.y(i, g);
-        g = (b === "insideStart") ? s : h;
-        l.calloutStartX = c.x(i, g);
-        l.calloutStartY = c.y(i, g);
-        if (s > h) {
-            e = -e
-        }
-        if (Math.abs(h - s) <= e * 2 || b === "outside") {
-            l.callout = 1
-        } else {
-            l.callout = 0
-        }
-        if (t) {
-            Ext.apply(l, r)
-        }
-        q.putMarker("labels", l, o)
-    },
-    drawBar: function(l, b, d, c, h, k, a, e) {
-        var g = this,
-            j = {},
-            f = g.attr.renderer,
-            i;
-        j.x = c;
-        j.y = h;
-        j.width = k - c;
-        j.height = a - h;
-        j.radius = g.attr.radius;
-        if (f) {
-            i = Ext.callback(f, null, [g, j, {
-                store: g.getStore()
-            }, e], 0, g.getSeries());
-            Ext.apply(j, i)
-        }
-        g.putMarker("items", j, e, !f)
-    },
-    renderClipped: function(G, u, F, C) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var q = this,
-            o = q.attr,
-            w = o.dataX,
-            v = o.dataY,
-            H = o.labels,
-            n = o.dataStartY,
-            m = o.groupCount,
-            E = o.groupOffset - (m - 1) * 0.5,
-            z = o.inGroupGapWidth,
-            t = u.lineWidth,
-            D = o.matrix,
-            B = D.elements[0],
-            j = D.elements[3],
-            e = D.elements[4],
-            d = G.roundPixel(D.elements[5]) - 1,
-            J = (B < 0 ? -1 : 1) * B - o.minGapWidth,
-            k = (Math.min(J, o.maxBarWidth) - z * (m - 1)) / m,
-            A = G.roundPixel(Math.max(o.minBarWidth, k)),
-            c = q.surfaceMatrix,
-            g, I, b, h, K, a, l = 0.5 * o.lineWidth,
-            L = Math.min(F[0], F[2]),
-            x = Math.max(F[0], F[2]),
-            y = Math.max(0, Math.floor(L)),
-            p = Math.min(w.length - 1, Math.ceil(x)),
-            f = H && q.getMarker("labels"),
-            s, r;
-        for (K = y; K <= p; K++) {
-            s = n ? n[K] : 0;
-            r = v[K];
-            a = w[K] * B + e + E * (A + z);
-            g = G.roundPixel(a - A / 2) + l;
-            h = G.roundPixel(r * j + d + t);
-            I = G.roundPixel(a + A / 2) - l;
-            b = G.roundPixel(s * j + d + t);
-            q.drawBar(u, G, F, g, h - l, I, b - l, K);
-            if (f && H[K] != null) {
-                q.drawLabel(H[K], a, b, h, K)
-            }
-            q.putMarker("markers", {
-                translationX: c.x(a, h),
-                translationY: c.y(a, h)
-            }, K, true)
-        }
-    },
-    getIndexNearPoint: function(l, k) {
-        var m = this,
-            g = m.attr,
-            h = g.dataX,
-            a = m.getSurface(),
-            b = a.getRect() || [0, 0, 0, 0],
-            j = b[3],
-            e, d, c, n, f = -1;
-        if (g.flipXY) {
-            e = j - k;
-            if (a.getInherited().rtl) {
-                d = b[2] - l
-            } else {
-                d = l
-            }
-        } else {
-            e = l;
-            d = j - k
-        }
-        for (c = 0; c < h.length; c++) {
-            n = m.getMarkerBBox("items", c);
-            if (Ext.draw.Draw.isPointInBBox(e, d, n)) {
-                f = c;
-                break
-            }
-        }
-        return f
-    }
-});
-Ext.define("Ext.chart.series.Bar", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.bar",
-    type: "bar",
-    seriesType: "barSeries",
-    requires: ["Ext.chart.series.sprite.Bar", "Ext.draw.sprite.Rect"],
-    config: {
-        itemInstancing: {
-            type: "rect",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    radius: 0
-                }
-            }
-        }
-    },
-    getItemForPoint: function(a, f) {
-        if (this.getSprites()) {
-            var d = this,
-                c = d.getChart(),
-                e = c.getInnerPadding(),
-                b = c.getInherited().rtl;
-            arguments[0] = a + (b ? e.right : -e.left);
-            arguments[1] = f + e.bottom;
-            return d.callParent(arguments)
-        }
-    },
-    updateXAxis: function(a) {
-        a.setLabelInSpan(true);
-        this.callParent(arguments)
-    },
-    updateHidden: function(a) {
-        this.callParent(arguments);
-        this.updateStacked()
-    },
-    updateStacked: function(c) {
-        var e = this,
-            g = e.getSprites(),
-            d = g.length,
-            f = [],
-            a = {},
-            b;
-        for (b = 0; b < d; b++) {
-            if (!g[b].attr.hidden) {
-                f.push(g[b])
-            }
-        }
-        d = f.length;
-        if (e.getStacked()) {
-            a.groupCount = 1;
-            a.groupOffset = 0;
-            for (b = 0; b < d; b++) {
-                f[b].setAttributes(a)
-            }
-        } else {
-            a.groupCount = f.length;
-            for (b = 0; b < d; b++) {
-                a.groupOffset = b;
-                f[b].setAttributes(a)
-            }
-        }
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar3D", {
-    extend: "Ext.chart.series.sprite.Bar",
-    alias: "sprite.bar3dSeries",
-    requires: ["Ext.draw.gradient.Linear"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                depthWidthRatio: "number",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            defaults: {
-                depthWidthRatio: 1 / 3,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                transformFillStroke: true
-            },
-            triggers: {
-                groupCount: "panzoom"
-            },
-            updaters: {
-                panzoom: function(c) {
-                    var g = this,
-                        e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        h = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = g.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * (h - g.depth) / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = (h - g.depth) / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    g.applyTransformations(true)
-                }
-            }
-        }
-    },
-    config: {
-        showStroke: false
-    },
-    depth: 0,
-    drawBar: function(p, b, d, c, l, o, a, h) {
-        var k = this,
-            i = k.attr,
-            n = {},
-            j = i.renderer,
-            m, g, f, e;
-        n.x = (c + o) * 0.5;
-        n.y = l;
-        n.width = (o - c) * 0.75;
-        n.height = a - l;
-        n.depth = g = n.width * i.depthWidthRatio;
-        n.orientation = i.flipXY ? "horizontal" : "vertical";
-        n.saturationFactor = i.saturationFactor;
-        n.brightnessFactor = i.brightnessFactor;
-        n.colorSpread = i.colorSpread;
-        if (g !== k.depth) {
-            k.depth = g;
-            f = k.getSeries();
-            f.fireEvent("depthchange", f, g)
-        }
-        if (j) {
-            e = [k, n, {
-                store: k.getStore()
-            }, h];
-            m = Ext.callback(j, null, e, 0, k.getSeries());
-            Ext.apply(n, m)
-        }
-        k.putMarker("items", n, h, !j)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Box", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.box",
-    type: "box",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                depth: "number",
-                orientation: "enums(vertical,horizontal)",
-                showStroke: "bool",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            triggers: {
-                x: "bbox",
-                y: "bbox",
-                width: "bbox",
-                height: "bbox",
-                depth: "bbox",
-                orientation: "bbox"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                depth: 8,
-                orientation: "vertical",
-                showStroke: false,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                lineJoin: "bevel"
-            }
-        }
-    },
-    constructor: function(a) {
-        this.callParent([a]);
-        this.topGradient = new Ext.draw.gradient.Linear({});
-        this.rightGradient = new Ext.draw.gradient.Linear({});
-        this.frontGradient = new Ext.draw.gradient.Linear({})
-    },
-    updatePlainBBox: function(d) {
-        var c = this.attr,
-            b = c.x,
-            g = c.y,
-            e = c.width,
-            a = c.height,
-            f = c.depth;
-        d.x = b - e * 0.5;
-        d.width = e + f;
-        if (a > 0) {
-            d.y = g;
-            d.height = a + f
-        } else {
-            d.y = g + f;
-            d.height = a - f
-        }
-    },
-    render: function(l, m) {
-        var u = this,
-            k = u.attr,
-            r = k.x,
-            j = k.y,
-            f = j + k.height,
-            i = j < f,
-            e = k.width * 0.5,
-            v = k.depth,
-            d = k.orientation === "horizontal",
-            g = k.globalAlpha < 1,
-            c = k.fillStyle,
-            n = Ext.draw.Color.create(c.isGradient ? c.getStops()[0].color : c),
-            h = k.saturationFactor,
-            o = k.brightnessFactor,
-            t = k.colorSpread,
-            b = n.getHSV(),
-            a = {},
-            s, q, p;
-        if (!k.showStroke) {
-            m.strokeStyle = Ext.draw.Color.RGBA_NONE
-        }
-        if (i) {
-            p = j;
-            j = f;
-            f = p
-        }
-        u.topGradient.setDegrees(d ? 0 : 80);
-        u.topGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.11) * o, 0, 1))
-        }]);
-        u.rightGradient.setDegrees(d ? 45 : 90);
-        u.rightGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.14) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.4) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.32) * o, 0, 1))
-        }]);
-        if (d) {
-            u.frontGradient.setDegrees(0)
-        } else {
-            u.frontGradient.setRadians(Math.atan2(j - f, e * 2))
-        }
-        u.frontGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 - t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.23) * o, 0, 1))
-        }]);
-        if (g || i) {
-            m.beginPath();
-            m.moveTo(r - e, f);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r + e + v, f + v);
-            m.lineTo(r + e, f);
-            m.closePath();
-            a.x = r - e;
-            a.y = j;
-            a.width = e + v;
-            a.height = v;
-            m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        if (g) {
-            m.beginPath();
-            m.moveTo(r - e, j);
-            m.lineTo(r - e + v, j + v);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r - e, f);
-            m.closePath();
-            a.x = r + e;
-            a.y = f;
-            a.width = v;
-            a.height = j + v - f;
-            m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, q);
-        m.lineTo(r - e + v, j + v);
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e, q);
-        m.closePath();
-        a.x = r - e;
-        a.y = j;
-        a.width = e + v;
-        a.height = v;
-        m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        m.beginPath();
-        m.moveTo(s, l.roundPixel(j));
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e + v, f + v);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r + e;
-        a.y = f;
-        a.width = v;
-        a.height = j + v - f;
-        m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, f);
-        m.lineTo(r - e, q);
-        m.lineTo(s, q);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r - e;
-        a.y = f;
-        a.width = e * 2;
-        a.height = j - f;
-        m.fillStyle = u.frontGradient.generateGradient(m, a);
-        m.fillStroke(k)
-    }
-});
-Ext.define("Ext.chart.series.Bar3D", {
-    extend: "Ext.chart.series.Bar",
-    requires: ["Ext.chart.series.sprite.Bar3D", "Ext.chart.series.sprite.Box"],
-    alias: "series.bar3d",
-    type: "bar3d",
-    seriesType: "bar3dSeries",
-    config: {
-        itemInstancing: {
-            type: "box",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    depth: 0
-                }
-            }
-        },
-        highlightCfg: {
-            opacity: 0.8
-        }
-    },
-    getSprites: function() {
-        var c = this.callParent(arguments),
-            b, d, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            d = b.attr.zIndex;
-            if (d < 0) {
-                b.setAttributes({
-                    zIndex: -d
-                })
-            }
-            if (b.setSeries) {
-                b.setSeries(this)
-            }
-        }
-        return c
-    },
-    getDepth: function() {
-        var a = this.getSprites()[0];
-        return a ? (a.depth || 0) : 0
-    },
-    getItemForPoint: function(m, k) {
-        if (this.getSprites()) {
-            var j = this,
-                b, o, a = j.getItemInstancing(),
-                h = j.getSprites(),
-                n = j.getStore(),
-                c = j.getHidden(),
-                g = j.getChart(),
-                l = g.getInnerPadding(),
-                f = g.getInherited().rtl,
-                p, d, e;
-            m = m + (f ? l.right : -l.left);
-            k = k + l.bottom;
-            for (b = h.length - 1; b >= 0; b--) {
-                if (!c[b]) {
-                    o = h[b];
-                    d = o.getIndexNearPoint(m, k);
-                    if (d !== -1) {
-                        e = j.getYField();
-                        p = {
-                            series: j,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: n.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: o
-                        };
-                        return p
-                    }
-                }
-            }
-            return null
-        }
-    }
-});
-Ext.define("Ext.draw.LimitedCache", {
-    config: {
-        limit: 40,
-        feeder: function() {
-            return 0
-        },
-        scope: null
-    },
-    cache: null,
-    constructor: function(a) {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0;
-        this.initConfig(a)
-    },
-    get: function(e) {
-        var c = this.cache,
-            b = this.getLimit(),
-            a = this.getFeeder(),
-            d = this.getScope() || this;
-        if (c[e]) {
-            return c[e].value
-        }
-        if (c.list[c.tail]) {
-            delete c[c.list[c.tail].cacheId]
-        }
-        c[e] = c.list[c.tail] = {
-            value: a.apply(d, Array.prototype.slice.call(arguments, 1)),
-            cacheId: e
-        };
-        c.tail++;
-        if (c.tail === b) {
-            c.tail = 0
-        }
-        return c[e].value
-    },
-    clear: function() {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0
-    }
-});
-Ext.define("Ext.draw.SegmentTree", {
-    config: {
-        strategy: "double"
-    },
-    time: function(m, l, n, c, E, d, e) {
-        var f = 0,
-            o, A, s = new Date(n[m.startIdx[0]]),
-            x = new Date(n[m.endIdx[l - 1]]),
-            D = Ext.Date,
-            u = [
-                [D.MILLI, 1, "ms1", null],
-                [D.MILLI, 2, "ms2", "ms1"],
-                [D.MILLI, 5, "ms5", "ms1"],
-                [D.MILLI, 10, "ms10", "ms5"],
-                [D.MILLI, 50, "ms50", "ms10"],
-                [D.MILLI, 100, "ms100", "ms50"],
-                [D.MILLI, 500, "ms500", "ms100"],
-                [D.SECOND, 1, "s1", "ms500"],
-                [D.SECOND, 10, "s10", "s1"],
-                [D.SECOND, 30, "s30", "s10"],
-                [D.MINUTE, 1, "mi1", "s10"],
-                [D.MINUTE, 5, "mi5", "mi1"],
-                [D.MINUTE, 10, "mi10", "mi5"],
-                [D.MINUTE, 30, "mi30", "mi10"],
-                [D.HOUR, 1, "h1", "mi30"],
-                [D.HOUR, 6, "h6", "h1"],
-                [D.HOUR, 12, "h12", "h6"],
-                [D.DAY, 1, "d1", "h12"],
-                [D.DAY, 7, "d7", "d1"],
-                [D.MONTH, 1, "mo1", "d1"],
-                [D.MONTH, 3, "mo3", "mo1"],
-                [D.MONTH, 6, "mo6", "mo3"],
-                [D.YEAR, 1, "y1", "mo3"],
-                [D.YEAR, 5, "y5", "y1"],
-                [D.YEAR, 10, "y10", "y5"],
-                [D.YEAR, 100, "y100", "y10"]
-            ],
-            z, b, k = f,
-            F = l,
-            j = false,
-            r = m.startIdx,
-            h = m.endIdx,
-            w = m.minIdx,
-            C = m.maxIdx,
-            a = m.open,
-            y = m.close,
-            g = m.minX,
-            q = m.minY,
-            p = m.maxX,
-            B = m.maxY,
-            v, t;
-        for (z = 0; l > f + 1 && z < u.length; z++) {
-            s = new Date(n[r[0]]);
-            b = u[z];
-            s = D.align(s, b[0], b[1]);
-            if (D.diff(s, x, b[0]) > n.length * 2 * b[1]) {
-                continue
-            }
-            if (b[3] && m.map["time_" + b[3]]) {
-                o = m.map["time_" + b[3]][0];
-                A = m.map["time_" + b[3]][1]
-            } else {
-                o = k;
-                A = F
-            }
-            f = l;
-            t = s;
-            j = true;
-            r[l] = r[o];
-            h[l] = h[o];
-            w[l] = w[o];
-            C[l] = C[o];
-            a[l] = a[o];
-            y[l] = y[o];
-            g[l] = g[o];
-            q[l] = q[o];
-            p[l] = p[o];
-            B[l] = B[o];
-            t = Ext.Date.add(t, b[0], b[1]);
-            for (v = o + 1; v < A; v++) {
-                if (n[h[v]] < +t) {
-                    h[l] = h[v];
-                    y[l] = y[v];
-                    if (B[v] > B[l]) {
-                        B[l] = B[v];
-                        p[l] = p[v];
-                        C[l] = C[v]
-                    }
-                    if (q[v] < q[l]) {
-                        q[l] = q[v];
-                        g[l] = g[v];
-                        w[l] = w[v]
-                    }
-                } else {
-                    l++;
-                    r[l] = r[v];
-                    h[l] = h[v];
-                    w[l] = w[v];
-                    C[l] = C[v];
-                    a[l] = a[v];
-                    y[l] = y[v];
-                    g[l] = g[v];
-                    q[l] = q[v];
-                    p[l] = p[v];
-                    B[l] = B[v];
-                    t = Ext.Date.add(t, b[0], b[1])
-                }
-            }
-            if (l > f) {
-                m.map["time_" + b[2]] = [f, l]
-            }
-        }
-    },
-    "double": function(h, u, j, a, t, b, c) {
-        var e = 0,
-            k, f = 1,
-            n, d, v, g, s, l, m, r, q, p, o;
-        while (u > e + 1) {
-            k = e;
-            e = u;
-            f += f;
-            for (n = k; n < e; n += 2) {
-                if (n === e - 1) {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n];
-                    g = h.minIdx[n];
-                    s = h.maxIdx[n];
-                    l = h.open[n];
-                    m = h.close[n];
-                    r = h.minX[n];
-                    q = h.minY[n];
-                    p = h.maxX[n];
-                    o = h.maxY[n]
-                } else {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n + 1];
-                    l = h.open[n];
-                    m = h.close[n];
-                    if (h.minY[n] <= h.minY[n + 1]) {
-                        g = h.minIdx[n];
-                        r = h.minX[n];
-                        q = h.minY[n]
-                    } else {
-                        g = h.minIdx[n + 1];
-                        r = h.minX[n + 1];
-                        q = h.minY[n + 1]
-                    }
-                    if (h.maxY[n] >= h.maxY[n + 1]) {
-                        s = h.maxIdx[n];
-                        p = h.maxX[n];
-                        o = h.maxY[n]
-                    } else {
-                        s = h.maxIdx[n + 1];
-                        p = h.maxX[n + 1];
-                        o = h.maxY[n + 1]
-                    }
-                }
-                h.startIdx[u] = d;
-                h.endIdx[u] = v;
-                h.minIdx[u] = g;
-                h.maxIdx[u] = s;
-                h.open[u] = l;
-                h.close[u] = m;
-                h.minX[u] = r;
-                h.minY[u] = q;
-                h.maxX[u] = p;
-                h.maxY[u] = o;
-                u++
-            }
-            h.map["double_" + f] = [e, u]
-        }
-    },
-    none: Ext.emptyFn,
-    aggregateData: function(h, a, r, c, d) {
-        var b = h.length,
-            e = [],
-            s = [],
-            f = [],
-            q = [],
-            j = [],
-            p = [],
-            n = [],
-            o = [],
-            m = [],
-            k = [],
-            g = {
-                startIdx: e,
-                endIdx: s,
-                minIdx: f,
-                maxIdx: q,
-                open: j,
-                minX: p,
-                minY: n,
-                maxX: o,
-                maxY: m,
-                close: k
-            },
-            l;
-        for (l = 0; l < b; l++) {
-            e[l] = l;
-            s[l] = l;
-            f[l] = l;
-            q[l] = l;
-            j[l] = a[l];
-            p[l] = h[l];
-            n[l] = c[l];
-            o[l] = h[l];
-            m[l] = r[l];
-            k[l] = d[l]
-        }
-        g.map = {
-            original: [0, b]
-        };
-        if (b) {
-            this[this.getStrategy()](g, b, h, a, r, c, d)
-        }
-        return g
-    },
-    binarySearchMin: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.startIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.startIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.startIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return g
-    },
-    binarySearchMax: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.endIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.endIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.endIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return a
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    setData: function(d, a, b, c, e) {
-        if (!b) {
-            e = c = b = a
-        }
-        this.dataX = d;
-        this.dataOpen = a;
-        this.dataHigh = b;
-        this.dataLow = c;
-        this.dataClose = e;
-        if (d.length === b.length && d.length === c.length) {
-            this.cache = this.aggregateData(d, a, b, c, e)
-        }
-    },
-    getAggregation: function(d, k, i) {
-        if (!this.cache) {
-            return null
-        }
-        var c = Infinity,
-            g = this.dataX[this.dataX.length - 1] - this.dataX[0],
-            l = this.cache.map,
-            m = l.original,
-            a, e, j, b, f, h;
-        for (a in l) {
-            e = l[a];
-            j = e[1] - e[0] - 1;
-            b = g / j;
-            if (i <= b && b < c) {
-                m = e;
-                c = b
-            }
-        }
-        f = Math.max(this.binarySearchMin(this.cache, m[0], m[1], d), m[0]);
-        h = Math.min(this.binarySearchMax(this.cache, m[0], m[1], k) + 1, m[1]);
-        return {
-            data: this.cache,
-            start: f,
-            end: h
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Aggregative", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    requires: ["Ext.draw.LimitedCache", "Ext.draw.SegmentTree"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataHigh: "data",
-                dataLow: "data",
-                dataClose: "data"
-            },
-            aliases: {
-                dataOpen: "dataY"
-            },
-            defaults: {
-                dataHigh: null,
-                dataLow: null,
-                dataClose: null
-            }
-        }
-    },
-    config: {
-        aggregator: {}
-    },
-    applyAggregator: function(b, a) {
-        return Ext.factory(b, Ext.draw.SegmentTree, a)
-    },
-    constructor: function() {
-        this.callParent(arguments)
-    },
-    processDataY: function() {
-        var d = this,
-            b = d.attr,
-            e = b.dataHigh,
-            a = b.dataLow,
-            f = b.dataClose,
-            c = b.dataY;
-        d.callParent(arguments);
-        if (b.dataX && c && c.length > 0) {
-            if (e) {
-                d.getAggregator().setData(b.dataX, b.dataY, e, a, f)
-            } else {
-                d.getAggregator().setData(b.dataX, b.dataY)
-            }
-        }
-    },
-    getGapWidth: function() {
-        return 1
-    },
-    renderClipped: function(b, c, g, f) {
-        var e = this,
-            d = Math.min(g[0], g[2]),
-            a = Math.max(g[0], g[2]),
-            h = e.getAggregator() && e.getAggregator().getAggregation(d, a, (a - d) / f[2] * e.getGapWidth());
-        if (h) {
-            e.dataStart = h.data.startIdx[h.start];
-            e.dataEnd = h.data.endIdx[h.end - 1];
-            e.renderAggregates(h.data, h.start, h.end, b, c, g, f)
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.CandleStick", {
-    alias: "sprite.candlestickSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                raiseStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                dropStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                barWidth: "number",
-                padding: "number",
-                ohlcType: "enums(candlestick,ohlc)"
-            },
-            defaults: {
-                raiseStyle: {
-                    strokeStyle: "green",
-                    fillStyle: "green"
-                },
-                dropStyle: {
-                    strokeStyle: "red",
-                    fillStyle: "red"
-                },
-                planar: false,
-                barWidth: 15,
-                padding: 3,
-                lineJoin: "miter",
-                miterLimit: 5,
-                ohlcType: "candlestick"
-            },
-            triggers: {
-                raiseStyle: "raiseStyle",
-                dropStyle: "dropStyle"
-            },
-            updaters: {
-                raiseStyle: function() {
-                    this.raiseTemplate && this.raiseTemplate.setAttributes(this.attr.raiseStyle)
-                },
-                dropStyle: function() {
-                    this.dropTemplate && this.dropTemplate.setAttributes(this.attr.dropStyle)
-                }
-            }
-        }
-    },
-    candlestick: function(i, c, a, e, h, f, b) {
-        var d = Math.min(c, h),
-            g = Math.max(c, h);
-        i.moveTo(f, e);
-        i.lineTo(f, g);
-        i.moveTo(f + b, g);
-        i.lineTo(f + b, d);
-        i.lineTo(f - b, d);
-        i.lineTo(f - b, g);
-        i.closePath();
-        i.moveTo(f, a);
-        i.lineTo(f, d)
-    },
-    ohlc: function(b, d, e, a, f, c, g) {
-        b.moveTo(c, e);
-        b.lineTo(c, a);
-        b.moveTo(c, d);
-        b.lineTo(c - g, d);
-        b.moveTo(c, f);
-        b.lineTo(c + g, f)
-    },
-    constructor: function() {
-        this.callParent(arguments);
-        this.raiseTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        });
-        this.dropTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        })
-    },
-    getGapWidth: function() {
-        var a = this.attr,
-            b = a.barWidth,
-            c = a.padding;
-        return b + c
-    },
-    renderAggregates: function(d, c, b, t, u, z) {
-        var D = this,
-            s = this.attr,
-            j = s.dataX,
-            v = s.matrix,
-            e = v.getXX(),
-            r = v.getYY(),
-            l = v.getDX(),
-            h = v.getDY(),
-            o = s.barWidth / e,
-            C, k = s.ohlcType,
-            f = Math.round(o * 0.5 * e),
-            a = d.open,
-            y = d.close,
-            B = d.maxY,
-            p = d.minY,
-            q = d.startIdx,
-            m, g, E, n, A, x, w = s.lineWidth * t.devicePixelRatio / 2;
-        w -= Math.floor(w);
-        u.save();
-        C = this.raiseTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] <= y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore();
-        u.save();
-        C = this.dropTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] > y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore()
-    }
-});
-Ext.define("Ext.chart.series.CandleStick", {
-    extend: "Ext.chart.series.Cartesian",
-    requires: ["Ext.chart.series.sprite.CandleStick"],
-    alias: "series.candlestick",
-    type: "candlestick",
-    seriesType: "candlestickSeries",
-    config: {
-        openField: null,
-        highField: null,
-        lowField: null,
-        closeField: null
-    },
-    fieldCategoryY: ["Open", "High", "Low", "Close"],
-    themeColorCount: function() {
-        return 2
-    }
-});
-Ext.define("Ext.chart.series.Polar", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        rotation: 0,
-        radius: null,
-        center: [0, 0],
-        offsetX: 0,
-        offsetY: 0,
-        showInLegend: true,
-        xField: null,
-        yField: null,
-        angleField: null,
-        radiusField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    deprecatedConfigs: {
-        field: "angleField",
-        lengthField: "radiusField"
-    },
-    constructor: function(b) {
-        var c = this,
-            a = c.getConfigurator(),
-            e = a.configs,
-            d;
-        if (b) {
-            for (d in c.deprecatedConfigs) {
-                if (d in b && !(b in e)) {
-                    Ext.raise("'" + d + "' config has been deprecated. Please use the '" + c.deprecatedConfigs[d] + "' config instead.")
-                }
-            }
-        }
-        c.callParent([b])
-    },
-    getXField: function() {
-        return this.getAngleField()
-    },
-    updateXField: function(a) {
-        this.setAngleField(a)
-    },
-    getYField: function() {
-        return this.getRadiusField()
-    },
-    updateYField: function(a) {
-        this.setRadiusField(a)
-    },
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b
-    },
-    isStoreDependantColorCount: true,
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            centerX: 0,
-            centerY: 0,
-            rotationCenterX: 0,
-            rotationCenterY: 0
-        }
-    },
-    applyRotation: function(a) {
-        return Ext.draw.sprite.AttributeParser.angle(a)
-    },
-    updateRotation: function(a) {
-        var b = this.getSprites();
-        if (b && b[0]) {
-            b[0].setAttributes({
-                baseRotation: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.Gauge", {
-    alias: "series.gauge",
-    extend: "Ext.chart.series.Polar",
-    type: "gauge",
-    seriesType: "pieslice",
-    requires: ["Ext.draw.sprite.Sector"],
-    config: {
-        needle: false,
-        needleLength: 90,
-        needleWidth: 4,
-        donut: 30,
-        showInLegend: false,
-        value: null,
-        colors: null,
-        sectors: null,
-        minimum: 0,
-        maximum: 100,
-        rotation: 0,
-        totalAngle: Math.PI / 2,
-        rect: [0, 0, 1, 1],
-        center: [0.5, 0.75],
-        radius: 0.5,
-        wholeDisk: false
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateNeedle: function(b) {
-        var a = this,
-            d = a.getSprites(),
-            c = a.valueToAngle(a.getValue());
-        if (d && d.length) {
-            d[0].setAttributes({
-                startAngle: (b ? c : 0),
-                endAngle: c,
-                strokeOpacity: (b ? 1 : 0),
-                lineWidth: (b ? a.getNeedleWidth() : 0)
-            });
-            a.doUpdateStyles()
-        }
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b + (c.getNeedle() ? 0 : 1)
-    },
-    updateColors: function(a, b) {
-        var f = this,
-            h = f.getSectors(),
-            j = h && h.length,
-            e = f.getSprites(),
-            c = Ext.Array.clone(a),
-            g = a && a.length,
-            d;
-        if (!g || !a[0]) {
-            return
-        }
-        for (d = 0; d < j; d++) {
-            c[d + 1] = h[d].color || c[d + 1] || a[d % g]
-        }
-        if (e.length) {
-            e[0].setAttributes({
-                strokeStyle: c[0]
-            })
-        }
-        this.setSubStyle({
-            fillStyle: c,
-            strokeStyle: c
-        });
-        this.doUpdateStyles()
-    },
-    updateRect: function(f) {
-        var d = this.getWholeDisk(),
-            c = d ? Math.PI : this.getTotalAngle() / 2,
-            g = this.getDonut() / 100,
-            e, b, a;
-        if (c <= Math.PI / 2) {
-            e = 2 * Math.sin(c);
-            b = 1 - g * Math.cos(c)
-        } else {
-            e = 2;
-            b = 1 - Math.cos(c)
-        }
-        a = Math.min(f[2] / e, f[3] / b);
-        this.setRadius(a);
-        this.setCenter([f[2] / 2, a + (f[3] - b * a) / 2])
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            centerX: a[0],
-            centerY: a[1],
-            rotationCenterX: a[0],
-            rotationCenterY: a[1]
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a - (this.getTotalAngle() + Math.PI) / 2
-        });
-        this.doUpdateStyles()
-    },
-    doUpdateShape: function(b, f) {
-        var a, d = this.getSectors(),
-            c = (d && d.length) || 0,
-            e = this.getNeedleLength() / 100;
-        a = [b * e, b];
-        while (c--) {
-            a.push(b)
-        }
-        this.setSubStyle({
-            endRho: a,
-            startRho: b / 100 * f
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        var b = this.getDonut();
-        this.doUpdateShape(a, b)
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.doUpdateShape(a, b)
-    },
-    valueToAngle: function(a) {
-        a = this.applyValue(a);
-        return this.getTotalAngle() * (a - this.getMinimum()) / (this.getMaximum() - this.getMinimum())
-    },
-    applyValue: function(a) {
-        return Math.min(this.getMaximum(), Math.max(a, this.getMinimum()))
-    },
-    updateValue: function(b) {
-        var a = this,
-            c = a.getNeedle(),
-            e = a.valueToAngle(b),
-            d = a.getSprites();
-        d[0].rendererData.value = b;
-        d[0].setAttributes({
-            startAngle: (c ? e : 0),
-            endAngle: e
-        });
-        a.doUpdateStyles()
-    },
-    processData: function() {
-        var f = this,
-            j = f.getStore(),
-            a, d, h, b, g, e = j && j.first(),
-            c, i;
-        if (e) {
-            c = f.getXField();
-            if (c) {
-                i = e.get(c)
-            }
-        }
-        if (a = f.getXAxis()) {
-            d = a.getMinimum();
-            h = a.getMaximum();
-            b = a.getSprites()[0].fx;
-            g = b.getDuration();
-            b.setDuration(0);
-            if (Ext.isNumber(d)) {
-                f.setMinimum(d)
-            } else {
-                a.setMinimum(f.getMinimum())
-            }
-            if (Ext.isNumber(h)) {
-                f.setMaximum(h)
-            } else {
-                a.setMaximum(f.getMaximum())
-            }
-            b.setDuration(g)
-        }
-        if (!Ext.isNumber(i)) {
-            i = f.getMinimum()
-        }
-        f.setValue(i)
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationCenterX: 0,
-                    rotationCenterY: 0,
-                    centerX: 0,
-                    centerY: 0,
-                    startRho: 0,
-                    endRho: 0,
-                    baseRotation: 0
-                }
-            }
-        }
-    },
-    normalizeSectors: function(f) {
-        var d = this,
-            c = (f && f.length) || 0,
-            b, e, g, a;
-        if (c) {
-            for (b = 0; b < c; b++) {
-                e = f[b];
-                if (typeof e === "number") {
-                    f[b] = {
-                        start: (b > 0 ? f[b - 1].end : d.getMinimum()),
-                        end: Math.min(e, d.getMaximum())
-                    };
-                    if (b == (c - 1) && f[b].end < d.getMaximum()) {
-                        f[b + 1] = {
-                            start: f[b].end,
-                            end: d.getMaximum()
-                        }
-                    }
-                } else {
-                    if (typeof e.start === "number") {
-                        g = Math.max(e.start, d.getMinimum())
-                    } else {
-                        g = (b > 0 ? f[b - 1].end : d.getMinimum())
-                    }
-                    if (typeof e.end === "number") {
-                        a = Math.min(e.end, d.getMaximum())
-                    } else {
-                        a = d.getMaximum()
-                    }
-                    f[b].start = g;
-                    f[b].end = a
-                }
-            }
-        } else {
-            f = [{
-                start: d.getMinimum(),
-                end: d.getMaximum()
-            }]
-        }
-        return f
-    },
-    getSprites: function() {
-        var j = this,
-            m = j.getStore(),
-            l = j.getValue(),
-            c, g;
-        if (!m && !Ext.isNumber(l)) {
-            return []
-        }
-        var h = j.getChart(),
-            b = j.getAnimation() || h && h.getAnimation(),
-            f = j.sprites,
-            k = 0,
-            o, n, e, d, a = [];
-        if (f && f.length) {
-            f[0].setAnimation(b);
-            return f
-        }
-        d = {
-            store: m,
-            field: j.getXField(),
-            angleField: j.getXField(),
-            value: l,
-            series: j
-        };
-        o = j.createSprite();
-        o.setAttributes({
-            zIndex: 10
-        }, true);
-        o.rendererData = d;
-        o.rendererIndex = k++;
-        a.push(j.getNeedleWidth());
-        j.getLabel().getTemplate().setField(true);
-        n = j.normalizeSectors(j.getSectors());
-        for (c = 0, g = n.length; c < g; c++) {
-            e = {
-                startAngle: j.valueToAngle(n[c].start),
-                endAngle: j.valueToAngle(n[c].end),
-                label: n[c].label,
-                fillStyle: n[c].color,
-                strokeOpacity: 0,
-                doCallout: false,
-                labelOverflowPadding: -1
-            };
-            Ext.apply(e, n[c].style);
-            o = j.createSprite();
-            o.rendererData = d;
-            o.rendererIndex = k++;
-            o.setAttributes(e, true);
-            a.push(e.lineWidth)
-        }
-        j.setSubStyle({
-            lineWidth: a
-        });
-        j.doUpdateStyles();
-        return f
-    }
-});
-Ext.define("Ext.chart.series.sprite.Line", {
-    alias: "sprite.lineSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                smooth: "bool",
-                fillArea: "bool",
-                step: "bool",
-                preciseStroke: "bool",
-                xAxis: "default",
-                yCap: "default"
-            },
-            defaults: {
-                smooth: false,
-                fillArea: false,
-                step: false,
-                preciseStroke: true,
-                xAxis: null,
-                yCap: Math.pow(2, 20),
-                yJump: 50
-            },
-            triggers: {
-                dataX: "dataX,bbox,smooth",
-                dataY: "dataY,bbox,smooth",
-                smooth: "smooth"
-            },
-            updaters: {
-                smooth: function(a) {
-                    var c = a.dataX,
-                        b = a.dataY;
-                    if (a.smooth && c && b && c.length > 2 && b.length > 2) {
-                        this.smoothX = Ext.draw.Draw.spline(c);
-                        this.smoothY = Ext.draw.Draw.spline(b)
-                    } else {
-                        delete this.smoothX;
-                        delete this.smoothY
-                    }
-                }
-            }
-        }
-    },
-    list: null,
-    updatePlainBBox: function(d) {
-        var b = this.attr,
-            c = Math.min(0, b.dataMinY),
-            a = Math.max(0, b.dataMaxY);
-        d.x = b.dataMinX;
-        d.y = c;
-        d.width = b.dataMaxX - b.dataMinX;
-        d.height = a - c
-    },
-    drawStrip: function(a, c) {
-        a.moveTo(c[0], c[1]);
-        for (var b = 2, d = c.length; b < d; b += 2) {
-            a.lineTo(c[b], c[b + 1])
-        }
-    },
-    drawStraightStroke: function(p, q, e, d, u, h) {
-        var w = this,
-            o = w.attr,
-            n = o.renderer,
-            g = o.step,
-            a = true,
-            l = {
-                type: "line",
-                smooth: false,
-                step: g
-            },
-            m = [],
-            l, z, v, f, k, j, t, c, s, b, r;
-        for (r = 3; r < u.length; r += 3) {
-            t = u[r - 3];
-            c = u[r - 2];
-            k = u[r];
-            j = u[r + 1];
-            s = u[r + 3];
-            b = u[r + 4];
-            if (n) {
-                l.x = k;
-                l.y = j;
-                l.x0 = t;
-                l.y0 = c;
-                v = [w, l, w.rendererData, e + r / 3];
-                z = Ext.callback(n, null, v, 0, w.getSeries())
-            }
-            if (Ext.isNumber(k + j + t + c)) {
-                if (a) {
-                    q.beginPath();
-                    q.moveTo(t, c);
-                    m.push(t, c);
-                    f = t;
-                    a = false
-                }
-            } else {
-                continue
-            }
-            if (g) {
-                q.lineTo(k, c);
-                m.push(k, c)
-            }
-            q.lineTo(k, j);
-            m.push(k, j);
-            if (z || !(Ext.isNumber(s + b))) {
-                q.save();
-                Ext.apply(q, z);
-                if (o.fillArea) {
-                    q.lineTo(k, h);
-                    q.lineTo(f, h);
-                    q.closePath();
-                    q.fill()
-                }
-                q.beginPath();
-                w.drawStrip(q, m);
-                m = [];
-                q.stroke();
-                q.restore();
-                q.beginPath();
-                a = true
-            }
-        }
-    },
-    calculateScale: function(c, a) {
-        var b = 0,
-            d = c;
-        while (d < a && c > 0) {
-            b++;
-            d += c >> b
-        }
-        return Math.pow(2, b > 0 ? b - 1 : b)
-    },
-    drawSmoothStroke: function(u, v, c, b, C, f) {
-        var G = this,
-            t = G.attr,
-            d = t.step,
-            z = t.matrix,
-            s = t.renderer,
-            e = z.getXX(),
-            p = z.getYY(),
-            m = z.getDX(),
-            k = z.getDY(),
-            r = G.smoothX,
-            q = G.smoothY,
-            I = G.calculateScale(t.dataX.length, b),
-            o, F, n, E, h, g, B, a, A, w, H, D, l = {
-                type: "line",
-                smooth: true,
-                step: d
-            };
-        v.beginPath();
-        v.moveTo(r[c * 3] * e + m, q[c * 3] * p + k);
-        for (A = 0, w = c * 3 + 1; A < C.length - 3; A += 3, w += 3 * I) {
-            o = r[w] * e + m;
-            F = q[w] * p + k;
-            n = r[w + 1] * e + m;
-            E = q[w + 1] * p + k;
-            h = u.roundPixel(C[A + 3]);
-            g = C[A + 4];
-            B = u.roundPixel(C[A]);
-            a = C[A + 1];
-            if (s) {
-                l.x0 = B;
-                l.y0 = a;
-                l.cx1 = o;
-                l.cy1 = F;
-                l.cx2 = n;
-                l.cy2 = E;
-                l.x = h;
-                l.y = g;
-                D = [G, l, G.rendererData, c + A / 3 + 1];
-                H = Ext.callback(s, null, D, 0, G.getSeries());
-                v.save();
-                Ext.apply(v, H)
-            }
-            if (t.fillArea) {
-                v.moveTo(B, a);
-                v.bezierCurveTo(o, F, n, E, h, g);
-                v.lineTo(h, f);
-                v.lineTo(B, f);
-                v.lineTo(B, a);
-                v.closePath();
-                v.fill();
-                v.beginPath()
-            }
-            v.moveTo(B, a);
-            v.bezierCurveTo(o, F, n, E, h, g);
-            v.stroke();
-            v.moveTo(B, a);
-            v.closePath();
-            if (s) {
-                v.restore()
-            }
-            v.beginPath();
-            v.moveTo(h, g)
-        }
-        v.beginPath()
-    },
-    drawLabel: function(k, i, h, o, a) {
-        var q = this,
-            n = q.attr,
-            e = q.getMarker("labels"),
-            d = e.getTemplate(),
-            m = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            g, f, j = n.labelOverflowPadding,
-            l, b, r, p, s;
-        m.x = c.x(i, h);
-        m.y = c.y(i, h);
-        if (n.flipXY) {
-            m.rotationRads = Math.PI * 0.5
-        } else {
-            m.rotationRads = 0
-        }
-        m.text = k;
-        if (d.attr.renderer) {
-            p = [k, e, m, q.rendererData, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                m.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        m.text = r.text
-                    }
-                    s = true
-                }
-            }
-        }
-        b = q.getMarkerBBox("labels", o, true);
-        if (!b) {
-            q.putMarker("labels", m, o);
-            b = q.getMarkerBBox("labels", o, true)
-        }
-        l = b.height / 2;
-        g = i;
-        switch (d.attr.display) {
-            case "under":
-                f = h - l - j;
-                break;
-            case "rotate":
-                g += j;
-                f = h - j;
-                m.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                f = h + l + j
-        }
-        m.x = c.x(g, f);
-        m.y = c.y(g, f);
-        if (s) {
-            Ext.apply(m, r)
-        }
-        q.putMarker("labels", m, o)
-    },
-    drawMarker: function(j, h, d) {
-        var g = this,
-            e = g.attr,
-            f = e.renderer,
-            c = g.surfaceMatrix,
-            b = {},
-            i, a;
-        if (f && g.getMarker("markers")) {
-            b.type = "marker";
-            b.x = j;
-            b.y = h;
-            a = [g, b, g.rendererData, d];
-            i = Ext.callback(f, null, a, 0, g.getSeries());
-            if (i) {
-                Ext.apply(b, i)
-            }
-        }
-        b.translationX = c.x(j, h);
-        b.translationY = c.y(j, h);
-        delete b.x;
-        delete b.y;
-        g.putMarker("markers", b, d, !f)
-    },
-    drawStroke: function(a, c, h, b, f, e) {
-        var d = this,
-            g = d.attr.smooth && d.smoothX && d.smoothY;
-        if (g) {
-            d.drawSmoothStroke(a, c, h, b, f, e)
-        } else {
-            d.drawStraightStroke(a, c, h, b, f, e)
-        }
-    },
-    renderAggregates: function(B, w, l, N, o, I, D) {
-        var m = this,
-            k = m.attr,
-            s = k.dataX,
-            r = k.dataY,
-            h = k.labels,
-            v = k.xAxis,
-            a = k.yCap,
-            g = k.smooth && m.smoothX && m.smoothY,
-            d = h && m.getMarker("labels"),
-            t = m.getMarker("markers"),
-            E = k.matrix,
-            u = N.devicePixelRatio,
-            C = E.getXX(),
-            f = E.getYY(),
-            c = E.getDX(),
-            b = E.getDY(),
-            q = m.list || (m.list = []),
-            F = B.minX,
-            e = B.maxX,
-            j = B.minY,
-            P = B.maxY,
-            U = B.startIdx,
-            S = true,
-            Q, T, L, K, R, G;
-        m.rendererData = {
-            store: m.getStore()
-        };
-        q.length = 0;
-        for (R = w; R < l; R++) {
-            var O = F[R],
-                p = e[R],
-                M = j[R],
-                n = P[R];
-            if (O < p) {
-                q.push(O * C + c, M * f + b, U[R]);
-                q.push(p * C + c, n * f + b, U[R])
-            } else {
-                if (O > p) {
-                    q.push(p * C + c, n * f + b, U[R]);
-                    q.push(O * C + c, M * f + b, U[R])
-                } else {
-                    q.push(p * C + c, n * f + b, U[R])
-                }
-            }
-        }
-        if (q.length) {
-            for (R = 0; R < q.length; R += 3) {
-                L = q[R];
-                K = q[R + 1];
-                if (Ext.isNumber(L + K)) {
-                    if (K > a) {
-                        K = a
-                    } else {
-                        if (K < -a) {
-                            K = -a
-                        }
-                    }
-                    q[R + 1] = K
-                } else {
-                    S = false;
-                    continue
-                }
-                G = q[R + 2];
-                if (t) {
-                    m.drawMarker(L, K, G)
-                }
-                if (d && h[G]) {
-                    m.drawLabel(h[G], L, K, G, D)
-                }
-            }
-            m.isContinuousLine = S;
-            if (g && !S) {
-                Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")
-            }
-            if (v) {
-                T = v.getAlignment() === "vertical";
-                if (Ext.isNumber(v.floatingAtCoord)) {
-                    Q = (T ? D[2] : D[3]) - v.floatingAtCoord
-                } else {
-                    Q = T ? D[0] : D[1]
-                }
-            } else {
-                Q = k.flipXY ? D[0] : D[1]
-            }
-            if (k.preciseStroke) {
-                if (k.fillArea) {
-                    o.fill()
-                }
-                if (k.transformFillStroke) {
-                    k.inverseMatrix.toContext(o)
-                }
-                m.drawStroke(N, o, w, l, q, Q);
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                o.stroke()
-            } else {
-                m.drawStroke(N, o, w, l, q, Q);
-                if (S && g && k.fillArea && !k.renderer) {
-                    var A = s[s.length - 1] * C + c + u,
-                        z = r[r.length - 1] * f + b,
-                        J = s[0] * C + c - u,
-                        H = r[0] * f + b;
-                    o.lineTo(A, z);
-                    o.lineTo(A, Q - k.lineWidth);
-                    o.lineTo(J, Q - k.lineWidth);
-                    o.lineTo(J, H)
-                }
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                if (k.fillArea) {
-                    o.fillStroke(k, true)
-                } else {
-                    o.stroke(true)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.Line", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.line",
-    type: "line",
-    seriesType: "lineSeries",
-    requires: ["Ext.chart.series.sprite.Line"],
-    config: {
-        selectionTolerance: 20,
-        smooth: false,
-        step: false,
-        fill: undefined,
-        aggregator: {
-            strategy: "double"
-        }
-    },
-    defaultSmoothness: 3,
-    overflowBuffer: 1,
-    themeMarkerCount: function() {
-        return 1
-    },
-    getDefaultSpriteConfig: function() {
-        var d = this,
-            e = d.callParent(arguments),
-            c = Ext.apply({}, d.getStyle()),
-            b, a = false;
-        if (typeof d.config.fill != "undefined") {
-            if (d.config.fill) {
-                a = true;
-                if (typeof c.fillStyle == "undefined") {
-                    if (typeof c.strokeStyle == "undefined") {
-                        b = d.getStyleWithTheme();
-                        c.fillStyle = b.fillStyle;
-                        c.strokeStyle = b.strokeStyle
-                    } else {
-                        c.fillStyle = c.strokeStyle
-                    }
-                }
-            }
-        } else {
-            if (c.fillStyle) {
-                a = true
-            }
-        }
-        if (!a) {
-            delete c.fillStyle
-        }
-        c = Ext.apply(e || {}, c);
-        return Ext.apply(c, {
-            fillArea: a,
-            step: d.config.step,
-            smooth: d.config.smooth,
-            selectionTolerance: d.config.selectionTolerance
-        })
-    },
-    updateStep: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.step !== b) {
-            a.setAttributes({
-                step: b
-            })
-        }
-    },
-    updateFill: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.fillArea !== b) {
-            a.setAttributes({
-                fillArea: b
-            })
-        }
-    },
-    updateSmooth: function(a) {
-        var b = this.getSprites()[0];
-        if (b && b.attr.smooth !== a) {
-            b.setAttributes({
-                smooth: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.PieSlice", {
-    extend: "Ext.draw.sprite.Sector",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pieslice",
-    inheritableStatics: {
-        def: {
-            processors: {
-                doCallout: "bool",
-                label: "string",
-                rotateLabels: "bool",
-                labelOverflowPadding: "number",
-                renderer: "default"
-            },
-            defaults: {
-                doCallout: true,
-                rotateLabels: true,
-                label: "",
-                labelOverflowPadding: 10,
-                renderer: null
-            }
-        }
-    },
-    config: {
-        rendererData: null,
-        rendererIndex: 0,
-        series: null
-    },
-    setGradientBBox: function(q, k) {
-        var j = this,
-            i = j.attr,
-            g = (i.fillStyle && i.fillStyle.isGradient) || (i.strokeStyle && i.strokeStyle.isGradient);
-        if (g && !i.constrainGradients) {
-            var b = j.getMidAngle(),
-                d = i.margin,
-                e = i.centerX,
-                c = i.centerY,
-                a = i.endRho,
-                l = i.matrix,
-                o = l.getScaleX(),
-                n = l.getScaleY(),
-                m = o * a,
-                f = n * a,
-                p = {
-                    width: m + m,
-                    height: f + f
-                };
-            if (d) {
-                e += d * Math.cos(b);
-                c += d * Math.sin(b)
-            }
-            p.x = l.x(e, c) - m;
-            p.y = l.y(e, c) - f;
-            q.setGradientBBox(p)
-        } else {
-            j.callParent([q, k])
-        }
-    },
-    render: function(b, c, g, f) {
-        var e = this,
-            a = e.attr,
-            h = {},
-            d;
-        if (a.renderer) {
-            h = {
-                type: "sector",
-                text: a.text,
-                centerX: a.centerX,
-                centerY: a.centerY,
-                margin: a.margin,
-                startAngle: Math.min(a.startAngle, a.endAngle),
-                endAngle: Math.max(a.startAngle, a.endAngle),
-                startRho: Math.min(a.startRho, a.endRho),
-                endRho: Math.max(a.startRho, a.endRho)
-            };
-            d = Ext.callback(a.renderer, null, [e, h, e.rendererData, e.rendererIndex], 0, e.getSeries());
-            e.setAttributes(d);
-            e.useAttributes(c, g)
-        }
-        e.callParent([b, c, g, f]);
-        if (a.label && e.getMarker("labels")) {
-            e.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            s = z.attr,
-            r = s.attributeId,
-            t = Math.min(s.startAngle, s.endAngle),
-            p = Math.max(s.startAngle, s.endAngle),
-            k = (t + p) * 0.5,
-            n = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            f = Math.sin(k),
-            c = Math.cos(k),
-            v = Math.min(s.startRho, s.endRho) + n,
-            m = Math.max(s.startRho, s.endRho) + n,
-            l = (v + m) * 0.5,
-            b = z.surfaceMatrix,
-            o = z.labelCfg || (z.labelCfg = {}),
-            e = z.getMarker("labels"),
-            d = e.getTemplate(),
-            a = d.getCalloutLine(),
-            q = a && a.length || 40,
-            u, j, i, A, w;
-        b.appendMatrix(s.matrix);
-        o.text = s.label;
-        j = h + c * l;
-        i = g + f * l;
-        o.x = b.x(j, i);
-        o.y = b.y(j, i);
-        j = h + c * m;
-        i = g + f * m;
-        o.calloutStartX = b.x(j, i);
-        o.calloutStartY = b.y(j, i);
-        j = h + c * (m + q);
-        i = g + f * (m + q);
-        o.calloutPlaceX = b.x(j, i);
-        o.calloutPlaceY = b.y(j, i);
-        if (!s.rotateLabels) {
-            o.rotationRads = 0
-        } else {
-            switch (d.attr.orientation) {
-                case "horizontal":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0)) + Math.PI / 2;
-                    break;
-                case "vertical":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0));
-                    break
-            }
-        }
-        o.calloutColor = (a && a.color) || z.attr.fillStyle;
-        if (a) {
-            if (a.width) {
-                o.calloutWidth = a.width
-            }
-        } else {
-            o.calloutHasLine = false
-        }
-        o.globalAlpha = s.globalAlpha * s.fillOpacity;
-        o.hidden = (s.startAngle == s.endAngle);
-        if (d.attr.renderer) {
-            w = [z.attr.label, e, o, z.rendererData, z.rendererIndex];
-            A = Ext.callback(d.attr.renderer, null, w, 0, z.getSeries());
-            if (typeof A === "string") {
-                o.text = A
-            } else {
-                Ext.apply(o, A)
-            }
-        }
-        z.putMarker("labels", o, r);
-        u = z.getMarkerBBox("labels", r, true);
-        if (u) {
-            if (s.doCallout) {
-                if (d.attr.display === "outside") {
-                    z.putMarker("labels", {
-                        callout: 1
-                    }, r)
-                } else {
-                    if (d.attr.display === "inside") {
-                        z.putMarker("labels", {
-                            callout: 0
-                        }, r)
-                    } else {
-                        z.putMarker("labels", {
-                            callout: 1 - z.sliceContainsLabel(s, u)
-                        }, r)
-                    }
-                }
-            } else {
-                z.putMarker("labels", {
-                    globalAlpha: z.sliceContainsLabel(s, u)
-                }, r)
-            }
-        }
-    },
-    sliceContainsLabel: function(d, f) {
-        var e = d.labelOverflowPadding,
-            h = (d.endRho + d.startRho) / 2,
-            g = h + (f.width + e) / 2,
-            i = h - (f.width + e) / 2,
-            j, c, b, a;
-        if (e < 0) {
-            return 1
-        }
-        if (f.width + e * 2 > (d.endRho - d.startRho)) {
-            return 0
-        }
-        c = Math.sqrt(d.endRho * d.endRho - g * g);
-        b = Math.sqrt(d.endRho * d.endRho - i * i);
-        j = Math.abs(d.endAngle - d.startAngle);
-        a = (j > Math.PI / 2 ? i : Math.abs(Math.tan(j / 2)) * i);
-        if (f.height + e * 2 > Math.min(c, b, a) * 2) {
-            return 0
-        }
-        return 1
-    }
-});
-Ext.define("Ext.chart.series.Pie", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.PieSlice"],
-    type: "pie",
-    alias: "series.pie",
-    seriesType: "pieslice",
-    config: {
-        donut: 0,
-        rotation: 0,
-        clockwise: true,
-        totalAngle: 2 * Math.PI,
-        hidden: [],
-        radiusFactor: 100,
-        highlightCfg: {
-            margin: 20
-        },
-        style: {}
-    },
-    directions: ["X"],
-    applyLabel: function(a, b) {
-        if (Ext.isObject(a) && !Ext.isString(a.orientation)) {
-            Ext.apply(a = Ext.Object.chain(a), {
-                orientation: "vertical"
-            })
-        }
-        return this.callParent([a, b])
-    },
-    updateLabelData: function() {
-        var h = this,
-            j = h.getStore(),
-            g = j.getData().items,
-            e = h.getSprites(),
-            a = h.getLabel().getTemplate().getField(),
-            d = h.getHidden(),
-            b, f, c, k;
-        if (e.length && a) {
-            c = [];
-            for (b = 0, f = g.length; b < f; b++) {
-                c.push(g[b].get(a))
-            }
-            for (b = 0, f = e.length; b < f; b++) {
-                k = e[b];
-                k.setAttributes({
-                    label: c[b]
-                });
-                k.putMarker("labels", {
-                    hidden: d[b]
-                }, k.attr.attributeId)
-            }
-        }
-    },
-    coordinateX: function() {
-        var t = this,
-            f = t.getStore(),
-            q = f.getData().items,
-            c = q.length,
-            b = t.getXField(),
-            e = t.getYField(),
-            l, a = 0,
-            m, k, s = 0,
-            o = t.getHidden(),
-            d = [],
-            p, g = 0,
-            h = t.getTotalAngle(),
-            r = t.getClockwise() ? 1 : -1,
-            j = t.getSprites(),
-            n;
-        if (!j) {
-            return
-        }
-        for (p = 0; p < c; p++) {
-            l = Math.abs(Number(q[p].get(b))) || 0;
-            k = e && Math.abs(Number(q[p].get(e))) || 0;
-            if (!o[p]) {
-                a += l;
-                if (k > s) {
-                    s = k
-                }
-            }
-            d[p] = a;
-            if (p >= o.length) {
-                o[p] = false
-            }
-        }
-        o.length = c;
-        t.maxY = s;
-        if (a !== 0) {
-            m = h / a
-        }
-        for (p = 0; p < c; p++) {
-            j[p].setAttributes({
-                startAngle: g,
-                endAngle: g = (m ? r * d[p] * m : 0),
-                globalAlpha: 1
-            })
-        }
-        if (c < t.sprites.length) {
-            for (p = c; p < t.sprites.length; p++) {
-                n = t.sprites[p];
-                n.getMarker("labels").clear(n.getId());
-                n.releaseMarker("labels");
-                n.destroy()
-            }
-            t.sprites.length = c
-        }
-        for (p = c; p < t.sprites.length; p++) {
-            j[p].setAttributes({
-                startAngle: h,
-                endAngle: h,
-                globalAlpha: 0
-            })
-        }
-        t.getChart().refreshLegendStore()
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            startRho: a * this.getDonut() * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    getStyleByIndex: function(c) {
-        var g = this,
-            j = g.getStore(),
-            k = j.getAt(c),
-            f = g.getYField(),
-            d = g.getRadius(),
-            a = {},
-            e, b, h;
-        if (k) {
-            h = f && Math.abs(Number(k.get(f))) || 0;
-            e = d * g.getDonut() * 0.01;
-            b = d * g.getRadiusFactor() * 0.01;
-            a = g.callParent([c]);
-            a.startRho = e;
-            a.endRho = g.maxY ? (e + (b - e) * h / g.maxY) : b
-        }
-        return a
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.setStyle({
-            startRho: a * b * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    rotationOffset: -Math.PI / 2,
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getSprites: function() {
-        var k = this,
-            h = k.getChart(),
-            n = k.getStore();
-        if (!h || !n) {
-            return []
-        }
-        k.getColors();
-        k.getSubStyle();
-        var j = n.getData().items,
-            b = j.length,
-            d = k.getAnimation() || h && h.getAnimation(),
-            g = k.sprites,
-            o, l = 0,
-            f, e, c = false,
-            m = k.getLabel(),
-            a = m.getTemplate();
-        f = {
-            store: n,
-            field: k.getXField(),
-            angleField: k.getXField(),
-            radiusField: k.getYField(),
-            series: k
-        };
-        for (e = 0; e < b; e++) {
-            o = g[e];
-            if (!o) {
-                o = k.createSprite();
-                if (k.getHighlight()) {
-                    o.config.highlight = k.getHighlight();
-                    o.addModifier("highlight", true)
-                }
-                if (a.getField()) {
-                    a.setAttributes({
-                        labelOverflowPadding: k.getLabelOverflowPadding()
-                    });
-                    a.fx.setCustomDurations({
-                        callout: 200
-                    })
-                }
-                o.setAttributes(k.getStyleByIndex(e));
-                o.rendererData = f;
-                o.rendererIndex = l++;
-                c = true
-            }
-            o.setAnimation(d)
-        }
-        if (c) {
-            k.doUpdateStyles()
-        }
-        return k.sprites
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        if (!this.getClockwise()) {
-            d *= -1;
-            f *= -1;
-            c *= -1;
-            f -= g;
-            c -= g
-        } else {
-            f += g;
-            c += g
-        }
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForAngle: function(a) {
-        var h = this,
-            f = h.getSprites(),
-            d;
-        a %= Math.PI * 2;
-        while (a < 0) {
-            a += Math.PI * 2
-        }
-        if (f) {
-            var j = h.getStore(),
-                g = j.getData().items,
-                c = h.getHidden(),
-                b = 0,
-                e = j.getCount();
-            for (; b < e; b++) {
-                if (!c[b]) {
-                    d = f[b].attr;
-                    if (d.startAngle <= a && d.endAngle >= a) {
-                        return {
-                            series: h,
-                            sprite: f[b],
-                            index: b,
-                            record: g[b],
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-        }
-        return null
-    },
-    getItemForPoint: function(f, e) {
-        var t = this,
-            c = t.getSprites();
-        if (c) {
-            var s = t.getCenter(),
-                q = t.getOffsetX(),
-                p = t.getOffsetY(),
-                j = f - s[0] + q,
-                h = e - s[1] + p,
-                b = t.getStore(),
-                g = t.getDonut(),
-                o = b.getData().items,
-                r = Math.atan2(h, j) - t.getRotation(),
-                a = Math.sqrt(j * j + h * h),
-                l = t.getRadius() * g * 0.01,
-                m = t.getHidden(),
-                n, d, k;
-            for (n = 0, d = o.length; n < d; n++) {
-                if (!m[n]) {
-                    k = c[n].attr;
-                    if (a >= l + k.margin && a <= k.endRho + k.margin) {
-                        if (t.betweenAngle(r, k.startAngle, k.endAngle)) {
-                            return {
-                                series: t,
-                                sprite: c[n],
-                                index: n,
-                                record: o[n],
-                                field: t.getXField()
-                            }
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            j = h.getStore();
-        if (j) {
-            var g = j.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                c = h.getXField(),
-                e = h.getHidden(),
-                d, a, k;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                k = a.fillStyle;
-                if (Ext.isObject(k)) {
-                    k = k.stops && k.stops[0].color
-                }
-                f.push({
-                    name: b ? String(g[d].get(b)) : c + " " + d,
-                    mark: k || a.strokeStyle || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Pie3DPart", {
-    extend: "Ext.draw.sprite.Path",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pie3dPart",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number",
-                thickness: "number",
-                bevelWidth: "number",
-                distortion: "number",
-                baseColor: "color",
-                colorSpread: "number",
-                baseRotation: "number",
-                part: "enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",
-                label: "string"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,partZIndex",
-                endAngle: "path,partZIndex",
-                startRho: "path",
-                endRho: "path,bbox",
-                margin: "path,bbox",
-                thickness: "path",
-                distortion: "path",
-                baseRotation: "path,partZIndex",
-                baseColor: "partZIndex,partColor",
-                colorSpread: "partColor",
-                part: "path,partZIndex",
-                globalAlpha: "canvas,alpha"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: Math.PI * 2,
-                endAngle: Math.PI * 2,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                thickness: 35,
-                distortion: 0.5,
-                baseRotation: 0,
-                baseColor: "white",
-                colorSpread: 1,
-                miterLimit: 1,
-                bevelWidth: 5,
-                strokeOpacity: 0,
-                part: "top",
-                label: ""
-            },
-            updaters: {
-                alpha: "alphaUpdater",
-                partColor: "partColorUpdater",
-                partZIndex: "partZIndexUpdater"
-            }
-        }
-    },
-    bevelParams: [],
-    constructor: function(a) {
-        this.callParent([a]);
-        this.bevelGradient = new Ext.draw.gradient.Linear({
-            stops: [{
-                offset: 0,
-                color: "rgba(255,255,255,0)"
-            }, {
-                offset: 0.7,
-                color: "rgba(255,255,255,0.6)"
-            }, {
-                offset: 1,
-                color: "rgba(255,255,255,0)"
-            }]
-        })
-    },
-    alphaUpdater: function(a) {
-        var d = this,
-            c = a.globalAlpha,
-            b = d.oldOpacity;
-        if (c !== b && (c === 1 || b === 1)) {
-            d.scheduleUpdater(a, "path", ["globalAlpha"]);
-            d.oldOpacity = c
-        }
-    },
-    partColorUpdater: function(a) {
-        var d = Ext.draw.Color.fly(a.baseColor),
-            b = d.toString(),
-            e = a.colorSpread,
-            c;
-        switch (a.part) {
-            case "top":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createLighter(0.1 * e)
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e)
-                    }]
-                });
-                break;
-            case "bottom":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.2 * e)
-                    }, {
-                        offset: 1,
-                        color: d.toString()
-                    }]
-                });
-                break;
-            case "outerFront":
-            case "outerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.15 * e).toString()
-                    }, {
-                        offset: 0.3,
-                        color: b
-                    }, {
-                        offset: 0.8,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.25 * e).toString()
-                    }]
-                });
-                break;
-            case "start":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "end":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "innerFront":
-            case "innerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 0.2,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 0.7,
-                        color: b
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e).toString()
-                    }]
-                });
-                break
-        }
-        a.fillStyle = c;
-        a.canvasAttributes.fillStyle = c
-    },
-    partZIndexUpdater: function(a) {
-        var c = Ext.draw.sprite.AttributeParser.angle,
-            e = a.baseRotation,
-            d = a.startAngle,
-            b = a.endAngle,
-            f;
-        switch (a.part) {
-            case "top":
-                a.zIndex = 5;
-                break;
-            case "outerFront":
-                d = c(d + e);
-                b = c(b + e);
-                if (d >= 0 && b < 0) {
-                    f = Math.sin(d)
-                } else {
-                    if (d <= 0 && b > 0) {
-                        f = Math.sin(b)
-                    } else {
-                        if (d >= 0 && b > 0) {
-                            if (d > b) {
-                                f = 0
-                            } else {
-                                f = Math.max(Math.sin(d), Math.sin(b))
-                            }
-                        } else {
-                            f = 1
-                        }
-                    }
-                }
-                a.zIndex = 4 + f;
-                break;
-            case "outerBack":
-                a.zIndex = 1;
-                break;
-            case "start":
-                a.zIndex = 4 + Math.sin(c(d + e));
-                break;
-            case "end":
-                a.zIndex = 4 + Math.sin(c(b + e));
-                break;
-            case "innerFront":
-                a.zIndex = 2;
-                break;
-            case "innerBack":
-                a.zIndex = 4 + Math.sin(c((d + b) / 2 + e));
-                break;
-            case "bottom":
-                a.zIndex = 0;
-                break
-        }
-        a.dirtyZIndex = true
-    },
-    updatePlainBBox: function(k) {
-        var f = this.attr,
-            a = f.part,
-            b = f.baseRotation,
-            e = f.centerX,
-            d = f.centerY,
-            j, c, i, h, g, l;
-        if (a === "start") {
-            c = f.startAngle + b
-        } else {
-            if (a === "end") {
-                c = f.endAngle + b
-            }
-        }
-        if (Ext.isNumber(c)) {
-            g = Math.sin(c);
-            l = Math.cos(c);
-            i = Math.min(e + l * f.startRho, e + l * f.endRho);
-            h = d + g * f.startRho * f.distortion;
-            k.x = i;
-            k.y = h;
-            k.width = l * (f.endRho - f.startRho);
-            k.height = f.thickness + g * (f.endRho - f.startRho) * 2;
-            return
-        }
-        if (a === "innerFront" || a === "innerBack") {
-            j = f.startRho
-        } else {
-            j = f.endRho
-        }
-        k.width = j * 2;
-        k.height = j * f.distortion * 2 + f.thickness;
-        k.x = f.centerX - j;
-        k.y = f.centerY - j * f.distortion
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.part === "start" || this.attr.part === "end") {
-            return this.callParent(arguments)
-        }
-        return this.updatePlainBBox(a)
-    },
-    updatePath: function(a) {
-        if (!this.attr.globalAlpha) {
-            return
-        }
-        if (this.attr.endAngle < this.attr.startAngle) {
-            return
-        }
-        this[this.attr.part + "Renderer"](a)
-    },
-    render: function(b, c) {
-        var d = this,
-            a = d.attr;
-        if (!a.globalAlpha) {
-            return
-        }
-        d.callParent([b, c]);
-        d.bevelRenderer(b, c);
-        if (a.label && d.getMarker("labels")) {
-            d.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            u = z.attr,
-            t = u.attributeId,
-            p = u.margin,
-            c = u.distortion,
-            i = u.centerX,
-            h = u.centerY,
-            j = u.baseRotation,
-            v = u.startAngle + j,
-            r = u.endAngle + j,
-            m = (v + r) / 2,
-            w = u.startRho + p,
-            o = u.endRho + p,
-            n = (w + o) / 2,
-            a = Math.sin(m),
-            b = Math.cos(m),
-            e = z.surfaceMatrix,
-            g = z.getMarker("labels"),
-            f = g.getTemplate(),
-            d = f.getCalloutLine(),
-            s = d && d.length || 40,
-            q = {},
-            l, k;
-        e.appendMatrix(u.matrix);
-        q.text = u.label;
-        l = i + b * n;
-        k = h + a * n * c;
-        q.x = e.x(l, k);
-        q.y = e.y(l, k);
-        l = i + b * o;
-        k = h + a * o * c;
-        q.calloutStartX = e.x(l, k);
-        q.calloutStartY = e.y(l, k);
-        l = i + b * (o + s);
-        k = h + a * (o + s) * c;
-        q.calloutPlaceX = e.x(l, k);
-        q.calloutPlaceY = e.y(l, k);
-        q.calloutWidth = 2;
-        z.putMarker("labels", q, t);
-        z.putMarker("labels", {
-            callout: 1
-        }, t)
-    },
-    bevelRenderer: function(b, c) {
-        var f = this,
-            a = f.attr,
-            e = a.bevelWidth,
-            g = f.bevelParams,
-            d;
-        for (d = 0; d < g.length; d++) {
-            c.beginPath();
-            c.ellipse.apply(c, g[d]);
-            c.save();
-            c.lineWidth = e;
-            c.strokeOpacity = e ? 1 : 0;
-            c.strokeGradient = f.bevelGradient;
-            c.stroke(a);
-            c.restore()
-        }
-    },
-    lidRenderer: function(o, m) {
-        var k = this.attr,
-            g = k.margin,
-            c = k.distortion,
-            i = k.centerX,
-            h = k.centerY,
-            f = k.baseRotation,
-            j = k.startAngle + f,
-            e = k.endAngle + f,
-            d = (j + e) / 2,
-            l = k.startRho,
-            b = k.endRho,
-            n = Math.sin(e),
-            a = Math.cos(e);
-        i += Math.cos(d) * g;
-        h += Math.sin(d) * g * c;
-        o.ellipse(i, h + m, l, l * c, 0, j, e, false);
-        o.lineTo(i + a * b, h + m + n * b * c);
-        o.ellipse(i, h + m, b, b * c, 0, e, j, true);
-        o.closePath()
-    },
-    topRenderer: function(a) {
-        this.lidRenderer(a, 0)
-    },
-    bottomRenderer: function(b) {
-        var a = this.attr;
-        if (a.globalAlpha < 1 || a.shadowColor !== Ext.draw.Color.RGBA_NONE) {
-            this.lidRenderer(b, a.thickness)
-        }
-    },
-    sideRenderer: function(l, s) {
-        var o = this.attr,
-            k = o.margin,
-            g = o.centerX,
-            f = o.centerY,
-            e = o.distortion,
-            h = o.baseRotation,
-            p = o.startAngle + h,
-            m = o.endAngle + h,
-            a = o.thickness,
-            q = o.startRho,
-            j = o.endRho,
-            r = (s === "start" && p) || (s === "end" && m),
-            b = Math.sin(r),
-            d = Math.cos(r),
-            c = o.globalAlpha < 1,
-            n = s === "start" && d < 0 || s === "end" && d > 0 || c,
-            i;
-        if (n) {
-            i = (p + m) / 2;
-            g += Math.cos(i) * k;
-            f += Math.sin(i) * k * e;
-            l.moveTo(g + d * q, f + b * q * e);
-            l.lineTo(g + d * j, f + b * j * e);
-            l.lineTo(g + d * j, f + b * j * e + a);
-            l.lineTo(g + d * q, f + b * q * e + a);
-            l.closePath()
-        }
-    },
-    startRenderer: function(a) {
-        this.sideRenderer(a, "start")
-    },
-    endRenderer: function(a) {
-        this.sideRenderer(a, "end")
-    },
-    rimRenderer: function(q, e, o, j) {
-        var w = this,
-            s = w.attr,
-            p = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            d = s.distortion,
-            i = s.baseRotation,
-            t = Ext.draw.sprite.AttributeParser.angle,
-            u = s.startAngle + i,
-            r = s.endAngle + i,
-            k = t((u + r) / 2),
-            a = s.thickness,
-            b = s.globalAlpha < 1,
-            c, n, v;
-        w.bevelParams = [];
-        u = t(u);
-        r = t(r);
-        h += Math.cos(k) * p;
-        g += Math.sin(k) * p * d;
-        c = u >= 0 && r >= 0;
-        n = u <= 0 && r <= 0;
-
-        function l() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, u, true);
-            q.lineTo(h + Math.cos(u) * e, g + Math.sin(u) * e * d);
-            v = [h, g, e, e * d, 0, u, Math.PI, false];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function f() {
-            q.ellipse(h, g + a, e, e * d, 0, 0, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, 0, true];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function x() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, Math.PI, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function m() {
-            q.ellipse(h, g + a, e, e * d, 0, u, 0, false);
-            q.lineTo(h + e, g);
-            v = [h, g, e, e * d, 0, 0, u, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-        if (j) {
-            if (!o || b) {
-                if (u >= 0 && r < 0) {
-                    l()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        f()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, 0, Math.PI, false);
-                                q.lineTo(h - e, g);
-                                v = [h, g, e, e * d, 0, Math.PI, 0, true];
-                                if (!o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                l();
-                                f()
-                            } else {
-                                v = [h, g, e, e * d, 0, u, r, false];
-                                if (c && !o || n && o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d + a);
-                                q.ellipse(h, g + a, e, e * d, 0, r, u, true);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        } else {
-            if (o || b) {
-                if (u >= 0 && r < 0) {
-                    x()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        m()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                x();
-                                m()
-                            } else {
-                                q.ellipse(h, g + a, e, e * d, 0, u, r, false);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-                                v = [h, g, e, e * d, 0, r, u, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, -Math.PI, 0, false);
-                                q.lineTo(h + e, g);
-                                v = [h, g, e, e * d, 0, 0, -Math.PI, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    innerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, true)
-    },
-    innerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, false)
-    },
-    outerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, true)
-    },
-    outerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, false)
-    }
-});
-Ext.define("Ext.draw.PathUtil", function() {
-    var a = Math.abs,
-        c = Math.pow,
-        e = Math.cos,
-        b = Math.acos,
-        d = Math.sqrt,
-        f = Math.PI;
-    return {
-        singleton: true,
-        requires: ["Ext.draw.overrides.Path", "Ext.draw.overrides.sprite.Path", "Ext.draw.overrides.sprite.Instancing", "Ext.draw.overrides.Surface"],
-        cubicRoots: function(m) {
-            var z = m[0],
-                x = m[1],
-                w = m[2],
-                v = m[3];
-            if (z === 0) {
-                return this.quadraticRoots(x, w, v)
-            }
-            var s = x / z,
-                r = w / z,
-                q = v / z,
-                k = (3 * r - c(s, 2)) / 9,
-                j = (9 * s * r - 27 * q - 2 * c(s, 3)) / 54,
-                p = c(k, 3) + c(j, 2),
-                n = [],
-                h, g, o, l, u, y = Ext.Number.sign;
-            if (p >= 0) {
-                h = y(j + d(p)) * c(a(j + d(p)), 1 / 3);
-                g = y(j - d(p)) * c(a(j - d(p)), 1 / 3);
-                n[0] = -s / 3 + (h + g);
-                n[1] = -s / 3 - (h + g) / 2;
-                n[2] = n[1];
-                o = a(d(3) * (h - g) / 2);
-                if (o !== 0) {
-                    n[1] = -1;
-                    n[2] = -1
-                }
-            } else {
-                l = b(j / d(-c(k, 3)));
-                n[0] = 2 * d(-k) * e(l / 3) - s / 3;
-                n[1] = 2 * d(-k) * e((l + 2 * f) / 3) - s / 3;
-                n[2] = 2 * d(-k) * e((l + 4 * f) / 3) - s / 3
-            }
-            for (u = 0; u < 3; u++) {
-                if (n[u] < 0 || n[u] > 1) {
-                    n[u] = -1
-                }
-            }
-            return n
-        },
-        quadraticRoots: function(h, g, n) {
-            var m, l, k, j;
-            if (h === 0) {
-                return this.linearRoot(g, n)
-            }
-            m = g * g - 4 * h * n;
-            if (m === 0) {
-                k = [-g / (2 * h)]
-            } else {
-                if (m > 0) {
-                    l = d(m);
-                    k = [(-g - l) / (2 * h), (-g + l) / (2 * h)]
-                } else {
-                    return []
-                }
-            }
-            for (j = 0; j < k.length; j++) {
-                if (k[j] < 0 || k[j] > 1) {
-                    k[j] = -1
-                }
-            }
-            return k
-        },
-        linearRoot: function(h, g) {
-            var i = -g / h;
-            if (h === 0 || i < 0 || i > 1) {
-                return []
-            }
-            return [i]
-        },
-        bezierCoeffs: function(h, g, k, j) {
-            var i = [];
-            i[0] = -h + 3 * g - 3 * k + j;
-            i[1] = 3 * h - 6 * g + 3 * k;
-            i[2] = -3 * h + 3 * g;
-            i[3] = h;
-            return i
-        },
-        cubicLineIntersections: function(I, G, F, E, l, k, j, h, M, p, K, n) {
-            var u = [],
-                N = [],
-                D = p - n,
-                z = K - M,
-                y = M * (n - p) - p * (K - M),
-                L = this.bezierCoeffs(I, G, F, E),
-                J = this.bezierCoeffs(l, k, j, h),
-                H, x, w, v, g, q, o, m;
-            u[0] = D * L[0] + z * J[0];
-            u[1] = D * L[1] + z * J[1];
-            u[2] = D * L[2] + z * J[2];
-            u[3] = D * L[3] + z * J[3] + y;
-            x = this.cubicRoots(u);
-            for (H = 0; H < x.length; H++) {
-                v = x[H];
-                if (v < 0 || v > 1) {
-                    continue
-                }
-                g = v * v;
-                q = g * v;
-                o = L[0] * q + L[1] * g + L[2] * v + L[3];
-                m = J[0] * q + J[1] * g + J[2] * v + J[3];
-                if ((K - M) !== 0) {
-                    w = (o - M) / (K - M)
-                } else {
-                    w = (m - p) / (n - p)
-                }
-                if (!(w < 0 || w > 1)) {
-                    N.push([o, m])
-                }
-            }
-            return N
-        },
-        splitCubic: function(g, q, p, o, m) {
-            var j = m * m,
-                n = m * j,
-                i = m - 1,
-                h = i * i,
-                k = i * h,
-                l = n * o - 3 * j * i * p + 3 * m * h * q - k * g;
-            return [
-                [g, m * q - i * g, j * p - 2 * m * i * q + h * g, l],
-                [l, j * o - 2 * m * i * p + h * q, m * o - i * p, o]
-            ]
-        },
-        cubicDimension: function(p, o, l, k) {
-            var j = 3 * (-p + 3 * (o - l) + k),
-                i = 6 * (p - 2 * o + l),
-                h = -3 * (p - o),
-                q, n, g = Math.min(p, k),
-                m = Math.max(p, k),
-                r;
-            if (j === 0) {
-                if (i === 0) {
-                    return [g, m]
-                } else {
-                    q = -h / i;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                }
-            } else {
-                r = i * i - 4 * j * h;
-                if (r >= 0) {
-                    r = d(r);
-                    q = (r - i) / 2 / j;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                    if (r > 0) {
-                        q -= r / j;
-                        if (0 < q && q < 1) {
-                            n = this.interpolateCubic(p, o, l, k, q);
-                            g = Math.min(g, n);
-                            m = Math.max(m, n)
-                        }
-                    }
-                }
-            }
-            return [g, m]
-        },
-        interpolateCubic: function(h, g, l, k, i) {
-            if (i === 0) {
-                return h
-            }
-            if (i === 1) {
-                return k
-            }
-            var j = (1 - i) / i;
-            return i * i * i * (k + j * (3 * l + j * (3 * g + j * h)))
-        },
-        cubicsIntersections: function(r, q, p, o, A, z, y, v, g, F, E, D, m, l, k, i) {
-            var C = this,
-                x = C.cubicDimension(r, q, p, o),
-                B = C.cubicDimension(A, z, y, v),
-                n = C.cubicDimension(g, F, E, D),
-                s = C.cubicDimension(m, l, k, i),
-                j, h, u, t, w = [];
-            if (x[0] > n[1] || x[1] < n[0] || B[0] > s[1] || B[1] < s[0]) {
-                return []
-            }
-            if (a(A - z) < 1 && a(y - v) < 1 && a(r - o) < 1 && a(q - p) < 1 && a(m - l) < 1 && a(k - i) < 1 && a(g - D) < 1 && a(F - E) < 1) {
-                return [
-                    [(r + o) * 0.5, (A + z) * 0.5]
-                ]
-            }
-            j = C.splitCubic(r, q, p, o, 0.5);
-            h = C.splitCubic(A, z, y, v, 0.5);
-            u = C.splitCubic(g, F, E, D, 0.5);
-            t = C.splitCubic(m, l, k, i, 0.5);
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[1], t[1])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[1], t[1])));
-            return w
-        },
-        linesIntersection: function(k, p, j, o, h, n, q, m) {
-            var l = (j - k) * (m - n) - (o - p) * (q - h),
-                i, g;
-            if (l === 0) {
-                return null
-            }
-            i = ((q - h) * (p - n) - (k - h) * (m - n)) / l;
-            g = ((j - k) * (p - n) - (o - p) * (k - h)) / l;
-            if (i >= 0 && i <= 1 && g >= 0 && g <= 1) {
-                return [k + i * (j - k), p + i * (o - p)]
-            }
-            return null
-        },
-        pointOnLine: function(j, m, h, l, g, n) {
-            var k, i;
-            if (a(h - j) < a(l - m)) {
-                i = j;
-                j = m;
-                m = i;
-                i = h;
-                h = l;
-                l = i;
-                i = g;
-                g = n;
-                n = i
-            }
-            k = (g - j) / (h - j);
-            if (k < 0 || k > 1) {
-                return false
-            }
-            return a(m + k * (l - m) - n) < 4
-        },
-        pointOnCubic: function(w, u, s, r, l, k, h, g, p, o) {
-            var C = this,
-                B = C.bezierCoeffs(w, u, s, r),
-                A = C.bezierCoeffs(l, k, h, g),
-                z, v, n, m, q;
-            B[3] -= p;
-            A[3] -= o;
-            n = C.cubicRoots(B);
-            m = C.cubicRoots(A);
-            for (z = 0; z < n.length; z++) {
-                q = n[z];
-                for (v = 0; v < m.length; v++) {
-                    if (q >= 0 && q <= 1 && a(q - m[v]) < 0.05) {
-                        return true
-                    }
-                }
-            }
-            return false
-        }
-    }
-});
-Ext.define("Ext.chart.series.Pie3D", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.Pie3DPart", "Ext.draw.PathUtil"],
-    type: "pie3d",
-    seriesType: "pie3d",
-    alias: "series.pie3d",
-    isPie3D: true,
-    config: {
-        rect: [0, 0, 0, 0],
-        thickness: 35,
-        distortion: 0.5,
-        donut: false,
-        hidden: [],
-        highlightCfg: {
-            margin: 20
-        },
-        shadow: false
-    },
-    rotationOffset: -Math.PI / 2,
-    setField: function(a) {
-        return this.setXField(a)
-    },
-    getField: function() {
-        return this.getXField()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            baseRotation: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateDistortion: function() {
-        this.setRadius()
-    },
-    updateThickness: function() {
-        this.setRadius()
-    },
-    updateColors: function(a) {
-        this.setSubStyle({
-            baseColor: a
-        })
-    },
-    applyShadow: function(a) {
-        if (a === true) {
-            a = {
-                shadowColor: "rgba(0,0,0,0.8)",
-                shadowBlur: 30
-            }
-        } else {
-            if (!Ext.isObject(a)) {
-                a = {
-                    shadowColor: Ext.draw.Color.RGBA_NONE
-                }
-            }
-        }
-        return a
-    },
-    updateShadow: function(g) {
-        var e = this,
-            f = e.getSprites(),
-            d = e.spritesPerSlice,
-            c = f && f.length,
-            b, a;
-        for (b = 1; b < c; b += d) {
-            a = f[b];
-            if (a.attr.part = "bottom") {
-                a.setAttributes(g)
-            }
-        }
-    },
-    getStyleByIndex: function(b) {
-        var d = this.callParent([b]),
-            c = this.getStyle(),
-            a = d.fillStyle || d.fill || d.color,
-            e = c.strokeStyle || c.stroke;
-        if (a) {
-            d.baseColor = a;
-            delete d.fillStyle;
-            delete d.fill;
-            delete d.color
-        }
-        if (e) {
-            d.strokeStyle = e
-        }
-        return d
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.getSprites(),
-            f = g.spritesPerSlice,
-            e = h && h.length,
-            c = 0,
-            b = 0,
-            a, d;
-        for (; c < e; c += f, b++) {
-            d = g.getStyleByIndex(b);
-            for (a = 0; a < f; a++) {
-                h[c + a].setAttributes(d)
-            }
-        }
-    },
-    coordinateX: function() {
-        var w = this,
-            m = w.getChart(),
-            u = m && m.getAnimation(),
-            f = w.getStore(),
-            t = f.getData().items,
-            d = t.length,
-            b = w.getXField(),
-            p = w.getRotation(),
-            s = w.getHidden(),
-            n, c = 0,
-            h, e = [],
-            k = w.getSprites(),
-            a = k.length,
-            l = w.spritesPerSlice,
-            g = 0,
-            o = Math.PI * 2,
-            v = 1e-10,
-            r, q;
-        for (r = 0; r < d; r++) {
-            n = Math.abs(Number(t[r].get(b))) || 0;
-            if (!s[r]) {
-                c += n
-            }
-            e[r] = c;
-            if (r >= s.length) {
-                s[r] = false
-            }
-        }
-        s.length = d;
-        if (c === 0) {
-            return
-        }
-        h = 2 * Math.PI / c;
-        for (r = 0; r < d; r++) {
-            e[r] *= h
-        }
-        for (r = 0; r < a; r++) {
-            k[r].setAnimation(u)
-        }
-        for (r = 0; r < d; r++) {
-            for (q = 0; q < l; q++) {
-                k[r * l + q].setAttributes({
-                    startAngle: g,
-                    endAngle: e[r] - v,
-                    globalAlpha: 1,
-                    baseRotation: p
-                })
-            }
-            g = e[r]
-        }
-        for (r *= l; r < a; r++) {
-            k[r].setAnimation(u);
-            k[r].setAttributes({
-                startAngle: o,
-                endAngle: o,
-                globalAlpha: 0,
-                baseRotation: p
-            })
-        }
-    },
-    updateLabelData: function() {
-        var l = this,
-            m = l.getStore(),
-            k = m.getData().items,
-            h = l.getSprites(),
-            b = l.getLabel().getTemplate().getField(),
-            f = l.getHidden(),
-            a = l.spritesPerSlice,
-            d, c, g, e, n;
-        if (h.length && b) {
-            e = [];
-            for (d = 0, g = k.length; d < g; d++) {
-                e.push(k[d].get(b))
-            }
-            for (d = 0, c = 0, g = h.length; d < g; d += a, c++) {
-                n = h[d];
-                n.setAttributes({
-                    label: e[c]
-                });
-                n.putMarker("labels", {
-                    hidden: f[c]
-                }, n.attr.attributeId)
-            }
-        }
-    },
-    applyRadius: function() {
-        var f = this,
-            d = f.getChart(),
-            h = d.getInnerPadding(),
-            e = d.getMainRect() || [0, 0, 1, 1],
-            c = e[2] - h * 2,
-            a = e[3] - h * 2 - f.getThickness(),
-            g = c / 2,
-            b = g * f.getDistortion();
-        if (b > a / 2) {
-            return a / (f.getDistortion() * 2)
-        } else {
-            return g
-        }
-    },
-    getSprites: function() {
-        var y = this,
-            e = y.getStore();
-        if (!e) {
-            return []
-        }
-        var n = y.getChart(),
-            p = y.getSurface(),
-            t = e.getData().items,
-            l = y.spritesPerSlice,
-            a = t.length,
-            v = y.getAnimation() || n && n.getAnimation(),
-            x = y.getCenter(),
-            w = y.getOffsetX(),
-            u = y.getOffsetY(),
-            b = y.getRadius(),
-            q = y.getRotation(),
-            d = y.getHighlight(),
-            c = {
-                centerX: x[0] + w,
-                centerY: x[1] + u - y.getThickness() / 2,
-                endRho: b,
-                startRho: b * y.getDonut() / 100,
-                thickness: y.getThickness(),
-                distortion: y.getDistortion()
-            },
-            k = y.sprites,
-            h = y.getLabel(),
-            f = h.getTemplate(),
-            m, g, o, s, r;
-        for (s = 0; s < a; s++) {
-            g = Ext.apply({}, this.getStyleByIndex(s), c);
-            if (!k[s * l]) {
-                for (r = 0; r < y.partNames.length; r++) {
-                    o = p.add({
-                        type: "pie3dPart",
-                        part: y.partNames[r]
-                    });
-                    if (r === 0 && f.getField()) {
-                        o.bindMarker("labels", h)
-                    }
-                    o.fx.setDurationOn("baseRotation", q);
-                    if (d) {
-                        o.config.highlight = d;
-                        o.addModifier("highlight", true)
-                    }
-                    o.setAttributes(g);
-                    k.push(o)
-                }
-            } else {
-                m = k.slice(s * l, (s + 1) * l);
-                for (r = 0; r < m.length; r++) {
-                    o = m[r];
-                    if (v) {
-                        o.setAnimation(v)
-                    }
-                    o.setAttributes(g)
-                }
-            }
-        }
-        return k
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        f += g;
-        c += g;
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            g = h.getSprites();
-        if (g) {
-            var l = h.getStore(),
-                b = l.getData().items,
-                a = h.spritesPerSlice,
-                e = h.getHidden(),
-                c, f, m, d;
-            for (c = 0, f = b.length; c < f; c++) {
-                if (!e[c]) {
-                    d = c * a;
-                    m = g[d];
-                    if (m.hitTest([k, j])) {
-                        return {
-                            series: h,
-                            sprite: g.slice(d, d + a),
-                            index: c,
-                            record: b[c],
-                            category: "sprites",
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            k = h.getStore();
-        if (k) {
-            var g = k.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                j = h.getField(),
-                e = h.getHidden(),
-                d, a, c;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                c = a.baseColor;
-                f.push({
-                    name: b ? String(g[d].get(b)) : j + " " + d,
-                    mark: c || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-}, function() {
-    var b = this.prototype,
-        a = Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;
-    b.partNames = a.replace(/^enums\(|\)/g, "").split(",");
-    b.spritesPerSlice = b.partNames.length
-});
-Ext.define("Ext.chart.series.sprite.Polar", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                baseRotation: "number",
-                labels: "default",
-                labelOverflowPadding: "number"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: Math.PI,
-                startRho: 0,
-                endRho: 150,
-                baseRotation: 0,
-                labels: null,
-                labelOverflowPadding: 10
-            },
-            triggers: {
-                centerX: "bbox",
-                centerY: "bbox",
-                startAngle: "bbox",
-                endAngle: "bbox",
-                startRho: "bbox",
-                endRho: "bbox",
-                baseRotation: "bbox"
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.centerX - a.endRho;
-        b.y = a.centerY + a.endRho;
-        b.width = a.endRho * 2;
-        b.height = a.endRho * 2
-    }
-});
-Ext.define("Ext.chart.series.sprite.Radar", {
-    alias: "sprite.radar",
-    extend: "Ext.chart.series.sprite.Polar",
-    getDataPointXY: function(d) {
-        var u = this,
-            n = u.attr,
-            f = n.centerX,
-            e = n.centerY,
-            o = n.matrix,
-            t = n.dataMinX,
-            s = n.dataMaxX,
-            k = n.dataX,
-            j = n.dataY,
-            l = n.endRho,
-            p = n.startRho,
-            g = n.baseRotation,
-            i, h, m, c, b, a, q;
-        if (n.rangeY) {
-            q = n.rangeY[1]
-        } else {
-            q = n.dataMaxY
-        }
-        c = (k[d] - t) / (s - t + 1) * 2 * Math.PI + g;
-        m = j[d] / q * (l - p) + p;
-        b = f + Math.cos(c) * m;
-        a = e + Math.sin(c) * m;
-        i = o.x(b, a);
-        h = o.y(b, a);
-        return [i, h]
-    },
-    render: function(a, l) {
-        var h = this,
-            f = h.attr,
-            g = f.dataX,
-            b = g.length,
-            e = h.surfaceMatrix,
-            d = {},
-            c, k, j, m;
-        l.beginPath();
-        for (c = 0; c < b; c++) {
-            m = h.getDataPointXY(c);
-            k = m[0];
-            j = m[1];
-            if (c === 0) {
-                l.moveTo(k, j)
-            }
-            l.lineTo(k, j);
-            d.translationX = e.x(k, j);
-            d.translationY = e.y(k, j);
-            h.putMarker("markers", d, c, true)
-        }
-        l.closePath();
-        l.fillStroke(f)
-    }
-});
-Ext.define("Ext.chart.series.Radar", {
-    extend: "Ext.chart.series.Polar",
-    type: "radar",
-    seriesType: "radar",
-    alias: "series.radar",
-    requires: ["Ext.chart.series.sprite.Radar"],
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 1
-    },
-    updateAngularAxis: function(a) {
-        a.processData(this)
-    },
-    updateRadialAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            endRho: a
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            m = h.sprites && h.sprites[0],
-            f = m.attr,
-            g = f.dataX,
-            a = g.length,
-            l = h.getStore(),
-            e = h.getMarker(),
-            b, o, p, d, n, c;
-        if (h.getHidden()) {
-            return null
-        }
-        if (m && e) {
-            c = m.getMarker("markers");
-            for (d = 0; d < a; d++) {
-                n = c.getBBoxFor(d);
-                b = (n.width + n.height) * 0.25;
-                p = m.getDataPointXY(d);
-                if (Math.abs(p[0] - k) < b && Math.abs(p[1] - j) < b) {
-                    o = {
-                        series: h,
-                        sprite: m,
-                        index: d,
-                        category: "markers",
-                        record: l.getData().items[d],
-                        field: h.getYField()
-                    };
-                    return o
-                }
-            }
-        }
-        return h.callParent(arguments)
-    },
-    getDefaultSpriteConfig: function() {
-        var a = this.callParent(),
-            b = {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationRads: 0,
-                    dataMinX: 0,
-                    dataMaxX: 0
-                }
-            };
-        if (a.fx) {
-            Ext.apply(a.fx, b)
-        } else {
-            a.fx = b
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = d.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.sprites[0],
-            a;
-        if (!c) {
-            return []
-        }
-        if (!b) {
-            b = d.createSprite()
-        }
-        if (e) {
-            a = b.getMarker("markers");
-            if (a) {
-                a.getTemplate().setAnimation(e)
-            }
-            b.setAnimation(e)
-        }
-        return d.sprites
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.series.sprite.Scatter", {
-    alias: "sprite.scatterSeries",
-    extend: "Ext.chart.series.sprite.Cartesian",
-    renderClipped: function(r, s, w, u) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var C = this,
-            q = C.attr,
-            l = q.dataX,
-            h = q.dataY,
-            z = q.labels,
-            j = C.getSeries(),
-            b = z && C.getMarker("labels"),
-            t = C.attr.matrix,
-            c = t.getXX(),
-            p = t.getYY(),
-            m = t.getDX(),
-            k = t.getDY(),
-            n = {},
-            D, B, d = r.getInherited().rtl && !q.flipXY ? -1 : 1,
-            a, A, o, e, g, f, v;
-        if (q.flipXY) {
-            a = u[1] - c * d;
-            A = u[1] + u[3] + c * d;
-            o = u[0] - p;
-            e = u[0] + u[2] + p
-        } else {
-            a = u[0] - c * d;
-            A = u[0] + u[2] + c * d;
-            o = u[1] - p;
-            e = u[1] + u[3] + p
-        }
-        for (v = 0; v < l.length; v++) {
-            g = l[v];
-            f = h[v];
-            g = g * c + m;
-            f = f * p + k;
-            if (a <= g && g <= A && o <= f && f <= e) {
-                if (q.renderer) {
-                    n = {
-                        type: "items",
-                        translationX: g,
-                        translationY: f
-                    };
-                    B = [C, n, {
-                        store: C.getStore()
-                    }, v];
-                    D = Ext.callback(q.renderer, null, B, 0, j);
-                    n = Ext.apply(n, D)
-                } else {
-                    n.translationX = g;
-                    n.translationY = f
-                }
-                C.putMarker("items", n, v, !q.renderer);
-                if (b && z[v]) {
-                    C.drawLabel(z[v], g, f, v, u)
-                }
-            }
-        }
-    },
-    drawLabel: function(j, h, g, p, a) {
-        var r = this,
-            m = r.attr,
-            d = r.getMarker("labels"),
-            c = d.getTemplate(),
-            l = r.labelCfg || (r.labelCfg = {}),
-            b = r.surfaceMatrix,
-            f, e, i = m.labelOverflowPadding,
-            o = m.flipXY,
-            k, n, s, q;
-        l.text = j;
-        n = r.getMarkerBBox("labels", p, true);
-        if (!n) {
-            r.putMarker("labels", l, p);
-            n = r.getMarkerBBox("labels", p, true)
-        }
-        if (o) {
-            l.rotationRads = Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        k = n.height / 2;
-        f = h;
-        switch (c.attr.display) {
-            case "under":
-                e = g - k - i;
-                break;
-            case "rotate":
-                f += i;
-                e = g - i;
-                l.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                e = g + k + i
-        }
-        l.x = b.x(f, e);
-        l.y = b.y(f, e);
-        if (c.attr.renderer) {
-            q = [j, d, l, {
-                store: r.getStore()
-            }, p];
-            s = Ext.callback(c.attr.renderer, null, q, 0, r.getSeries());
-            if (typeof s === "string") {
-                l.text = s
-            } else {
-                Ext.apply(l, s)
-            }
-        }
-        r.putMarker("labels", l, p)
-    }
-});
-Ext.define("Ext.chart.series.Scatter", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.scatter",
-    type: "scatter",
-    seriesType: "scatterSeries",
-    requires: ["Ext.chart.series.sprite.Scatter"],
-    config: {
-        itemInstancing: {
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0
-                }
-            }
-        }
-    },
-    themeMarkerCount: function() {
-        return 1
-    },
-    applyMarker: function(b, a) {
-        this.getItemInstancing();
-        this.setItemInstancing(b);
-        return this.callParent(arguments)
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getMarkerStyleByIndex(0),
-            c = a.fillStyle;
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.theme.Blue", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue", "chart.theme.Blue"],
-    config: {
-        baseColor: "#4d7fe6"
-    }
-});
-Ext.define("Ext.chart.theme.BlueGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue-gradients", "chart.theme.Blue:gradients"],
-    config: {
-        baseColor: "#4d7fe6",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category1", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1", "chart.theme.Category1"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"]
-    }
-});
-Ext.define("Ext.chart.theme.Category1Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1-gradients", "chart.theme.Category1:gradients"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category2", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2", "chart.theme.Category2"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"]
-    }
-});
-Ext.define("Ext.chart.theme.Category2Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2-gradients", "chart.theme.Category2:gradients"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category3", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3", "chart.theme.Category3"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"]
-    }
-});
-Ext.define("Ext.chart.theme.Category3Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3-gradients", "chart.theme.Category3:gradients"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category4", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4", "chart.theme.Category4"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"]
-    }
-});
-Ext.define("Ext.chart.theme.Category4Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4-gradients", "chart.theme.Category4:gradients"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category5", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5", "chart.theme.Category5"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"]
-    }
-});
-Ext.define("Ext.chart.theme.Category5Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5-gradients", "chart.theme.Category5:gradients"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category6", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6", "chart.theme.Category6"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"]
-    }
-});
-Ext.define("Ext.chart.theme.Category6Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6-gradients", "chart.theme.Category6:gradients"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.DefaultGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default-gradients", "chart.theme.Base:gradients"],
-    config: {
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Green", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green", "chart.theme.Green"],
-    config: {
-        baseColor: "#b1da5a"
-    }
-});
-Ext.define("Ext.chart.theme.GreenGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green-gradients", "chart.theme.Green:gradients"],
-    config: {
-        baseColor: "#b1da5a",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Midnight", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.midnight", "chart.theme.Midnight"],
-    config: {
-        colors: ["#A837FF", "#4AC0F2", "#FF4D35", "#FF8809", "#61C102", "#FF37EA"],
-        chart: {
-            defaults: {
-                background: "rgb(52, 52, 53)"
-            }
-        },
-        axis: {
-            defaults: {
-                style: {
-                    strokeStyle: "rgb(224, 224, 227)"
-                },
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                title: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                grid: {
-                    strokeStyle: "rgb(112, 112, 115)"
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                }
-            }
-        },
-        sprites: {
-            text: {
-                fillStyle: "rgb(224, 224, 227)"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Muted", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.muted", "chart.theme.Muted"],
-    config: {
-        colors: ["#8ca640", "#974144", "#4091ba", "#8e658e", "#3b8d8b", "#b86465", "#d2af69", "#6e8852", "#3dcc7e", "#a6bed1", "#cbaa4b", "#998baa"]
-    }
-});
-Ext.define("Ext.chart.theme.Purple", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple", "chart.theme.Purple"],
-    config: {
-        baseColor: "#da5abd"
-    }
-});
-Ext.define("Ext.chart.theme.PurpleGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple-gradients", "chart.theme.Purple:gradients"],
-    config: {
-        baseColor: "#da5abd",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Red", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red", "chart.theme.Red"],
-    config: {
-        baseColor: "#e84b67"
-    }
-});
-Ext.define("Ext.chart.theme.RedGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red-gradients", "chart.theme.Red:gradients"],
-    config: {
-        baseColor: "#e84b67",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Sky", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky", "chart.theme.Sky"],
-    config: {
-        baseColor: "#4ce0e7"
-    }
-});
-Ext.define("Ext.chart.theme.SkyGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky-gradients", "chart.theme.Sky:gradients"],
-    config: {
-        baseColor: "#4ce0e7",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Yellow", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow", "chart.theme.Yellow"],
-    config: {
-        baseColor: "#fec935"
-    }
-});
-Ext.define("Ext.chart.theme.YellowGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow-gradients", "chart.theme.Yellow:gradients"],
-    config: {
-        baseColor: "#fec935",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.draw.Point", {
-    requires: ["Ext.draw.Draw", "Ext.draw.Matrix"],
-    isPoint: true,
-    x: 0,
-    y: 0,
-    length: 0,
-    angle: 0,
-    angleUnits: "degrees",
-    statics: {
-        fly: (function() {
-            var a = null;
-            return function(b, c) {
-                if (!a) {
-                    a = new Ext.draw.Point()
-                }
-                a.constructor(b, c);
-                return a
-            }
-        })()
-    },
-    constructor: function(a, c) {
-        var b = this;
-        if (typeof a === "number") {
-            b.x = a;
-            if (typeof c === "number") {
-                b.y = c
-            } else {
-                b.y = a
-            }
-        } else {
-            if (Ext.isArray(a)) {
-                b.x = a[0];
-                b.y = a[1]
-            } else {
-                if (a) {
-                    b.x = a.x;
-                    b.y = a.y
-                }
-            }
-        }
-        b.calculatePolar()
-    },
-    calculateCartesian: function() {
-        var b = this,
-            a = b.length,
-            c = b.angle;
-        if (b.angleUnits === "degrees") {
-            c = Ext.draw.Draw.rad(c)
-        }
-        b.x = Math.cos(c) * a;
-        b.y = Math.sin(c) * a
-    },
-    calculatePolar: function() {
-        var b = this,
-            a = b.x,
-            c = b.y;
-        b.length = Math.sqrt(a * a + c * c);
-        b.angle = Math.atan2(c, a);
-        if (b.angleUnits === "degrees") {
-            b.angle = Ext.draw.Draw.degrees(b.angle)
-        }
-    },
-    setX: function(a) {
-        this.x = a;
-        this.calculatePolar()
-    },
-    setY: function(a) {
-        this.y = a;
-        this.calculatePolar()
-    },
-    set: function(a, b) {
-        this.constructor(a, b)
-    },
-    setAngle: function(a) {
-        this.angle = a;
-        this.calculateCartesian()
-    },
-    setLength: function(a) {
-        this.length = a;
-        this.calculateCartesian()
-    },
-    setPolar: function(b, a) {
-        this.angle = b;
-        this.length = a;
-        this.calculateCartesian()
-    },
-    clone: function() {
-        return new Ext.draw.Point(this.x, this.y)
-    },
-    add: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x + b.x, this.y + b.y)
-    },
-    sub: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x - b.x, this.y - b.y)
-    },
-    mul: function(a) {
-        return new Ext.draw.Point(this.x * a, this.y * a)
-    },
-    div: function(a) {
-        return new Ext.draw.Point(this.x / a, this.y / a)
-    },
-    dot: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x * b.x + this.y * b.y
-    },
-    equals: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x === b.x && this.y === b.y
-    },
-    rotate: function(f, c) {
-        var d, e, b, g, a;
-        if (this.angleUnits === "degrees") {
-            f = Ext.draw.Draw.rad(f);
-            d = Math.sin(f);
-            e = Math.cos(f)
-        }
-        if (c) {
-            b = c.x;
-            g = c.y
-        } else {
-            b = 0;
-            g = 0
-        }
-        a = Ext.draw.Matrix.fly([e, d, -d, e, b - e * b + g * d, g - e * g + b * -d]).transformPoint(this);
-        return new Ext.draw.Point(a)
-    },
-    transform: function(a) {
-        if (a && a.isMatrix) {
-            return new Ext.draw.Point(a.transformPoint(this))
-        } else {
-            if (arguments.length === 6) {
-                return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))
-            } else {
-                Ext.raise("Invalid parameters.")
-            }
-        }
-    },
-    round: function() {
-        return new Ext.draw.Point(Math.round(this.x), Math.round(this.y))
-    },
-    ceil: function() {
-        return new Ext.draw.Point(Math.ceil(this.x), Math.ceil(this.y))
-    },
-    floor: function() {
-        return new Ext.draw.Point(Math.floor(this.x), Math.floor(this.y))
-    },
-    abs: function(a, b) {
-        return new Ext.draw.Point(Math.abs(this.x), Math.abs(this.y))
-    },
-    normalize: function(c) {
-        var b = this.x,
-            f = this.y,
-            a, e, d;
-        c = c || 1;
-        if (b === 0) {
-            a = 0;
-            e = c * Ext.Number.sign(f)
-        } else {
-            d = f / b;
-            a = c / Math.sqrt(1 + d * d);
-            e = a * d
-        }
-        return new Ext.draw.Point(a, e)
-    },
-    getDistanceToLine: function(c, b) {
-        if (arguments.length === 4) {
-            c = new Ext.draw.Point(arguments[0], arguments[1]);
-            b = new Ext.draw.Point(arguments[2], arguments[3])
-        }
-        var d = b.sub(c).normalize(),
-            a = c.sub(this);
-        return a.sub(d.mul(a.dot(d)))
-    },
-    isZero: function() {
-        return this.x === 0 && this.y === 0
-    },
-    isNumber: function() {
-        return Ext.isNumber(this.x + this.y)
-    }
-});
-Ext.define("Ext.draw.plugin.SpriteEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.spriteevents",
-    requires: ["Ext.draw.PathUtil"],
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    spriteMouseMoveEvents: {
-        spritemousemove: true,
-        spritemouseover: true,
-        spritemouseout: true
-    },
-    init: function(a) {
-        var b = "handleEvent";
-        this.drawContainer = a;
-        a.addElementListener({
-            click: b,
-            dblclick: b,
-            mousedown: b,
-            mousemove: b,
-            mouseup: b,
-            mouseover: b,
-            mouseout: b,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasSpriteMouseMoveListeners: function() {
-        var b = this.drawContainer.hasListeners,
-            a;
-        for (a in this.spriteMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    hitTestEvent: function(f) {
-        var b = this.drawContainer.getItems(),
-            a, d, c;
-        for (c = b.length - 1; c >= 0; c--) {
-            a = b.get(c);
-            d = a.hitTestEvent(f);
-            if (d) {
-                return d
-            }
-        }
-        return null
-    },
-    handleEvent: function(f) {
-        var d = this,
-            b = d.drawContainer,
-            g = f.type in d.mouseMoveEvents,
-            a = d.lastSprite,
-            c;
-        if (g && !d.hasSpriteMouseMoveListeners()) {
-            return
-        }
-        c = d.hitTestEvent(f);
-        if (g && !Ext.Object.equals(c, a)) {
-            if (a) {
-                b.fireEvent("spritemouseout", a, f)
-            }
-            if (c) {
-                b.fireEvent("spritemouseover", c, f)
-            }
-        }
-        if (c) {
-            b.fireEvent("sprite" + f.type, c, f)
-        }
-        d.lastSprite = c
-    }
-});
-Ext.define("Ext.chart.TipSurface", {
-    extend: "Ext.draw.Container",
-    spriteArray: false,
-    renderFirst: true,
-    constructor: function(a) {
-        this.callParent([a]);
-        if (a.sprites) {
-            this.spriteArray = [].concat(a.sprites);
-            delete a.sprites
-        }
-    },
-    onRender: function() {
-        var c = this,
-            b = 0,
-            a = 0,
-            d, e;
-        this.callParent(arguments);
-        e = c.spriteArray;
-        if (c.renderFirst && e) {
-            c.renderFirst = false;
-            for (a = e.length; b < a; b++) {
-                d = c.surface.add(e[b]);
-                d.setAttributes({
-                    hidden: false
-                }, true)
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.interactions.ItemInfo", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "iteminfo",
-    alias: "interaction.iteminfo",
-    config: {
-        extjsGestures: {
-            start: {
-                event: "click",
-                handler: "onInfoGesture"
-            },
-            move: {
-                event: "mousemove",
-                handler: "onInfoGesture"
-            },
-            end: {
-                event: "mouseleave",
-                handler: "onInfoGesture"
-            }
-        }
-    },
-    item: null,
-    onInfoGesture: function(f, a) {
-        var c = this,
-            b = c.getItemForEvent(f),
-            d = b && b.series.tooltip;
-        if (d) {
-            d.onMouseMove.call(d, f)
-        }
-        if (b !== c.item) {
-            if (b) {
-                b.series.showTip(b)
-            } else {
-                c.item.series.hideTip(c.item)
-            }
-            c.item = b
-        }
-        return false
-    }
-});
\ No newline at end of file
diff --git a/serverside/jsmod/5.4-3/proxmoxlib.js b/serverside/jsmod/5.4-3/proxmoxlib.js
deleted file mode 100644
index 6e316d75b9709a147c7f820c6b9dd9fa07f7f69e..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/proxmoxlib.js
+++ /dev/null
@@ -1,6757 +0,0 @@
-// 1.0-25
-Ext.ns('Proxmox');
-Ext.ns('Proxmox.Setup');
-
-if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
-    throw "Proxmox library not initialized";
-}
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	dir: function() {},
-	log: function() {}
-    };
-}
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (Proxmox.CSRFPreventionToken) {
-	if (!options.headers) {
-	    options.headers = {};
-	}
-	options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-    }
-});
-
-Ext.define('Proxmox.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    enabledText: gettext('Enabled'),
-    disabledText: gettext('Disabled'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    stateText: gettext('State'),
-    groupText: gettext('Group'),
-
-    language_map: {
-	zh_CN: 'Chinese (Simplified)',
-	zh_TW: 'Chinese (Traditional)',
-	ca: 'Catalan',
-	da: 'Danish',
-	en: 'English',
-	eu: 'Euskera (Basque)',
-	fr: 'French',
-	de: 'German',
-	it: 'Italian',
-	es: 'Spanish',
-	ja: 'Japanese',
-	nb: 'Norwegian (Bokmal)',
-	nn: 'Norwegian (Nynorsk)',
-	fa: 'Persian (Farsi)',
-	pl: 'Polish',
-	pt_BR: 'Portuguese (Brazil)',
-	ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	tr: 'Turkish'
-    },
-
-    render_language: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (English)';
-	}
-	var text = Proxmox.Utils.language_map[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    language_array: function() {
-	var data = [['__default__', Proxmox.Utils.render_language('')]];
-	Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
-	    data.push([key, Proxmox.Utils.render_language(value)]);
-	});
-
-	return data;
-    },
-
-    getNoSubKeyHtml: function(url) {
-	// url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
-	return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'http://www.proxmox.com');
-    },
-
-    format_boolean_with_default: function(value) {
-	if (Ext.isDefined(value) && value !== '__default__') {
-	    return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-	}
-	return Proxmox.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-	return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-	return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_enabled_toggle: function(value) {
-	return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
-    },
-
-    format_expire: function(date) {
-	if (!date) {
-	    return Proxmox.Utils.neverText;
-	}
-	return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_duration_long: function(ut) {
-
-	var days = Math.floor(ut / 86400);
-	ut -= days*86400;
-	var hours = Math.floor(ut / 3600);
-	ut -= hours*3600;
-	var mins = Math.floor(ut / 60);
-	ut -= mins*60;
-
-	var hours_str = '00' + hours.toString();
-	hours_str = hours_str.substr(hours_str.length - 2);
-	var mins_str = "00" + mins.toString();
-	mins_str = mins_str.substr(mins_str.length - 2);
-	var ut_str = "00" + ut.toString();
-	ut_str = ut_str.substr(ut_str.length - 2);
-
-	if (days) {
-	    var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
-	    return days.toString() + ' ' + ds + ' ' +
-		hours_str + ':' + mins_str + ':' + ut_str;
-	} else {
-	    return hours_str + ':' + mins_str + ':' + ut_str;
-	}
-    },
-
-    format_subscription_level: function(level) {
-	if (level === 'c') {
-	    return 'Community';
-	} else if (level === 'b') {
-	    return 'Basic';
-	} else if (level === 's') {
-	    return 'Standard';
-	} else if (level === 'p') {
-	    return 'Premium';
-	} else {
-	    return Proxmox.Utils.noneText;
-	}
-    },
-
-    compute_min_label_width: function(text, width) {
-
-	if (width === undefined) { width = 100; }
-
-	var tm = new Ext.util.TextMetrics();
-	var min = tm.getWidth(text + ':');
-
-	return min < width ? width : min;
-    },
-
-    setAuthData: function(data) {
-	Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
-	Proxmox.UserName = data.username;
-	Proxmox.LoggedOut = data.LoggedOut;
-	// creates a session cookie (expire = null)
-	// that way the cookie gets deleted after the browser window is closed
-	Ext.util.Cookies.set(Proxmox.Setup.auth_cookie_name, data.ticket, null, '/', null, true);
-    },
-
-    authOK: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
-    },
-
-    authClear: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-	var el = comp.el;
-	if (!el) {
-	    return;
-	}
-	if (!msg) {
-	    el.unmask();
-	} else {
-	    if (msg === true) {
-		el.mask(gettext("Loading..."));
-	    } else {
-		el.mask(msg);
-	    }
-	}
-    },
-
-    monStoreErrors: function(me, store, clearMaskBeforeLoad) {
-	if (clearMaskBeforeLoad) {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		Proxmox.Utils.setErrorMask(me, false);
-	    });
-	} else {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		if (!me.loadCount) {
-		    me.loadCount = 0; // make sure it is numeric
-		    Proxmox.Utils.setErrorMask(me, true);
-		}
-	    });
-	}
-
-	// only works with 'proxmox' proxy
-	me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-	    me.loadCount++;
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-
-	    var msg;
-	    /*jslint nomen: true */
-	    var operation = request._operation;
-	    var error = operation.getError();
-	    if (error.statusText) {
-		msg = error.statusText + ' (' + error.status + ')';
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    extractRequestError: function(result, verbose) {
-	var msg = gettext('Successful');
-
-	if (!result.success) {
-	    msg = gettext("Unknown error");
-	    if (result.message) {
-		msg = result.message;
-		if (result.status) {
-		    msg += ' (' + result.status + ')';
-		}
-	    }
-	    if (verbose && Ext.isObject(result.errors)) {
-		msg += "<br>";
-		Ext.Object.each(result.errors, function(prop, desc) {
-		    msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
-			Ext.htmlEncode(desc);
-		});
-	    }
-	}
-
-	return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-	var newopts = Ext.apply({
-	    waitMsg: gettext('Please wait...')
-	}, reqOpts);
-
-	if (!newopts.url.match(/^\/api2/)) {
-	    newopts.url = '/api2/extjs' + newopts.url;
-	}
-	delete newopts.callback;
-
-	var createWrapper = function(successFn, callbackFn, failureFn) {
-	    Ext.apply(newopts, {
-		success: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    var result = Ext.decode(response.responseText);
-		    response.result = result;
-		    if (!result.success) {
-			response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.callback(callbackFn, options.scope, [options, false, response]);
-			Ext.callback(failureFn, options.scope, [response, options]);
-			return;
-		    }
-		    Ext.callback(callbackFn, options.scope, [options, true, response]);
-		    Ext.callback(successFn, options.scope, [response, options]);
-		},
-		failure: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    response.result = {};
-		    try {
-			response.result = Ext.decode(response.responseText);
-		    } catch(e) {}
-		    var msg = gettext('Connection error') + ' - server offline?';
-		    if (response.aborted) {
-			msg = gettext('Connection error') + ' - aborted.';
-		    } else if (response.timedout) {
-			msg = gettext('Connection error') + ' - Timeout.';
-		    } else if (response.status && response.statusText) {
-			msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-		    }
-		    response.htmlStatus = msg;
-		    Ext.callback(callbackFn, options.scope, [options, false, response]);
-		    Ext.callback(failureFn, options.scope, [response, options]);
-		}
-	    });
-	};
-
-	createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-	var target = newopts.waitMsgTarget;
-	if (target) {
-	    if (Proxmox.Utils.toolkit === 'touch') {
-		target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-	    } else {
-		// Note: ExtJS bug - this does not work when component is not rendered
-		target.setLoading(newopts.waitMsg);
-	    }
-	}
-	Ext.Ajax.request(newopts);
-    },
-
-    checked_command: function(orig_cmd) {
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/localhost/subscription',
-	    method: 'GET',
-	    //waitMsgTarget: me,
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-
-		if (data.status !== 'Active') {
-		    Ext.Msg.show({
-			title: gettext('No valid subscription'),
-			icon: Ext.Msg.WARNING,
-			msg: Proxmox.Utils.getNoSubKeyHtml(data.url),
-			buttons: Ext.Msg.OK,
-			callback: function(btn) {
-			    if (btn !== 'ok') {
-				return;
-			    }
-			    orig_cmd();
-			}
-		    });
-		} else {
-		    orig_cmd();
-		}
-	    }
-	});
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-	    Ext.Object.each(data, function(name, val) {
-		if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-		    values[name] = val;
-                }
-            });
-	}
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-	if (create) {
-	    if (isAdd) {
-		return gettext('Add') + ': ' + subject;
-	    } else {
-		return gettext('Create') + ': ' + subject;
-	    }
-	} else {
-	    return gettext('Edit') + ': ' + subject;
-	}
-    },
-
-    network_iface_types: {
-	eth: gettext("Network Device"),
-	bridge: 'Linux Bridge',
-	bond: 'Linux Bond',
-	vlan: 'Linux VLAN',
-	OVSBridge: 'OVS Bridge',
-	OVSBond: 'OVS Bond',
-	OVSPort: 'OVS Port',
-	OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-	return Proxmox.Utils.network_iface_types[value] ||
-	    Proxmox.Utils.unknownText;
-    },
-
-    task_desc_table: {
-	acmenewcert: [ 'SRV', gettext('Order Certificate') ],
-	acmeregister: [ 'ACME Account', gettext('Register') ],
-	acmedeactivate: [ 'ACME Account', gettext('Deactivate') ],
-	acmeupdate: [ 'ACME Account', gettext('Update') ],
-	acmerefresh: [ 'ACME Account', gettext('Refresh') ],
-	acmerenew: [ 'SRV', gettext('Renew Certificate') ],
-	acmerevoke: [ 'SRV', gettext('Revoke Certificate') ],
-	'move_volume': [ 'CT', gettext('Move Volume') ],
-	clustercreate: [ '', gettext('Create Cluster') ],
-	clusterjoin: [ '', gettext('Join Cluster') ],
-	diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ],
-	vncproxy: [ 'VM/CT', gettext('Console') ],
-	spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-	vncshell: [ '', gettext('Shell') ],
-	spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-	qmsnapshot: [ 'VM', gettext('Snapshot') ],
-	qmrollback: [ 'VM', gettext('Rollback') ],
-	qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-	qmcreate: [ 'VM', gettext('Create') ],
-	qmrestore: [ 'VM', gettext('Restore') ],
-	qmdestroy: [ 'VM', gettext('Destroy') ],
-	qmigrate: [ 'VM', gettext('Migrate') ],
-	qmclone: [ 'VM', gettext('Clone') ],
-	qmmove: [ 'VM', gettext('Move disk') ],
-	qmtemplate: [ 'VM', gettext('Convert to template') ],
-	qmstart: [ 'VM', gettext('Start') ],
-	qmstop: [ 'VM', gettext('Stop') ],
-	qmreset: [ 'VM', gettext('Reset') ],
-	qmshutdown: [ 'VM', gettext('Shutdown') ],
-	qmsuspend: [ 'VM', gettext('Hibernate') ],
-	qmpause: [ 'VM', gettext('Pause') ],
-	qmresume: [ 'VM', gettext('Resume') ],
-	qmconfig: [ 'VM', gettext('Configure') ],
-	vzsnapshot: [ 'CT', gettext('Snapshot') ],
-	vzrollback: [ 'CT', gettext('Rollback') ],
-	vzdelsnapshot: [ 'CT', gettext('Delete Snapshot') ],
-	vzcreate: ['CT', gettext('Create') ],
-	vzrestore: ['CT', gettext('Restore') ],
-	vzdestroy: ['CT', gettext('Destroy') ],
-	vzmigrate: [ 'CT', gettext('Migrate') ],
-	vzclone: [ 'CT', gettext('Clone') ],
-	vztemplate: [ 'CT', gettext('Convert to template') ],
-	vzstart: ['CT', gettext('Start') ],
-	vzstop: ['CT', gettext('Stop') ],
-	vzmount: ['CT', gettext('Mount') ],
-	vzumount: ['CT', gettext('Unmount') ],
-	vzshutdown: ['CT', gettext('Shutdown') ],
-	vzsuspend: [ 'CT', gettext('Suspend') ],
-	vzresume: [ 'CT', gettext('Resume') ],
-	hamigrate: [ 'HA', gettext('Migrate') ],
-	hastart: [ 'HA', gettext('Start') ],
-	hastop: [ 'HA', gettext('Stop') ],
-	srvstart: ['SRV', gettext('Start') ],
-	srvstop: ['SRV', gettext('Stop') ],
-	srvrestart: ['SRV', gettext('Restart') ],
-	srvreload: ['SRV', gettext('Reload') ],
-	cephcreatemgr: ['Ceph Manager', gettext('Create') ],
-	cephdestroymgr: ['Ceph Manager', gettext('Destroy') ],
-	cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-	cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-	cephcreateosd: ['Ceph OSD', gettext('Create') ],
-	cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-	cephcreatepool: ['Ceph Pool', gettext('Create') ],
-	cephdestroypool: ['Ceph Pool', gettext('Destroy') ],
-	cephfscreate: ['CephFS', gettext('Create') ],
-	cephcreatemds: ['Ceph Metadata Server', gettext('Create') ],
-	cephdestroymds: ['Ceph Metadata Server', gettext('Destroy') ],
-	imgcopy: ['', gettext('Copy data') ],
-	imgdel: ['', gettext('Erase data') ],
-	unknownimgdel: ['', gettext('Destroy image from unknown guest') ],
-	download: ['', gettext('Download') ],
-	vzdump: ['VM/CT', gettext('Backup') ],
-	aptupdate: ['', gettext('Update package database') ],
-	startall: [ '', gettext('Start all VMs and Containers') ],
-	stopall: [ '', gettext('Stop all VMs and Containers') ],
-	migrateall: [ '', gettext('Migrate all VMs and Containers') ],
-	dircreate: [ gettext('Directory Storage'), gettext('Create') ],
-	lvmcreate: [ gettext('LVM Storage'), gettext('Create') ],
-	lvmthincreate: [ gettext('LVM-Thin Storage'), gettext('Create') ],
-	zfscreate: [ gettext('ZFS Storage'), gettext('Create') ]
-    },
-
-    format_task_description: function(type, id) {
-	var farray = Proxmox.Utils.task_desc_table[type];
-	var text;
-	if (!farray) {
-	    text = type;
-	    if (id) {
-		type += ' ' + id;
-	    }
-	    return text;
-	}
-	var prefix = farray[0];
-	text = farray[1];
-	if (prefix) {
-	    return prefix + ' ' + id + ' - ' + text;
-	}
-	return text;
-    },
-
-    format_size: function(size) {
-	/*jslint confusion: true */
-
-	var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
-	var num = 0;
-
-	while (size >= 1024 && ((num++)+1) < units.length) {
-	    size = size / 1024;
-	}
-
-	return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    render_uptime: function(value) {
-
-	var uptime = value;
-
-	if (uptime === undefined) {
-	    return '';
-	}
-
-	if (uptime <= 0) {
-	    return '-';
-	}
-
-	return Proxmox.Utils.format_duration_long(uptime);
-    },
-
-    parse_task_upid: function(upid) {
-	var task = {};
-
-	var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-	if (!res) {
-	    throw "unable to parse upid '" + upid + "'";
-	}
-	task.node = res[1];
-	task.pid = parseInt(res[2], 16);
-	task.pstart = parseInt(res[3], 16);
-	task.starttime = parseInt(res[4], 16);
-	task.type = res[5];
-	task.id = res[6];
-	task.user = res[7];
-
-	task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	return task;
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-	var servertime = new Date(value * 1000);
-	return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    openXtermJsViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    xtermjs: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    cmd: cmd,
-
-	});
-	var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
-	if (nw) {
-	    nw.focus();
-	}
-    }
-
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-
-	var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-	var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-	var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-	var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-
-
-	me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-	me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/([0-9]{1,2})$");
-
-	var IPV6_REGEXP = "(?:" +
-	    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-	    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-	    ")";
-
-	me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-	me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/([0-9]{1,3})$");
-	me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-	me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-
-	var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
-	me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
-
-	me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
-	me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
-	me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
-    }
-});
-// ExtJS related things
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-	return Proxmox.Utils.IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP4_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 32);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24' + "<br>" + gettext('Valid CIDR Range') + ': 8-32',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return Proxmox.Utils.IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP6_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 128);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64' + "<br>" + gettext('Valid CIDR Range') + ': 8-128',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-	return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-
-    IP64Address:  function(v) {
-        return Proxmox.Utils.IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    MacAddress: function(v) {
-	return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    MacPrefix:  function(v) {
-	return (/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i).test(v);
-    },
-    MacPrefixMask: /[a-fA-F0-9:]/,
-    MacPrefixText: gettext('Example') + ': 02:8f - ' + gettext('only unicast addresses are allowed'),
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext("Allowed characters") + ": 'a-z', '0-9', '_'" + "<br />" +
-		       gettext("Minimum characters") + ": 2" + "<br />" +
-		       gettext("Maximum characters") + ": 21" + "<br />" +
-		       gettext("Must start with") + ": 'a-z'",
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'" + "<br />" +
-		   gettext("Minimum characters") + ": 2" + "<br />" +
-		   gettext("Must start with") + ": 'A-Z', 'a-z'<br />" +
-		   gettext("Must end with") + ": 'A-Z', 'a-z', '0-9'<br />",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'" + "<br />" +
-		  gettext("Minimum characters") + ": 2" + "<br />" +
-		  gettext("Must start with") + ": " + gettext("letter"),
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-	return Proxmox.Utils.DnsName_match.test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name'),
-
-    // workaround for https://www.sencha.com/forum/showthread.php?302150
-    proxmoxMail: function(v) {
-        return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
-    },
-    proxmoxMailText: gettext('Example') + ": user@example.com",
-
-    DnsOrIp: function(v) {
-	if (!Proxmox.Utils.DnsName_match.test(v) &&
-	    !Proxmox.Utils.IP64_match.test(v)) {
-	    return false;
-	}
-
-	return true;
-    },
-    DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
-
-    HostList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == "") {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
-		!Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
-		!Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    HostListText: gettext('Not a valid list of hosts'),
-
-    password: function(val, field) {
-        if (field.initialPassField) {
-            var pwd = field.up('form').down(
-		'[name=' + field.initialPassField + ']');
-            return (val == pwd.getValue());
-        }
-        return true;
-    },
-
-    passwordText: gettext('Passwords do not match')
-});
-
-// Firefox 52+ Touchscreen bug
-// see https://www.sencha.com/forum/showthread.php?336762-Examples-don-t-work-in-Firefox-52-touchscreen/page2
-// and https://bugzilla.proxmox.com/show_bug.cgi?id=1223
-Ext.define('EXTJS_23846.Element', {
-    override: 'Ext.dom.Element'
-}, function(Element) {
-    var supports = Ext.supports,
-        proto = Element.prototype,
-        eventMap = proto.eventMap,
-        additiveEvents = proto.additiveEvents;
-
-    if (Ext.os.is.Desktop && supports.TouchEvents && !supports.PointerEvents) {
-        eventMap.touchstart = 'mousedown';
-        eventMap.touchmove = 'mousemove';
-        eventMap.touchend = 'mouseup';
-        eventMap.touchcancel = 'mouseup';
-
-        additiveEvents.mousedown = 'mousedown';
-        additiveEvents.mousemove = 'mousemove';
-        additiveEvents.mouseup = 'mouseup';
-        additiveEvents.touchstart = 'touchstart';
-        additiveEvents.touchmove = 'touchmove';
-        additiveEvents.touchend = 'touchend';
-        additiveEvents.touchcancel = 'touchcancel';
-
-        additiveEvents.pointerdown = 'mousedown';
-        additiveEvents.pointermove = 'mousemove';
-        additiveEvents.pointerup = 'mouseup';
-        additiveEvents.pointercancel = 'mouseup';
-    }
-});
-
-Ext.define('EXTJS_23846.Gesture', {
-    override: 'Ext.event.publisher.Gesture'
-}, function(Gesture) {
-    var me = Gesture.instance;
-
-    if (Ext.supports.TouchEvents && !Ext.isWebKit && Ext.os.is.Desktop) {
-        me.handledDomEvents.push('mousedown', 'mousemove', 'mouseup');
-        me.registerEvents();
-    }
-});
-
-// we always want the number in x.y format and never in, e.g., x,y
-Ext.define('PVE.form.field.Number', {
-    override: 'Ext.form.field.Number',
-    submitLocaleSeparator: false
-});
-
-// ExtJs 5-6 has an issue with caching
-// see https://www.sencha.com/forum/showthread.php?308989
-Ext.define('Proxmox.UnderlayPool', {
-    override: 'Ext.dom.UnderlayPool',
-
-    checkOut: function () {
-        var cache = this.cache,
-            len = cache.length,
-            el;
-
-        // do cleanup because some of the objects might have been destroyed
-	while (len--) {
-            if (cache[len].destroyed) {
-                cache.splice(len, 1);
-            }
-        }
-        // end do cleanup
-
-	el = cache.shift();
-
-        if (!el) {
-            el = Ext.Element.create(this.elementConfig);
-            el.setVisibilityMode(2);
-            //<debug>
-            // tell the spec runner to ignore this element when checking if the dom is clean
-	    el.dom.setAttribute('data-sticky', true);
-            //</debug>
-	}
-
-        return el;
-    }
-});
-
-// 'Enter' in Textareas and aria multiline fields should not activate the
-// defaultbutton, fixed in extjs 6.0.2
-Ext.define('PVE.panel.Panel', {
-    override: 'Ext.panel.Panel',
-
-    fireDefaultButton: function(e) {
-	if (e.target.getAttribute('aria-multiline') === 'true' ||
-	    e.target.tagName === "TEXTAREA") {
-	    return true;
-	}
-	return this.callParent(arguments);
-    }
-});
-
-// if the order of the values are not the same in originalValue and value
-// extjs will not overwrite value, but marks the field dirty and thus
-// the reset button will be enabled (but clicking it changes nothing)
-// so if the arrays are not the same after resetting, we
-// clear and set it
-Ext.define('Proxmox.form.ComboBox', {
-    override: 'Ext.form.field.ComboBox',
-
-    reset: function() {
-	// copied from combobox
-	var me = this;
-	me.callParent();
-
-	// clear and set when not the same
-	var value = me.getValue();
-	if (Ext.isArray(me.originalValue) && Ext.isArray(value) && !Ext.Array.equals(value, me.originalValue)) {
-	    me.clearValue();
-	    me.setValue(me.originalValue);
-	}
-    }
-});
-
-// when refreshing a grid/tree view, restoring the focus moves the view back to
-// the previously focused item. Save scroll position before refocusing.
-Ext.define(null, {
-    override: 'Ext.view.Table',
-
-    jumpToFocus: false,
-
-    saveFocusState: function() {
-        var me = this,
-            store = me.dataSource,
-            actionableMode = me.actionableMode,
-            navModel = me.getNavigationModel(),
-            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
-            refocusRow, refocusCol;
-
-        if (focusPosition) {
-            // Separate this from the instance that the nav model is using.
-            focusPosition = focusPosition.clone();
-
-            // Exit actionable mode.
-            // We must inform any Actionables that they must relinquish control.
-            // Tabbability must be reset.
-            if (actionableMode) {
-                me.ownerGrid.setActionableMode(false);
-            }
-
-            // Blur the focused descendant, but do not trigger focusLeave.
-            me.el.dom.focus();
-
-            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
-            // clear the navigation position
-            navModel.setPosition();
-
-            // The following function will attempt to refocus back in the same mode to the same cell
-            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
-            return function() {
-                // If we still have data, attempt to refocus in the same mode.
-                if (store.getCount()) {
-
-                    // Adjust expectations of where we are able to refocus according to what kind of destruction
-                    // might have been wrought on this view's DOM during focus save.
-                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
-                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
-                    focusPosition = new Ext.grid.CellContext(me).setPosition(
-                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
-
-                    if (actionableMode) {
-                        me.ownerGrid.setActionableMode(true, focusPosition);
-                    } else {
-                        me.cellFocused = true;
-
-			// we sometimes want to scroll back to where we were
-			var x = me.getScrollX();
-			var y = me.getScrollY();
-
-                        // Pass "preventNavigation" as true so that that does not cause selection.
-                        navModel.setPosition(focusPosition, null, null, null, true);
-
-			if (!me.jumpToFocus) {
-			    me.scrollTo(x,y);
-			}
-                    }
-                }
-                // No rows - focus associated column header
-                else {
-                    focusPosition.column.focus();
-                }
-            };
-        }
-        return Ext.emptyFn;
-    }
-});
-
-// should be fixed with ExtJS 6.0.2, see:
-// https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
-Ext.define('Proxmox.Datepicker', {
-    override: 'Ext.picker.Date',
-    hideMode: 'visibility'
-});
-
-// ExtJS 6.0.1 has no setSubmitValue() (although you find it in the docs).
-// Note: this.submitValue is a boolean flag, whereas getSubmitValue() returns
-// data to be submitted.
-Ext.define('Proxmox.form.field.Text', {
-    override: 'Ext.form.field.Text',
-
-    setSubmitValue: function(v) {
-	this.submitValue = v;
-    },
-});
-
-// this should be fixed with ExtJS 6.0.2
-// make mousescrolling work in firefox in the containers overflowhandler
-Ext.define(null, {
-    override: 'Ext.layout.container.boxOverflow.Scroller',
-
-    createWheelListener: function() {
-	var me = this;
-	if (Ext.isFirefox) {
-	    me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
-	} else {
-	    me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
-	}
-    },
-
-    // special wheel handler for firefox. differs from the default onMouseWheel
-    // handler by using deltaY instead of wheelDeltaY and no normalizing,
-    // because it is already
-    onMouseWheelFirefox: function(e) {
-	e.stopEvent();
-	var delta = e.browserEvent.deltaY || 0;
-	this.scrollBy(delta * this.wheelIncrement, false);
-    }
-
-});
-
-// force alert boxes to be rendered with an Error Icon
-// since Ext.Msg is an object and not a prototype, we need to override it
-// after the framework has been initiated
-Ext.onReady(function() {
-/*jslint confusion: true */
-    Ext.override(Ext.Msg, {
-	alert: function(title, message, fn, scope) {
-	    if (Ext.isString(title)) {
-		var config = {
-		    title: title,
-		    message: message,
-		    icon: this.ERROR,
-		    buttons: this.OK,
-		    fn: fn,
-		    scope : scope,
-		    minWidth: this.minWidth
-		};
-	    return this.show(config);
-	    }
-	}
-    });
-/*jslint confusion: false */
-});
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" id="{id}-iframeEl" data-ref="iframeEl" name="{frameName}" width="100%" height="100%" frameborder="0" allowfullscreen="true"></iframe>'
-    ],
-    childEls: ['iframeEl'],
-
-    initComponent: function () {
-        this.callParent();
-
-        this.frameName = this.frameName || this.id + '-frame';
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-                doc = this.getDoc();
-                if (doc) {
-		    /*jslint nomen: true*/
-                    Ext.get(doc).un(this._docListeners);
-		    /*jslint nomen: false*/
-                    if (destroying && doc.hasOwnProperty) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-		/*jslint nomen: true*/
-                Ext.get(doc).on(
-                    me._docListeners = {
-                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                        mousemove: fn, // window resize drag detection
-                        mouseup: fn,   // window resize termination
-                        click: fn,     // not sure, but just to be safe
-                        dblclick: fn,  // not sure again
-                        scope: me
-                    }
-                );
-		/*jslint nomen: false*/
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.get(this.getWin()).on('beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if (me.src) {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    onRelayedEvent: function (event) {
-        // relay event from the iframe's document to the document that owns the iframe...
-
-        var iframeEl = this.iframeEl,
-
-            // Get the left-based iframe position
-            iframeXY = iframeEl.getTrueXY(),
-            originalEventXY = event.getXY(),
-
-            // Get the left-based XY position.
-            // This is because the consumer of the injected event will
-            // perform its own RTL normalization.
-            eventXY = event.getTrueXY();
-
-        // the event from the inner document has XY relative to that document's origin,
-        // so adjust it to use the origin of the iframe in the outer document:
-        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
-
-        event.injectEvent(iframeEl); // blame the iframe for the event...
-
-        event.xy = originalEventXY; // restore the original XY (just for safety)
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
-Ext.define('Proxmox.Mixin.CBind', {
-    extend: 'Ext.Mixin',
-
-    mixinConfig: {
-        before: {
-            initComponent: 'cloneTemplates'
-        }
-    },
-
-    cloneTemplates: function() {
-	var me = this;
-	
- 	if (typeof(me.cbindData) == "function") {
-	    me.cbindData = me.cbindData(me.initialConfig) || {};
-	}
-	
-	var getConfigValue = function(cname) {
-
-	    if (cname in me.initialConfig) {
-		return me.initialConfig[cname];
-	    }
-	    if (cname in me.cbindData) {
-		return me.cbindData[cname];
-	    }	    
-	    if (cname in me) {
-		return me[cname];
-	    }
-	    throw "unable to get cbind data for '" + cname + "'";
-	};
-	
-	var applyCBind = function(obj) {
-	    var cbind = obj.cbind, prop, cdata, cvalue, match, found;
-	    if (!cbind) return;
-
-	    for (prop in cbind) {
-		cdata = cbind[prop];
-
-		found = false;
-		if (match = /^\{(!)?([a-z_][a-z0-9_]*)\}$/i.exec(cdata)) {
-		    var cvalue = getConfigValue(match[2]);
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)+)\}$/i.exec(cdata)) {
-		    var keys = match[2].split('.');
-		    var cvalue = getConfigValue(keys.shift());
-		    keys.forEach(function(k) {
-			if (k in cvalue) {
-			    cvalue = cvalue[k];
-			} else {
-			    throw "unable to get cbind data for '" + match[2] + "'";
-			}
-		    });
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else {
-		    obj[prop] = cdata.replace(/{([a-z_][a-z0-9_]*)\}/ig, function(match, cname) {
-			var cvalue = getConfigValue(cname);
-			found = true;
-			return cvalue;
-		    });
-		}
-		if (!found) {
-		    throw "unable to parse cbind template '" + cdata + "'";
-		}
-
-	    }
-	};
-
-	if (me.cbind) {
-	    applyCBind(me);
-	}
-	
-	var cloneTemplateArray = function(org) {
-	    var copy, i, found, el, elcopy, arrayLength;
-
-	    arrayLength = org.length;
-	    found = false;
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    found = true;
-		    break;
-		}
-	    }
-
-	    if (!found) return org; // no need to copy
-
-	    copy = [];
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    elcopy = cloneTemplateObject(el);
-		    if (elcopy.cbind) {
-			applyCBind(elcopy);
-		    }
-		    copy.push(elcopy);
-		} else if (el.constructor == Array) {
-		    elcopy = cloneTemplateArray(el);
-		    copy.push(elcopy);
-		} else {
-		    copy.push(el);
-		}
-	    }
-	    return copy;
-	};
-	
-	var cloneTemplateObject = function(org) {
-	    var res = {}, prop, el, copy;
-	    for (prop in org) {
-		el = org[prop];
-		if (el.constructor == Object && el.xtype) {
-		    copy = cloneTemplateObject(el);
-		    if (copy.cbind) {
-			applyCBind(copy);
-		    }
-		    res[prop] = copy;
-		} else if (el.constructor == Array) {
-		    copy = cloneTemplateArray(el);
-		    res[prop] = copy;
-		} else {
-		    res[prop] = el;
-		}
-	    }
-	    return res;
-	};
-
-	var condCloneProperties = function() {
-	    var prop, el, i, tmp;
-	
-	    for (prop in me) {
-		el = me[prop];
-		if (el === undefined || el === null) continue;
-		if (typeof(el) === 'object' && el.constructor == Object) {
-		    if (el.xtype && prop != 'config') {
-			me[prop] = cloneTemplateObject(el);
-		    }
-		} else if (el.constructor == Array) {
-		    tmp = cloneTemplateArray(el);
-		    me[prop] = tmp;
-		}
-	    }
-	};
-
-	condCloneProperties();
-    }
-});
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash. 
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"} 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ] 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('Proxmox.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-    
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-	me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-	var me = this;
-
-	var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-	    if (me.readArray) {
-
-		var rec_hash = {};
-		Ext.Array.each(root, function(rec) {
-		    if (Ext.isDefined(rec.key)) {
-			rec_hash[rec.key] = rec;
-		    }
-		});
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			var rec = rec_hash[key];
-			if (Ext.isDefined(rec)) {
-			    if (!Ext.isDefined(rec.value)) {
-				rec.value = rowdef.defaultValue;
-			    }
-			    data.push(rec);
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue} );
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined });
-			}
-		    });
-		} else {
-		    Ext.Array.each(root, function(rec) {
-			if (Ext.isDefined(rec.key)) {
-			    data.push(rec);
-			}
-		    });
-		}
-		
-	    } else { 
-		
-		var org_root = root;
-
-		if (Ext.isArray(org_root)) {
-		    if (root.length == 1) {
-			root = org_root[0];
-		    } else {
-			root = {};
-		    }
-		}
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			if (Ext.isDefined(root[key])) {
-			    data.push({key: key, value: root[key]});
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue});
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined});
-			}
-		    });
-		} else {
-		    Ext.Object.each(root, function(key, value) {
-			data.push({key: key, value: value });
-		    });
-		}
-	    }
-	}
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-	return data;
-    }
-});
-
-Ext.define('Proxmox.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.proxmox',
-
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-
-    afterRequest: function(request, success) {
-	this.fireEvent('afterload', this, request, success);
-	return;
-    },
-
-    constructor: function(config) {
-
-	Ext.applyIf(config, {
-	    reader: {
-		type: 'json',
-		rootProperty: config.root || 'data'
-	    }
-	});
-
-	this.callParent([config]);
-    }
-}, function() {
-
-    Ext.define('KeyValue', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value', 'pending', 'delete' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('proxmox-tasks', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'starttime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'endtime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'upid', 'user', 'status', 'type', 'id'
-	],
-	idProperty: 'upid'
-    });
-
-    Ext.define('proxmox-cluster-log', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'uid' , type: 'int' },
-	    { name: 'time', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pri', type: 'int' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'user', 'tag', 'msg',
-	    {
-		name: 'id',
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-		    // compute unique ID
-		    return info.uid + ':' + info.node;
-		}
-	    }
-	],
-	idProperty: 'id'
-    });
-
-});
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- *
- * Note that you have to call yourself startUpdate() for the background load
- * to begin
- */
-Ext.define('Proxmox.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.update',
-
-    isStopped: true,
-
-    autoStart: false,
-
-    destroy: function() {
-	var me = this;
-	me.stopUpdate();
-	me.callParent();
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.interval) {
-	    config.interval = 3000;
-	}
-
-	if (!config.storeid) {
-	    throw "no storeid specified";
-	}
-
-	var load_task = new Ext.util.DelayedTask();
-
-	var run_load_task = function() {
-	    if (me.isStopped) {
-		return;
-	    }
-
-	    if (Proxmox.Utils.authOK()) {
-		var start = new Date();
-		me.load(function() {
-		    var runtime = (new Date()) - start;
-		    var interval = config.interval + runtime*2;
-		    load_task.delay(interval, run_load_task);
-		});
-	    } else {
-		load_task.delay(200, run_load_task);
-	    }
-	};
-
-	Ext.apply(config, {
-	    startUpdate: function() {
-		me.isStopped = false;
-		// run_load_task(); this makes problems with chrome
-		load_task.delay(1, run_load_task);
-	    },
-	    stopUpdate: function() {
-		me.isStopped = true;
-		load_task.cancel();
-	    }
-	});
-
-	me.callParent([config]);
-
-	me.load_task = load_task;
-
-	if (me.autoStart) {
-	    me.startUpdate();
-	}
-    }
-});
-/*
- * The DiffStore is a in-memory store acting as proxy between a real store
- * instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the real store, to avoid the annoying visual flickering of using
- * the real store directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the real store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: the realstore which will autorefresh its content from the API
- * Only works if rstore has a model and use 'idProperty'
- * sortAfterUpdate: sort the diffstore before rendering the view
- */
-Ext.define('Proxmox.data.DiffStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.diff',
-
-    sortAfterUpdate: false,
-    
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.rstore) {
-	    throw "no rstore specified";
-	}
-
-	if (!config.rstore.model) {
-	    throw "no rstore model specified";
-	}
-
-	var rstore = config.rstore;
-
-	Ext.apply(config, {
-	    model: rstore.model,
-	    proxy: { type: 'memory' }
-	});
-
-	me.callParent([config]);
-
-	var first_load = true;
-
-	var cond_add_item = function(data, id) {
-	    var olditem = me.getById(id);
-	    if (olditem) {
-		olditem.beginEdit();
-		Ext.Array.each(me.model.prototype.fields, function(field) {
-		    if (olditem.data[field.name] !== data[field.name]) {
-			olditem.set(field.name, data[field.name]);
-		    }
-		});
-		olditem.endEdit(true);
-		olditem.commit(); 
-	    } else {
-		var newrec = Ext.create(me.model, data);
-		var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-		me.insert(pos, newrec);
-	    }
-	};
-
-	var loadFn = function(s, records, success) {
-
-	    if (!success) {
-		return;
-	    }
-
-	    me.suspendEvents();
-
-	    // getSource returns null if data is not filtered
-	    // if it is filtered it returns all records
-	    var allItems = me.getData().getSource() || me.getData();
-
-	    // remove vanished items
-	    allItems.each(function(olditem) {
-		var item = rstore.getById(olditem.getId());
-		if (!item) {
-		    me.remove(olditem);
-		}
-	    });
-
-	    rstore.each(function(item) {
-		cond_add_item(item.data, item.getId());
-	    });
-
-	    me.filter();
-
-	    if (me.sortAfterUpdate) {
-		me.sort();
-	    }
-
-	    first_load = false;
-
-	    me.resumeEvents();
-	    me.fireEvent('refresh', me);
-	    me.fireEvent('datachanged', me);
-	};
-
-	if (rstore.isLoaded()) {
-	    // if store is already loaded,
-	    // insert items instantly
-	    loadFn(rstore, [], true);
-	}
-
-	me.mon(rstore, 'load', loadFn);
-    }
-});
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('Proxmox.data.ObjectStore',  {
-    extend: 'Proxmox.data.UpdateStore',
-
-    getRecord: function() {
-	var me = this;
-	var record = Ext.create('Ext.data.Model');
-	me.getData().each(function(item) {
-	    record.set(item.data.key, item.data.value);
-	});
-	record.commit(true);
-	return record;
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-        config = config || {};
-
-	if (!config.storeid) {
-	    config.storeid =  'proxmox-store-' + (++Ext.idSeed);
-	}
-
-        Ext.applyIf(config, {
-	    model: 'KeyValue',
-            proxy: {
-                type: 'proxmox',
-		url: config.url,
-		extraParams: config.extraParams,
-                reader: {
-		    type: 'jsonobject',
-		    rows: config.rows,
-		    readArray: config.readArray,
-		    rootProperty: config.root || 'data'
-		}
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
-/* Extends the Proxmox.data.UpdateStore type
- *
- *
- */
-Ext.define('Proxmox.data.RRDStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    alias: 'store.proxmoxRRDStore',
-
-    setRRDUrl: function(timeframe, cf) {
-	var me = this;
-	if (!timeframe) {
-	    timeframe = me.timeframe;
-	}
-
-	if (!cf) {
-	    cf = me.cf;
-	}
-
-	me.proxy.url = me.rrdurl + "?timeframe=" + timeframe + "&cf=" + cf;
-    },
-
-    proxy: {
-	type: 'proxmox'
-    },
-
-    timeframe: 'hour',
-
-    cf: 'AVERAGE',
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	// set default interval to 30seconds
-	if (!config.interval) {
-	    config.interval = 30000;
-	}
-
-	// set a new storeid
-	if (!config.storeid) {
-	    config.storeid = 'rrdstore-' + (++Ext.idSeed);
-	}
-
-	// rrdurl is required
-	if (!config.rrdurl) {
-	    throw "no rrdurl specified";
-	}
-
-	var stateid = 'proxmoxRRDTypeSelection';
-	var sp = Ext.state.Manager.getProvider();
-	var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-	    if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-		me.timeframe = stateinit.timeframe;
-		me.rrdcffn = stateinit.cf;
-	    }
-	}
-
-	me.callParent([config]);
-
-	me.setRRDUrl();
-	me.mon(sp, 'statechange', function(prov, key, state){
-	    if (key === stateid) {
-		if (state && state.id) {
-		    if (state.timeframe !== me.timeframe || state.cf !== me.cf) {
-		        me.timeframe = state.timeframe;
-		        me.cf = state.cf;
-			me.setRRDUrl();
-			me.reload();
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Timezone', {
-    extend: 'Ext.data.Model',
-    fields: ['zone']
-});
-
-Ext.define('Proxmox.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-    model: 'Timezone',
-    data: [
-	    ['Africa/Abidjan'],
-	    ['Africa/Accra'],
-	    ['Africa/Addis_Ababa'],
-	    ['Africa/Algiers'],
-	    ['Africa/Asmara'],
-	    ['Africa/Bamako'],
-	    ['Africa/Bangui'],
-	    ['Africa/Banjul'],
-	    ['Africa/Bissau'],
-	    ['Africa/Blantyre'],
-	    ['Africa/Brazzaville'],
-	    ['Africa/Bujumbura'],
-	    ['Africa/Cairo'],
-	    ['Africa/Casablanca'],
-	    ['Africa/Ceuta'],
-	    ['Africa/Conakry'],
-	    ['Africa/Dakar'],
-	    ['Africa/Dar_es_Salaam'],
-	    ['Africa/Djibouti'],
-	    ['Africa/Douala'],
-	    ['Africa/El_Aaiun'],
-	    ['Africa/Freetown'],
-	    ['Africa/Gaborone'],
-	    ['Africa/Harare'],
-	    ['Africa/Johannesburg'],
-	    ['Africa/Kampala'],
-	    ['Africa/Khartoum'],
-	    ['Africa/Kigali'],
-	    ['Africa/Kinshasa'],
-	    ['Africa/Lagos'],
-	    ['Africa/Libreville'],
-	    ['Africa/Lome'],
-	    ['Africa/Luanda'],
-	    ['Africa/Lubumbashi'],
-	    ['Africa/Lusaka'],
-	    ['Africa/Malabo'],
-	    ['Africa/Maputo'],
-	    ['Africa/Maseru'],
-	    ['Africa/Mbabane'],
-	    ['Africa/Mogadishu'],
-	    ['Africa/Monrovia'],
-	    ['Africa/Nairobi'],
-	    ['Africa/Ndjamena'],
-	    ['Africa/Niamey'],
-	    ['Africa/Nouakchott'],
-	    ['Africa/Ouagadougou'],
-	    ['Africa/Porto-Novo'],
-	    ['Africa/Sao_Tome'],
-	    ['Africa/Tripoli'],
-	    ['Africa/Tunis'],
-	    ['Africa/Windhoek'],
-	    ['America/Adak'],
-	    ['America/Anchorage'],
-	    ['America/Anguilla'],
-	    ['America/Antigua'],
-	    ['America/Araguaina'],
-	    ['America/Argentina/Buenos_Aires'],
-	    ['America/Argentina/Catamarca'],
-	    ['America/Argentina/Cordoba'],
-	    ['America/Argentina/Jujuy'],
-	    ['America/Argentina/La_Rioja'],
-	    ['America/Argentina/Mendoza'],
-	    ['America/Argentina/Rio_Gallegos'],
-	    ['America/Argentina/Salta'],
-	    ['America/Argentina/San_Juan'],
-	    ['America/Argentina/San_Luis'],
-	    ['America/Argentina/Tucuman'],
-	    ['America/Argentina/Ushuaia'],
-	    ['America/Aruba'],
-	    ['America/Asuncion'],
-	    ['America/Atikokan'],
-	    ['America/Bahia'],
-	    ['America/Bahia_Banderas'],
-	    ['America/Barbados'],
-	    ['America/Belem'],
-	    ['America/Belize'],
-	    ['America/Blanc-Sablon'],
-	    ['America/Boa_Vista'],
-	    ['America/Bogota'],
-	    ['America/Boise'],
-	    ['America/Cambridge_Bay'],
-	    ['America/Campo_Grande'],
-	    ['America/Cancun'],
-	    ['America/Caracas'],
-	    ['America/Cayenne'],
-	    ['America/Cayman'],
-	    ['America/Chicago'],
-	    ['America/Chihuahua'],
-	    ['America/Costa_Rica'],
-	    ['America/Cuiaba'],
-	    ['America/Curacao'],
-	    ['America/Danmarkshavn'],
-	    ['America/Dawson'],
-	    ['America/Dawson_Creek'],
-	    ['America/Denver'],
-	    ['America/Detroit'],
-	    ['America/Dominica'],
-	    ['America/Edmonton'],
-	    ['America/Eirunepe'],
-	    ['America/El_Salvador'],
-	    ['America/Fortaleza'],
-	    ['America/Glace_Bay'],
-	    ['America/Godthab'],
-	    ['America/Goose_Bay'],
-	    ['America/Grand_Turk'],
-	    ['America/Grenada'],
-	    ['America/Guadeloupe'],
-	    ['America/Guatemala'],
-	    ['America/Guayaquil'],
-	    ['America/Guyana'],
-	    ['America/Halifax'],
-	    ['America/Havana'],
-	    ['America/Hermosillo'],
-	    ['America/Indiana/Indianapolis'],
-	    ['America/Indiana/Knox'],
-	    ['America/Indiana/Marengo'],
-	    ['America/Indiana/Petersburg'],
-	    ['America/Indiana/Tell_City'],
-	    ['America/Indiana/Vevay'],
-	    ['America/Indiana/Vincennes'],
-	    ['America/Indiana/Winamac'],
-	    ['America/Inuvik'],
-	    ['America/Iqaluit'],
-	    ['America/Jamaica'],
-	    ['America/Juneau'],
-	    ['America/Kentucky/Louisville'],
-	    ['America/Kentucky/Monticello'],
-	    ['America/La_Paz'],
-	    ['America/Lima'],
-	    ['America/Los_Angeles'],
-	    ['America/Maceio'],
-	    ['America/Managua'],
-	    ['America/Manaus'],
-	    ['America/Marigot'],
-	    ['America/Martinique'],
-	    ['America/Matamoros'],
-	    ['America/Mazatlan'],
-	    ['America/Menominee'],
-	    ['America/Merida'],
-	    ['America/Mexico_City'],
-	    ['America/Miquelon'],
-	    ['America/Moncton'],
-	    ['America/Monterrey'],
-	    ['America/Montevideo'],
-	    ['America/Montreal'],
-	    ['America/Montserrat'],
-	    ['America/Nassau'],
-	    ['America/New_York'],
-	    ['America/Nipigon'],
-	    ['America/Nome'],
-	    ['America/Noronha'],
-	    ['America/North_Dakota/Center'],
-	    ['America/North_Dakota/New_Salem'],
-	    ['America/Ojinaga'],
-	    ['America/Panama'],
-	    ['America/Pangnirtung'],
-	    ['America/Paramaribo'],
-	    ['America/Phoenix'],
-	    ['America/Port-au-Prince'],
-	    ['America/Port_of_Spain'],
-	    ['America/Porto_Velho'],
-	    ['America/Puerto_Rico'],
-	    ['America/Rainy_River'],
-	    ['America/Rankin_Inlet'],
-	    ['America/Recife'],
-	    ['America/Regina'],
-	    ['America/Resolute'],
-	    ['America/Rio_Branco'],
-	    ['America/Santa_Isabel'],
-	    ['America/Santarem'],
-	    ['America/Santiago'],
-	    ['America/Santo_Domingo'],
-	    ['America/Sao_Paulo'],
-	    ['America/Scoresbysund'],
-	    ['America/Shiprock'],
-	    ['America/St_Barthelemy'],
-	    ['America/St_Johns'],
-	    ['America/St_Kitts'],
-	    ['America/St_Lucia'],
-	    ['America/St_Thomas'],
-	    ['America/St_Vincent'],
-	    ['America/Swift_Current'],
-	    ['America/Tegucigalpa'],
-	    ['America/Thule'],
-	    ['America/Thunder_Bay'],
-	    ['America/Tijuana'],
-	    ['America/Toronto'],
-	    ['America/Tortola'],
-	    ['America/Vancouver'],
-	    ['America/Whitehorse'],
-	    ['America/Winnipeg'],
-	    ['America/Yakutat'],
-	    ['America/Yellowknife'],
-	    ['Antarctica/Casey'],
-	    ['Antarctica/Davis'],
-	    ['Antarctica/DumontDUrville'],
-	    ['Antarctica/Macquarie'],
-	    ['Antarctica/Mawson'],
-	    ['Antarctica/McMurdo'],
-	    ['Antarctica/Palmer'],
-	    ['Antarctica/Rothera'],
-	    ['Antarctica/South_Pole'],
-	    ['Antarctica/Syowa'],
-	    ['Antarctica/Vostok'],
-	    ['Arctic/Longyearbyen'],
-	    ['Asia/Aden'],
-	    ['Asia/Almaty'],
-	    ['Asia/Amman'],
-	    ['Asia/Anadyr'],
-	    ['Asia/Aqtau'],
-	    ['Asia/Aqtobe'],
-	    ['Asia/Ashgabat'],
-	    ['Asia/Baghdad'],
-	    ['Asia/Bahrain'],
-	    ['Asia/Baku'],
-	    ['Asia/Bangkok'],
-	    ['Asia/Beirut'],
-	    ['Asia/Bishkek'],
-	    ['Asia/Brunei'],
-	    ['Asia/Choibalsan'],
-	    ['Asia/Chongqing'],
-	    ['Asia/Colombo'],
-	    ['Asia/Damascus'],
-	    ['Asia/Dhaka'],
-	    ['Asia/Dili'],
-	    ['Asia/Dubai'],
-	    ['Asia/Dushanbe'],
-	    ['Asia/Gaza'],
-	    ['Asia/Harbin'],
-	    ['Asia/Ho_Chi_Minh'],
-	    ['Asia/Hong_Kong'],
-	    ['Asia/Hovd'],
-	    ['Asia/Irkutsk'],
-	    ['Asia/Jakarta'],
-	    ['Asia/Jayapura'],
-	    ['Asia/Jerusalem'],
-	    ['Asia/Kabul'],
-	    ['Asia/Kamchatka'],
-	    ['Asia/Karachi'],
-	    ['Asia/Kashgar'],
-	    ['Asia/Kathmandu'],
-	    ['Asia/Kolkata'],
-	    ['Asia/Krasnoyarsk'],
-	    ['Asia/Kuala_Lumpur'],
-	    ['Asia/Kuching'],
-	    ['Asia/Kuwait'],
-	    ['Asia/Macau'],
-	    ['Asia/Magadan'],
-	    ['Asia/Makassar'],
-	    ['Asia/Manila'],
-	    ['Asia/Muscat'],
-	    ['Asia/Nicosia'],
-	    ['Asia/Novokuznetsk'],
-	    ['Asia/Novosibirsk'],
-	    ['Asia/Omsk'],
-	    ['Asia/Oral'],
-	    ['Asia/Phnom_Penh'],
-	    ['Asia/Pontianak'],
-	    ['Asia/Pyongyang'],
-	    ['Asia/Qatar'],
-	    ['Asia/Qyzylorda'],
-	    ['Asia/Rangoon'],
-	    ['Asia/Riyadh'],
-	    ['Asia/Sakhalin'],
-	    ['Asia/Samarkand'],
-	    ['Asia/Seoul'],
-	    ['Asia/Shanghai'],
-	    ['Asia/Singapore'],
-	    ['Asia/Taipei'],
-	    ['Asia/Tashkent'],
-	    ['Asia/Tbilisi'],
-	    ['Asia/Tehran'],
-	    ['Asia/Thimphu'],
-	    ['Asia/Tokyo'],
-	    ['Asia/Ulaanbaatar'],
-	    ['Asia/Urumqi'],
-	    ['Asia/Vientiane'],
-	    ['Asia/Vladivostok'],
-	    ['Asia/Yakutsk'],
-	    ['Asia/Yekaterinburg'],
-	    ['Asia/Yerevan'],
-	    ['Atlantic/Azores'],
-	    ['Atlantic/Bermuda'],
-	    ['Atlantic/Canary'],
-	    ['Atlantic/Cape_Verde'],
-	    ['Atlantic/Faroe'],
-	    ['Atlantic/Madeira'],
-	    ['Atlantic/Reykjavik'],
-	    ['Atlantic/South_Georgia'],
-	    ['Atlantic/St_Helena'],
-	    ['Atlantic/Stanley'],
-	    ['Australia/Adelaide'],
-	    ['Australia/Brisbane'],
-	    ['Australia/Broken_Hill'],
-	    ['Australia/Currie'],
-	    ['Australia/Darwin'],
-	    ['Australia/Eucla'],
-	    ['Australia/Hobart'],
-	    ['Australia/Lindeman'],
-	    ['Australia/Lord_Howe'],
-	    ['Australia/Melbourne'],
-	    ['Australia/Perth'],
-	    ['Australia/Sydney'],
-	    ['Europe/Amsterdam'],
-	    ['Europe/Andorra'],
-	    ['Europe/Athens'],
-	    ['Europe/Belgrade'],
-	    ['Europe/Berlin'],
-	    ['Europe/Bratislava'],
-	    ['Europe/Brussels'],
-	    ['Europe/Bucharest'],
-	    ['Europe/Budapest'],
-	    ['Europe/Chisinau'],
-	    ['Europe/Copenhagen'],
-	    ['Europe/Dublin'],
-	    ['Europe/Gibraltar'],
-	    ['Europe/Guernsey'],
-	    ['Europe/Helsinki'],
-	    ['Europe/Isle_of_Man'],
-	    ['Europe/Istanbul'],
-	    ['Europe/Jersey'],
-	    ['Europe/Kaliningrad'],
-	    ['Europe/Kiev'],
-	    ['Europe/Lisbon'],
-	    ['Europe/Ljubljana'],
-	    ['Europe/London'],
-	    ['Europe/Luxembourg'],
-	    ['Europe/Madrid'],
-	    ['Europe/Malta'],
-	    ['Europe/Mariehamn'],
-	    ['Europe/Minsk'],
-	    ['Europe/Monaco'],
-	    ['Europe/Moscow'],
-	    ['Europe/Oslo'],
-	    ['Europe/Paris'],
-	    ['Europe/Podgorica'],
-	    ['Europe/Prague'],
-	    ['Europe/Riga'],
-	    ['Europe/Rome'],
-	    ['Europe/Samara'],
-	    ['Europe/San_Marino'],
-	    ['Europe/Sarajevo'],
-	    ['Europe/Simferopol'],
-	    ['Europe/Skopje'],
-	    ['Europe/Sofia'],
-	    ['Europe/Stockholm'],
-	    ['Europe/Tallinn'],
-	    ['Europe/Tirane'],
-	    ['Europe/Uzhgorod'],
-	    ['Europe/Vaduz'],
-	    ['Europe/Vatican'],
-	    ['Europe/Vienna'],
-	    ['Europe/Vilnius'],
-	    ['Europe/Volgograd'],
-	    ['Europe/Warsaw'],
-	    ['Europe/Zagreb'],
-	    ['Europe/Zaporozhye'],
-	    ['Europe/Zurich'],
-	    ['Indian/Antananarivo'],
-	    ['Indian/Chagos'],
-	    ['Indian/Christmas'],
-	    ['Indian/Cocos'],
-	    ['Indian/Comoro'],
-	    ['Indian/Kerguelen'],
-	    ['Indian/Mahe'],
-	    ['Indian/Maldives'],
-	    ['Indian/Mauritius'],
-	    ['Indian/Mayotte'],
-	    ['Indian/Reunion'],
-	    ['Pacific/Apia'],
-	    ['Pacific/Auckland'],
-	    ['Pacific/Chatham'],
-	    ['Pacific/Chuuk'],
-	    ['Pacific/Easter'],
-	    ['Pacific/Efate'],
-	    ['Pacific/Enderbury'],
-	    ['Pacific/Fakaofo'],
-	    ['Pacific/Fiji'],
-	    ['Pacific/Funafuti'],
-	    ['Pacific/Galapagos'],
-	    ['Pacific/Gambier'],
-	    ['Pacific/Guadalcanal'],
-	    ['Pacific/Guam'],
-	    ['Pacific/Honolulu'],
-	    ['Pacific/Johnston'],
-	    ['Pacific/Kiritimati'],
-	    ['Pacific/Kosrae'],
-	    ['Pacific/Kwajalein'],
-	    ['Pacific/Majuro'],
-	    ['Pacific/Marquesas'],
-	    ['Pacific/Midway'],
-	    ['Pacific/Nauru'],
-	    ['Pacific/Niue'],
-	    ['Pacific/Norfolk'],
-	    ['Pacific/Noumea'],
-	    ['Pacific/Pago_Pago'],
-	    ['Pacific/Palau'],
-	    ['Pacific/Pitcairn'],
-	    ['Pacific/Pohnpei'],
-	    ['Pacific/Port_Moresby'],
-	    ['Pacific/Rarotonga'],
-	    ['Pacific/Saipan'],
-	    ['Pacific/Tahiti'],
-	    ['Pacific/Tarawa'],
-	    ['Pacific/Tongatapu'],
-	    ['Pacific/Wake'],
-	    ['Pacific/Wallis']
-	]
-});
-Ext.define('Proxmox.form.field.Integer',{
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.proxmoxintegerfield',
-
-    config: {
-	deleteEmpty: false
-    },
-
-    allowDecimals: false,
-    allowExponential: false,
-    step: 1,
-
-   getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== undefined && val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    }
-
-});
-Ext.define('Proxmox.form.field.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.proxmoxtextfield'],
-
-    config: {
-	skipEmptyText: true,
-
-	deleteEmpty: false,
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-	var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-    }
-});
-Ext.define('Proxmox.DateTimeField', {
-    extend: 'Ext.form.FieldContainer',
-    xtype: 'promxoxDateTimeField',
-
-    layout: 'hbox',
-
-    referenceHolder: true,
-
-    submitFormat: 'U',
-
-    getValue: function() {
-	var me = this;
-	var d = me.lookupReference('dateentry').getValue();
-
-	if (d === undefined || d === null) { return null; }
-
-	var t = me.lookupReference('timeentry').getValue();
-
-	if (t === undefined || t === null) { return null; }
-
-	var offset = (t.getHours()*3600+t.getMinutes()*60)*1000;
-
-	return new Date(d.getTime() + offset);
-    },
-
-    getSubmitValue: function() {
-        var me = this;
-        var format = me.submitFormat;
-        var value = me.getValue();
-
-        return value ? Ext.Date.format(value, format) : null;
-    },
-
-    items: [
-	{
-	    xtype: 'datefield',
-	    editable: false,
-	    reference: 'dateentry',
-	    flex: 1,
-	    format: 'Y-m-d'
-	},
-	{
-	    xtype: 'timefield',
-	    reference: 'timeentry',
-	    format: 'H:i',
-	    width: 80,
-	    value: '00:00',
-	    increment: 60
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	var value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    }
-});
-Ext.define('Proxmox.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.proxmoxcheckbox'],
-
-    config: {
-	defaultValue: undefined,
-	deleteDefaultValue: false,
-	deleteEmpty: false
-    },
-
-    inputValue: '1',
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-		if ((val == me.getDefaultValue()) && me.getDeleteDefaultValue()) {
-		    data['delete'] = me.getName();
-		} else {
-                    data[me.getName()] = val;
-		}
-            } else if (me.getDeleteEmpty()) {
-               data = {};
-               data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-	var me = this;
-
-	if (value === 1) {
-            me.callParent([true]);
-	} else {
-            me.callParent([value]);
-	}
-    }
-
-});
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('Proxmox.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.proxmoxKVComboBox',
-
-    config: {
-	deleteEmpty: true
-    },
-
-    comboItems: undefined,
-    displayField: 'value',
-    valueField: 'key',
-    queryMode: 'local',
-
-    // overide framework function to implement deleteEmpty behaviour
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '' && val !== '__default__') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    validator: function(val) {
-	var me = this;
-
-	if (me.editable || val === null || val === '') {
-	    return true;
-	}
-
-	if (me.store.getCount() > 0) {
-	    var values = me.multiSelect ? val.split(me.delimiter) : [val];
-	    var items = me.store.getData().collect('value', 'data');
-	    if (Ext.Array.every(values, function(value) {
-		return Ext.Array.contains(items, value);
-	    })) {
-		return true;
-	    }
-	}
-
-	// returns a boolean or string
-	/*jslint confusion: true */
-	return "value '" + val + "' not allowed!";
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.store = Ext.create('Ext.data.ArrayStore', {
-	    model: 'KeyValue',
-	    data : me.comboItems
-	});
-
-	if (me.initialConfig.editable === undefined) {
-	    me.editable = false;
-	}
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.form.LanguageSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'proxmoxLanguageSelector',
-
-    comboItems: Proxmox.Utils.language_array()
-});
-/*
- * ComboGrid component: a ComboBox where the dropdown menu (the
- * "Picker") is a Grid with Rows and Columns expects a listConfig
- * object with a columns property roughly based on the GridPicker from
- * https://www.sencha.com/forum/showthread.php?299909
- *
-*/
-
-Ext.define('Proxmox.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-	    (key == e.BACKSPACE || key == e.DELETE)) {
-	    me.setValue('');
-	}
-
-        me.callParent(arguments);
-    },
-
-    // needed to trigger onKeyUp etc.
-    enableKeyEvents: true,
-
-    editable: false,
-
-    // override ExtJS method
-    // if the field has multiSelect enabled, the store is not loaded, and
-    // the displayfield == valuefield, it saves the rawvalue as an array
-    // but the getRawValue method is only defined in the textfield class
-    // (which has not to deal with arrays) an returns the string in the
-    // field (not an array)
-    //
-    // so if we have multiselect enabled, return the rawValue (which
-    // should be an array) and else we do callParent so
-    // it should not impact any other use of the class
-    getRawValue: function() {
-	var me = this;
-	if (me.multiSelect) {
-	    return me.rawValue;
-	} else {
-	    return me.callParent();
-	}
-    },
-
-// override ExtJS protected method
-    onBindStore: function(store, initial) {
-        var me = this,
-            picker = me.picker,
-            extraKeySpec,
-            valueCollectionConfig;
-
-        // We're being bound, not unbound...
-        if (store) {
-            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2'
-            if (store.autoCreated) {
-                me.queryMode = 'local';
-                me.valueField = me.displayField = 'field1';
-                if (!store.expanded) {
-                    me.displayField = 'field2';
-                }
-
-                // displayTpl config will need regenerating with the autogenerated displayField name 'field1'
-                me.setDisplayTpl(null);
-            }
-            if (!Ext.isDefined(me.valueField)) {
-                me.valueField = me.displayField;
-            }
-
-            // Add a byValue index to the store so that we can efficiently look up records by the value field
-            // when setValue passes string value(s).
-            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys
-            // are found, they are all returned by the get call.
-            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default,
-            // if unique is true, CollectionKey keeps the *last* matching value.
-            extraKeySpec = {
-                byValue: {
-                    rootProperty: 'data',
-                    unique: false
-                }
-            };
-            extraKeySpec.byValue.property = me.valueField;
-            store.setExtraKeys(extraKeySpec);
-
-            if (me.displayField === me.valueField) {
-                store.byText = store.byValue;
-            } else {
-                extraKeySpec.byText = {
-                    rootProperty: 'data',
-                    unique: false
-                };
-                extraKeySpec.byText.property = me.displayField;
-                store.setExtraKeys(extraKeySpec);
-            }
-
-            // We hold a collection of the values which have been selected, keyed by this field's valueField.
-            // This collection also functions as the selected items collection for the BoundList's selection model
-            valueCollectionConfig = {
-                rootProperty: 'data',
-                extraKeys: {
-                    byInternalId: {
-                        property: 'internalId'
-                    },
-                    byValue: {
-                        property: me.valueField,
-                        rootProperty: 'data'
-                    }
-                },
-                // Whenever this collection is changed by anyone, whether by this field adding to it,
-                // or the BoundList operating, we must refresh our value.
-                listeners: {
-                    beginupdate: me.onValueCollectionBeginUpdate,
-                    endupdate: me.onValueCollectionEndUpdate,
-                    scope: me
-                }
-            };
-
-            // This becomes our collection of selected records for the Field.
-            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);
-
-            // We use the selected Collection as our value collection and the basis
-            // for rendering the tag list.
-
-            //proxmox override: since the picker is represented by a grid panel,
-            // we changed here the selection to RowModel
-            me.pickerSelectionModel = new Ext.selection.RowModel({
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
-                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row
-                // and released.  In these situations, the event target for the click event won't be the row where the mouse
-                // was released but the boundview.  The view will then determine that it should fire a container click, and
-                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will
-                // prevent the model from deselecting.
-                deselectOnContainerClick: false,
-                enableInitialSelection: false,
-                pruneRemoved: false,
-                selected: me.valueCollection,
-                store: store,
-                listeners: {
-                    scope: me,
-                    lastselectedchanged: me.updateBindSelection
-                }
-            });
-
-            if (!initial) {
-                me.resetToDefault();
-            }
-
-            if (picker) {
-                picker.setSelectionModel(me.pickerSelectionModel);
-                if (picker.getStore() !== store) {
-                    picker.bindStore(store);
-                }
-            }
-        }
-    },
-
-    // copied from ComboBox
-    createPicker: function() {
-        var me = this;
-        var picker;
-
-        var pickerCfg = Ext.apply({
-                // proxmox overrides: display a grid for selection
-                xtype: 'gridpanel',
-                id: me.pickerId,
-                pickerField: me,
-                floating: true,
-                hidden: true,
-                store: me.store,
-                displayField: me.displayField,
-                preserveScrollOnRefresh: true,
-                pageSize: me.pageSize,
-                tpl: me.tpl,
-                selModel: me.pickerSelectionModel,
-                focusOnToFront: false
-            }, me.listConfig, me.defaultListConfig);
-
-        picker = me.picker || Ext.widget(pickerCfg);
-
-        if (picker.getStore() !== me.store) {
-            picker.bindStore(me.store);
-        }
-
-        if (me.pageSize) {
-            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
-        }
-
-        // proxmox overrides: pass missing method in gridPanel to its view
-        picker.refresh = function() {
-            picker.getSelectionModel().select(me.valueCollection.getRange());
-            picker.getView().refresh();
-        };
-        picker.getNodeByRecord = function() {
-            picker.getView().getNodeByRecord(arguments);
-        };
-
-        // We limit the height of the picker to fit in the space above
-        // or below this field unless the picker has its own ideas about that.
-        if (!picker.initialConfig.maxHeight) {
-            picker.on({
-                beforeshow: me.onBeforePickerShow,
-                scope: me
-            });
-        }
-        picker.getSelectionModel().on({
-            beforeselect: me.onBeforeSelect,
-            beforedeselect: me.onBeforeDeselect,
-            focuschange: me.onFocusChange,
-            selectionChange: function (sm, selectedRecords) {
-                var me = this;
-                if (selectedRecords.length) {
-                    me.setValue(selectedRecords);
-                    me.fireEvent('select', me, selectedRecords);
-                }
-            },
-            scope: me
-        });
-
-	// hack for extjs6
-	// when the clicked item is the same as the previously selected,
-	// it does not select the item
-	// instead we hide the picker
-	if (!me.multiSelect) {
-	    picker.on('itemclick', function (sm,record) {
-		if (picker.getSelection()[0] === record) {
-		    picker.hide();
-		}
-	    });
-	}
-
-	// when our store is not yet loaded, we increase
-	// the height of the gridpanel, so that we can see
-	// the loading mask
-	//
-	// we save the minheight to reset it after the load
-	picker.on('show', function() {
-	    if (me.enableLoadMask) {
-		me.savedMinHeight = picker.getMinHeight();
-		picker.setMinHeight(100);
-	    }
-	});
-
-        picker.getNavigationModel().navigateOnSpace = false;
-
-        return picker;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    queryMode: 'local',
-	    matchFieldWidth: false
-	});
-
-	Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-	Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-        // Create the picker at an early stage, so it is available to store the previous selection
-        if (!me.picker) {
-            me.createPicker();
-        }
-
-	if (me.editable) {
-	    // The trigger.picker causes first a focus event on the field then
-	    // toggles the selection picker. Thus skip expanding in this case,
-	    // else our focus listner expands and the picker.trigger then
-	    // collapses it directly afterwards.
-	    Ext.override(me.triggers.picker, {
-		onMouseDown : function (e) {
-		    // copied "should we focus" check from Ext.form.trigger.Trigger
-		    if (e.pointerType !== 'touch' && !this.field.owns(Ext.Element.getActiveElement())) {
-			me.skip_expand_on_focus = true;
-		    }
-		    this.callParent(arguments);
-		}
-	    });
-
-	    me.on("focus", function(me) {
-		if (!me.isExpanded && !me.skip_expand_on_focus) {
-		    me.expand();
-		}
-		me.skip_expand_on_focus = false;
-	    });
-	}
-
-	me.mon(me.store, 'beforeload', function() {
-	    if (!me.isDisabled()) {
-		me.enableLoadMask = true;
-	    }
-	});
-
-	// hack: autoSelect does not work
-	me.mon(me.store, 'load', function(store, r, success, o) {
-	    if (success) {
-		me.clearInvalid();
-
-		if (me.enableLoadMask) {
-		    delete me.enableLoadMask;
-
-		    // if the picker exists,
-		    // we reset its minheight to the saved var/0
-		    // we have to update the layout, otherwise the height
-		    // gets not recalculated
-		    if (me.picker) {
-			me.picker.setMinHeight(me.savedMinHeight || 0);
-			delete me.savedMinHeight;
-			me.picker.updateLayout();
-		    }
-		}
-
-		var def = me.getValue() || me.preferredValue;
-		if (def) {
-		    me.setValue(def, true); // sync with grid
-		}
-		var found = false;
-		if (def) {
-		    if (Ext.isArray(def)) {
-			Ext.Array.each(def, function(v) {
-			    if (store.findRecord(me.valueField, v)) {
-				found = true;
-				return false; // break
-			    }
-			});
-		    } else {
-			found = store.findRecord(me.valueField, def);
-		    }
-		}
-
-		if (!found) {
-		    var rec = me.store.first();
-		    if (me.autoSelect && rec && rec.data) {
-			def = rec.data[me.valueField];
-			me.setValue(def, true);
-		    } else {
-			me.setValue(me.editable ? def : '', true);
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Proxmox.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxRRDTypeSelector'],
-
-    displayField: 'text',
-    valueField: 'id',
-    editable: false,
-    queryMode: 'local',
-    value: 'hour',
-    stateEvents: [ 'select' ],
-    stateful: true,
-    stateId: 'proxmoxRRDTypeSelection',
-    store: {
-	type: 'array',
-	fields: [ 'id', 'timeframe', 'cf', 'text' ],
-	data : [
-	    [ 'hour', 'hour', 'AVERAGE',
-	      gettext('Hour') + ' (' + gettext('average') +')' ],
-	    [ 'hourmax', 'hour', 'MAX',
-	      gettext('Hour') + ' (' + gettext('maximum') + ')' ],
-	    [ 'day', 'day', 'AVERAGE',
-	      gettext('Day') + ' (' + gettext('average') + ')' ],
-	    [ 'daymax', 'day', 'MAX',
-	      gettext('Day') + ' (' + gettext('maximum') + ')' ],
-	    [ 'week', 'week', 'AVERAGE',
-	      gettext('Week') + ' (' + gettext('average') + ')' ],
-	    [ 'weekmax', 'week', 'MAX',
-	      gettext('Week') + ' (' + gettext('maximum') + ')' ],
-	    [ 'month', 'month', 'AVERAGE',
-	      gettext('Month') + ' (' + gettext('average') + ')' ],
-	    [ 'monthmax', 'month', 'MAX',
-	      gettext('Month') + ' (' + gettext('maximum') + ')' ],
-	    [ 'year', 'year', 'AVERAGE',
-	      gettext('Year') + ' (' + gettext('average') + ')' ],
-	    [ 'yearmax', 'year', 'MAX',
-	      gettext('Year') + ' (' + gettext('maximum') + ')' ]
-	]
-    },
-    // save current selection in the state Provider so RRDView can read it
-    getState: function() {
-	var ind = this.getStore().findExact('id', this.getValue());
-	var rec = this.getStore().getAt(ind);
-	if (!rec) {
-	    return;
-	}
-	return {
-	    id: rec.data.id,
-	    timeframe: rec.data.timeframe,
-	    cf: rec.data.cf
-	};
-    },
-    // set selection based on last saved state
-    applyState : function(state) {
-	if (state && state.id) {
-	    this.setValue(state.id);
-	}
-    }
-});
-Ext.define('Proxmox.form.BondModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-
-    openvswitch: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.openvswitch) {
-           me.comboItems = [
-	       ['active-backup', 'active-backup'],
-	       ['balance-slb', 'balance-slb'],
-	       ['lacp-balance-slb', 'LACP (balance-slb)'],
-	       ['lacp-balance-tcp', 'LACP (balance-tcp)']
-	   ];
-	} else {
-            me.comboItems = [
-		['balance-rr', 'balance-rr'],
-		['active-backup', 'active-backup'],
-		['balance-xor', 'balance-xor'],
-		['broadcast', 'broadcast'],
-		['802.3ad', 'LACP (802.3ad)'],
-		['balance-tlb', 'balance-tlb'],
-		['balance-alb', 'balance-alb']
-	    ];
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('Proxmox.form.BondPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-    comboItems: [
-	    ['layer2', 'layer2'],
-	    ['layer2+3', 'layer2+3'],
-	    ['layer3+4', 'layer3+4']
-    ]
-});
-
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('Proxmox.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.proxmoxButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-
-	    // Note: me.realHandler may be a string (see named scopes)
-	    var realHandler = me.handler;
-
-	    me.handler = function(button, event) {
-		var rec, msg;
-		if (me.selModel) {
-		    rec = me.selModel.getSelection()[0];
-		    if (!rec || (me.enableFn(rec) === false)) {
-			return;
-		    }
-		}
-
-		if (me.confirmMsg) {
-		    msg = me.confirmMsg;
-		    if (Ext.isFunction(me.confirmMsg)) {
-			msg = me.confirmMsg(rec);
-		    }
-		    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		    Ext.Msg.show({
-			title: gettext('Confirm'),
-			icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-			msg: msg,
-			buttons: Ext.Msg.YESNO,
-			defaultFocus: me.dangerous ? 'no' : 'yes',
-			callback: function(btn) {
-			    if (btn !== 'yes') {
-				return;
-			    }
-			    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-			}
-		    });
-		} else {
-		    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-		}
-	    };
-	}
-
-	me.callParent();
-
-	var grid;
-	if (!me.selModel && me.selModel !== null) {
-	    grid = me.up('grid');
-	    if (grid && grid.selModel) {
-		me.selModel = grid.selModel;
-	    }
-	}
-
-	if (me.waitMsgTarget === true) {
-	    grid = me.up('grid');
-	    if (grid) {
-		me.waitMsgTarget = grid;
-	    } else {
-		throw "unable to find waitMsgTarget";
-	    }
-	}
-	
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else  {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-
-
-Ext.define('Proxmox.button.StdRemoveButton', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.proxmoxStdRemoveButton',
-
-    text: gettext('Remove'),
-
-    disabled: true,
-
-    config: {
-	baseurl: undefined
-    },
-
-    getUrl: function(rec) {
-	var me = this;
-	
-	return me.baseurl + '/' + rec.getId();
-    },
-
-    // also works with names scopes
-    callback: function(options, success, response) {},
-
-    getRecordName: function(rec) { return rec.getId() },
-
-    confirmMsg: function (rec) {
-	var me = this;
-
-	var name = me.getRecordName(rec);
-	return Ext.String.format(
-	    gettext('Are you sure you want to remove entry {0}'),
-	    "'" + name + "'");
-    },
-
-    handler: function(btn, event, rec) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.getUrl(rec),
-	    method: 'DELETE',
-	    waitMsgTarget: me.waitMsgTarget,
-	    callback: function(options, success, response) {
-		Ext.callback(me.callback, me.scope, [options, success, response], 0, me);
-	    },
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-/* help button pointing to an online documentation
-   for components contained in a modal window
-*/
-/*global
-  proxmoxOnlineHelpInfo
-*/
-Ext.define('Proxmox.button.Help', {
-    extend: 'Ext.button.Button',
-    xtype: 'proxmoxHelpButton',
-
-    text: gettext('Help'),
-
-    // make help button less flashy by styling it like toolbar buttons
-    iconCls: ' x-btn-icon-el-default-toolbar-small fa fa-question-circle',
-    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-
-    hidden: true,
-
-    listenToGlobalEvent: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	listen: {
-	    global: {
-		proxmoxShowHelp: 'onProxmoxShowHelp',
-		proxmoxHideHelp: 'onProxmoxHideHelp'
-	    }
-	},
-	onProxmoxShowHelp: function(helpLink) {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.setOnlineHelp(helpLink);
-		me.show();
-	    }
-	},
-	onProxmoxHideHelp: function() {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.hide();
-	    }
-	}
-    },
-
-    getOnlineHelpInfo: function (ref) {
-	var helpMap;
-	if (typeof proxmoxOnlineHelpInfo !== 'undefined') {
-	    helpMap = proxmoxOnlineHelpInfo;
-	} else if (typeof pveOnlineHelpInfo !== 'undefined') {
-	    // be backward compatible with older pve-doc-generators
-	    helpMap = pveOnlineHelpInfo;
-	} else {
-	    throw "no global OnlineHelpInfo map declared";
-	}
-
-	return helpMap[ref];
-    },
-
-    // this sets the link and the tooltip text
-    setOnlineHelp:function(blockid) {
-	var me = this;
-
-	var info = me.getOnlineHelpInfo(blockid);
-	if (info) {
-	    me.onlineHelp = blockid;
-	    var title = info.title;
-	    if (info.subtitle) {
-		title += ' - ' + info.subtitle;
-	    }
-	    me.setTooltip(title);
-	}
-    },
-
-    // helper to set the onlineHelp via a config object
-    setHelpConfig: function(config) {
-	var me = this;
-	me.setOnlineHelp(config.onlineHelp);
-    },
-
-    handler: function() {
-	var me = this;
-	var docsURI;
-
-	if (me.onlineHelp) {
-	    var info = me.getOnlineHelpInfo(me.onlineHelp);
-	    if (info) {
-		docsURI = window.location.origin + info.link;
-	    }
-	}
-
-	if (docsURI) {
-	    window.open(docsURI);
-	} else {
-	    Ext.Msg.alert(gettext('Help'), gettext('No Help available'));
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-	var me = this;
-
-	me.callParent();
-
-	if  (me.onlineHelp) {
-	    me.setOnlineHelp(me.onlineHelp); // set tooltip
-	}
-    }
-});
-/* Renders a list of key values objets
-
-mandatory config parameters:
-rows: an object container where each propery is a key-value object we want to render
-       var rows = {
-           keyboard: {
-               header: gettext('Keyboard Layout'),
-               editor: 'Your.KeyboardEdit',
-               required: true
-           },
-
-optional:
-disabled: setting this parameter to true will disable selection and focus on the
-proxmoxObjectGrid as well as greying out input elements.
-Useful for a readonly tabular display
-
-*/
-
-Ext.define('Proxmox.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.proxmoxObjectGrid'],
-    disabled: false,
-    hideHeaders: true,
-
-    monStoreErrors: false,
-
-    add_combobox_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxKVComboBox',
-		    name: name,
-		    comboItems: opts.comboItems,
-		    value: opts.defaultValue,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_text_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxtextfield',
-		    name: name,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    vtype: opts.vtype,
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_boolean_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue || 0,
-	    header: text,
-	    renderer: opts.renderer || Proxmox.Utils.format_boolean,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxcheckbox',
-		    name: name,
-		    uncheckedValue: 0,
-		    defaultValue: opts.defaultValue  || 0,
-		    checked: opts.defaultValue ? true : false,
-		    deleteDefaultValue: opts.deleteDefaultValue ? true : false,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_integer_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {}
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxintegerfield',
-		    name: name,
-		    minValue: opts.minValue,
-		    maxValue: opts.maxValue,
-		    emptyText: gettext('Default'),
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    value: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    editorConfig: {}, // default config passed to editor
-
-    run_editor: function() {
-	var me = this;
-
-	var sm = me.getSelectionModel();
-	var rec = sm.getSelection()[0];
-	if (!rec) {
-	    return;
-	}
-
-	var rows = me.rows;
-	var rowdef = rows[rec.data.key];
-	if (!rowdef.editor) {
-	    return;
-	}
-
-	var win;
-	var config;
-	if (Ext.isString(rowdef.editor)) {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    win = Ext.create(rowdef.editor, config);
-	} else {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    Ext.apply(config, rowdef.editor);
-	    win = Ext.createWidget(rowdef.editor.xtype, config);
-	    win.load();
-	}
-
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    getObjectValue: function(key, defaultValue) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-	return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-	var renderer = rowdef.renderer;
-	if (renderer) {
-	    return renderer(value, metaData, record, rowIndex, colIndex, store);
-	}
-
-	return value;
-    },
-
-    listeners: {
-	itemkeydown: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER) {
-		this.pressedIndex = index;
-	    }
-	},
-	itemkeyup: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER && index == this.pressedIndex) {
-		this.run_editor();
-	    }
-
-	    this.pressedIndex = undefined;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	var rstore = me.rstore;
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore,
-	    sorters: [],
-	    filters: []
-	});
-
-	if (rows) {
-	    Ext.Object.each(rows, function(key, rowdef) {
-		if (Ext.isDefined(rowdef.defaultValue)) {
-		    store.add({ key: key, value: rowdef.defaultValue });
-		} else if (rowdef.required) {
-		    store.add({ key: key, value: undefined });
-		}
-	    });
-	}
-
-	if (me.sorterFn) {
-	    store.sorters.add(Ext.create('Ext.util.Sorter', {
-		sorterFn: me.sorterFn
-	    }));
-	}
-
-	store.filters.add(Ext.create('Ext.util.Filter', {
-	    filterFn: function(item) {
-		if (rows) {
-		    var rowdef = rows[item.data.key];
-		    if (!rowdef || (rowdef.visible === false)) {
-			return false;
-		    }
-		}
-		return true;
-	    }
-	}));
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.applyIf(me, {
-	    store: store,
-	    stateful: false,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: me.cwidth1 || 200,
-		    dataIndex: 'key',
-		    renderer: me.renderKey
-		},
-		{
-		    flex: 1,
-		    header: gettext('Value'),
-		    dataIndex: 'value',
-		    renderer: me.renderValue
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.monStoreErrors) {
-	    Proxmox.Utils.monStoreErrors(me, me.store);
-	}
-   }
-});
-Ext.define('Proxmox.grid.PendingObjectGrid', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxPendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    var value = rec.data.value;
-	    if (pending) {
-		if (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') {
-		    value = rec.data.pending;
-		} else if (rec.data['delete'] === 1) {
-		    value = defaultValue;
-		}
-	    }
-
-            if (Ext.isDefined(value) && (value !== '')) {
-		return value;
-            } else {
-		return defaultValue;
-            }
-	}
-	return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var keys = rowdef.multiKey ||  [ key ];
-	var pending = false;
-
-	Ext.Array.each(keys, function(k) {
-	    var rec = me.store.getById(k);
-	    if (rec && rec.data && (
-		    (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') ||
-		    rec.data['delete'] === 1
-	    )) {
-		pending = true;
-		return false; // break
-	    }
-	});
-
-	return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var renderer = rowdef.renderer;
-	var current = '';
-	var pendingdelete = '';
-	var pending = '';
-
-	if (renderer) {
-	    current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-	    if (me.hasPendingChanges(key)) {
-		pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-	    }
-	    if (pending == current) {
-		pending = undefined;
-	    }
-	} else {
-	    current = value || '';
-	    pending = record.data.pending;
-	}
-
-	if (record.data['delete']) {
-	    var delete_all = true;
-	    if (rowdef.multiKey) {
-		Ext.Array.each(rowdef.multiKey, function(k) {
-		    var rec = me.store.getById(k);
-		    if (rec && rec.data && rec.data['delete'] !== 1) {
-			delete_all = false;
-			return false; // break
-		    }
-		});
-	    }
-	    if (delete_all) {
-		pending = '<div style="text-decoration: line-through;">'+ current +'</div>';
-	    }
-	}
-
-	if (pending) {
-	    return current + '<div style="color:red">' + pending + '</div>';
-	} else {
-	    return current;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		model: 'KeyValuePendingDelete',
-		readArray: true,
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('Proxmox.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-    listeners: {
-	activate: function() {
-	    // notify owning container that it should display a help button
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-	    }
-	},
-	deactivate: function() {
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-	    }
-	}
-    },
-    border: false,
-
-    // override this with an URL to a relevant chapter of the pve manual
-    // setting this will display a help button in our parent panel
-    onlineHelp: undefined,
-
-    // will be set if the inputpanel has advanced items
-    hasAdvanced: false,
-
-    // if the panel has advanced items,
-    // this will determine if they are shown by default
-    showAdvanced: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-	return values;
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-	if (Ext.isFunction(me.onGetValues)) {
-	    dirtyOnly = false;
-	}
-
-	var values = {};
-
-	Ext.Array.each(me.query('[isFormField]'), function(field) {
-            if (!dirtyOnly || field.isDirty()) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-	    }
-	});
-
-	return me.onGetValues(values);
-    },
-
-    setAdvancedVisible: function(visible) {
-	var me = this;
-	var advItems = me.getComponent('advancedContainer');
-	if (advItems) {
-	    advItems.setVisible(visible);
-	}
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-	    var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-		field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var items;
-
-	if (me.items) {
-	    me.columns = 1;
-	    items = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.items
-		}
-	    ];
-	    me.items = undefined;
-	} else if (me.column4) {
-	    me.columns = 4;
-	    items = [
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column2
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column3
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column4
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else if (me.column1) {
-	    me.columns = 2;
-	    items = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column2 || [] // allow empty column
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else {
-	    throw "unsupported config";
-	}
-
-	var advItems;
-	if (me.advancedItems) {
-	    advItems = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.advancedItems
-		}
-	    ];
-	    me.advancedItems = undefined;
-	} else if (me.advancedColumn1) {
-	    advItems = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumn1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.advancedColumn2 || [] // allow empty column
-		}
-	    ];
-
-	    me.advancedColumn1 = undefined;
-	    me.advancedColumn2 = undefined;
-
-	    if (me.advancedColumnB) {
-		advItems.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumnB
-		});
-		me.advancedColumnB = undefined;
-	    }
-	}
-
-	if (advItems) {
-	    me.hasAdvanced = true;
-	    advItems.unshift({
-		columnWidth: 1,
-		xtype: 'box',
-		hidden: false,
-		border: true,
-		autoEl: {
-		    tag: 'hr'
-		}
-	    });
-	    items.push({
-		columnWidth: 1,
-		xtype: 'container',
-		itemId: 'advancedContainer',
-		hidden: !me.showAdvanced,
-		layout: 'column',
-		defaults: {
-		    border: false
-		},
-		items: advItems
-	    });
-	}
-
-	if (me.useFieldContainer) {
-	    Ext.apply(me, {
-		layout: 'fit',
-		items: Ext.apply(me.useFieldContainer, {
-		    layout: 'column',
-		    defaultType: 'container',
-		    items: items
-		})
-	    });
-	} else {
-	    Ext.apply(me, {
-		layout: 'column',
-		defaultType: 'container',
-		items: items
-	    });
-	}
-
-	me.callParent();
-    }
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxLogView',
-
-    pageSize: 500,
-    viewBuffer: 50,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    // callback for load failure, used for ceph
-    failCallback: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-	    if (viewModel.get('hide_timespan')) {
-		return;
-	    }
-
-	    if (since > until) {
-		Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
-		return;
-	    }
-
-	    viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
-	    viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
-	    me.getView().loadTask.delay(200);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	updateView: function(text, first, total) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    var content = me.lookup('content');
-	    var data = viewModel.get('data');
-
-	    if (first === data.first && total === data.total && text.length === data.textlen) {
-		return; // same content, skip setting and scrolling
-	    }
-	    viewModel.set('data', {
-		first: first,
-		total: total,
-		textlen: text.length
-	    });
-
-	    var scrollPos = me.scrollPosBottom();
-
-	    content.update(text);
-
-	    if (view.scrollToEnd && scrollPos <= 0) {
-		// we use setTimeout to work around scroll handling on touchscreens
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    }
-	},
-
-	doLoad: function() {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    Proxmox.Utils.API2Request({
-		url: me.getView().url,
-		params: viewModel.get('params'),
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var total = response.result.total;
-		    var lines = new Array();
-		    var first = Infinity;
-
-		    Ext.Array.each(response.result.data, function(line) {
-			if (first > line.n) {
-			    first = line.n;
-			}
-			lines[line.n - 1] = Ext.htmlEncode(line.t);
-		    });
-
-		    lines.length = total;
-		    me.updateView(lines.join('<br>'), first - 1, total);
-		},
-		failure: function(response) {
-		    if (view.failCallback) {
-			view.failCallback(response);
-		    } else {
-			var msg = response.htmlStatus;
-			Proxmox.Utils.setErrorMask(me, msg);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-
-	    var lineHeight = view.lineHeight;
-	    var line = view.getScrollY()/lineHeight;
-	    var start = viewModel.get('params.start');
-	    var limit = viewModel.get('params.limit');
-	    var viewLines = view.getHeight()/lineHeight;
-
-	    var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
-	    var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
-
-	    if (viewStart < start || viewEnd > (start+limit)) {
-		viewModel.set('params.start',
-		    Math.max(parseInt(line - limit/2 + 10, 10), 0));
-		view.loadTask.delay(200);
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    viewModel.set('params.limit', view.pageSize);
-	    viewModel.set('hide_timespan', !view.log_select_timespan);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200);
-		    }
-		},
-		interval: 1000
-	    });
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    until: null,
-	    since: null,
-	    hide_timespan: false,
-	    data: {
-		start: 0,
-		total: 0,
-		textlen: 0
-	    },
-	    params: {
-		start: 0,
-		limit: 500,
-	    }
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-	bind: {
-	    hidden: '{hide_timespan}'
-	},
-	items: [
-	    '->',
-	    'Since: ',
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    'Until: ',
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		handler: 'updateParams'
-	    }
-	],
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-Ext.define('Proxmox.widget.RRDChart', {
-    extend: 'Ext.chart.CartesianChart',
-    alias: 'widget.proxmoxRRDChart',
-
-    unit: undefined, // bytes, bytespersecond, percent
-    
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	convertToUnits: function(value) {
-	    var units = ['', 'k','M','G','T', 'P'];
-	    var si = 0;
-	    while(value >= 1000  && si < (units.length -1)){
-		value = value / 1000;
-		si++;
-	    }
-
-	    // javascript floating point weirdness
-	    value = Ext.Number.correctFloat(value);
-	    
-	    // limit to 2 decimal points
-	    value = Ext.util.Format.number(value, "0.##");
-	    
-	    return value.toString() + " " + units[si];
-	},
-
-	leftAxisRenderer: function(axis, label, layoutContext) {
-	    var me = this;
-
-	    return me.convertToUnits(label);
-	},
-
-	onSeriesTooltipRender: function(tooltip, record, item) {
-	    var me = this.getView();
-	    
-	    var suffix = '';
-	    
-	    if (me.unit === 'percent') {
-		suffix = '%';
-	    } else if (me.unit === 'bytes') {
-		suffix = 'B';
-	    } else if (me.unit === 'bytespersecond') {
-		suffix = 'B/s';
-	    }
-	    
-	    var prefix = item.field;
-	    if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
-		prefix = me.fieldTitles[me.fields.indexOf(item.field)];
-	    }
-            tooltip.setHtml(prefix + ': ' + this.convertToUnits(record.get(item.field)) + suffix +
-			    '<br>' + new Date(record.get('time')));
-	},
-
-	onAfterAnimation: function(chart, eopts) {
-	    // if the undobuton is disabled,
-	    // disable our tool
-
-	    var ourUndoZoomButton = chart.tools[0];
-	    var undoButton = chart.interactions[0].getUndoButton();
-	    ourUndoZoomButton.setDisabled(undoButton.isDisabled());
-	}
-    },
-    
-    width: 770,
-    height: 300,
-    animation: false,
-    interactions: [{
-	type: 'crosszoom'
-    }],
-    axes: [{
-	type: 'numeric',
-	position: 'left',
-	grid: true,
-	renderer: 'leftAxisRenderer',
-	//renderer: function(axis, label) { return label; },
-	minimum: 0
-    }, {
-	type: 'time',
-	position: 'bottom',
-	grid: true,
-	fields: ['time']
-    }],
-    legend: {
-	docked: 'bottom'
-    },
-    listeners: {
-	animationend: 'onAfterAnimation'
-    },
-
-
-    initComponent: function() {
-	var me = this;
-	var series = {};
-
-	if (!me.store) {
-	    throw "cannot work without store";
-	}
-
-	if (!me.fields) {
-	    throw "cannot work without fields";
-	}
-
-	me.callParent();
-
-	// add correct label for left axis
-	var axisTitle = "";
-	if (me.unit === 'percent') {
-	    axisTitle = "%";
-	} else if (me.unit === 'bytes') {
-	    axisTitle = "Bytes";
-	} else if (me.unit === 'bytespersecond') {
-	    axisTitle = "Bytes/s";
-	} else if (me.fieldTitles && me.fieldTitles.length === 1) {
-	    axisTitle = me.fieldTitles[0];
-	} else if (me.fields.length === 1) {
-	    axisTitle = me.fields[0];
-	}
-
-	me.axes[0].setTitle(axisTitle);
-
-	if (!me.noTool) {
-	    me.addTool([{
-		type: 'minus',
-		disabled: true,
-		tooltip: gettext('Undo Zoom'),
-		handler: function(){
-		    var undoButton = me.interactions[0].getUndoButton();
-		    if (undoButton.handler) {
-			undoButton.handler();
-		    }
-		}
-	    },{
-		type: 'restore',
-		tooltip: gettext('Toggle Legend'),
-		handler: function(){
-		    if (me.legend) {
-			me.legend.setVisible(!me.legend.isVisible());
-		    }
-		}
-	    }]);
-	}
-
-	// add a series for each field we get
-	me.fields.forEach(function(item, index){
-	    var title = item;
-	    if (me.fieldTitles && me.fieldTitles[index]) {
-		title = me.fieldTitles[index];
-	    }
-	    me.addSeries(Ext.apply(
-		{
-		    type: 'line',
-		    xField: 'time',
-		    yField: item,
-		    title: title,
-		    fill: true,
-		    style: {
-			lineWidth: 1.5,
-			opacity: 0.60
-		    },
-		    marker: {
-			opacity: 0,
-			scaling: 0.01,
-			fx: {
-			    duration: 200,
-			    easing: 'easeOut'
-			}
-		    },
-		    highlightCfg: {
-			opacity: 1,
-			scaling: 1.5
-		    },
-		    tooltip: {
-			trackMouse: true,
-			renderer: 'onSeriesTooltipRender'
-		    }
-		},
-		me.seriesConfig
-	    ));
-	});
-
-	// enable animation after the store is loaded
-	me.store.onAfter('load', function() {
-	    me.setAnimation(true);
-	}, this, {single: true});
-    }
-});
-Ext.define('Proxmox.panel.GaugeWidget', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.proxmoxGauge',
-
-    defaults: {
-	style: {
-	    'text-align':'center'
-	}
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	},
-	{
-	    xtype: 'polar',
-	    height: 120,
-	    border: false,
-	    itemId: 'chart',
-	    series: [{
-		type: 'gauge',
-		value: 0,
-		colors: ['#f5f5f5'],
-		sectors: [0],
-		donut: 90,
-		needleLength: 100,
-		totalAngle: Math.PI
-	    }],
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '',
-		textAlign: 'center',
-		textBaseline: 'bottom',
-		x: 125,
-		y: 110,
-		fontSize: 30
-	    }]
-	},
-	{
-	    xtype: 'box',
-	    itemId: 'text'
-	}
-    ],
-
-    header: false,
-    border: false,
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-    warningColor: '#fc0',
-    criticalColor: '#FF6C59',
-    defaultColor: '#7289DA',
-    backgroundColor: '#2C2F33',
-
-    initialValue: 0,
-
-
-    updateValue: function(value, text) {
-	var me = this;
-	var color = me.defaultColor;
-	var attr = {};
-
-	if (value >= me.criticalThreshold) {
-	    color = me.criticalColor;
-	} else if (value >= me.warningThreshold) {
-	    color = me.warningColor;
-	}
-
-	me.chart.series[0].setColors([color, me.backgroundColor]);
-	me.chart.series[0].setValue(value*100);
-
-	me.valueSprite.setText(' '+(value*100).toFixed(0) + '%');
-	attr.x = me.chart.getWidth()/2;
-	attr.y = me.chart.getHeight()-20;
-	if (me.spriteFontSize) {
-	    attr.fontSize = me.spriteFontSize;
-	}
-	me.valueSprite.setAttributes(attr, true);
-
-	if (text !== undefined) {
-	    me.text.setHtml(text);
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.text = me.getComponent('text');
-	me.chart = me.getComponent('chart');
-	me.valueSprite = me.chart.getSurface('chart').get('valueSprite');
-    }
-});
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('Proxmox.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxWindowEdit',
-
-    // autoLoad trigger a load() after component creation
-    autoLoad: false,
-
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set isCreate to true if you want a Create button (instead
-    // OK and RESET)
-    isCreate: false,
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    // custom submitText
-    submitText: undefined,
-
-    backgroundDelay: 0,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-
-    // finds the first form field
-    defaultFocus: 'field[disabled=false][hidden=false]',
-
-    showProgress: false,
-
-    showTaskViewer: false,
-
-    // gets called if we have a progress bar or taskview and it detected that
-    // the task finished. function(success)
-    taskDone: Ext.emptyFn,
-
-    // gets called when the api call is finished, right at the beginning
-    // function(success, response, options)
-    apiCallDone: Ext.emptyFn,
-
-    // assign a reference from docs, to add a help button docked to the
-    // bottom of the window. If undefined we magically fall back to the
-    // onlineHelp of our first item, if set.
-    onlineHelp: undefined,
-
-    isValid: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-	return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	Ext.iterate(values, function(fieldId, val) {
-	    var field = form.findField(fieldId);
-	    if (field && !field.up('inputpanel')) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setValues(values);
-	});
-    },
-
-    submit: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	var values = me.getValues();
-	Ext.Object.each(values, function(name, val) {
-	    if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-		    values[name] = '';
-		}
-	    }
-	});
-
-	if (me.digest) {
-	    values.digest = me.digest;
-	}
-
-	if (me.backgroundDelay) {
-	    values.background_delay = me.backgroundDelay;
-	}
-
-	var url =  me.url;
-	if (me.method === 'DELETE') {
-	    url = url + "?" + Ext.Object.toQueryString(values);
-	    values = undefined;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    waitMsgTarget: me,
-	    method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-	    params: values,
-	    failure: function(response, options) {
-		me.apiCallDone(false, response, options);
-
-		if (response.result && response.result.errors) {
-		    form.markInvalid(response.result.errors);
-		}
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var hasProgressBar = (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
-		    response.result.data ? true : false;
-
-		me.apiCallDone(true, response, options);
-
-		if (hasProgressBar) {
-		    // stay around so we can trigger our close events
-		    // when background action is completed
-		    me.hide();
-
-		    var upid = response.result.data;
-		    var viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
-		    var win = Ext.create('Proxmox.window.Task' + viewerClass, {
-			upid: upid,
-			taskDone: me.taskDone,
-			listeners: {
-			    destroy: function () {
-				me.close();
-			    }
-			}
-		    });
-		    win.show();
-		} else {
-		    me.close();
-		}
-	    }
-	});
-    },
-
-    load: function(options) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	options = options || {};
-
-	var newopts = Ext.apply({
-	    waitMsgTarget: me
-	}, options);
-
-	var createWrapper = function(successFn) {
-	    Ext.apply(newopts, {
-		url: me.url,
-		method: 'GET',
-		success: function(response, opts) {
-		    form.clearInvalid();
-		    me.digest = response.result.data.digest;
-		    if (successFn) {
-			successFn(response, opts);
-		    } else {
-			me.setValues(response.result.data);
-		    }
-		    // hack: fix ExtJS bug
-		    Ext.Array.each(me.query('radiofield'), function(f) {
-			f.resetOriginalValue();
-		    });
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-			me.close();
-		    });
-		}
-	    });
-	};
-
-	createWrapper(options.success);
-
-	Proxmox.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.url) {
-	    throw "no url specified";
-	}
-
-	if (me.create) {throw "deprecated parameter, use isCreate";}
-
-	var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-	me.items = undefined;
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    url: me.url,
-	    method: me.method || 'PUT',
-	    trackResetOnLoad: true,
-	    bodyPadding: 10,
-	    border: false,
-	    defaults: Ext.apply({}, me.defaults, {
-		border: false
-	    }),
-	    fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-		labelWidth: 100,
-		anchor: '100%'
-            }),
-	    items: items
-	});
-
-	var inputPanel = me.formPanel.down('inputpanel');
-
-	var form = me.formPanel.getForm();
-
-	var submitText;
-	if (me.isCreate) {
-	    if (me.submitText) {
-		submitText = me.submitText;
-	    } else if (me.isAdd) {
-		submitText = gettext('Add');
-	    } else if (me.isRemove) {
-		submitText = gettext('Remove');
-	    } else {
-		submitText = gettext('Create');
-	    }
-	} else {
-	    submitText = me.submitText || gettext('OK');
-	}
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    reference: 'submitbutton',
-	    text: submitText,
-	    disabled: !me.isCreate,
-	    handler: function() {
-		me.submit();
-	    }
-	});
-
-	var resetBtn = Ext.create('Ext.Button', {
-	    text: 'Reset',
-	    disabled: true,
-	    handler: function(){
-		form.reset();
-	    }
-	});
-
-	var set_button_status = function() {
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-	    submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
-	    resetBtn.setDisabled(!dirty);
-
-	    if (inputPanel && inputPanel.hasAdvanced) {
-		// we want to show the advanced options
-		// as soon as some of it is not valid
-		var advancedItems = me.down('#advancedContainer').query('field');
-		var valid = true;
-		advancedItems.forEach(function(field) {
-		    if (!field.isValid()) {
-			valid = false;
-		    }
-		});
-
-		if (!valid) {
-		    inputPanel.setAdvancedVisible(true);
-		    me.down('#advancedcb').setValue(true);
-		}
-	    }
-	};
-
-	form.on('dirtychange', set_button_status);
-	form.on('validitychange', set_button_status);
-
-	var colwidth = 300;
-	if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-	    colwidth += me.fieldDefaults.labelWidth - 100;
-	}
-
-	var twoColumn = inputPanel &&
-	    (inputPanel.column1 || inputPanel.column2);
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
-	}
-
-	if (me.isCreate) {
-		me.buttons = [ submitBtn ] ;
-	} else {
-		me.buttons = [ submitBtn, resetBtn ];
-	}
-
-	if (inputPanel && inputPanel.hasAdvanced) {
-	    var sp = Ext.state.Manager.getProvider();
-	    var advchecked = sp.get('proxmox-advanced-cb');
-	    inputPanel.setAdvancedVisible(advchecked);
-	    me.buttons.unshift(
-	       {
-		   xtype: 'proxmoxcheckbox',
-		   itemId: 'advancedcb',
-		   boxLabelAlign: 'before',
-		   boxLabel: gettext('Advanced'),
-		   stateId: 'proxmox-advanced-cb',
-		   value: advchecked,
-		   listeners: {
-		       change: function(cb, val) {
-			   inputPanel.setAdvancedVisible(val);
-			   sp.set('proxmox-advanced-cb', val);
-		       }
-		   }
-	       }
-	    );
-	}
-
-	var onlineHelp = me.onlineHelp;
-	if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
-	    onlineHelp = inputPanel.onlineHelp;
-	}
-
-	if (onlineHelp) {
-	    var helpButton = Ext.create('Proxmox.button.Help');
-	    me.buttons.unshift(helpButton, '->');
-	    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
-	}
-
-	Ext.applyIf(me, {
-	    modal: true,
-	    width: twoColumn ? colwidth*2 : colwidth,
-	    border: false,
-	    items: [ me.formPanel ]
-	});
-
-	me.callParent();
-
-	// always mark invalid fields
-	me.on('afterlayout', function() {
-	    // on touch devices, the isValid function
-	    // triggers a layout, which triggers an isValid
-	    // and so on
-	    // to prevent this we disable the layouting here
-	    // and enable it afterwards
-	    me.suspendLayout = true;
-	    me.isValid();
-	    me.suspendLayout = false;
-	});
-
-	if (me.autoLoad) {
-	    me.load();
-	}
-    }
-});
-Ext.define('Proxmox.window.PasswordEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'proxmoxWindowPasswordEdit',
-
-    subject: gettext('Password'),
-
-    url: '/api2/extjs/access/password',
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    allowBlank: false,
-	    name: 'password',
-	    listeners: {
-                change: function(field){
-		    field.next().validate();
-                },
-                blur: function(field){
-		    field.next().validate();
-                }
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'),
-	    name: 'verifypassword',
-	    allowBlank: false,
-	    vtype: 'password',
-	    initialPassField: 'password',
-	    submitValue: false
-	},
-	{
-	    xtype: 'hiddenfield',
-	    name: 'userid'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	me.callParent();
-	me.down('[name=userid]').setValue(me.userid);
-    }
-});
-Ext.define('Proxmox.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskProgress',
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: {
-		status: { defaultValue: 'unknown' },
-		exitstatus: { defaultValue: 'unknown' }
-	    }
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var getObjectValue = function(key, defaultValue) {
-	    var rec = statstore.getById(key);
-	    if (rec) {
-		return rec.data.value;
-	    }
-	    return defaultValue;
-	};
-
-	var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-	me.mon(statstore, 'load', function() {
-	    var status = getObjectValue('status');
-	    if (status === 'stopped') {
-		var exitstatus = getObjectValue('exitstatus');
-		if (exitstatus == 'OK') {
-		    pbar.reset();
-		    pbar.updateText("Done!");
-		    Ext.Function.defer(me.close, 1000, me);
-		} else {
-		    me.close();
-		    Ext.Msg.alert('Task failed', exitstatus);
-		}
-		me.taskDone(exitstatus == 'OK');
-	    }
-	});
-
-	var descr = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	Ext.apply(me, {
-	    title: gettext('Task') + ': ' + descr,
-	    width: 300,
-	    layout: 'auto',
-	    modal: true,
-	    bodyPadding: 5,
-	    items: pbar,
-	    buttons: [
-		{ 
-		    text: gettext('Details'),
-		    handler: function() {			
-			var win = Ext.create('Proxmox.window.TaskViewer', { 
-			    taskDone: me.taskDone,
-			    upid: me.upid
-			});
-			win.show();
-			me.close();
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	statstore.startUpdate();
-
-	pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('Proxmox.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskViewer',
-
-    extraTitle: '', // string to prepend after the generic task title
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statgrid;
-
-	var rows = {
-	    status: {
-		header: gettext('Status'),
-		defaultValue: 'unknown',
-		renderer: function(value) {
-		    if (value != 'stopped') {
-			return value;
-		    }
-		    var es = statgrid.getObjectValue('exitstatus');
-		    if (es) {
-			return value + ': ' + es;
-		    }
-		}
-	    },
-	    exitstatus: { 
-		visible: false
-	    },
-	    type: {
-		header: gettext('Task type'),
-		required: true
-	    },
-	    user: {
-		header: gettext('User name'),
-		required: true 
-	    },
-	    node: {
-		header: gettext('Node'),
-		required: true 
-	    },
-	    pid: {
-		header: gettext('Process ID'),
-		required: true
-	    },
-	    starttime: {
-		header: gettext('Start Time'),
-		required: true, 
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    upid: {
-		header: gettext('Unique task ID')
-	    }
-	};
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: rows
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var stop_task = function() {
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + task.node + "/tasks/" + me.upid,
-		waitMsgTarget: me,
-		method: 'DELETE',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var stop_btn1 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	var stop_btn2 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	statgrid = Ext.create('Proxmox.grid.ObjectGrid', {
-	    title: gettext('Status'),
-	    layout: 'fit',
-	    tbar: [ stop_btn1 ],
-	    rstore: statstore,
-	    rows: rows,
-	    border: false
-	});
-
-	var logView = Ext.create('Proxmox.panel.LogView', {
-	    title: gettext('Output'),
-	    tbar: [ stop_btn2 ],
-	    border: false,
-	    url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-	});
-
-	me.mon(statstore, 'load', function() {
-	    var status = statgrid.getObjectValue('status');
-	    
-	    if (status === 'stopped') {
-		logView.scrollToEnd = false;
-		logView.requestUpdate();
-		statstore.stopUpdate();
-		me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
-	    }
-
-	    stop_btn1.setDisabled(status !== 'running');
-	    stop_btn2.setDisabled(status !== 'running');
-	});
-
-	statstore.startUpdate();
-
-	Ext.apply(me, {
-	    title: "Task viewer: " + task.desc + me.extraTitle,
-	    width: 800,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [{
-		xtype: 'tabpanel',
-		region: 'center',
-		items: [ logView, statgrid ]
-	    }]
-        });
-
-	me.callParent();
-
-	logView.fireEvent('show', logView);
-    }
-});
-
-Ext.define('apt-pkglist', {
-    extend: 'Ext.data.Model',
-    fields: [ 'Package', 'Title', 'Description', 'Section', 'Arch',
-	      'Priority', 'Version', 'OldVersion', 'ChangeLogUrl', 'Origin' ],
-    idProperty: 'Package'
-});
-
-Ext.define('Proxmox.node.APT', {
-    extend: 'Ext.grid.GridPanel',
-
-    xtype: 'proxmoxNodeAPT',
-
-    upgradeBtn: undefined,
-
-    columns: [
-	{
-	    header: gettext('Package'),
-	    width: 200,
-	    sortable: true,
-	    dataIndex: 'Package'
-	},
-	{
-	    text: gettext('Version'),
-	    columns: [
-		{
-		    header: gettext('current'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'OldVersion'
-		},
-		{
-		    header: gettext('new'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'Version'
-		}
-	    ]
-	},
-	{
-	    header: gettext('Description'),
-	    sortable: false,
-	    dataIndex: 'Title',
-	    flex: 1
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'apt-pkglist',
-	    groupField: 'Origin',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/apt/update"
-	    },
-	    sorters: [
-		{
-		    property : 'Package',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
-            groupHeaderTpl: '{[ "Origin: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
-	    enableGroupingMenu: false
-	});
-
-	var rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {
-            getAdditionalData: function (data, rowIndex, record, orig) {
-                var headerCt = this.view.headerCt;
-                var colspan = headerCt.getColumnCount();
-                // Usually you would style the my-body-class in CSS file
-                return {
-                    rowBody: '<div style="padding: 1em">' +
-			Ext.String.htmlEncode(data.Description) +
-			'</div>',
-                    rowBodyColspan: colspan
-                };
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	var apt_command = function(cmd){
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/apt/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.mon(win, 'close', reload);
-		}
-	    });
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var update_btn = new Ext.Button({
-	    text: gettext('Refresh'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { apt_command('update'); });
-	    }
-	});
-
-	var show_changelog = function(rec) {
-	    if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		return;
-	    }
-
-	    var view = Ext.createWidget('component', {
-		autoScroll: true,
-		style: {
-		    'background-color': 'white',
-		    'white-space': 'pre',
-		    'font-family': 'monospace',
-		    padding: '5px'
-		}
-	    });
-
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Changelog') + ": " + rec.data.Package,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		modal: true,
-		items: [ view ]
-	    });
-
-	    Proxmox.Utils.API2Request({
-		waitMsgTarget: me,
-		url: "/nodes/" + me.nodename + "/apt/changelog",
-		params: {
-		    name: rec.data.Package,
-		    version: rec.data.Version
-		},
-		method: 'GET',
-		failure: function(response, opts) {
-		    win.close();
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    win.show();
-		    view.update(Ext.htmlEncode(response.result.data));
-		}
-	    });
-
-	};
-
-	var changelog_btn = new Proxmox.button.Button({
-	    text: gettext('Changelog'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function(b, e, rec) {
-		show_changelog(rec);
-	    }
-	});
-
-	if (me.upgradeBtn) {
-	    me.tbar =  [ update_btn, me.upgradeBtn, changelog_btn ];
-	} else {
-	    me.tbar =  [ update_btn, changelog_btn ];
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-update',
-	    selModel: sm,
-            viewConfig: {
-		stripeRows: false,
-		emptyText: '<div style="display:table; width:100%; height:100%;"><div style="display:table-cell; vertical-align: middle; text-align:center;"><b>' + gettext('No updates available.') + '</div></div>'
-	    },
-	    features: [ groupingFeature, rowBodyFeature ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: function(v, rec) {
-		    show_changelog(rec);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeNetworkEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.iftype) {
-	    throw "no network device type specified";
-	}
-
-	me.isCreate = !me.iface;
-
-	var iface_vtype;
-
-	if (me.iftype === 'bridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'bond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'eth' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'vlan' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSBridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'OVSBond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'OVSIntPort') {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSPort') {
-	    iface_vtype = 'InterfaceName';
-	} else {
-	    console.log(me.iftype);
-	    throw "unknown network device type specified";
-	}
-
-	me.subject = Proxmox.Utils.render_network_iface_type(me.iftype);
-
-	var column2 = [];
-
-	if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' ||
-	      me.iftype === 'OVSBond')) {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Autostart'),
-		name: 'autostart',
-		uncheckedValue: 0,
-		checked: me.isCreate ? true : undefined
-	    });
-	}
-
-	if (me.iftype === 'bridge') {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('VLAN aware'),
-		name: 'bridge_vlan_aware',
-		deleteEmpty: !me.isCreate
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'bridge_ports'
-	    });
-	} else if (me.iftype === 'OVSBridge') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'ovs_ports'
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'OVSPort' || me.iftype === 'OVSIntPort') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'bond') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Slaves'),
-		name: 'slaves'
-	    });
-
-	    var policySelector = Ext.createWidget('bondPolicySelector', {
-		fieldLabel: gettext('Hash policy'),
-		name: 'bond_xmit_hash_policy',
-		deleteEmpty: !me.isCreate,
-		disabled: true
-	    });
-
-	    column2.push({
-		xtype: 'bondModeSelector',
-		fieldLabel: gettext('Mode'),
-		name: 'bond_mode',
-		value: me.isCreate ? 'balance-rr' : undefined,
-		listeners: {
-		    change: function(f, value) {
-			if (value === 'balance-xor' ||
-			    value === '802.3ad') {
-			    policySelector.setDisabled(false);
-			} else {
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			}
-		    }
-		},
-		allowBlank: false
-	    });
-
-	    column2.push(policySelector);
-
-	} else if (me.iftype === 'OVSBond') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	}
-
-	column2.push({
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Comment'),
-	    allowBlank: true,
-	    nodename: me.nodename,
-	    name: 'comments'
-	});
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network";
-	    method = 'POST';
-	} else {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network/" + me.iface;
-	    method = 'PUT';
-	}
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: me.iftype
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		fieldLabel: gettext('Name'),
-		name: 'iface',
-		value: me.iface,
-		vtype: iface_vtype,
-		allowBlank: false
-	    }
-	];
-
-	if (me.iftype === 'OVSBond') {
-	    column1.push(
-		{
-		    xtype: 'bondModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    name: 'bond_mode',
-		    openvswitch: true,
-		    value: me.isCreate ? 'active-backup' : undefined,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Slaves'),
-		    name: 'ovs_bonds'
-		}
-	    );
-	} else {
-
-	    column1.push(
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('IP address'),
-		    vtype: 'IPAddress',
-		    name: 'address'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Subnet mask'),
-		    vtype: 'IPAddress',
-		    name: 'netmask',
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.items) {
-			    return true;
-			}
-			var address = me.down('field[name=address]').getValue();
-			if (value !== '') {
-			    if (address === '') {
-				return "Subnet mask requires option 'IP address'";
-			    }
-			} else {
-			    if (address !== '') {
-				return "Option 'IP address' requires a subnet mask";
-			    }
-			}
-
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway'),
-		    vtype: 'IPAddress',
-		    name: 'gateway'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('IPv6 address'),
-		    vtype: 'IP6Address',
-		    name: 'address6'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Prefix length'),
-		    vtype: 'IP6PrefixLength',
-		    name: 'netmask6',
-		    value: '',
-		    allowBlank: true,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.items) {
-			    return true;
-			}
-			var address = me.down('field[name=address6]').getValue();
-			if (value !== '') {
-			    if (address === '') {
-				return "IPv6 prefix length requires option 'IPv6 address'";
-			    }
-			} else {
-			    if (address !== '') {
-				return "Option 'IPv6 address' requires an IPv6 prefix length";
-			    }
-			}
-
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway'),
-		    vtype: 'IP6Address',
-		    name: 'gateway6'
-		}
-	    );
-	}
-
-	Ext.applyIf(me, {
-	    url: url,
-	    method: method,
-	    items: {
-                xtype: 'inputpanel',
-		column1: column1,
-		column2: column2
-	    }
-	});
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.down('field[name=iface]').setValue(me.iface_default);
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.type !== me.iftype) {
-			var msg = "Got unexpected device type";
-			Ext.Msg.alert(gettext('Error'), msg, function() {
-			    me.close();
-			});
-			return;
-		    }
-		    me.setValues(data);
-		    me.isValid(); // trigger validation
-		}
-	    });
-	}
-    }
-});
-Ext.define('proxmox-networks', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'iface', 'type', 'active', 'autostart',
-	'bridge_ports', 'slaves',
-	'address', 'netmask', 'gateway',
-	'address6', 'netmask6', 'gateway6',
-	'comments'
-    ],
-    idProperty: 'iface'
-});
-
-Ext.define('Proxmox.node.NetworkView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.proxmoxNodeNetworkView'],
-
-    // defines what types of network devices we want to create
-    // order is always the same
-    types: ['bridge', 'bond', 'ovs'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseUrl = '/nodes/' + me.nodename + '/network';
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'proxmox-networks',
-	    proxy: {
-                type: 'proxmox',
-                url: '/api2/json' + baseUrl
-	    },
-	    sorters: [
-		{
-		    property : 'iface',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reload = function() {
-	    var changeitem = me.down('#changes');
-	    Proxmox.Utils.API2Request({
-		url: baseUrl,
-		failure: function(response, opts) {
-		    store.loadData({});
-		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		    changeitem.update('');
-		    changeitem.setHidden(true);
-		},
-		success: function(response, opts) {
-		    var result = Ext.decode(response.responseText);
-		    store.loadData(result.data);
-		    var changes = result.changes;
-		    if (changes === undefined || changes === '') {
-			changes = gettext("No changes");
-			changeitem.setHidden(true);
-		    } else {
-			changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
-			changeitem.setHidden(false);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.node.NetworkEdit', {
-		nodename: me.nodename,
-		iface: rec.data.iface,
-		iftype: rec.data.type
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: run_editor
-	});
-
-	var del_btn = new Ext.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    handler: function(){
-		var grid = me.down('gridpanel');
-		var sm = grid.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var iface = rec.data.iface;
-
-		Proxmox.Utils.API2Request({
-		    url: baseUrl + '/' + iface,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var set_button_status = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    edit_btn.setDisabled(!rec);
-	    del_btn.setDisabled(!rec);
-	};
-
-	var render_ports = function(value, metaData, record) {
-	    if (value === 'bridge') {
-		return record.data.bridge_ports;
-	    } else if (value === 'bond') {
-		return record.data.slaves;
-	    } else if (value === 'OVSBridge') {
-		return record.data.ovs_ports;
-	    } else if (value === 'OVSBond') {
-		return record.data.ovs_bonds;
-	    }
-	};
-
-	var find_next_iface_id = function(prefix) {
-	    var next;
-	    for (next = 0; next <= 9999; next++) {
-		if (!store.getById(prefix + next.toString())) {
-		    break;
-		}
-	    }
-	    return prefix + next.toString();
-	};
-
-	var menu_items = [];
-
-	if (me.types.indexOf('bridge') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bridge'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bridge',
-			iface_default: find_next_iface_id('vmbr')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('bond') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bond'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bond',
-			iface_default: find_next_iface_id('bond')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('ovs') !== -1) {
-	    if (menu_items.length > 0) {
-		menu_items.push({ xtype: 'menuseparator' });
-	    }
-
-	    menu_items.push(
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBridge',
-			    iface_default: find_next_iface_id('vmbr')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBond'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBond',
-			    iface_default: find_next_iface_id('bond')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSIntPort'
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		}
-	    );
-	}
-
-	Ext.apply(me, {
-	    layout: 'border',
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    menu: {
-			plain: true,
-			items: menu_items
-		    }
-		}, ' ',
-		{
-		    text: gettext('Revert'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: baseUrl,
-			    method: 'DELETE',
-			    waitMsgTarget: me,
-			    callback: function() {
-				reload();
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		edit_btn,
-		del_btn
-	    ],
-	    items: [
-		{
-		    xtype: 'gridpanel',
-		    stateful: true,
-		    stateId: 'grid-node-network',
-		    store: store,
-		    region: 'center',
-		    border: false,
-		    columns: [
-			{
-			    header: gettext('Name'),
-			    sortable: true,
-			    dataIndex: 'iface'
-			},
-			{
-			    header: gettext('Type'),
-			    sortable: true,
-			    width: 120,
-			    renderer: Proxmox.Utils.render_network_iface_type,
-			    dataIndex: 'type'
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Active'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'active',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText,
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Autostart'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'autostart',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('VLAN aware'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'bridge_vlan_aware',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    header: gettext('Ports/Slaves'),
-			    dataIndex: 'type',
-			    renderer: render_ports
-			},
-			{
-			    header: gettext('IP address'),
-			    sortable: true,
-			    width: 120,
-			    dataIndex: 'address',
-			    renderer: function(value, metaData, rec) {
-				if (rec.data.address && rec.data.address6) {
-				    return rec.data.address + "<br>"
-				           + rec.data.address6 + '/' + rec.data.netmask6;
-				} else if (rec.data.address6) {
-				    return rec.data.address6 + '/' + rec.data.netmask6;
-				} else {
-				    return rec.data.address;
-				}
-			    }
-			},
-			{
-			    header: gettext('Subnet mask'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'netmask'
-			},
-			{
-			    header: gettext('Gateway'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'gateway',
-			    renderer: function(value, metaData, rec) {
-				if (rec.data.gateway && rec.data.gateway6) {
-				    return rec.data.gateway + "<br>" + rec.data.gateway6;
-				} else if (rec.data.gateway6) {
-				    return rec.data.gateway6;
-				} else {
-				    return rec.data.gateway;
-				}
-			    }
-			},
-			{
-			    header: gettext('Comment'),
-			    dataIndex: 'comments',
-			    flex: 1,
-			    renderer: Ext.String.htmlEncode
-			}
-		    ],
-		    listeners: {
-			selectionchange: set_button_status,
-			itemdblclick: run_editor
-		    }
-		},
-		{
-		    border: false,
-		    region: 'south',
-		    autoScroll: true,
-		    hidden: true,
-		    itemId: 'changes',
-		    tbar: [
-			gettext('Pending changes') + ' (' +
-			    gettext('Please reboot to activate changes') + ')'
-		    ],
-		    split: true,
-		    bodyPadding: 5,
-		    flex: 0.6,
-		    html: gettext("No changes")
-		}
-	    ],
-	});
-
-	me.callParent();
-	reload();
-    }
-});
-Ext.define('Proxmox.node.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeDNSEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-                fieldLabel: gettext('Search domain'),
-                name: 'search',
-                allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 1",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns1'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS server') + " 2",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns2'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 3",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns3'
-	    }
-	];
-
-	Ext.applyIf(me, {
-	    subject: gettext('DNS'),
-	    url: "/api2/extjs/nodes/" + me.nodename + "/dns",
-	    fieldDefaults: {
-		labelWidth: 120
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('Proxmox.node.HostsView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxNodeHostsView',
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-    },
-
-    tbar: [
-	{
-	    text: gettext('Save'),
-	    disabled: true,
-	    itemId: 'savebtn',
-	    handler: function() {
-		var me = this.up('panel');
-		Proxmox.Utils.API2Request({
-		    params: {
-			digest: me.digest,
-			data: me.down('#hostsfield').getValue()
-		    },
-		    method: 'POST',
-		    url: '/nodes/' + me.nodename + '/hosts',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			me.reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	{
-	    text: gettext('Revert'),
-	    disabled: true,
-	    itemId: 'resetbtn',
-	    handler: function() {
-		var me = this.up('panel');
-		me.down('#hostsfield').reset();
-	    }
-	}
-    ],
-
-	    layout: 'fit',
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'hostsfield',
-	    fieldStyle: {
-		'font-family': 'monospace',
-		'white-space': 'pre'
-	    },
-	    listeners: {
-		dirtychange: function(ta, dirty) {
-		    var me = this.up('panel');
-		    me.down('#savebtn').setDisabled(!dirty);
-		    me.down('#resetbtn').setDisabled(!dirty);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/hosts",
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.store);
-
-	me.mon(me.store, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    me.digest = records[0].data.digest;
-	    var data = records[0].data.data;
-	    me.down('#hostsfield').setValue(data);
-	    me.down('#hostsfield').resetOriginalValue();
-	});
-
-	me.reload();
-    }
-});
-Ext.define('Proxmox.node.DNSView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeDNSView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.DNSEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/dns",
-	    cwidth1: 130,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		search: {
-		    header: 'Search domain',
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns1: {
-		    header: gettext('DNS server') + " 1",
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns2: {
-		    header: gettext('DNS server') + " 2",
-		    renderer: Ext.htmlEncode
-		},
-		dns3: {
-		    header: gettext('DNS server') + " 3",
-		    renderer: Ext.htmlEncode
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
-Ext.define('Proxmox.node.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeTasks'],
-    stateful: true,
-    stateId: 'grid-node-tasks',
-    loadMask: true,
-    sortableColumns: false,
-    vmidFilter: 0,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.BufferedStore', {
-	    pageSize: 500,
-	    autoLoad: true,
-	    remoteFilter: true,
-	    model: 'proxmox-tasks',
-	    proxy: {
-                type: 'proxmox',
-		startParam: 'start',
-		limitParam: 'limit',
-                url: "/api2/json/nodes/" + me.nodename + "/tasks"
-	    }
-	});
-
-	var userfilter = '';
-	var filter_errors = 0;
-
-	var updateProxyParams = function() {
-	    var params = {
-		errors: filter_errors
-	    };
-	    if (userfilter) {
-		params.userfilter = userfilter;
-	    }
-	    if (me.vmidFilter) {
-		params.vmid = me.vmidFilter;
-	    }
-	    store.proxy.extraParams = params;
-	};
-
-	updateProxyParams();
-
-	var reload_task = Ext.create('Ext.util.DelayedTask',function() {
-	    updateProxyParams();
-	    store.reload();
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	var view_btn = new Ext.Button({
-	    text: gettext('View'),
-	    disabled: true,
-	    handler: run_task_viewer
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	Ext.apply(me, {
-	    store: store,
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: false, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    tbar: [
-		view_btn, '->', gettext('User name') +':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: userfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    userfilter = field.getValue();
-			    reload_task.delay(500);
-			}
-		    }
-		}, ' ', gettext('Only Errors') + ':', ' ',
-		{
-		    xtype: 'checkbox',
-		    hideLabel: true,
-		    checked: filter_errors,
-		    listeners: {
-			change: function(field, checked) {
-			    filter_errors = checked ? 1 : 0;
-			    reload_task.delay(10);
-			}
-		    }
-		}, ' '
-	    ],
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 100,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 100,
-		    renderer: function(value, metaData, record) {
-			return Ext.Date.format(value,"M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return "ERROR: " + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		selectionchange: function(v, selections) {
-		    view_btn.setDisabled(!(selections && selections[0]));
-		},
-		show: function() { reload_task.delay(10); },
-		destroy: function() { reload_task.cancel(); }
-	    }
-	});
-
-	me.callParent();
-
-    }
-});
-Ext.define('proxmox-services', {
-    extend: 'Ext.data.Model',
-    fields: [ 'service', 'name', 'desc', 'state' ],
-    idProperty: 'service'
-});
-
-Ext.define('Proxmox.node.ServiceView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeServiceView'],
-
-    startOnlyServices: {},
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 1000,
-	    storeid: 'proxmox-services' + me.nodename,
-	    model: 'proxmox-services',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/services"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sortAfterUpdate: true,
-	    sorters: [
-		{
-		    property : 'name',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var view_service_log = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + rec.data.service,
-		modal: true,
-		items: {
-		    xtype: 'proxmoxLogView',
-		    width: 800,
-		    height: 400,
-		    url: "/api2/extjs/nodes/" + me.nodename + "/syslog?service=" +
-			rec.data.service,
-		    log_select_timespan: 1
-		}
-	    });
-	    win.show();
-	};
-
-	var service_cmd = function(cmd) {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/services/" + rec.data.service + "/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.loading = true;
-		},
-		success: function(response, opts) {
-		    rstore.startUpdate();
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid
-		    });
-		    win.show();
-		}
-	    });
-	};
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var syslog_btn = new Ext.Button({
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: view_service_log
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		start_btn.disable();
-		stop_btn.disable();
-		restart_btn.disable();
-		syslog_btn.disable();
-		return;
-	    }
-	    var service = rec.data.service;
-	    var state = rec.data.state;
-
-	    syslog_btn.enable();
-
-	    if (me.startOnlyServices[service]) {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		}
-		stop_btn.disable();
-	    } else {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		    stop_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		    stop_btn.disable();
-		}
-	    }
-	};
-
-	me.mon(store, 'refresh', set_button_status);
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    tbar: [ start_btn, stop_btn, restart_btn, syslog_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Description'),
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'desc',
-		    flex: 2
-		}
-	    ],
-	    listeners: {
-		selectionchange: set_button_status,
-		itemdblclick: view_service_log,
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeTimeEdit'],
-
-    subject: gettext('Time zone'),
-
-    width: 400,
-
-    autoLoad: true,
-
-    fieldDefaults: {
-	labelWidth: 70
-    },
-
-    items: {
-	xtype: 'combo',
-	fieldLabel: gettext('Time zone'),
-	name: 'timezone',
-	queryMode: 'local',
-	store: Ext.create('Proxmox.data.TimezoneStore'),
-	displayField: 'zone',
-	forceSelection: true,
-	editable: false,
-	allowBlank: false
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/time";
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeTimeView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var tzoffset = (new Date()).getTimezoneOffset()*60000;
-	var renderlocaltime = function(value) {
-	    var servertime = new Date((value * 1000) + tzoffset);
-	    return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-	};
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.TimeEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/time",
-	    cwidth1: 150,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		timezone: { 
-		    header: gettext('Time zone'), 
-		    required: true
-		},
-		localtime: { 
-		    header: gettext('Server time'), 
-		    required: true, 
-		    renderer: renderlocaltime 
-		}
-	    },
-	    tbar: [ 
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
diff --git a/serverside/jsmod/5.4-3/proxmoxlib.js.original b/serverside/jsmod/5.4-3/proxmoxlib.js.original
deleted file mode 100644
index 921391f984f2aae334f4fe97f9fbb8762d11a265..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/proxmoxlib.js.original
+++ /dev/null
@@ -1,6757 +0,0 @@
-// 1.0-25
-Ext.ns('Proxmox');
-Ext.ns('Proxmox.Setup');
-
-if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
-    throw "Proxmox library not initialized";
-}
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	dir: function() {},
-	log: function() {}
-    };
-}
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (Proxmox.CSRFPreventionToken) {
-	if (!options.headers) {
-	    options.headers = {};
-	}
-	options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-    }
-});
-
-Ext.define('Proxmox.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    enabledText: gettext('Enabled'),
-    disabledText: gettext('Disabled'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    stateText: gettext('State'),
-    groupText: gettext('Group'),
-
-    language_map: {
-	zh_CN: 'Chinese (Simplified)',
-	zh_TW: 'Chinese (Traditional)',
-	ca: 'Catalan',
-	da: 'Danish',
-	en: 'English',
-	eu: 'Euskera (Basque)',
-	fr: 'French',
-	de: 'German',
-	it: 'Italian',
-	es: 'Spanish',
-	ja: 'Japanese',
-	nb: 'Norwegian (Bokmal)',
-	nn: 'Norwegian (Nynorsk)',
-	fa: 'Persian (Farsi)',
-	pl: 'Polish',
-	pt_BR: 'Portuguese (Brazil)',
-	ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	tr: 'Turkish'
-    },
-
-    render_language: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (English)';
-	}
-	var text = Proxmox.Utils.language_map[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    language_array: function() {
-	var data = [['__default__', Proxmox.Utils.render_language('')]];
-	Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
-	    data.push([key, Proxmox.Utils.render_language(value)]);
-	});
-
-	return data;
-    },
-
-    getNoSubKeyHtml: function(url) {
-	// url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
-	return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'http://www.proxmox.com');
-    },
-
-    format_boolean_with_default: function(value) {
-	if (Ext.isDefined(value) && value !== '__default__') {
-	    return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-	}
-	return Proxmox.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-	return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-	return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_enabled_toggle: function(value) {
-	return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
-    },
-
-    format_expire: function(date) {
-	if (!date) {
-	    return Proxmox.Utils.neverText;
-	}
-	return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_duration_long: function(ut) {
-
-	var days = Math.floor(ut / 86400);
-	ut -= days*86400;
-	var hours = Math.floor(ut / 3600);
-	ut -= hours*3600;
-	var mins = Math.floor(ut / 60);
-	ut -= mins*60;
-
-	var hours_str = '00' + hours.toString();
-	hours_str = hours_str.substr(hours_str.length - 2);
-	var mins_str = "00" + mins.toString();
-	mins_str = mins_str.substr(mins_str.length - 2);
-	var ut_str = "00" + ut.toString();
-	ut_str = ut_str.substr(ut_str.length - 2);
-
-	if (days) {
-	    var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
-	    return days.toString() + ' ' + ds + ' ' +
-		hours_str + ':' + mins_str + ':' + ut_str;
-	} else {
-	    return hours_str + ':' + mins_str + ':' + ut_str;
-	}
-    },
-
-    format_subscription_level: function(level) {
-	if (level === 'c') {
-	    return 'Community';
-	} else if (level === 'b') {
-	    return 'Basic';
-	} else if (level === 's') {
-	    return 'Standard';
-	} else if (level === 'p') {
-	    return 'Premium';
-	} else {
-	    return Proxmox.Utils.noneText;
-	}
-    },
-
-    compute_min_label_width: function(text, width) {
-
-	if (width === undefined) { width = 100; }
-
-	var tm = new Ext.util.TextMetrics();
-	var min = tm.getWidth(text + ':');
-
-	return min < width ? width : min;
-    },
-
-    setAuthData: function(data) {
-	Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
-	Proxmox.UserName = data.username;
-	Proxmox.LoggedOut = data.LoggedOut;
-	// creates a session cookie (expire = null)
-	// that way the cookie gets deleted after the browser window is closed
-	Ext.util.Cookies.set(Proxmox.Setup.auth_cookie_name, data.ticket, null, '/', null, true);
-    },
-
-    authOK: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
-    },
-
-    authClear: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-	var el = comp.el;
-	if (!el) {
-	    return;
-	}
-	if (!msg) {
-	    el.unmask();
-	} else {
-	    if (msg === true) {
-		el.mask(gettext("Loading..."));
-	    } else {
-		el.mask(msg);
-	    }
-	}
-    },
-
-    monStoreErrors: function(me, store, clearMaskBeforeLoad) {
-	if (clearMaskBeforeLoad) {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		Proxmox.Utils.setErrorMask(me, false);
-	    });
-	} else {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		if (!me.loadCount) {
-		    me.loadCount = 0; // make sure it is numeric
-		    Proxmox.Utils.setErrorMask(me, true);
-		}
-	    });
-	}
-
-	// only works with 'proxmox' proxy
-	me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-	    me.loadCount++;
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-
-	    var msg;
-	    /*jslint nomen: true */
-	    var operation = request._operation;
-	    var error = operation.getError();
-	    if (error.statusText) {
-		msg = error.statusText + ' (' + error.status + ')';
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    extractRequestError: function(result, verbose) {
-	var msg = gettext('Successful');
-
-	if (!result.success) {
-	    msg = gettext("Unknown error");
-	    if (result.message) {
-		msg = result.message;
-		if (result.status) {
-		    msg += ' (' + result.status + ')';
-		}
-	    }
-	    if (verbose && Ext.isObject(result.errors)) {
-		msg += "<br>";
-		Ext.Object.each(result.errors, function(prop, desc) {
-		    msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
-			Ext.htmlEncode(desc);
-		});
-	    }
-	}
-
-	return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-	var newopts = Ext.apply({
-	    waitMsg: gettext('Please wait...')
-	}, reqOpts);
-
-	if (!newopts.url.match(/^\/api2/)) {
-	    newopts.url = '/api2/extjs' + newopts.url;
-	}
-	delete newopts.callback;
-
-	var createWrapper = function(successFn, callbackFn, failureFn) {
-	    Ext.apply(newopts, {
-		success: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    var result = Ext.decode(response.responseText);
-		    response.result = result;
-		    if (!result.success) {
-			response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.callback(callbackFn, options.scope, [options, false, response]);
-			Ext.callback(failureFn, options.scope, [response, options]);
-			return;
-		    }
-		    Ext.callback(callbackFn, options.scope, [options, true, response]);
-		    Ext.callback(successFn, options.scope, [response, options]);
-		},
-		failure: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    response.result = {};
-		    try {
-			response.result = Ext.decode(response.responseText);
-		    } catch(e) {}
-		    var msg = gettext('Connection error') + ' - server offline?';
-		    if (response.aborted) {
-			msg = gettext('Connection error') + ' - aborted.';
-		    } else if (response.timedout) {
-			msg = gettext('Connection error') + ' - Timeout.';
-		    } else if (response.status && response.statusText) {
-			msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-		    }
-		    response.htmlStatus = msg;
-		    Ext.callback(callbackFn, options.scope, [options, false, response]);
-		    Ext.callback(failureFn, options.scope, [response, options]);
-		}
-	    });
-	};
-
-	createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-	var target = newopts.waitMsgTarget;
-	if (target) {
-	    if (Proxmox.Utils.toolkit === 'touch') {
-		target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-	    } else {
-		// Note: ExtJS bug - this does not work when component is not rendered
-		target.setLoading(newopts.waitMsg);
-	    }
-	}
-	Ext.Ajax.request(newopts);
-    },
-
-    checked_command: function(orig_cmd) {
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/localhost/subscription',
-	    method: 'GET',
-	    //waitMsgTarget: me,
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-
-		if (data.status !== 'Active') {
-		    Ext.Msg.show({
-			title: gettext('No valid subscription'),
-			icon: Ext.Msg.WARNING,
-			msg: Proxmox.Utils.getNoSubKeyHtml(data.url),
-			buttons: Ext.Msg.OK,
-			callback: function(btn) {
-			    if (btn !== 'ok') {
-				return;
-			    }
-			    orig_cmd();
-			}
-		    });
-		} else {
-		    orig_cmd();
-		}
-	    }
-	});
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-	    Ext.Object.each(data, function(name, val) {
-		if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-		    values[name] = val;
-                }
-            });
-	}
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-	if (create) {
-	    if (isAdd) {
-		return gettext('Add') + ': ' + subject;
-	    } else {
-		return gettext('Create') + ': ' + subject;
-	    }
-	} else {
-	    return gettext('Edit') + ': ' + subject;
-	}
-    },
-
-    network_iface_types: {
-	eth: gettext("Network Device"),
-	bridge: 'Linux Bridge',
-	bond: 'Linux Bond',
-	vlan: 'Linux VLAN',
-	OVSBridge: 'OVS Bridge',
-	OVSBond: 'OVS Bond',
-	OVSPort: 'OVS Port',
-	OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-	return Proxmox.Utils.network_iface_types[value] ||
-	    Proxmox.Utils.unknownText;
-    },
-
-    task_desc_table: {
-	acmenewcert: [ 'SRV', gettext('Order Certificate') ],
-	acmeregister: [ 'ACME Account', gettext('Register') ],
-	acmedeactivate: [ 'ACME Account', gettext('Deactivate') ],
-	acmeupdate: [ 'ACME Account', gettext('Update') ],
-	acmerefresh: [ 'ACME Account', gettext('Refresh') ],
-	acmerenew: [ 'SRV', gettext('Renew Certificate') ],
-	acmerevoke: [ 'SRV', gettext('Revoke Certificate') ],
-	'move_volume': [ 'CT', gettext('Move Volume') ],
-	clustercreate: [ '', gettext('Create Cluster') ],
-	clusterjoin: [ '', gettext('Join Cluster') ],
-	diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ],
-	vncproxy: [ 'VM/CT', gettext('Console') ],
-	spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-	vncshell: [ '', gettext('Shell') ],
-	spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-	qmsnapshot: [ 'VM', gettext('Snapshot') ],
-	qmrollback: [ 'VM', gettext('Rollback') ],
-	qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-	qmcreate: [ 'VM', gettext('Create') ],
-	qmrestore: [ 'VM', gettext('Restore') ],
-	qmdestroy: [ 'VM', gettext('Destroy') ],
-	qmigrate: [ 'VM', gettext('Migrate') ],
-	qmclone: [ 'VM', gettext('Clone') ],
-	qmmove: [ 'VM', gettext('Move disk') ],
-	qmtemplate: [ 'VM', gettext('Convert to template') ],
-	qmstart: [ 'VM', gettext('Start') ],
-	qmstop: [ 'VM', gettext('Stop') ],
-	qmreset: [ 'VM', gettext('Reset') ],
-	qmshutdown: [ 'VM', gettext('Shutdown') ],
-	qmsuspend: [ 'VM', gettext('Hibernate') ],
-	qmpause: [ 'VM', gettext('Pause') ],
-	qmresume: [ 'VM', gettext('Resume') ],
-	qmconfig: [ 'VM', gettext('Configure') ],
-	vzsnapshot: [ 'CT', gettext('Snapshot') ],
-	vzrollback: [ 'CT', gettext('Rollback') ],
-	vzdelsnapshot: [ 'CT', gettext('Delete Snapshot') ],
-	vzcreate: ['CT', gettext('Create') ],
-	vzrestore: ['CT', gettext('Restore') ],
-	vzdestroy: ['CT', gettext('Destroy') ],
-	vzmigrate: [ 'CT', gettext('Migrate') ],
-	vzclone: [ 'CT', gettext('Clone') ],
-	vztemplate: [ 'CT', gettext('Convert to template') ],
-	vzstart: ['CT', gettext('Start') ],
-	vzstop: ['CT', gettext('Stop') ],
-	vzmount: ['CT', gettext('Mount') ],
-	vzumount: ['CT', gettext('Unmount') ],
-	vzshutdown: ['CT', gettext('Shutdown') ],
-	vzsuspend: [ 'CT', gettext('Suspend') ],
-	vzresume: [ 'CT', gettext('Resume') ],
-	hamigrate: [ 'HA', gettext('Migrate') ],
-	hastart: [ 'HA', gettext('Start') ],
-	hastop: [ 'HA', gettext('Stop') ],
-	srvstart: ['SRV', gettext('Start') ],
-	srvstop: ['SRV', gettext('Stop') ],
-	srvrestart: ['SRV', gettext('Restart') ],
-	srvreload: ['SRV', gettext('Reload') ],
-	cephcreatemgr: ['Ceph Manager', gettext('Create') ],
-	cephdestroymgr: ['Ceph Manager', gettext('Destroy') ],
-	cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-	cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-	cephcreateosd: ['Ceph OSD', gettext('Create') ],
-	cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-	cephcreatepool: ['Ceph Pool', gettext('Create') ],
-	cephdestroypool: ['Ceph Pool', gettext('Destroy') ],
-	cephfscreate: ['CephFS', gettext('Create') ],
-	cephcreatemds: ['Ceph Metadata Server', gettext('Create') ],
-	cephdestroymds: ['Ceph Metadata Server', gettext('Destroy') ],
-	imgcopy: ['', gettext('Copy data') ],
-	imgdel: ['', gettext('Erase data') ],
-	unknownimgdel: ['', gettext('Destroy image from unknown guest') ],
-	download: ['', gettext('Download') ],
-	vzdump: ['VM/CT', gettext('Backup') ],
-	aptupdate: ['', gettext('Update package database') ],
-	startall: [ '', gettext('Start all VMs and Containers') ],
-	stopall: [ '', gettext('Stop all VMs and Containers') ],
-	migrateall: [ '', gettext('Migrate all VMs and Containers') ],
-	dircreate: [ gettext('Directory Storage'), gettext('Create') ],
-	lvmcreate: [ gettext('LVM Storage'), gettext('Create') ],
-	lvmthincreate: [ gettext('LVM-Thin Storage'), gettext('Create') ],
-	zfscreate: [ gettext('ZFS Storage'), gettext('Create') ]
-    },
-
-    format_task_description: function(type, id) {
-	var farray = Proxmox.Utils.task_desc_table[type];
-	var text;
-	if (!farray) {
-	    text = type;
-	    if (id) {
-		type += ' ' + id;
-	    }
-	    return text;
-	}
-	var prefix = farray[0];
-	text = farray[1];
-	if (prefix) {
-	    return prefix + ' ' + id + ' - ' + text;
-	}
-	return text;
-    },
-
-    format_size: function(size) {
-	/*jslint confusion: true */
-
-	var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
-	var num = 0;
-
-	while (size >= 1024 && ((num++)+1) < units.length) {
-	    size = size / 1024;
-	}
-
-	return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    render_uptime: function(value) {
-
-	var uptime = value;
-
-	if (uptime === undefined) {
-	    return '';
-	}
-
-	if (uptime <= 0) {
-	    return '-';
-	}
-
-	return Proxmox.Utils.format_duration_long(uptime);
-    },
-
-    parse_task_upid: function(upid) {
-	var task = {};
-
-	var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-	if (!res) {
-	    throw "unable to parse upid '" + upid + "'";
-	}
-	task.node = res[1];
-	task.pid = parseInt(res[2], 16);
-	task.pstart = parseInt(res[3], 16);
-	task.starttime = parseInt(res[4], 16);
-	task.type = res[5];
-	task.id = res[6];
-	task.user = res[7];
-
-	task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	return task;
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-	var servertime = new Date(value * 1000);
-	return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    openXtermJsViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    xtermjs: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    cmd: cmd,
-
-	});
-	var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
-	if (nw) {
-	    nw.focus();
-	}
-    }
-
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-
-	var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-	var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-	var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-	var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-
-
-	me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-	me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/([0-9]{1,2})$");
-
-	var IPV6_REGEXP = "(?:" +
-	    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-	    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-	    ")";
-
-	me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-	me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/([0-9]{1,3})$");
-	me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-	me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-
-	var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
-	me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
-
-	me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
-	me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
-	me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
-    }
-});
-// ExtJS related things
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-	return Proxmox.Utils.IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP4_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 32);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24' + "<br>" + gettext('Valid CIDR Range') + ': 8-32',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return Proxmox.Utils.IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP6_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 128);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64' + "<br>" + gettext('Valid CIDR Range') + ': 8-128',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-	return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-
-    IP64Address:  function(v) {
-        return Proxmox.Utils.IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    MacAddress: function(v) {
-	return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    MacPrefix:  function(v) {
-	return (/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i).test(v);
-    },
-    MacPrefixMask: /[a-fA-F0-9:]/,
-    MacPrefixText: gettext('Example') + ': 02:8f - ' + gettext('only unicast addresses are allowed'),
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext("Allowed characters") + ": 'a-z', '0-9', '_'" + "<br />" +
-		       gettext("Minimum characters") + ": 2" + "<br />" +
-		       gettext("Maximum characters") + ": 21" + "<br />" +
-		       gettext("Must start with") + ": 'a-z'",
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'" + "<br />" +
-		   gettext("Minimum characters") + ": 2" + "<br />" +
-		   gettext("Must start with") + ": 'A-Z', 'a-z'<br />" +
-		   gettext("Must end with") + ": 'A-Z', 'a-z', '0-9'<br />",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'" + "<br />" +
-		  gettext("Minimum characters") + ": 2" + "<br />" +
-		  gettext("Must start with") + ": " + gettext("letter"),
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-	return Proxmox.Utils.DnsName_match.test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name'),
-
-    // workaround for https://www.sencha.com/forum/showthread.php?302150
-    proxmoxMail: function(v) {
-        return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
-    },
-    proxmoxMailText: gettext('Example') + ": user@example.com",
-
-    DnsOrIp: function(v) {
-	if (!Proxmox.Utils.DnsName_match.test(v) &&
-	    !Proxmox.Utils.IP64_match.test(v)) {
-	    return false;
-	}
-
-	return true;
-    },
-    DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
-
-    HostList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == "") {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
-		!Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
-		!Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    HostListText: gettext('Not a valid list of hosts'),
-
-    password: function(val, field) {
-        if (field.initialPassField) {
-            var pwd = field.up('form').down(
-		'[name=' + field.initialPassField + ']');
-            return (val == pwd.getValue());
-        }
-        return true;
-    },
-
-    passwordText: gettext('Passwords do not match')
-});
-
-// Firefox 52+ Touchscreen bug
-// see https://www.sencha.com/forum/showthread.php?336762-Examples-don-t-work-in-Firefox-52-touchscreen/page2
-// and https://bugzilla.proxmox.com/show_bug.cgi?id=1223
-Ext.define('EXTJS_23846.Element', {
-    override: 'Ext.dom.Element'
-}, function(Element) {
-    var supports = Ext.supports,
-        proto = Element.prototype,
-        eventMap = proto.eventMap,
-        additiveEvents = proto.additiveEvents;
-
-    if (Ext.os.is.Desktop && supports.TouchEvents && !supports.PointerEvents) {
-        eventMap.touchstart = 'mousedown';
-        eventMap.touchmove = 'mousemove';
-        eventMap.touchend = 'mouseup';
-        eventMap.touchcancel = 'mouseup';
-
-        additiveEvents.mousedown = 'mousedown';
-        additiveEvents.mousemove = 'mousemove';
-        additiveEvents.mouseup = 'mouseup';
-        additiveEvents.touchstart = 'touchstart';
-        additiveEvents.touchmove = 'touchmove';
-        additiveEvents.touchend = 'touchend';
-        additiveEvents.touchcancel = 'touchcancel';
-
-        additiveEvents.pointerdown = 'mousedown';
-        additiveEvents.pointermove = 'mousemove';
-        additiveEvents.pointerup = 'mouseup';
-        additiveEvents.pointercancel = 'mouseup';
-    }
-});
-
-Ext.define('EXTJS_23846.Gesture', {
-    override: 'Ext.event.publisher.Gesture'
-}, function(Gesture) {
-    var me = Gesture.instance;
-
-    if (Ext.supports.TouchEvents && !Ext.isWebKit && Ext.os.is.Desktop) {
-        me.handledDomEvents.push('mousedown', 'mousemove', 'mouseup');
-        me.registerEvents();
-    }
-});
-
-// we always want the number in x.y format and never in, e.g., x,y
-Ext.define('PVE.form.field.Number', {
-    override: 'Ext.form.field.Number',
-    submitLocaleSeparator: false
-});
-
-// ExtJs 5-6 has an issue with caching
-// see https://www.sencha.com/forum/showthread.php?308989
-Ext.define('Proxmox.UnderlayPool', {
-    override: 'Ext.dom.UnderlayPool',
-
-    checkOut: function () {
-        var cache = this.cache,
-            len = cache.length,
-            el;
-
-        // do cleanup because some of the objects might have been destroyed
-	while (len--) {
-            if (cache[len].destroyed) {
-                cache.splice(len, 1);
-            }
-        }
-        // end do cleanup
-
-	el = cache.shift();
-
-        if (!el) {
-            el = Ext.Element.create(this.elementConfig);
-            el.setVisibilityMode(2);
-            //<debug>
-            // tell the spec runner to ignore this element when checking if the dom is clean
-	    el.dom.setAttribute('data-sticky', true);
-            //</debug>
-	}
-
-        return el;
-    }
-});
-
-// 'Enter' in Textareas and aria multiline fields should not activate the
-// defaultbutton, fixed in extjs 6.0.2
-Ext.define('PVE.panel.Panel', {
-    override: 'Ext.panel.Panel',
-
-    fireDefaultButton: function(e) {
-	if (e.target.getAttribute('aria-multiline') === 'true' ||
-	    e.target.tagName === "TEXTAREA") {
-	    return true;
-	}
-	return this.callParent(arguments);
-    }
-});
-
-// if the order of the values are not the same in originalValue and value
-// extjs will not overwrite value, but marks the field dirty and thus
-// the reset button will be enabled (but clicking it changes nothing)
-// so if the arrays are not the same after resetting, we
-// clear and set it
-Ext.define('Proxmox.form.ComboBox', {
-    override: 'Ext.form.field.ComboBox',
-
-    reset: function() {
-	// copied from combobox
-	var me = this;
-	me.callParent();
-
-	// clear and set when not the same
-	var value = me.getValue();
-	if (Ext.isArray(me.originalValue) && Ext.isArray(value) && !Ext.Array.equals(value, me.originalValue)) {
-	    me.clearValue();
-	    me.setValue(me.originalValue);
-	}
-    }
-});
-
-// when refreshing a grid/tree view, restoring the focus moves the view back to
-// the previously focused item. Save scroll position before refocusing.
-Ext.define(null, {
-    override: 'Ext.view.Table',
-
-    jumpToFocus: false,
-
-    saveFocusState: function() {
-        var me = this,
-            store = me.dataSource,
-            actionableMode = me.actionableMode,
-            navModel = me.getNavigationModel(),
-            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
-            refocusRow, refocusCol;
-
-        if (focusPosition) {
-            // Separate this from the instance that the nav model is using.
-            focusPosition = focusPosition.clone();
-
-            // Exit actionable mode.
-            // We must inform any Actionables that they must relinquish control.
-            // Tabbability must be reset.
-            if (actionableMode) {
-                me.ownerGrid.setActionableMode(false);
-            }
-
-            // Blur the focused descendant, but do not trigger focusLeave.
-            me.el.dom.focus();
-
-            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
-            // clear the navigation position
-            navModel.setPosition();
-
-            // The following function will attempt to refocus back in the same mode to the same cell
-            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
-            return function() {
-                // If we still have data, attempt to refocus in the same mode.
-                if (store.getCount()) {
-
-                    // Adjust expectations of where we are able to refocus according to what kind of destruction
-                    // might have been wrought on this view's DOM during focus save.
-                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
-                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
-                    focusPosition = new Ext.grid.CellContext(me).setPosition(
-                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
-
-                    if (actionableMode) {
-                        me.ownerGrid.setActionableMode(true, focusPosition);
-                    } else {
-                        me.cellFocused = true;
-
-			// we sometimes want to scroll back to where we were
-			var x = me.getScrollX();
-			var y = me.getScrollY();
-
-                        // Pass "preventNavigation" as true so that that does not cause selection.
-                        navModel.setPosition(focusPosition, null, null, null, true);
-
-			if (!me.jumpToFocus) {
-			    me.scrollTo(x,y);
-			}
-                    }
-                }
-                // No rows - focus associated column header
-                else {
-                    focusPosition.column.focus();
-                }
-            };
-        }
-        return Ext.emptyFn;
-    }
-});
-
-// should be fixed with ExtJS 6.0.2, see:
-// https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
-Ext.define('Proxmox.Datepicker', {
-    override: 'Ext.picker.Date',
-    hideMode: 'visibility'
-});
-
-// ExtJS 6.0.1 has no setSubmitValue() (although you find it in the docs).
-// Note: this.submitValue is a boolean flag, whereas getSubmitValue() returns
-// data to be submitted.
-Ext.define('Proxmox.form.field.Text', {
-    override: 'Ext.form.field.Text',
-
-    setSubmitValue: function(v) {
-	this.submitValue = v;
-    },
-});
-
-// this should be fixed with ExtJS 6.0.2
-// make mousescrolling work in firefox in the containers overflowhandler
-Ext.define(null, {
-    override: 'Ext.layout.container.boxOverflow.Scroller',
-
-    createWheelListener: function() {
-	var me = this;
-	if (Ext.isFirefox) {
-	    me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
-	} else {
-	    me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
-	}
-    },
-
-    // special wheel handler for firefox. differs from the default onMouseWheel
-    // handler by using deltaY instead of wheelDeltaY and no normalizing,
-    // because it is already
-    onMouseWheelFirefox: function(e) {
-	e.stopEvent();
-	var delta = e.browserEvent.deltaY || 0;
-	this.scrollBy(delta * this.wheelIncrement, false);
-    }
-
-});
-
-// force alert boxes to be rendered with an Error Icon
-// since Ext.Msg is an object and not a prototype, we need to override it
-// after the framework has been initiated
-Ext.onReady(function() {
-/*jslint confusion: true */
-    Ext.override(Ext.Msg, {
-	alert: function(title, message, fn, scope) {
-	    if (Ext.isString(title)) {
-		var config = {
-		    title: title,
-		    message: message,
-		    icon: this.ERROR,
-		    buttons: this.OK,
-		    fn: fn,
-		    scope : scope,
-		    minWidth: this.minWidth
-		};
-	    return this.show(config);
-	    }
-	}
-    });
-/*jslint confusion: false */
-});
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" id="{id}-iframeEl" data-ref="iframeEl" name="{frameName}" width="100%" height="100%" frameborder="0" allowfullscreen="true"></iframe>'
-    ],
-    childEls: ['iframeEl'],
-
-    initComponent: function () {
-        this.callParent();
-
-        this.frameName = this.frameName || this.id + '-frame';
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-                doc = this.getDoc();
-                if (doc) {
-		    /*jslint nomen: true*/
-                    Ext.get(doc).un(this._docListeners);
-		    /*jslint nomen: false*/
-                    if (destroying && doc.hasOwnProperty) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-		/*jslint nomen: true*/
-                Ext.get(doc).on(
-                    me._docListeners = {
-                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                        mousemove: fn, // window resize drag detection
-                        mouseup: fn,   // window resize termination
-                        click: fn,     // not sure, but just to be safe
-                        dblclick: fn,  // not sure again
-                        scope: me
-                    }
-                );
-		/*jslint nomen: false*/
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.get(this.getWin()).on('beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if (me.src) {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    onRelayedEvent: function (event) {
-        // relay event from the iframe's document to the document that owns the iframe...
-
-        var iframeEl = this.iframeEl,
-
-            // Get the left-based iframe position
-            iframeXY = iframeEl.getTrueXY(),
-            originalEventXY = event.getXY(),
-
-            // Get the left-based XY position.
-            // This is because the consumer of the injected event will
-            // perform its own RTL normalization.
-            eventXY = event.getTrueXY();
-
-        // the event from the inner document has XY relative to that document's origin,
-        // so adjust it to use the origin of the iframe in the outer document:
-        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
-
-        event.injectEvent(iframeEl); // blame the iframe for the event...
-
-        event.xy = originalEventXY; // restore the original XY (just for safety)
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
-Ext.define('Proxmox.Mixin.CBind', {
-    extend: 'Ext.Mixin',
-
-    mixinConfig: {
-        before: {
-            initComponent: 'cloneTemplates'
-        }
-    },
-
-    cloneTemplates: function() {
-	var me = this;
-	
- 	if (typeof(me.cbindData) == "function") {
-	    me.cbindData = me.cbindData(me.initialConfig) || {};
-	}
-	
-	var getConfigValue = function(cname) {
-
-	    if (cname in me.initialConfig) {
-		return me.initialConfig[cname];
-	    }
-	    if (cname in me.cbindData) {
-		return me.cbindData[cname];
-	    }	    
-	    if (cname in me) {
-		return me[cname];
-	    }
-	    throw "unable to get cbind data for '" + cname + "'";
-	};
-	
-	var applyCBind = function(obj) {
-	    var cbind = obj.cbind, prop, cdata, cvalue, match, found;
-	    if (!cbind) return;
-
-	    for (prop in cbind) {
-		cdata = cbind[prop];
-
-		found = false;
-		if (match = /^\{(!)?([a-z_][a-z0-9_]*)\}$/i.exec(cdata)) {
-		    var cvalue = getConfigValue(match[2]);
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)+)\}$/i.exec(cdata)) {
-		    var keys = match[2].split('.');
-		    var cvalue = getConfigValue(keys.shift());
-		    keys.forEach(function(k) {
-			if (k in cvalue) {
-			    cvalue = cvalue[k];
-			} else {
-			    throw "unable to get cbind data for '" + match[2] + "'";
-			}
-		    });
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else {
-		    obj[prop] = cdata.replace(/{([a-z_][a-z0-9_]*)\}/ig, function(match, cname) {
-			var cvalue = getConfigValue(cname);
-			found = true;
-			return cvalue;
-		    });
-		}
-		if (!found) {
-		    throw "unable to parse cbind template '" + cdata + "'";
-		}
-
-	    }
-	};
-
-	if (me.cbind) {
-	    applyCBind(me);
-	}
-	
-	var cloneTemplateArray = function(org) {
-	    var copy, i, found, el, elcopy, arrayLength;
-
-	    arrayLength = org.length;
-	    found = false;
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    found = true;
-		    break;
-		}
-	    }
-
-	    if (!found) return org; // no need to copy
-
-	    copy = [];
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    elcopy = cloneTemplateObject(el);
-		    if (elcopy.cbind) {
-			applyCBind(elcopy);
-		    }
-		    copy.push(elcopy);
-		} else if (el.constructor == Array) {
-		    elcopy = cloneTemplateArray(el);
-		    copy.push(elcopy);
-		} else {
-		    copy.push(el);
-		}
-	    }
-	    return copy;
-	};
-	
-	var cloneTemplateObject = function(org) {
-	    var res = {}, prop, el, copy;
-	    for (prop in org) {
-		el = org[prop];
-		if (el.constructor == Object && el.xtype) {
-		    copy = cloneTemplateObject(el);
-		    if (copy.cbind) {
-			applyCBind(copy);
-		    }
-		    res[prop] = copy;
-		} else if (el.constructor == Array) {
-		    copy = cloneTemplateArray(el);
-		    res[prop] = copy;
-		} else {
-		    res[prop] = el;
-		}
-	    }
-	    return res;
-	};
-
-	var condCloneProperties = function() {
-	    var prop, el, i, tmp;
-	
-	    for (prop in me) {
-		el = me[prop];
-		if (el === undefined || el === null) continue;
-		if (typeof(el) === 'object' && el.constructor == Object) {
-		    if (el.xtype && prop != 'config') {
-			me[prop] = cloneTemplateObject(el);
-		    }
-		} else if (el.constructor == Array) {
-		    tmp = cloneTemplateArray(el);
-		    me[prop] = tmp;
-		}
-	    }
-	};
-
-	condCloneProperties();
-    }
-});
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash. 
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"} 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ] 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('Proxmox.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-    
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-	me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-	var me = this;
-
-	var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-	    if (me.readArray) {
-
-		var rec_hash = {};
-		Ext.Array.each(root, function(rec) {
-		    if (Ext.isDefined(rec.key)) {
-			rec_hash[rec.key] = rec;
-		    }
-		});
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			var rec = rec_hash[key];
-			if (Ext.isDefined(rec)) {
-			    if (!Ext.isDefined(rec.value)) {
-				rec.value = rowdef.defaultValue;
-			    }
-			    data.push(rec);
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue} );
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined });
-			}
-		    });
-		} else {
-		    Ext.Array.each(root, function(rec) {
-			if (Ext.isDefined(rec.key)) {
-			    data.push(rec);
-			}
-		    });
-		}
-		
-	    } else { 
-		
-		var org_root = root;
-
-		if (Ext.isArray(org_root)) {
-		    if (root.length == 1) {
-			root = org_root[0];
-		    } else {
-			root = {};
-		    }
-		}
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			if (Ext.isDefined(root[key])) {
-			    data.push({key: key, value: root[key]});
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue});
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined});
-			}
-		    });
-		} else {
-		    Ext.Object.each(root, function(key, value) {
-			data.push({key: key, value: value });
-		    });
-		}
-	    }
-	}
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-	return data;
-    }
-});
-
-Ext.define('Proxmox.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.proxmox',
-
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-
-    afterRequest: function(request, success) {
-	this.fireEvent('afterload', this, request, success);
-	return;
-    },
-
-    constructor: function(config) {
-
-	Ext.applyIf(config, {
-	    reader: {
-		type: 'json',
-		rootProperty: config.root || 'data'
-	    }
-	});
-
-	this.callParent([config]);
-    }
-}, function() {
-
-    Ext.define('KeyValue', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value', 'pending', 'delete' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('proxmox-tasks', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'starttime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'endtime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'upid', 'user', 'status', 'type', 'id'
-	],
-	idProperty: 'upid'
-    });
-
-    Ext.define('proxmox-cluster-log', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'uid' , type: 'int' },
-	    { name: 'time', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pri', type: 'int' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'user', 'tag', 'msg',
-	    {
-		name: 'id',
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-		    // compute unique ID
-		    return info.uid + ':' + info.node;
-		}
-	    }
-	],
-	idProperty: 'id'
-    });
-
-});
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- *
- * Note that you have to call yourself startUpdate() for the background load
- * to begin
- */
-Ext.define('Proxmox.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.update',
-
-    isStopped: true,
-
-    autoStart: false,
-
-    destroy: function() {
-	var me = this;
-	me.stopUpdate();
-	me.callParent();
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.interval) {
-	    config.interval = 3000;
-	}
-
-	if (!config.storeid) {
-	    throw "no storeid specified";
-	}
-
-	var load_task = new Ext.util.DelayedTask();
-
-	var run_load_task = function() {
-	    if (me.isStopped) {
-		return;
-	    }
-
-	    if (Proxmox.Utils.authOK()) {
-		var start = new Date();
-		me.load(function() {
-		    var runtime = (new Date()) - start;
-		    var interval = config.interval + runtime*2;
-		    load_task.delay(interval, run_load_task);
-		});
-	    } else {
-		load_task.delay(200, run_load_task);
-	    }
-	};
-
-	Ext.apply(config, {
-	    startUpdate: function() {
-		me.isStopped = false;
-		// run_load_task(); this makes problems with chrome
-		load_task.delay(1, run_load_task);
-	    },
-	    stopUpdate: function() {
-		me.isStopped = true;
-		load_task.cancel();
-	    }
-	});
-
-	me.callParent([config]);
-
-	me.load_task = load_task;
-
-	if (me.autoStart) {
-	    me.startUpdate();
-	}
-    }
-});
-/*
- * The DiffStore is a in-memory store acting as proxy between a real store
- * instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the real store, to avoid the annoying visual flickering of using
- * the real store directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the real store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: the realstore which will autorefresh its content from the API
- * Only works if rstore has a model and use 'idProperty'
- * sortAfterUpdate: sort the diffstore before rendering the view
- */
-Ext.define('Proxmox.data.DiffStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.diff',
-
-    sortAfterUpdate: false,
-    
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.rstore) {
-	    throw "no rstore specified";
-	}
-
-	if (!config.rstore.model) {
-	    throw "no rstore model specified";
-	}
-
-	var rstore = config.rstore;
-
-	Ext.apply(config, {
-	    model: rstore.model,
-	    proxy: { type: 'memory' }
-	});
-
-	me.callParent([config]);
-
-	var first_load = true;
-
-	var cond_add_item = function(data, id) {
-	    var olditem = me.getById(id);
-	    if (olditem) {
-		olditem.beginEdit();
-		Ext.Array.each(me.model.prototype.fields, function(field) {
-		    if (olditem.data[field.name] !== data[field.name]) {
-			olditem.set(field.name, data[field.name]);
-		    }
-		});
-		olditem.endEdit(true);
-		olditem.commit(); 
-	    } else {
-		var newrec = Ext.create(me.model, data);
-		var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-		me.insert(pos, newrec);
-	    }
-	};
-
-	var loadFn = function(s, records, success) {
-
-	    if (!success) {
-		return;
-	    }
-
-	    me.suspendEvents();
-
-	    // getSource returns null if data is not filtered
-	    // if it is filtered it returns all records
-	    var allItems = me.getData().getSource() || me.getData();
-
-	    // remove vanished items
-	    allItems.each(function(olditem) {
-		var item = rstore.getById(olditem.getId());
-		if (!item) {
-		    me.remove(olditem);
-		}
-	    });
-
-	    rstore.each(function(item) {
-		cond_add_item(item.data, item.getId());
-	    });
-
-	    me.filter();
-
-	    if (me.sortAfterUpdate) {
-		me.sort();
-	    }
-
-	    first_load = false;
-
-	    me.resumeEvents();
-	    me.fireEvent('refresh', me);
-	    me.fireEvent('datachanged', me);
-	};
-
-	if (rstore.isLoaded()) {
-	    // if store is already loaded,
-	    // insert items instantly
-	    loadFn(rstore, [], true);
-	}
-
-	me.mon(rstore, 'load', loadFn);
-    }
-});
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('Proxmox.data.ObjectStore',  {
-    extend: 'Proxmox.data.UpdateStore',
-
-    getRecord: function() {
-	var me = this;
-	var record = Ext.create('Ext.data.Model');
-	me.getData().each(function(item) {
-	    record.set(item.data.key, item.data.value);
-	});
-	record.commit(true);
-	return record;
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-        config = config || {};
-
-	if (!config.storeid) {
-	    config.storeid =  'proxmox-store-' + (++Ext.idSeed);
-	}
-
-        Ext.applyIf(config, {
-	    model: 'KeyValue',
-            proxy: {
-                type: 'proxmox',
-		url: config.url,
-		extraParams: config.extraParams,
-                reader: {
-		    type: 'jsonobject',
-		    rows: config.rows,
-		    readArray: config.readArray,
-		    rootProperty: config.root || 'data'
-		}
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
-/* Extends the Proxmox.data.UpdateStore type
- *
- *
- */
-Ext.define('Proxmox.data.RRDStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    alias: 'store.proxmoxRRDStore',
-
-    setRRDUrl: function(timeframe, cf) {
-	var me = this;
-	if (!timeframe) {
-	    timeframe = me.timeframe;
-	}
-
-	if (!cf) {
-	    cf = me.cf;
-	}
-
-	me.proxy.url = me.rrdurl + "?timeframe=" + timeframe + "&cf=" + cf;
-    },
-
-    proxy: {
-	type: 'proxmox'
-    },
-
-    timeframe: 'hour',
-
-    cf: 'AVERAGE',
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	// set default interval to 30seconds
-	if (!config.interval) {
-	    config.interval = 30000;
-	}
-
-	// set a new storeid
-	if (!config.storeid) {
-	    config.storeid = 'rrdstore-' + (++Ext.idSeed);
-	}
-
-	// rrdurl is required
-	if (!config.rrdurl) {
-	    throw "no rrdurl specified";
-	}
-
-	var stateid = 'proxmoxRRDTypeSelection';
-	var sp = Ext.state.Manager.getProvider();
-	var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-	    if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-		me.timeframe = stateinit.timeframe;
-		me.rrdcffn = stateinit.cf;
-	    }
-	}
-
-	me.callParent([config]);
-
-	me.setRRDUrl();
-	me.mon(sp, 'statechange', function(prov, key, state){
-	    if (key === stateid) {
-		if (state && state.id) {
-		    if (state.timeframe !== me.timeframe || state.cf !== me.cf) {
-		        me.timeframe = state.timeframe;
-		        me.cf = state.cf;
-			me.setRRDUrl();
-			me.reload();
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Timezone', {
-    extend: 'Ext.data.Model',
-    fields: ['zone']
-});
-
-Ext.define('Proxmox.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-    model: 'Timezone',
-    data: [
-	    ['Africa/Abidjan'],
-	    ['Africa/Accra'],
-	    ['Africa/Addis_Ababa'],
-	    ['Africa/Algiers'],
-	    ['Africa/Asmara'],
-	    ['Africa/Bamako'],
-	    ['Africa/Bangui'],
-	    ['Africa/Banjul'],
-	    ['Africa/Bissau'],
-	    ['Africa/Blantyre'],
-	    ['Africa/Brazzaville'],
-	    ['Africa/Bujumbura'],
-	    ['Africa/Cairo'],
-	    ['Africa/Casablanca'],
-	    ['Africa/Ceuta'],
-	    ['Africa/Conakry'],
-	    ['Africa/Dakar'],
-	    ['Africa/Dar_es_Salaam'],
-	    ['Africa/Djibouti'],
-	    ['Africa/Douala'],
-	    ['Africa/El_Aaiun'],
-	    ['Africa/Freetown'],
-	    ['Africa/Gaborone'],
-	    ['Africa/Harare'],
-	    ['Africa/Johannesburg'],
-	    ['Africa/Kampala'],
-	    ['Africa/Khartoum'],
-	    ['Africa/Kigali'],
-	    ['Africa/Kinshasa'],
-	    ['Africa/Lagos'],
-	    ['Africa/Libreville'],
-	    ['Africa/Lome'],
-	    ['Africa/Luanda'],
-	    ['Africa/Lubumbashi'],
-	    ['Africa/Lusaka'],
-	    ['Africa/Malabo'],
-	    ['Africa/Maputo'],
-	    ['Africa/Maseru'],
-	    ['Africa/Mbabane'],
-	    ['Africa/Mogadishu'],
-	    ['Africa/Monrovia'],
-	    ['Africa/Nairobi'],
-	    ['Africa/Ndjamena'],
-	    ['Africa/Niamey'],
-	    ['Africa/Nouakchott'],
-	    ['Africa/Ouagadougou'],
-	    ['Africa/Porto-Novo'],
-	    ['Africa/Sao_Tome'],
-	    ['Africa/Tripoli'],
-	    ['Africa/Tunis'],
-	    ['Africa/Windhoek'],
-	    ['America/Adak'],
-	    ['America/Anchorage'],
-	    ['America/Anguilla'],
-	    ['America/Antigua'],
-	    ['America/Araguaina'],
-	    ['America/Argentina/Buenos_Aires'],
-	    ['America/Argentina/Catamarca'],
-	    ['America/Argentina/Cordoba'],
-	    ['America/Argentina/Jujuy'],
-	    ['America/Argentina/La_Rioja'],
-	    ['America/Argentina/Mendoza'],
-	    ['America/Argentina/Rio_Gallegos'],
-	    ['America/Argentina/Salta'],
-	    ['America/Argentina/San_Juan'],
-	    ['America/Argentina/San_Luis'],
-	    ['America/Argentina/Tucuman'],
-	    ['America/Argentina/Ushuaia'],
-	    ['America/Aruba'],
-	    ['America/Asuncion'],
-	    ['America/Atikokan'],
-	    ['America/Bahia'],
-	    ['America/Bahia_Banderas'],
-	    ['America/Barbados'],
-	    ['America/Belem'],
-	    ['America/Belize'],
-	    ['America/Blanc-Sablon'],
-	    ['America/Boa_Vista'],
-	    ['America/Bogota'],
-	    ['America/Boise'],
-	    ['America/Cambridge_Bay'],
-	    ['America/Campo_Grande'],
-	    ['America/Cancun'],
-	    ['America/Caracas'],
-	    ['America/Cayenne'],
-	    ['America/Cayman'],
-	    ['America/Chicago'],
-	    ['America/Chihuahua'],
-	    ['America/Costa_Rica'],
-	    ['America/Cuiaba'],
-	    ['America/Curacao'],
-	    ['America/Danmarkshavn'],
-	    ['America/Dawson'],
-	    ['America/Dawson_Creek'],
-	    ['America/Denver'],
-	    ['America/Detroit'],
-	    ['America/Dominica'],
-	    ['America/Edmonton'],
-	    ['America/Eirunepe'],
-	    ['America/El_Salvador'],
-	    ['America/Fortaleza'],
-	    ['America/Glace_Bay'],
-	    ['America/Godthab'],
-	    ['America/Goose_Bay'],
-	    ['America/Grand_Turk'],
-	    ['America/Grenada'],
-	    ['America/Guadeloupe'],
-	    ['America/Guatemala'],
-	    ['America/Guayaquil'],
-	    ['America/Guyana'],
-	    ['America/Halifax'],
-	    ['America/Havana'],
-	    ['America/Hermosillo'],
-	    ['America/Indiana/Indianapolis'],
-	    ['America/Indiana/Knox'],
-	    ['America/Indiana/Marengo'],
-	    ['America/Indiana/Petersburg'],
-	    ['America/Indiana/Tell_City'],
-	    ['America/Indiana/Vevay'],
-	    ['America/Indiana/Vincennes'],
-	    ['America/Indiana/Winamac'],
-	    ['America/Inuvik'],
-	    ['America/Iqaluit'],
-	    ['America/Jamaica'],
-	    ['America/Juneau'],
-	    ['America/Kentucky/Louisville'],
-	    ['America/Kentucky/Monticello'],
-	    ['America/La_Paz'],
-	    ['America/Lima'],
-	    ['America/Los_Angeles'],
-	    ['America/Maceio'],
-	    ['America/Managua'],
-	    ['America/Manaus'],
-	    ['America/Marigot'],
-	    ['America/Martinique'],
-	    ['America/Matamoros'],
-	    ['America/Mazatlan'],
-	    ['America/Menominee'],
-	    ['America/Merida'],
-	    ['America/Mexico_City'],
-	    ['America/Miquelon'],
-	    ['America/Moncton'],
-	    ['America/Monterrey'],
-	    ['America/Montevideo'],
-	    ['America/Montreal'],
-	    ['America/Montserrat'],
-	    ['America/Nassau'],
-	    ['America/New_York'],
-	    ['America/Nipigon'],
-	    ['America/Nome'],
-	    ['America/Noronha'],
-	    ['America/North_Dakota/Center'],
-	    ['America/North_Dakota/New_Salem'],
-	    ['America/Ojinaga'],
-	    ['America/Panama'],
-	    ['America/Pangnirtung'],
-	    ['America/Paramaribo'],
-	    ['America/Phoenix'],
-	    ['America/Port-au-Prince'],
-	    ['America/Port_of_Spain'],
-	    ['America/Porto_Velho'],
-	    ['America/Puerto_Rico'],
-	    ['America/Rainy_River'],
-	    ['America/Rankin_Inlet'],
-	    ['America/Recife'],
-	    ['America/Regina'],
-	    ['America/Resolute'],
-	    ['America/Rio_Branco'],
-	    ['America/Santa_Isabel'],
-	    ['America/Santarem'],
-	    ['America/Santiago'],
-	    ['America/Santo_Domingo'],
-	    ['America/Sao_Paulo'],
-	    ['America/Scoresbysund'],
-	    ['America/Shiprock'],
-	    ['America/St_Barthelemy'],
-	    ['America/St_Johns'],
-	    ['America/St_Kitts'],
-	    ['America/St_Lucia'],
-	    ['America/St_Thomas'],
-	    ['America/St_Vincent'],
-	    ['America/Swift_Current'],
-	    ['America/Tegucigalpa'],
-	    ['America/Thule'],
-	    ['America/Thunder_Bay'],
-	    ['America/Tijuana'],
-	    ['America/Toronto'],
-	    ['America/Tortola'],
-	    ['America/Vancouver'],
-	    ['America/Whitehorse'],
-	    ['America/Winnipeg'],
-	    ['America/Yakutat'],
-	    ['America/Yellowknife'],
-	    ['Antarctica/Casey'],
-	    ['Antarctica/Davis'],
-	    ['Antarctica/DumontDUrville'],
-	    ['Antarctica/Macquarie'],
-	    ['Antarctica/Mawson'],
-	    ['Antarctica/McMurdo'],
-	    ['Antarctica/Palmer'],
-	    ['Antarctica/Rothera'],
-	    ['Antarctica/South_Pole'],
-	    ['Antarctica/Syowa'],
-	    ['Antarctica/Vostok'],
-	    ['Arctic/Longyearbyen'],
-	    ['Asia/Aden'],
-	    ['Asia/Almaty'],
-	    ['Asia/Amman'],
-	    ['Asia/Anadyr'],
-	    ['Asia/Aqtau'],
-	    ['Asia/Aqtobe'],
-	    ['Asia/Ashgabat'],
-	    ['Asia/Baghdad'],
-	    ['Asia/Bahrain'],
-	    ['Asia/Baku'],
-	    ['Asia/Bangkok'],
-	    ['Asia/Beirut'],
-	    ['Asia/Bishkek'],
-	    ['Asia/Brunei'],
-	    ['Asia/Choibalsan'],
-	    ['Asia/Chongqing'],
-	    ['Asia/Colombo'],
-	    ['Asia/Damascus'],
-	    ['Asia/Dhaka'],
-	    ['Asia/Dili'],
-	    ['Asia/Dubai'],
-	    ['Asia/Dushanbe'],
-	    ['Asia/Gaza'],
-	    ['Asia/Harbin'],
-	    ['Asia/Ho_Chi_Minh'],
-	    ['Asia/Hong_Kong'],
-	    ['Asia/Hovd'],
-	    ['Asia/Irkutsk'],
-	    ['Asia/Jakarta'],
-	    ['Asia/Jayapura'],
-	    ['Asia/Jerusalem'],
-	    ['Asia/Kabul'],
-	    ['Asia/Kamchatka'],
-	    ['Asia/Karachi'],
-	    ['Asia/Kashgar'],
-	    ['Asia/Kathmandu'],
-	    ['Asia/Kolkata'],
-	    ['Asia/Krasnoyarsk'],
-	    ['Asia/Kuala_Lumpur'],
-	    ['Asia/Kuching'],
-	    ['Asia/Kuwait'],
-	    ['Asia/Macau'],
-	    ['Asia/Magadan'],
-	    ['Asia/Makassar'],
-	    ['Asia/Manila'],
-	    ['Asia/Muscat'],
-	    ['Asia/Nicosia'],
-	    ['Asia/Novokuznetsk'],
-	    ['Asia/Novosibirsk'],
-	    ['Asia/Omsk'],
-	    ['Asia/Oral'],
-	    ['Asia/Phnom_Penh'],
-	    ['Asia/Pontianak'],
-	    ['Asia/Pyongyang'],
-	    ['Asia/Qatar'],
-	    ['Asia/Qyzylorda'],
-	    ['Asia/Rangoon'],
-	    ['Asia/Riyadh'],
-	    ['Asia/Sakhalin'],
-	    ['Asia/Samarkand'],
-	    ['Asia/Seoul'],
-	    ['Asia/Shanghai'],
-	    ['Asia/Singapore'],
-	    ['Asia/Taipei'],
-	    ['Asia/Tashkent'],
-	    ['Asia/Tbilisi'],
-	    ['Asia/Tehran'],
-	    ['Asia/Thimphu'],
-	    ['Asia/Tokyo'],
-	    ['Asia/Ulaanbaatar'],
-	    ['Asia/Urumqi'],
-	    ['Asia/Vientiane'],
-	    ['Asia/Vladivostok'],
-	    ['Asia/Yakutsk'],
-	    ['Asia/Yekaterinburg'],
-	    ['Asia/Yerevan'],
-	    ['Atlantic/Azores'],
-	    ['Atlantic/Bermuda'],
-	    ['Atlantic/Canary'],
-	    ['Atlantic/Cape_Verde'],
-	    ['Atlantic/Faroe'],
-	    ['Atlantic/Madeira'],
-	    ['Atlantic/Reykjavik'],
-	    ['Atlantic/South_Georgia'],
-	    ['Atlantic/St_Helena'],
-	    ['Atlantic/Stanley'],
-	    ['Australia/Adelaide'],
-	    ['Australia/Brisbane'],
-	    ['Australia/Broken_Hill'],
-	    ['Australia/Currie'],
-	    ['Australia/Darwin'],
-	    ['Australia/Eucla'],
-	    ['Australia/Hobart'],
-	    ['Australia/Lindeman'],
-	    ['Australia/Lord_Howe'],
-	    ['Australia/Melbourne'],
-	    ['Australia/Perth'],
-	    ['Australia/Sydney'],
-	    ['Europe/Amsterdam'],
-	    ['Europe/Andorra'],
-	    ['Europe/Athens'],
-	    ['Europe/Belgrade'],
-	    ['Europe/Berlin'],
-	    ['Europe/Bratislava'],
-	    ['Europe/Brussels'],
-	    ['Europe/Bucharest'],
-	    ['Europe/Budapest'],
-	    ['Europe/Chisinau'],
-	    ['Europe/Copenhagen'],
-	    ['Europe/Dublin'],
-	    ['Europe/Gibraltar'],
-	    ['Europe/Guernsey'],
-	    ['Europe/Helsinki'],
-	    ['Europe/Isle_of_Man'],
-	    ['Europe/Istanbul'],
-	    ['Europe/Jersey'],
-	    ['Europe/Kaliningrad'],
-	    ['Europe/Kiev'],
-	    ['Europe/Lisbon'],
-	    ['Europe/Ljubljana'],
-	    ['Europe/London'],
-	    ['Europe/Luxembourg'],
-	    ['Europe/Madrid'],
-	    ['Europe/Malta'],
-	    ['Europe/Mariehamn'],
-	    ['Europe/Minsk'],
-	    ['Europe/Monaco'],
-	    ['Europe/Moscow'],
-	    ['Europe/Oslo'],
-	    ['Europe/Paris'],
-	    ['Europe/Podgorica'],
-	    ['Europe/Prague'],
-	    ['Europe/Riga'],
-	    ['Europe/Rome'],
-	    ['Europe/Samara'],
-	    ['Europe/San_Marino'],
-	    ['Europe/Sarajevo'],
-	    ['Europe/Simferopol'],
-	    ['Europe/Skopje'],
-	    ['Europe/Sofia'],
-	    ['Europe/Stockholm'],
-	    ['Europe/Tallinn'],
-	    ['Europe/Tirane'],
-	    ['Europe/Uzhgorod'],
-	    ['Europe/Vaduz'],
-	    ['Europe/Vatican'],
-	    ['Europe/Vienna'],
-	    ['Europe/Vilnius'],
-	    ['Europe/Volgograd'],
-	    ['Europe/Warsaw'],
-	    ['Europe/Zagreb'],
-	    ['Europe/Zaporozhye'],
-	    ['Europe/Zurich'],
-	    ['Indian/Antananarivo'],
-	    ['Indian/Chagos'],
-	    ['Indian/Christmas'],
-	    ['Indian/Cocos'],
-	    ['Indian/Comoro'],
-	    ['Indian/Kerguelen'],
-	    ['Indian/Mahe'],
-	    ['Indian/Maldives'],
-	    ['Indian/Mauritius'],
-	    ['Indian/Mayotte'],
-	    ['Indian/Reunion'],
-	    ['Pacific/Apia'],
-	    ['Pacific/Auckland'],
-	    ['Pacific/Chatham'],
-	    ['Pacific/Chuuk'],
-	    ['Pacific/Easter'],
-	    ['Pacific/Efate'],
-	    ['Pacific/Enderbury'],
-	    ['Pacific/Fakaofo'],
-	    ['Pacific/Fiji'],
-	    ['Pacific/Funafuti'],
-	    ['Pacific/Galapagos'],
-	    ['Pacific/Gambier'],
-	    ['Pacific/Guadalcanal'],
-	    ['Pacific/Guam'],
-	    ['Pacific/Honolulu'],
-	    ['Pacific/Johnston'],
-	    ['Pacific/Kiritimati'],
-	    ['Pacific/Kosrae'],
-	    ['Pacific/Kwajalein'],
-	    ['Pacific/Majuro'],
-	    ['Pacific/Marquesas'],
-	    ['Pacific/Midway'],
-	    ['Pacific/Nauru'],
-	    ['Pacific/Niue'],
-	    ['Pacific/Norfolk'],
-	    ['Pacific/Noumea'],
-	    ['Pacific/Pago_Pago'],
-	    ['Pacific/Palau'],
-	    ['Pacific/Pitcairn'],
-	    ['Pacific/Pohnpei'],
-	    ['Pacific/Port_Moresby'],
-	    ['Pacific/Rarotonga'],
-	    ['Pacific/Saipan'],
-	    ['Pacific/Tahiti'],
-	    ['Pacific/Tarawa'],
-	    ['Pacific/Tongatapu'],
-	    ['Pacific/Wake'],
-	    ['Pacific/Wallis']
-	]
-});
-Ext.define('Proxmox.form.field.Integer',{
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.proxmoxintegerfield',
-
-    config: {
-	deleteEmpty: false
-    },
-
-    allowDecimals: false,
-    allowExponential: false,
-    step: 1,
-
-   getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== undefined && val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    }
-
-});
-Ext.define('Proxmox.form.field.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.proxmoxtextfield'],
-
-    config: {
-	skipEmptyText: true,
-
-	deleteEmpty: false,
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-	var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-    }
-});
-Ext.define('Proxmox.DateTimeField', {
-    extend: 'Ext.form.FieldContainer',
-    xtype: 'promxoxDateTimeField',
-
-    layout: 'hbox',
-
-    referenceHolder: true,
-
-    submitFormat: 'U',
-
-    getValue: function() {
-	var me = this;
-	var d = me.lookupReference('dateentry').getValue();
-
-	if (d === undefined || d === null) { return null; }
-
-	var t = me.lookupReference('timeentry').getValue();
-
-	if (t === undefined || t === null) { return null; }
-
-	var offset = (t.getHours()*3600+t.getMinutes()*60)*1000;
-
-	return new Date(d.getTime() + offset);
-    },
-
-    getSubmitValue: function() {
-        var me = this;
-        var format = me.submitFormat;
-        var value = me.getValue();
-
-        return value ? Ext.Date.format(value, format) : null;
-    },
-
-    items: [
-	{
-	    xtype: 'datefield',
-	    editable: false,
-	    reference: 'dateentry',
-	    flex: 1,
-	    format: 'Y-m-d'
-	},
-	{
-	    xtype: 'timefield',
-	    reference: 'timeentry',
-	    format: 'H:i',
-	    width: 80,
-	    value: '00:00',
-	    increment: 60
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	var value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    }
-});
-Ext.define('Proxmox.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.proxmoxcheckbox'],
-
-    config: {
-	defaultValue: undefined,
-	deleteDefaultValue: false,
-	deleteEmpty: false
-    },
-
-    inputValue: '1',
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-		if ((val == me.getDefaultValue()) && me.getDeleteDefaultValue()) {
-		    data['delete'] = me.getName();
-		} else {
-                    data[me.getName()] = val;
-		}
-            } else if (me.getDeleteEmpty()) {
-               data = {};
-               data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-	var me = this;
-
-	if (value === 1) {
-            me.callParent([true]);
-	} else {
-            me.callParent([value]);
-	}
-    }
-
-});
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('Proxmox.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.proxmoxKVComboBox',
-
-    config: {
-	deleteEmpty: true
-    },
-
-    comboItems: undefined,
-    displayField: 'value',
-    valueField: 'key',
-    queryMode: 'local',
-
-    // overide framework function to implement deleteEmpty behaviour
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '' && val !== '__default__') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    validator: function(val) {
-	var me = this;
-
-	if (me.editable || val === null || val === '') {
-	    return true;
-	}
-
-	if (me.store.getCount() > 0) {
-	    var values = me.multiSelect ? val.split(me.delimiter) : [val];
-	    var items = me.store.getData().collect('value', 'data');
-	    if (Ext.Array.every(values, function(value) {
-		return Ext.Array.contains(items, value);
-	    })) {
-		return true;
-	    }
-	}
-
-	// returns a boolean or string
-	/*jslint confusion: true */
-	return "value '" + val + "' not allowed!";
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.store = Ext.create('Ext.data.ArrayStore', {
-	    model: 'KeyValue',
-	    data : me.comboItems
-	});
-
-	if (me.initialConfig.editable === undefined) {
-	    me.editable = false;
-	}
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.form.LanguageSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'proxmoxLanguageSelector',
-
-    comboItems: Proxmox.Utils.language_array()
-});
-/*
- * ComboGrid component: a ComboBox where the dropdown menu (the
- * "Picker") is a Grid with Rows and Columns expects a listConfig
- * object with a columns property roughly based on the GridPicker from
- * https://www.sencha.com/forum/showthread.php?299909
- *
-*/
-
-Ext.define('Proxmox.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-	    (key == e.BACKSPACE || key == e.DELETE)) {
-	    me.setValue('');
-	}
-
-        me.callParent(arguments);
-    },
-
-    // needed to trigger onKeyUp etc.
-    enableKeyEvents: true,
-
-    editable: false,
-
-    // override ExtJS method
-    // if the field has multiSelect enabled, the store is not loaded, and
-    // the displayfield == valuefield, it saves the rawvalue as an array
-    // but the getRawValue method is only defined in the textfield class
-    // (which has not to deal with arrays) an returns the string in the
-    // field (not an array)
-    //
-    // so if we have multiselect enabled, return the rawValue (which
-    // should be an array) and else we do callParent so
-    // it should not impact any other use of the class
-    getRawValue: function() {
-	var me = this;
-	if (me.multiSelect) {
-	    return me.rawValue;
-	} else {
-	    return me.callParent();
-	}
-    },
-
-// override ExtJS protected method
-    onBindStore: function(store, initial) {
-        var me = this,
-            picker = me.picker,
-            extraKeySpec,
-            valueCollectionConfig;
-
-        // We're being bound, not unbound...
-        if (store) {
-            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2'
-            if (store.autoCreated) {
-                me.queryMode = 'local';
-                me.valueField = me.displayField = 'field1';
-                if (!store.expanded) {
-                    me.displayField = 'field2';
-                }
-
-                // displayTpl config will need regenerating with the autogenerated displayField name 'field1'
-                me.setDisplayTpl(null);
-            }
-            if (!Ext.isDefined(me.valueField)) {
-                me.valueField = me.displayField;
-            }
-
-            // Add a byValue index to the store so that we can efficiently look up records by the value field
-            // when setValue passes string value(s).
-            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys
-            // are found, they are all returned by the get call.
-            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default,
-            // if unique is true, CollectionKey keeps the *last* matching value.
-            extraKeySpec = {
-                byValue: {
-                    rootProperty: 'data',
-                    unique: false
-                }
-            };
-            extraKeySpec.byValue.property = me.valueField;
-            store.setExtraKeys(extraKeySpec);
-
-            if (me.displayField === me.valueField) {
-                store.byText = store.byValue;
-            } else {
-                extraKeySpec.byText = {
-                    rootProperty: 'data',
-                    unique: false
-                };
-                extraKeySpec.byText.property = me.displayField;
-                store.setExtraKeys(extraKeySpec);
-            }
-
-            // We hold a collection of the values which have been selected, keyed by this field's valueField.
-            // This collection also functions as the selected items collection for the BoundList's selection model
-            valueCollectionConfig = {
-                rootProperty: 'data',
-                extraKeys: {
-                    byInternalId: {
-                        property: 'internalId'
-                    },
-                    byValue: {
-                        property: me.valueField,
-                        rootProperty: 'data'
-                    }
-                },
-                // Whenever this collection is changed by anyone, whether by this field adding to it,
-                // or the BoundList operating, we must refresh our value.
-                listeners: {
-                    beginupdate: me.onValueCollectionBeginUpdate,
-                    endupdate: me.onValueCollectionEndUpdate,
-                    scope: me
-                }
-            };
-
-            // This becomes our collection of selected records for the Field.
-            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);
-
-            // We use the selected Collection as our value collection and the basis
-            // for rendering the tag list.
-
-            //proxmox override: since the picker is represented by a grid panel,
-            // we changed here the selection to RowModel
-            me.pickerSelectionModel = new Ext.selection.RowModel({
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
-                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row
-                // and released.  In these situations, the event target for the click event won't be the row where the mouse
-                // was released but the boundview.  The view will then determine that it should fire a container click, and
-                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will
-                // prevent the model from deselecting.
-                deselectOnContainerClick: false,
-                enableInitialSelection: false,
-                pruneRemoved: false,
-                selected: me.valueCollection,
-                store: store,
-                listeners: {
-                    scope: me,
-                    lastselectedchanged: me.updateBindSelection
-                }
-            });
-
-            if (!initial) {
-                me.resetToDefault();
-            }
-
-            if (picker) {
-                picker.setSelectionModel(me.pickerSelectionModel);
-                if (picker.getStore() !== store) {
-                    picker.bindStore(store);
-                }
-            }
-        }
-    },
-
-    // copied from ComboBox
-    createPicker: function() {
-        var me = this;
-        var picker;
-
-        var pickerCfg = Ext.apply({
-                // proxmox overrides: display a grid for selection
-                xtype: 'gridpanel',
-                id: me.pickerId,
-                pickerField: me,
-                floating: true,
-                hidden: true,
-                store: me.store,
-                displayField: me.displayField,
-                preserveScrollOnRefresh: true,
-                pageSize: me.pageSize,
-                tpl: me.tpl,
-                selModel: me.pickerSelectionModel,
-                focusOnToFront: false
-            }, me.listConfig, me.defaultListConfig);
-
-        picker = me.picker || Ext.widget(pickerCfg);
-
-        if (picker.getStore() !== me.store) {
-            picker.bindStore(me.store);
-        }
-
-        if (me.pageSize) {
-            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
-        }
-
-        // proxmox overrides: pass missing method in gridPanel to its view
-        picker.refresh = function() {
-            picker.getSelectionModel().select(me.valueCollection.getRange());
-            picker.getView().refresh();
-        };
-        picker.getNodeByRecord = function() {
-            picker.getView().getNodeByRecord(arguments);
-        };
-
-        // We limit the height of the picker to fit in the space above
-        // or below this field unless the picker has its own ideas about that.
-        if (!picker.initialConfig.maxHeight) {
-            picker.on({
-                beforeshow: me.onBeforePickerShow,
-                scope: me
-            });
-        }
-        picker.getSelectionModel().on({
-            beforeselect: me.onBeforeSelect,
-            beforedeselect: me.onBeforeDeselect,
-            focuschange: me.onFocusChange,
-            selectionChange: function (sm, selectedRecords) {
-                var me = this;
-                if (selectedRecords.length) {
-                    me.setValue(selectedRecords);
-                    me.fireEvent('select', me, selectedRecords);
-                }
-            },
-            scope: me
-        });
-
-	// hack for extjs6
-	// when the clicked item is the same as the previously selected,
-	// it does not select the item
-	// instead we hide the picker
-	if (!me.multiSelect) {
-	    picker.on('itemclick', function (sm,record) {
-		if (picker.getSelection()[0] === record) {
-		    picker.hide();
-		}
-	    });
-	}
-
-	// when our store is not yet loaded, we increase
-	// the height of the gridpanel, so that we can see
-	// the loading mask
-	//
-	// we save the minheight to reset it after the load
-	picker.on('show', function() {
-	    if (me.enableLoadMask) {
-		me.savedMinHeight = picker.getMinHeight();
-		picker.setMinHeight(100);
-	    }
-	});
-
-        picker.getNavigationModel().navigateOnSpace = false;
-
-        return picker;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    queryMode: 'local',
-	    matchFieldWidth: false
-	});
-
-	Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-	Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-        // Create the picker at an early stage, so it is available to store the previous selection
-        if (!me.picker) {
-            me.createPicker();
-        }
-
-	if (me.editable) {
-	    // The trigger.picker causes first a focus event on the field then
-	    // toggles the selection picker. Thus skip expanding in this case,
-	    // else our focus listner expands and the picker.trigger then
-	    // collapses it directly afterwards.
-	    Ext.override(me.triggers.picker, {
-		onMouseDown : function (e) {
-		    // copied "should we focus" check from Ext.form.trigger.Trigger
-		    if (e.pointerType !== 'touch' && !this.field.owns(Ext.Element.getActiveElement())) {
-			me.skip_expand_on_focus = true;
-		    }
-		    this.callParent(arguments);
-		}
-	    });
-
-	    me.on("focus", function(me) {
-		if (!me.isExpanded && !me.skip_expand_on_focus) {
-		    me.expand();
-		}
-		me.skip_expand_on_focus = false;
-	    });
-	}
-
-	me.mon(me.store, 'beforeload', function() {
-	    if (!me.isDisabled()) {
-		me.enableLoadMask = true;
-	    }
-	});
-
-	// hack: autoSelect does not work
-	me.mon(me.store, 'load', function(store, r, success, o) {
-	    if (success) {
-		me.clearInvalid();
-
-		if (me.enableLoadMask) {
-		    delete me.enableLoadMask;
-
-		    // if the picker exists,
-		    // we reset its minheight to the saved var/0
-		    // we have to update the layout, otherwise the height
-		    // gets not recalculated
-		    if (me.picker) {
-			me.picker.setMinHeight(me.savedMinHeight || 0);
-			delete me.savedMinHeight;
-			me.picker.updateLayout();
-		    }
-		}
-
-		var def = me.getValue() || me.preferredValue;
-		if (def) {
-		    me.setValue(def, true); // sync with grid
-		}
-		var found = false;
-		if (def) {
-		    if (Ext.isArray(def)) {
-			Ext.Array.each(def, function(v) {
-			    if (store.findRecord(me.valueField, v)) {
-				found = true;
-				return false; // break
-			    }
-			});
-		    } else {
-			found = store.findRecord(me.valueField, def);
-		    }
-		}
-
-		if (!found) {
-		    var rec = me.store.first();
-		    if (me.autoSelect && rec && rec.data) {
-			def = rec.data[me.valueField];
-			me.setValue(def, true);
-		    } else {
-			me.setValue(me.editable ? def : '', true);
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Proxmox.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxRRDTypeSelector'],
-
-    displayField: 'text',
-    valueField: 'id',
-    editable: false,
-    queryMode: 'local',
-    value: 'hour',
-    stateEvents: [ 'select' ],
-    stateful: true,
-    stateId: 'proxmoxRRDTypeSelection',
-    store: {
-	type: 'array',
-	fields: [ 'id', 'timeframe', 'cf', 'text' ],
-	data : [
-	    [ 'hour', 'hour', 'AVERAGE',
-	      gettext('Hour') + ' (' + gettext('average') +')' ],
-	    [ 'hourmax', 'hour', 'MAX',
-	      gettext('Hour') + ' (' + gettext('maximum') + ')' ],
-	    [ 'day', 'day', 'AVERAGE',
-	      gettext('Day') + ' (' + gettext('average') + ')' ],
-	    [ 'daymax', 'day', 'MAX',
-	      gettext('Day') + ' (' + gettext('maximum') + ')' ],
-	    [ 'week', 'week', 'AVERAGE',
-	      gettext('Week') + ' (' + gettext('average') + ')' ],
-	    [ 'weekmax', 'week', 'MAX',
-	      gettext('Week') + ' (' + gettext('maximum') + ')' ],
-	    [ 'month', 'month', 'AVERAGE',
-	      gettext('Month') + ' (' + gettext('average') + ')' ],
-	    [ 'monthmax', 'month', 'MAX',
-	      gettext('Month') + ' (' + gettext('maximum') + ')' ],
-	    [ 'year', 'year', 'AVERAGE',
-	      gettext('Year') + ' (' + gettext('average') + ')' ],
-	    [ 'yearmax', 'year', 'MAX',
-	      gettext('Year') + ' (' + gettext('maximum') + ')' ]
-	]
-    },
-    // save current selection in the state Provider so RRDView can read it
-    getState: function() {
-	var ind = this.getStore().findExact('id', this.getValue());
-	var rec = this.getStore().getAt(ind);
-	if (!rec) {
-	    return;
-	}
-	return {
-	    id: rec.data.id,
-	    timeframe: rec.data.timeframe,
-	    cf: rec.data.cf
-	};
-    },
-    // set selection based on last saved state
-    applyState : function(state) {
-	if (state && state.id) {
-	    this.setValue(state.id);
-	}
-    }
-});
-Ext.define('Proxmox.form.BondModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-
-    openvswitch: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.openvswitch) {
-           me.comboItems = [
-	       ['active-backup', 'active-backup'],
-	       ['balance-slb', 'balance-slb'],
-	       ['lacp-balance-slb', 'LACP (balance-slb)'],
-	       ['lacp-balance-tcp', 'LACP (balance-tcp)']
-	   ];
-	} else {
-            me.comboItems = [
-		['balance-rr', 'balance-rr'],
-		['active-backup', 'active-backup'],
-		['balance-xor', 'balance-xor'],
-		['broadcast', 'broadcast'],
-		['802.3ad', 'LACP (802.3ad)'],
-		['balance-tlb', 'balance-tlb'],
-		['balance-alb', 'balance-alb']
-	    ];
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('Proxmox.form.BondPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-    comboItems: [
-	    ['layer2', 'layer2'],
-	    ['layer2+3', 'layer2+3'],
-	    ['layer3+4', 'layer3+4']
-    ]
-});
-
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('Proxmox.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.proxmoxButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-
-	    // Note: me.realHandler may be a string (see named scopes)
-	    var realHandler = me.handler;
-
-	    me.handler = function(button, event) {
-		var rec, msg;
-		if (me.selModel) {
-		    rec = me.selModel.getSelection()[0];
-		    if (!rec || (me.enableFn(rec) === false)) {
-			return;
-		    }
-		}
-
-		if (me.confirmMsg) {
-		    msg = me.confirmMsg;
-		    if (Ext.isFunction(me.confirmMsg)) {
-			msg = me.confirmMsg(rec);
-		    }
-		    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		    Ext.Msg.show({
-			title: gettext('Confirm'),
-			icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-			msg: msg,
-			buttons: Ext.Msg.YESNO,
-			defaultFocus: me.dangerous ? 'no' : 'yes',
-			callback: function(btn) {
-			    if (btn !== 'yes') {
-				return;
-			    }
-			    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-			}
-		    });
-		} else {
-		    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-		}
-	    };
-	}
-
-	me.callParent();
-
-	var grid;
-	if (!me.selModel && me.selModel !== null) {
-	    grid = me.up('grid');
-	    if (grid && grid.selModel) {
-		me.selModel = grid.selModel;
-	    }
-	}
-
-	if (me.waitMsgTarget === true) {
-	    grid = me.up('grid');
-	    if (grid) {
-		me.waitMsgTarget = grid;
-	    } else {
-		throw "unable to find waitMsgTarget";
-	    }
-	}
-	
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else  {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-
-
-Ext.define('Proxmox.button.StdRemoveButton', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.proxmoxStdRemoveButton',
-
-    text: gettext('Remove'),
-
-    disabled: true,
-
-    config: {
-	baseurl: undefined
-    },
-
-    getUrl: function(rec) {
-	var me = this;
-	
-	return me.baseurl + '/' + rec.getId();
-    },
-
-    // also works with names scopes
-    callback: function(options, success, response) {},
-
-    getRecordName: function(rec) { return rec.getId() },
-
-    confirmMsg: function (rec) {
-	var me = this;
-
-	var name = me.getRecordName(rec);
-	return Ext.String.format(
-	    gettext('Are you sure you want to remove entry {0}'),
-	    "'" + name + "'");
-    },
-
-    handler: function(btn, event, rec) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.getUrl(rec),
-	    method: 'DELETE',
-	    waitMsgTarget: me.waitMsgTarget,
-	    callback: function(options, success, response) {
-		Ext.callback(me.callback, me.scope, [options, success, response], 0, me);
-	    },
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-/* help button pointing to an online documentation
-   for components contained in a modal window
-*/
-/*global
-  proxmoxOnlineHelpInfo
-*/
-Ext.define('Proxmox.button.Help', {
-    extend: 'Ext.button.Button',
-    xtype: 'proxmoxHelpButton',
-
-    text: gettext('Help'),
-
-    // make help button less flashy by styling it like toolbar buttons
-    iconCls: ' x-btn-icon-el-default-toolbar-small fa fa-question-circle',
-    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-
-    hidden: true,
-
-    listenToGlobalEvent: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	listen: {
-	    global: {
-		proxmoxShowHelp: 'onProxmoxShowHelp',
-		proxmoxHideHelp: 'onProxmoxHideHelp'
-	    }
-	},
-	onProxmoxShowHelp: function(helpLink) {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.setOnlineHelp(helpLink);
-		me.show();
-	    }
-	},
-	onProxmoxHideHelp: function() {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.hide();
-	    }
-	}
-    },
-
-    getOnlineHelpInfo: function (ref) {
-	var helpMap;
-	if (typeof proxmoxOnlineHelpInfo !== 'undefined') {
-	    helpMap = proxmoxOnlineHelpInfo;
-	} else if (typeof pveOnlineHelpInfo !== 'undefined') {
-	    // be backward compatible with older pve-doc-generators
-	    helpMap = pveOnlineHelpInfo;
-	} else {
-	    throw "no global OnlineHelpInfo map declared";
-	}
-
-	return helpMap[ref];
-    },
-
-    // this sets the link and the tooltip text
-    setOnlineHelp:function(blockid) {
-	var me = this;
-
-	var info = me.getOnlineHelpInfo(blockid);
-	if (info) {
-	    me.onlineHelp = blockid;
-	    var title = info.title;
-	    if (info.subtitle) {
-		title += ' - ' + info.subtitle;
-	    }
-	    me.setTooltip(title);
-	}
-    },
-
-    // helper to set the onlineHelp via a config object
-    setHelpConfig: function(config) {
-	var me = this;
-	me.setOnlineHelp(config.onlineHelp);
-    },
-
-    handler: function() {
-	var me = this;
-	var docsURI;
-
-	if (me.onlineHelp) {
-	    var info = me.getOnlineHelpInfo(me.onlineHelp);
-	    if (info) {
-		docsURI = window.location.origin + info.link;
-	    }
-	}
-
-	if (docsURI) {
-	    window.open(docsURI);
-	} else {
-	    Ext.Msg.alert(gettext('Help'), gettext('No Help available'));
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-	var me = this;
-
-	me.callParent();
-
-	if  (me.onlineHelp) {
-	    me.setOnlineHelp(me.onlineHelp); // set tooltip
-	}
-    }
-});
-/* Renders a list of key values objets
-
-mandatory config parameters:
-rows: an object container where each propery is a key-value object we want to render
-       var rows = {
-           keyboard: {
-               header: gettext('Keyboard Layout'),
-               editor: 'Your.KeyboardEdit',
-               required: true
-           },
-
-optional:
-disabled: setting this parameter to true will disable selection and focus on the
-proxmoxObjectGrid as well as greying out input elements.
-Useful for a readonly tabular display
-
-*/
-
-Ext.define('Proxmox.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.proxmoxObjectGrid'],
-    disabled: false,
-    hideHeaders: true,
-
-    monStoreErrors: false,
-
-    add_combobox_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxKVComboBox',
-		    name: name,
-		    comboItems: opts.comboItems,
-		    value: opts.defaultValue,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_text_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxtextfield',
-		    name: name,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    vtype: opts.vtype,
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_boolean_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue || 0,
-	    header: text,
-	    renderer: opts.renderer || Proxmox.Utils.format_boolean,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxcheckbox',
-		    name: name,
-		    uncheckedValue: 0,
-		    defaultValue: opts.defaultValue  || 0,
-		    checked: opts.defaultValue ? true : false,
-		    deleteDefaultValue: opts.deleteDefaultValue ? true : false,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_integer_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {}
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxintegerfield',
-		    name: name,
-		    minValue: opts.minValue,
-		    maxValue: opts.maxValue,
-		    emptyText: gettext('Default'),
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    value: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    editorConfig: {}, // default config passed to editor
-
-    run_editor: function() {
-	var me = this;
-
-	var sm = me.getSelectionModel();
-	var rec = sm.getSelection()[0];
-	if (!rec) {
-	    return;
-	}
-
-	var rows = me.rows;
-	var rowdef = rows[rec.data.key];
-	if (!rowdef.editor) {
-	    return;
-	}
-
-	var win;
-	var config;
-	if (Ext.isString(rowdef.editor)) {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    win = Ext.create(rowdef.editor, config);
-	} else {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    Ext.apply(config, rowdef.editor);
-	    win = Ext.createWidget(rowdef.editor.xtype, config);
-	    win.load();
-	}
-
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    getObjectValue: function(key, defaultValue) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-	return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-	var renderer = rowdef.renderer;
-	if (renderer) {
-	    return renderer(value, metaData, record, rowIndex, colIndex, store);
-	}
-
-	return value;
-    },
-
-    listeners: {
-	itemkeydown: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER) {
-		this.pressedIndex = index;
-	    }
-	},
-	itemkeyup: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER && index == this.pressedIndex) {
-		this.run_editor();
-	    }
-
-	    this.pressedIndex = undefined;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	var rstore = me.rstore;
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore,
-	    sorters: [],
-	    filters: []
-	});
-
-	if (rows) {
-	    Ext.Object.each(rows, function(key, rowdef) {
-		if (Ext.isDefined(rowdef.defaultValue)) {
-		    store.add({ key: key, value: rowdef.defaultValue });
-		} else if (rowdef.required) {
-		    store.add({ key: key, value: undefined });
-		}
-	    });
-	}
-
-	if (me.sorterFn) {
-	    store.sorters.add(Ext.create('Ext.util.Sorter', {
-		sorterFn: me.sorterFn
-	    }));
-	}
-
-	store.filters.add(Ext.create('Ext.util.Filter', {
-	    filterFn: function(item) {
-		if (rows) {
-		    var rowdef = rows[item.data.key];
-		    if (!rowdef || (rowdef.visible === false)) {
-			return false;
-		    }
-		}
-		return true;
-	    }
-	}));
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.applyIf(me, {
-	    store: store,
-	    stateful: false,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: me.cwidth1 || 200,
-		    dataIndex: 'key',
-		    renderer: me.renderKey
-		},
-		{
-		    flex: 1,
-		    header: gettext('Value'),
-		    dataIndex: 'value',
-		    renderer: me.renderValue
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.monStoreErrors) {
-	    Proxmox.Utils.monStoreErrors(me, me.store);
-	}
-   }
-});
-Ext.define('Proxmox.grid.PendingObjectGrid', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxPendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    var value = rec.data.value;
-	    if (pending) {
-		if (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') {
-		    value = rec.data.pending;
-		} else if (rec.data['delete'] === 1) {
-		    value = defaultValue;
-		}
-	    }
-
-            if (Ext.isDefined(value) && (value !== '')) {
-		return value;
-            } else {
-		return defaultValue;
-            }
-	}
-	return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var keys = rowdef.multiKey ||  [ key ];
-	var pending = false;
-
-	Ext.Array.each(keys, function(k) {
-	    var rec = me.store.getById(k);
-	    if (rec && rec.data && (
-		    (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') ||
-		    rec.data['delete'] === 1
-	    )) {
-		pending = true;
-		return false; // break
-	    }
-	});
-
-	return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var renderer = rowdef.renderer;
-	var current = '';
-	var pendingdelete = '';
-	var pending = '';
-
-	if (renderer) {
-	    current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-	    if (me.hasPendingChanges(key)) {
-		pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-	    }
-	    if (pending == current) {
-		pending = undefined;
-	    }
-	} else {
-	    current = value || '';
-	    pending = record.data.pending;
-	}
-
-	if (record.data['delete']) {
-	    var delete_all = true;
-	    if (rowdef.multiKey) {
-		Ext.Array.each(rowdef.multiKey, function(k) {
-		    var rec = me.store.getById(k);
-		    if (rec && rec.data && rec.data['delete'] !== 1) {
-			delete_all = false;
-			return false; // break
-		    }
-		});
-	    }
-	    if (delete_all) {
-		pending = '<div style="text-decoration: line-through;">'+ current +'</div>';
-	    }
-	}
-
-	if (pending) {
-	    return current + '<div style="color:red">' + pending + '</div>';
-	} else {
-	    return current;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		model: 'KeyValuePendingDelete',
-		readArray: true,
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('Proxmox.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-    listeners: {
-	activate: function() {
-	    // notify owning container that it should display a help button
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-	    }
-	},
-	deactivate: function() {
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-	    }
-	}
-    },
-    border: false,
-
-    // override this with an URL to a relevant chapter of the pve manual
-    // setting this will display a help button in our parent panel
-    onlineHelp: undefined,
-
-    // will be set if the inputpanel has advanced items
-    hasAdvanced: false,
-
-    // if the panel has advanced items,
-    // this will determine if they are shown by default
-    showAdvanced: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-	return values;
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-	if (Ext.isFunction(me.onGetValues)) {
-	    dirtyOnly = false;
-	}
-
-	var values = {};
-
-	Ext.Array.each(me.query('[isFormField]'), function(field) {
-            if (!dirtyOnly || field.isDirty()) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-	    }
-	});
-
-	return me.onGetValues(values);
-    },
-
-    setAdvancedVisible: function(visible) {
-	var me = this;
-	var advItems = me.getComponent('advancedContainer');
-	if (advItems) {
-	    advItems.setVisible(visible);
-	}
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-	    var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-		field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var items;
-
-	if (me.items) {
-	    me.columns = 1;
-	    items = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.items
-		}
-	    ];
-	    me.items = undefined;
-	} else if (me.column4) {
-	    me.columns = 4;
-	    items = [
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column2
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column3
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column4
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else if (me.column1) {
-	    me.columns = 2;
-	    items = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column2 || [] // allow empty column
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else {
-	    throw "unsupported config";
-	}
-
-	var advItems;
-	if (me.advancedItems) {
-	    advItems = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.advancedItems
-		}
-	    ];
-	    me.advancedItems = undefined;
-	} else if (me.advancedColumn1) {
-	    advItems = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumn1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.advancedColumn2 || [] // allow empty column
-		}
-	    ];
-
-	    me.advancedColumn1 = undefined;
-	    me.advancedColumn2 = undefined;
-
-	    if (me.advancedColumnB) {
-		advItems.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumnB
-		});
-		me.advancedColumnB = undefined;
-	    }
-	}
-
-	if (advItems) {
-	    me.hasAdvanced = true;
-	    advItems.unshift({
-		columnWidth: 1,
-		xtype: 'box',
-		hidden: false,
-		border: true,
-		autoEl: {
-		    tag: 'hr'
-		}
-	    });
-	    items.push({
-		columnWidth: 1,
-		xtype: 'container',
-		itemId: 'advancedContainer',
-		hidden: !me.showAdvanced,
-		layout: 'column',
-		defaults: {
-		    border: false
-		},
-		items: advItems
-	    });
-	}
-
-	if (me.useFieldContainer) {
-	    Ext.apply(me, {
-		layout: 'fit',
-		items: Ext.apply(me.useFieldContainer, {
-		    layout: 'column',
-		    defaultType: 'container',
-		    items: items
-		})
-	    });
-	} else {
-	    Ext.apply(me, {
-		layout: 'column',
-		defaultType: 'container',
-		items: items
-	    });
-	}
-
-	me.callParent();
-    }
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxLogView',
-
-    pageSize: 500,
-    viewBuffer: 50,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    // callback for load failure, used for ceph
-    failCallback: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-	    if (viewModel.get('hide_timespan')) {
-		return;
-	    }
-
-	    if (since > until) {
-		Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
-		return;
-	    }
-
-	    viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
-	    viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
-	    me.getView().loadTask.delay(200);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	updateView: function(text, first, total) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    var content = me.lookup('content');
-	    var data = viewModel.get('data');
-
-	    if (first === data.first && total === data.total && text.length === data.textlen) {
-		return; // same content, skip setting and scrolling
-	    }
-	    viewModel.set('data', {
-		first: first,
-		total: total,
-		textlen: text.length
-	    });
-
-	    var scrollPos = me.scrollPosBottom();
-
-	    content.update(text);
-
-	    if (view.scrollToEnd && scrollPos <= 0) {
-		// we use setTimeout to work around scroll handling on touchscreens
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    }
-	},
-
-	doLoad: function() {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    Proxmox.Utils.API2Request({
-		url: me.getView().url,
-		params: viewModel.get('params'),
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var total = response.result.total;
-		    var lines = new Array();
-		    var first = Infinity;
-
-		    Ext.Array.each(response.result.data, function(line) {
-			if (first > line.n) {
-			    first = line.n;
-			}
-			lines[line.n - 1] = Ext.htmlEncode(line.t);
-		    });
-
-		    lines.length = total;
-		    me.updateView(lines.join('<br>'), first - 1, total);
-		},
-		failure: function(response) {
-		    if (view.failCallback) {
-			view.failCallback(response);
-		    } else {
-			var msg = response.htmlStatus;
-			Proxmox.Utils.setErrorMask(me, msg);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-
-	    var lineHeight = view.lineHeight;
-	    var line = view.getScrollY()/lineHeight;
-	    var start = viewModel.get('params.start');
-	    var limit = viewModel.get('params.limit');
-	    var viewLines = view.getHeight()/lineHeight;
-
-	    var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
-	    var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
-
-	    if (viewStart < start || viewEnd > (start+limit)) {
-		viewModel.set('params.start',
-		    Math.max(parseInt(line - limit/2 + 10, 10), 0));
-		view.loadTask.delay(200);
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    viewModel.set('params.limit', view.pageSize);
-	    viewModel.set('hide_timespan', !view.log_select_timespan);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200);
-		    }
-		},
-		interval: 1000
-	    });
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    until: null,
-	    since: null,
-	    hide_timespan: false,
-	    data: {
-		start: 0,
-		total: 0,
-		textlen: 0
-	    },
-	    params: {
-		start: 0,
-		limit: 500,
-	    }
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-	bind: {
-	    hidden: '{hide_timespan}'
-	},
-	items: [
-	    '->',
-	    'Since: ',
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    'Until: ',
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		handler: 'updateParams'
-	    }
-	],
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-Ext.define('Proxmox.widget.RRDChart', {
-    extend: 'Ext.chart.CartesianChart',
-    alias: 'widget.proxmoxRRDChart',
-
-    unit: undefined, // bytes, bytespersecond, percent
-    
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	convertToUnits: function(value) {
-	    var units = ['', 'k','M','G','T', 'P'];
-	    var si = 0;
-	    while(value >= 1000  && si < (units.length -1)){
-		value = value / 1000;
-		si++;
-	    }
-
-	    // javascript floating point weirdness
-	    value = Ext.Number.correctFloat(value);
-	    
-	    // limit to 2 decimal points
-	    value = Ext.util.Format.number(value, "0.##");
-	    
-	    return value.toString() + " " + units[si];
-	},
-
-	leftAxisRenderer: function(axis, label, layoutContext) {
-	    var me = this;
-
-	    return me.convertToUnits(label);
-	},
-
-	onSeriesTooltipRender: function(tooltip, record, item) {
-	    var me = this.getView();
-	    
-	    var suffix = '';
-	    
-	    if (me.unit === 'percent') {
-		suffix = '%';
-	    } else if (me.unit === 'bytes') {
-		suffix = 'B';
-	    } else if (me.unit === 'bytespersecond') {
-		suffix = 'B/s';
-	    }
-	    
-	    var prefix = item.field;
-	    if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
-		prefix = me.fieldTitles[me.fields.indexOf(item.field)];
-	    }
-            tooltip.setHtml(prefix + ': ' + this.convertToUnits(record.get(item.field)) + suffix +
-			    '<br>' + new Date(record.get('time')));
-	},
-
-	onAfterAnimation: function(chart, eopts) {
-	    // if the undobuton is disabled,
-	    // disable our tool
-
-	    var ourUndoZoomButton = chart.tools[0];
-	    var undoButton = chart.interactions[0].getUndoButton();
-	    ourUndoZoomButton.setDisabled(undoButton.isDisabled());
-	}
-    },
-    
-    width: 770,
-    height: 300,
-    animation: false,
-    interactions: [{
-	type: 'crosszoom'
-    }],
-    axes: [{
-	type: 'numeric',
-	position: 'left',
-	grid: true,
-	renderer: 'leftAxisRenderer',
-	//renderer: function(axis, label) { return label; },
-	minimum: 0
-    }, {
-	type: 'time',
-	position: 'bottom',
-	grid: true,
-	fields: ['time']
-    }],
-    legend: {
-	docked: 'bottom'
-    },
-    listeners: {
-	animationend: 'onAfterAnimation'
-    },
-
-
-    initComponent: function() {
-	var me = this;
-	var series = {};
-
-	if (!me.store) {
-	    throw "cannot work without store";
-	}
-
-	if (!me.fields) {
-	    throw "cannot work without fields";
-	}
-
-	me.callParent();
-
-	// add correct label for left axis
-	var axisTitle = "";
-	if (me.unit === 'percent') {
-	    axisTitle = "%";
-	} else if (me.unit === 'bytes') {
-	    axisTitle = "Bytes";
-	} else if (me.unit === 'bytespersecond') {
-	    axisTitle = "Bytes/s";
-	} else if (me.fieldTitles && me.fieldTitles.length === 1) {
-	    axisTitle = me.fieldTitles[0];
-	} else if (me.fields.length === 1) {
-	    axisTitle = me.fields[0];
-	}
-
-	me.axes[0].setTitle(axisTitle);
-
-	if (!me.noTool) {
-	    me.addTool([{
-		type: 'minus',
-		disabled: true,
-		tooltip: gettext('Undo Zoom'),
-		handler: function(){
-		    var undoButton = me.interactions[0].getUndoButton();
-		    if (undoButton.handler) {
-			undoButton.handler();
-		    }
-		}
-	    },{
-		type: 'restore',
-		tooltip: gettext('Toggle Legend'),
-		handler: function(){
-		    if (me.legend) {
-			me.legend.setVisible(!me.legend.isVisible());
-		    }
-		}
-	    }]);
-	}
-
-	// add a series for each field we get
-	me.fields.forEach(function(item, index){
-	    var title = item;
-	    if (me.fieldTitles && me.fieldTitles[index]) {
-		title = me.fieldTitles[index];
-	    }
-	    me.addSeries(Ext.apply(
-		{
-		    type: 'line',
-		    xField: 'time',
-		    yField: item,
-		    title: title,
-		    fill: true,
-		    style: {
-			lineWidth: 1.5,
-			opacity: 0.60
-		    },
-		    marker: {
-			opacity: 0,
-			scaling: 0.01,
-			fx: {
-			    duration: 200,
-			    easing: 'easeOut'
-			}
-		    },
-		    highlightCfg: {
-			opacity: 1,
-			scaling: 1.5
-		    },
-		    tooltip: {
-			trackMouse: true,
-			renderer: 'onSeriesTooltipRender'
-		    }
-		},
-		me.seriesConfig
-	    ));
-	});
-
-	// enable animation after the store is loaded
-	me.store.onAfter('load', function() {
-	    me.setAnimation(true);
-	}, this, {single: true});
-    }
-});
-Ext.define('Proxmox.panel.GaugeWidget', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.proxmoxGauge',
-
-    defaults: {
-	style: {
-	    'text-align':'center'
-	}
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	},
-	{
-	    xtype: 'polar',
-	    height: 120,
-	    border: false,
-	    itemId: 'chart',
-	    series: [{
-		type: 'gauge',
-		value: 0,
-		colors: ['#f5f5f5'],
-		sectors: [0],
-		donut: 90,
-		needleLength: 100,
-		totalAngle: Math.PI
-	    }],
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '',
-		textAlign: 'center',
-		textBaseline: 'bottom',
-		x: 125,
-		y: 110,
-		fontSize: 30
-	    }]
-	},
-	{
-	    xtype: 'box',
-	    itemId: 'text'
-	}
-    ],
-
-    header: false,
-    border: false,
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-    warningColor: '#fc0',
-    criticalColor: '#FF6C59',
-    defaultColor: '#c2ddf2',
-    backgroundColor: '#f5f5f5',
-
-    initialValue: 0,
-
-
-    updateValue: function(value, text) {
-	var me = this;
-	var color = me.defaultColor;
-	var attr = {};
-
-	if (value >= me.criticalThreshold) {
-	    color = me.criticalColor;
-	} else if (value >= me.warningThreshold) {
-	    color = me.warningColor;
-	}
-
-	me.chart.series[0].setColors([color, me.backgroundColor]);
-	me.chart.series[0].setValue(value*100);
-
-	me.valueSprite.setText(' '+(value*100).toFixed(0) + '%');
-	attr.x = me.chart.getWidth()/2;
-	attr.y = me.chart.getHeight()-20;
-	if (me.spriteFontSize) {
-	    attr.fontSize = me.spriteFontSize;
-	}
-	me.valueSprite.setAttributes(attr, true);
-
-	if (text !== undefined) {
-	    me.text.setHtml(text);
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.text = me.getComponent('text');
-	me.chart = me.getComponent('chart');
-	me.valueSprite = me.chart.getSurface('chart').get('valueSprite');
-    }
-});
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('Proxmox.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxWindowEdit',
-
-    // autoLoad trigger a load() after component creation
-    autoLoad: false,
-
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set isCreate to true if you want a Create button (instead
-    // OK and RESET)
-    isCreate: false,
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    // custom submitText
-    submitText: undefined,
-
-    backgroundDelay: 0,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-
-    // finds the first form field
-    defaultFocus: 'field[disabled=false][hidden=false]',
-
-    showProgress: false,
-
-    showTaskViewer: false,
-
-    // gets called if we have a progress bar or taskview and it detected that
-    // the task finished. function(success)
-    taskDone: Ext.emptyFn,
-
-    // gets called when the api call is finished, right at the beginning
-    // function(success, response, options)
-    apiCallDone: Ext.emptyFn,
-
-    // assign a reference from docs, to add a help button docked to the
-    // bottom of the window. If undefined we magically fall back to the
-    // onlineHelp of our first item, if set.
-    onlineHelp: undefined,
-
-    isValid: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-	return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	Ext.iterate(values, function(fieldId, val) {
-	    var field = form.findField(fieldId);
-	    if (field && !field.up('inputpanel')) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setValues(values);
-	});
-    },
-
-    submit: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	var values = me.getValues();
-	Ext.Object.each(values, function(name, val) {
-	    if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-		    values[name] = '';
-		}
-	    }
-	});
-
-	if (me.digest) {
-	    values.digest = me.digest;
-	}
-
-	if (me.backgroundDelay) {
-	    values.background_delay = me.backgroundDelay;
-	}
-
-	var url =  me.url;
-	if (me.method === 'DELETE') {
-	    url = url + "?" + Ext.Object.toQueryString(values);
-	    values = undefined;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    waitMsgTarget: me,
-	    method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-	    params: values,
-	    failure: function(response, options) {
-		me.apiCallDone(false, response, options);
-
-		if (response.result && response.result.errors) {
-		    form.markInvalid(response.result.errors);
-		}
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var hasProgressBar = (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
-		    response.result.data ? true : false;
-
-		me.apiCallDone(true, response, options);
-
-		if (hasProgressBar) {
-		    // stay around so we can trigger our close events
-		    // when background action is completed
-		    me.hide();
-
-		    var upid = response.result.data;
-		    var viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
-		    var win = Ext.create('Proxmox.window.Task' + viewerClass, {
-			upid: upid,
-			taskDone: me.taskDone,
-			listeners: {
-			    destroy: function () {
-				me.close();
-			    }
-			}
-		    });
-		    win.show();
-		} else {
-		    me.close();
-		}
-	    }
-	});
-    },
-
-    load: function(options) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	options = options || {};
-
-	var newopts = Ext.apply({
-	    waitMsgTarget: me
-	}, options);
-
-	var createWrapper = function(successFn) {
-	    Ext.apply(newopts, {
-		url: me.url,
-		method: 'GET',
-		success: function(response, opts) {
-		    form.clearInvalid();
-		    me.digest = response.result.data.digest;
-		    if (successFn) {
-			successFn(response, opts);
-		    } else {
-			me.setValues(response.result.data);
-		    }
-		    // hack: fix ExtJS bug
-		    Ext.Array.each(me.query('radiofield'), function(f) {
-			f.resetOriginalValue();
-		    });
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-			me.close();
-		    });
-		}
-	    });
-	};
-
-	createWrapper(options.success);
-
-	Proxmox.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.url) {
-	    throw "no url specified";
-	}
-
-	if (me.create) {throw "deprecated parameter, use isCreate";}
-
-	var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-	me.items = undefined;
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    url: me.url,
-	    method: me.method || 'PUT',
-	    trackResetOnLoad: true,
-	    bodyPadding: 10,
-	    border: false,
-	    defaults: Ext.apply({}, me.defaults, {
-		border: false
-	    }),
-	    fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-		labelWidth: 100,
-		anchor: '100%'
-            }),
-	    items: items
-	});
-
-	var inputPanel = me.formPanel.down('inputpanel');
-
-	var form = me.formPanel.getForm();
-
-	var submitText;
-	if (me.isCreate) {
-	    if (me.submitText) {
-		submitText = me.submitText;
-	    } else if (me.isAdd) {
-		submitText = gettext('Add');
-	    } else if (me.isRemove) {
-		submitText = gettext('Remove');
-	    } else {
-		submitText = gettext('Create');
-	    }
-	} else {
-	    submitText = me.submitText || gettext('OK');
-	}
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    reference: 'submitbutton',
-	    text: submitText,
-	    disabled: !me.isCreate,
-	    handler: function() {
-		me.submit();
-	    }
-	});
-
-	var resetBtn = Ext.create('Ext.Button', {
-	    text: 'Reset',
-	    disabled: true,
-	    handler: function(){
-		form.reset();
-	    }
-	});
-
-	var set_button_status = function() {
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-	    submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
-	    resetBtn.setDisabled(!dirty);
-
-	    if (inputPanel && inputPanel.hasAdvanced) {
-		// we want to show the advanced options
-		// as soon as some of it is not valid
-		var advancedItems = me.down('#advancedContainer').query('field');
-		var valid = true;
-		advancedItems.forEach(function(field) {
-		    if (!field.isValid()) {
-			valid = false;
-		    }
-		});
-
-		if (!valid) {
-		    inputPanel.setAdvancedVisible(true);
-		    me.down('#advancedcb').setValue(true);
-		}
-	    }
-	};
-
-	form.on('dirtychange', set_button_status);
-	form.on('validitychange', set_button_status);
-
-	var colwidth = 300;
-	if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-	    colwidth += me.fieldDefaults.labelWidth - 100;
-	}
-
-	var twoColumn = inputPanel &&
-	    (inputPanel.column1 || inputPanel.column2);
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
-	}
-
-	if (me.isCreate) {
-		me.buttons = [ submitBtn ] ;
-	} else {
-		me.buttons = [ submitBtn, resetBtn ];
-	}
-
-	if (inputPanel && inputPanel.hasAdvanced) {
-	    var sp = Ext.state.Manager.getProvider();
-	    var advchecked = sp.get('proxmox-advanced-cb');
-	    inputPanel.setAdvancedVisible(advchecked);
-	    me.buttons.unshift(
-	       {
-		   xtype: 'proxmoxcheckbox',
-		   itemId: 'advancedcb',
-		   boxLabelAlign: 'before',
-		   boxLabel: gettext('Advanced'),
-		   stateId: 'proxmox-advanced-cb',
-		   value: advchecked,
-		   listeners: {
-		       change: function(cb, val) {
-			   inputPanel.setAdvancedVisible(val);
-			   sp.set('proxmox-advanced-cb', val);
-		       }
-		   }
-	       }
-	    );
-	}
-
-	var onlineHelp = me.onlineHelp;
-	if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
-	    onlineHelp = inputPanel.onlineHelp;
-	}
-
-	if (onlineHelp) {
-	    var helpButton = Ext.create('Proxmox.button.Help');
-	    me.buttons.unshift(helpButton, '->');
-	    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
-	}
-
-	Ext.applyIf(me, {
-	    modal: true,
-	    width: twoColumn ? colwidth*2 : colwidth,
-	    border: false,
-	    items: [ me.formPanel ]
-	});
-
-	me.callParent();
-
-	// always mark invalid fields
-	me.on('afterlayout', function() {
-	    // on touch devices, the isValid function
-	    // triggers a layout, which triggers an isValid
-	    // and so on
-	    // to prevent this we disable the layouting here
-	    // and enable it afterwards
-	    me.suspendLayout = true;
-	    me.isValid();
-	    me.suspendLayout = false;
-	});
-
-	if (me.autoLoad) {
-	    me.load();
-	}
-    }
-});
-Ext.define('Proxmox.window.PasswordEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'proxmoxWindowPasswordEdit',
-
-    subject: gettext('Password'),
-
-    url: '/api2/extjs/access/password',
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    allowBlank: false,
-	    name: 'password',
-	    listeners: {
-                change: function(field){
-		    field.next().validate();
-                },
-                blur: function(field){
-		    field.next().validate();
-                }
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'),
-	    name: 'verifypassword',
-	    allowBlank: false,
-	    vtype: 'password',
-	    initialPassField: 'password',
-	    submitValue: false
-	},
-	{
-	    xtype: 'hiddenfield',
-	    name: 'userid'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	me.callParent();
-	me.down('[name=userid]').setValue(me.userid);
-    }
-});
-Ext.define('Proxmox.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskProgress',
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: {
-		status: { defaultValue: 'unknown' },
-		exitstatus: { defaultValue: 'unknown' }
-	    }
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var getObjectValue = function(key, defaultValue) {
-	    var rec = statstore.getById(key);
-	    if (rec) {
-		return rec.data.value;
-	    }
-	    return defaultValue;
-	};
-
-	var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-	me.mon(statstore, 'load', function() {
-	    var status = getObjectValue('status');
-	    if (status === 'stopped') {
-		var exitstatus = getObjectValue('exitstatus');
-		if (exitstatus == 'OK') {
-		    pbar.reset();
-		    pbar.updateText("Done!");
-		    Ext.Function.defer(me.close, 1000, me);
-		} else {
-		    me.close();
-		    Ext.Msg.alert('Task failed', exitstatus);
-		}
-		me.taskDone(exitstatus == 'OK');
-	    }
-	});
-
-	var descr = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	Ext.apply(me, {
-	    title: gettext('Task') + ': ' + descr,
-	    width: 300,
-	    layout: 'auto',
-	    modal: true,
-	    bodyPadding: 5,
-	    items: pbar,
-	    buttons: [
-		{ 
-		    text: gettext('Details'),
-		    handler: function() {			
-			var win = Ext.create('Proxmox.window.TaskViewer', { 
-			    taskDone: me.taskDone,
-			    upid: me.upid
-			});
-			win.show();
-			me.close();
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	statstore.startUpdate();
-
-	pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('Proxmox.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskViewer',
-
-    extraTitle: '', // string to prepend after the generic task title
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statgrid;
-
-	var rows = {
-	    status: {
-		header: gettext('Status'),
-		defaultValue: 'unknown',
-		renderer: function(value) {
-		    if (value != 'stopped') {
-			return value;
-		    }
-		    var es = statgrid.getObjectValue('exitstatus');
-		    if (es) {
-			return value + ': ' + es;
-		    }
-		}
-	    },
-	    exitstatus: { 
-		visible: false
-	    },
-	    type: {
-		header: gettext('Task type'),
-		required: true
-	    },
-	    user: {
-		header: gettext('User name'),
-		required: true 
-	    },
-	    node: {
-		header: gettext('Node'),
-		required: true 
-	    },
-	    pid: {
-		header: gettext('Process ID'),
-		required: true
-	    },
-	    starttime: {
-		header: gettext('Start Time'),
-		required: true, 
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    upid: {
-		header: gettext('Unique task ID')
-	    }
-	};
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: rows
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var stop_task = function() {
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + task.node + "/tasks/" + me.upid,
-		waitMsgTarget: me,
-		method: 'DELETE',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var stop_btn1 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	var stop_btn2 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	statgrid = Ext.create('Proxmox.grid.ObjectGrid', {
-	    title: gettext('Status'),
-	    layout: 'fit',
-	    tbar: [ stop_btn1 ],
-	    rstore: statstore,
-	    rows: rows,
-	    border: false
-	});
-
-	var logView = Ext.create('Proxmox.panel.LogView', {
-	    title: gettext('Output'),
-	    tbar: [ stop_btn2 ],
-	    border: false,
-	    url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-	});
-
-	me.mon(statstore, 'load', function() {
-	    var status = statgrid.getObjectValue('status');
-	    
-	    if (status === 'stopped') {
-		logView.scrollToEnd = false;
-		logView.requestUpdate();
-		statstore.stopUpdate();
-		me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
-	    }
-
-	    stop_btn1.setDisabled(status !== 'running');
-	    stop_btn2.setDisabled(status !== 'running');
-	});
-
-	statstore.startUpdate();
-
-	Ext.apply(me, {
-	    title: "Task viewer: " + task.desc + me.extraTitle,
-	    width: 800,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [{
-		xtype: 'tabpanel',
-		region: 'center',
-		items: [ logView, statgrid ]
-	    }]
-        });
-
-	me.callParent();
-
-	logView.fireEvent('show', logView);
-    }
-});
-
-Ext.define('apt-pkglist', {
-    extend: 'Ext.data.Model',
-    fields: [ 'Package', 'Title', 'Description', 'Section', 'Arch',
-	      'Priority', 'Version', 'OldVersion', 'ChangeLogUrl', 'Origin' ],
-    idProperty: 'Package'
-});
-
-Ext.define('Proxmox.node.APT', {
-    extend: 'Ext.grid.GridPanel',
-
-    xtype: 'proxmoxNodeAPT',
-
-    upgradeBtn: undefined,
-
-    columns: [
-	{
-	    header: gettext('Package'),
-	    width: 200,
-	    sortable: true,
-	    dataIndex: 'Package'
-	},
-	{
-	    text: gettext('Version'),
-	    columns: [
-		{
-		    header: gettext('current'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'OldVersion'
-		},
-		{
-		    header: gettext('new'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'Version'
-		}
-	    ]
-	},
-	{
-	    header: gettext('Description'),
-	    sortable: false,
-	    dataIndex: 'Title',
-	    flex: 1
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'apt-pkglist',
-	    groupField: 'Origin',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/apt/update"
-	    },
-	    sorters: [
-		{
-		    property : 'Package',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
-            groupHeaderTpl: '{[ "Origin: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
-	    enableGroupingMenu: false
-	});
-
-	var rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {
-            getAdditionalData: function (data, rowIndex, record, orig) {
-                var headerCt = this.view.headerCt;
-                var colspan = headerCt.getColumnCount();
-                // Usually you would style the my-body-class in CSS file
-                return {
-                    rowBody: '<div style="padding: 1em">' +
-			Ext.String.htmlEncode(data.Description) +
-			'</div>',
-                    rowBodyColspan: colspan
-                };
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	var apt_command = function(cmd){
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/apt/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.mon(win, 'close', reload);
-		}
-	    });
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var update_btn = new Ext.Button({
-	    text: gettext('Refresh'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { apt_command('update'); });
-	    }
-	});
-
-	var show_changelog = function(rec) {
-	    if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		return;
-	    }
-
-	    var view = Ext.createWidget('component', {
-		autoScroll: true,
-		style: {
-		    'background-color': 'white',
-		    'white-space': 'pre',
-		    'font-family': 'monospace',
-		    padding: '5px'
-		}
-	    });
-
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Changelog') + ": " + rec.data.Package,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		modal: true,
-		items: [ view ]
-	    });
-
-	    Proxmox.Utils.API2Request({
-		waitMsgTarget: me,
-		url: "/nodes/" + me.nodename + "/apt/changelog",
-		params: {
-		    name: rec.data.Package,
-		    version: rec.data.Version
-		},
-		method: 'GET',
-		failure: function(response, opts) {
-		    win.close();
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    win.show();
-		    view.update(Ext.htmlEncode(response.result.data));
-		}
-	    });
-
-	};
-
-	var changelog_btn = new Proxmox.button.Button({
-	    text: gettext('Changelog'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function(b, e, rec) {
-		show_changelog(rec);
-	    }
-	});
-
-	if (me.upgradeBtn) {
-	    me.tbar =  [ update_btn, me.upgradeBtn, changelog_btn ];
-	} else {
-	    me.tbar =  [ update_btn, changelog_btn ];
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-update',
-	    selModel: sm,
-            viewConfig: {
-		stripeRows: false,
-		emptyText: '<div style="display:table; width:100%; height:100%;"><div style="display:table-cell; vertical-align: middle; text-align:center;"><b>' + gettext('No updates available.') + '</div></div>'
-	    },
-	    features: [ groupingFeature, rowBodyFeature ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: function(v, rec) {
-		    show_changelog(rec);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeNetworkEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.iftype) {
-	    throw "no network device type specified";
-	}
-
-	me.isCreate = !me.iface;
-
-	var iface_vtype;
-
-	if (me.iftype === 'bridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'bond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'eth' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'vlan' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSBridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'OVSBond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'OVSIntPort') {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSPort') {
-	    iface_vtype = 'InterfaceName';
-	} else {
-	    console.log(me.iftype);
-	    throw "unknown network device type specified";
-	}
-
-	me.subject = Proxmox.Utils.render_network_iface_type(me.iftype);
-
-	var column2 = [];
-
-	if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' ||
-	      me.iftype === 'OVSBond')) {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Autostart'),
-		name: 'autostart',
-		uncheckedValue: 0,
-		checked: me.isCreate ? true : undefined
-	    });
-	}
-
-	if (me.iftype === 'bridge') {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('VLAN aware'),
-		name: 'bridge_vlan_aware',
-		deleteEmpty: !me.isCreate
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'bridge_ports'
-	    });
-	} else if (me.iftype === 'OVSBridge') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'ovs_ports'
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'OVSPort' || me.iftype === 'OVSIntPort') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'bond') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Slaves'),
-		name: 'slaves'
-	    });
-
-	    var policySelector = Ext.createWidget('bondPolicySelector', {
-		fieldLabel: gettext('Hash policy'),
-		name: 'bond_xmit_hash_policy',
-		deleteEmpty: !me.isCreate,
-		disabled: true
-	    });
-
-	    column2.push({
-		xtype: 'bondModeSelector',
-		fieldLabel: gettext('Mode'),
-		name: 'bond_mode',
-		value: me.isCreate ? 'balance-rr' : undefined,
-		listeners: {
-		    change: function(f, value) {
-			if (value === 'balance-xor' ||
-			    value === '802.3ad') {
-			    policySelector.setDisabled(false);
-			} else {
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			}
-		    }
-		},
-		allowBlank: false
-	    });
-
-	    column2.push(policySelector);
-
-	} else if (me.iftype === 'OVSBond') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	}
-
-	column2.push({
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Comment'),
-	    allowBlank: true,
-	    nodename: me.nodename,
-	    name: 'comments'
-	});
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network";
-	    method = 'POST';
-	} else {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network/" + me.iface;
-	    method = 'PUT';
-	}
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: me.iftype
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		fieldLabel: gettext('Name'),
-		name: 'iface',
-		value: me.iface,
-		vtype: iface_vtype,
-		allowBlank: false
-	    }
-	];
-
-	if (me.iftype === 'OVSBond') {
-	    column1.push(
-		{
-		    xtype: 'bondModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    name: 'bond_mode',
-		    openvswitch: true,
-		    value: me.isCreate ? 'active-backup' : undefined,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Slaves'),
-		    name: 'ovs_bonds'
-		}
-	    );
-	} else {
-
-	    column1.push(
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('IP address'),
-		    vtype: 'IPAddress',
-		    name: 'address'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Subnet mask'),
-		    vtype: 'IPAddress',
-		    name: 'netmask',
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.items) {
-			    return true;
-			}
-			var address = me.down('field[name=address]').getValue();
-			if (value !== '') {
-			    if (address === '') {
-				return "Subnet mask requires option 'IP address'";
-			    }
-			} else {
-			    if (address !== '') {
-				return "Option 'IP address' requires a subnet mask";
-			    }
-			}
-
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway'),
-		    vtype: 'IPAddress',
-		    name: 'gateway'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('IPv6 address'),
-		    vtype: 'IP6Address',
-		    name: 'address6'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Prefix length'),
-		    vtype: 'IP6PrefixLength',
-		    name: 'netmask6',
-		    value: '',
-		    allowBlank: true,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.items) {
-			    return true;
-			}
-			var address = me.down('field[name=address6]').getValue();
-			if (value !== '') {
-			    if (address === '') {
-				return "IPv6 prefix length requires option 'IPv6 address'";
-			    }
-			} else {
-			    if (address !== '') {
-				return "Option 'IPv6 address' requires an IPv6 prefix length";
-			    }
-			}
-
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway'),
-		    vtype: 'IP6Address',
-		    name: 'gateway6'
-		}
-	    );
-	}
-
-	Ext.applyIf(me, {
-	    url: url,
-	    method: method,
-	    items: {
-                xtype: 'inputpanel',
-		column1: column1,
-		column2: column2
-	    }
-	});
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.down('field[name=iface]').setValue(me.iface_default);
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.type !== me.iftype) {
-			var msg = "Got unexpected device type";
-			Ext.Msg.alert(gettext('Error'), msg, function() {
-			    me.close();
-			});
-			return;
-		    }
-		    me.setValues(data);
-		    me.isValid(); // trigger validation
-		}
-	    });
-	}
-    }
-});
-Ext.define('proxmox-networks', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'iface', 'type', 'active', 'autostart',
-	'bridge_ports', 'slaves',
-	'address', 'netmask', 'gateway',
-	'address6', 'netmask6', 'gateway6',
-	'comments'
-    ],
-    idProperty: 'iface'
-});
-
-Ext.define('Proxmox.node.NetworkView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.proxmoxNodeNetworkView'],
-
-    // defines what types of network devices we want to create
-    // order is always the same
-    types: ['bridge', 'bond', 'ovs'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseUrl = '/nodes/' + me.nodename + '/network';
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'proxmox-networks',
-	    proxy: {
-                type: 'proxmox',
-                url: '/api2/json' + baseUrl
-	    },
-	    sorters: [
-		{
-		    property : 'iface',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reload = function() {
-	    var changeitem = me.down('#changes');
-	    Proxmox.Utils.API2Request({
-		url: baseUrl,
-		failure: function(response, opts) {
-		    store.loadData({});
-		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		    changeitem.update('');
-		    changeitem.setHidden(true);
-		},
-		success: function(response, opts) {
-		    var result = Ext.decode(response.responseText);
-		    store.loadData(result.data);
-		    var changes = result.changes;
-		    if (changes === undefined || changes === '') {
-			changes = gettext("No changes");
-			changeitem.setHidden(true);
-		    } else {
-			changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
-			changeitem.setHidden(false);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.node.NetworkEdit', {
-		nodename: me.nodename,
-		iface: rec.data.iface,
-		iftype: rec.data.type
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: run_editor
-	});
-
-	var del_btn = new Ext.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    handler: function(){
-		var grid = me.down('gridpanel');
-		var sm = grid.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var iface = rec.data.iface;
-
-		Proxmox.Utils.API2Request({
-		    url: baseUrl + '/' + iface,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var set_button_status = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    edit_btn.setDisabled(!rec);
-	    del_btn.setDisabled(!rec);
-	};
-
-	var render_ports = function(value, metaData, record) {
-	    if (value === 'bridge') {
-		return record.data.bridge_ports;
-	    } else if (value === 'bond') {
-		return record.data.slaves;
-	    } else if (value === 'OVSBridge') {
-		return record.data.ovs_ports;
-	    } else if (value === 'OVSBond') {
-		return record.data.ovs_bonds;
-	    }
-	};
-
-	var find_next_iface_id = function(prefix) {
-	    var next;
-	    for (next = 0; next <= 9999; next++) {
-		if (!store.getById(prefix + next.toString())) {
-		    break;
-		}
-	    }
-	    return prefix + next.toString();
-	};
-
-	var menu_items = [];
-
-	if (me.types.indexOf('bridge') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bridge'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bridge',
-			iface_default: find_next_iface_id('vmbr')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('bond') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bond'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bond',
-			iface_default: find_next_iface_id('bond')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('ovs') !== -1) {
-	    if (menu_items.length > 0) {
-		menu_items.push({ xtype: 'menuseparator' });
-	    }
-
-	    menu_items.push(
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBridge',
-			    iface_default: find_next_iface_id('vmbr')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBond'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBond',
-			    iface_default: find_next_iface_id('bond')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSIntPort'
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		}
-	    );
-	}
-
-	Ext.apply(me, {
-	    layout: 'border',
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    menu: {
-			plain: true,
-			items: menu_items
-		    }
-		}, ' ',
-		{
-		    text: gettext('Revert'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: baseUrl,
-			    method: 'DELETE',
-			    waitMsgTarget: me,
-			    callback: function() {
-				reload();
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		edit_btn,
-		del_btn
-	    ],
-	    items: [
-		{
-		    xtype: 'gridpanel',
-		    stateful: true,
-		    stateId: 'grid-node-network',
-		    store: store,
-		    region: 'center',
-		    border: false,
-		    columns: [
-			{
-			    header: gettext('Name'),
-			    sortable: true,
-			    dataIndex: 'iface'
-			},
-			{
-			    header: gettext('Type'),
-			    sortable: true,
-			    width: 120,
-			    renderer: Proxmox.Utils.render_network_iface_type,
-			    dataIndex: 'type'
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Active'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'active',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText,
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Autostart'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'autostart',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('VLAN aware'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'bridge_vlan_aware',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    header: gettext('Ports/Slaves'),
-			    dataIndex: 'type',
-			    renderer: render_ports
-			},
-			{
-			    header: gettext('IP address'),
-			    sortable: true,
-			    width: 120,
-			    dataIndex: 'address',
-			    renderer: function(value, metaData, rec) {
-				if (rec.data.address && rec.data.address6) {
-				    return rec.data.address + "<br>"
-				           + rec.data.address6 + '/' + rec.data.netmask6;
-				} else if (rec.data.address6) {
-				    return rec.data.address6 + '/' + rec.data.netmask6;
-				} else {
-				    return rec.data.address;
-				}
-			    }
-			},
-			{
-			    header: gettext('Subnet mask'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'netmask'
-			},
-			{
-			    header: gettext('Gateway'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'gateway',
-			    renderer: function(value, metaData, rec) {
-				if (rec.data.gateway && rec.data.gateway6) {
-				    return rec.data.gateway + "<br>" + rec.data.gateway6;
-				} else if (rec.data.gateway6) {
-				    return rec.data.gateway6;
-				} else {
-				    return rec.data.gateway;
-				}
-			    }
-			},
-			{
-			    header: gettext('Comment'),
-			    dataIndex: 'comments',
-			    flex: 1,
-			    renderer: Ext.String.htmlEncode
-			}
-		    ],
-		    listeners: {
-			selectionchange: set_button_status,
-			itemdblclick: run_editor
-		    }
-		},
-		{
-		    border: false,
-		    region: 'south',
-		    autoScroll: true,
-		    hidden: true,
-		    itemId: 'changes',
-		    tbar: [
-			gettext('Pending changes') + ' (' +
-			    gettext('Please reboot to activate changes') + ')'
-		    ],
-		    split: true,
-		    bodyPadding: 5,
-		    flex: 0.6,
-		    html: gettext("No changes")
-		}
-	    ],
-	});
-
-	me.callParent();
-	reload();
-    }
-});
-Ext.define('Proxmox.node.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeDNSEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-                fieldLabel: gettext('Search domain'),
-                name: 'search',
-                allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 1",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns1'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS server') + " 2",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns2'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 3",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns3'
-	    }
-	];
-
-	Ext.applyIf(me, {
-	    subject: gettext('DNS'),
-	    url: "/api2/extjs/nodes/" + me.nodename + "/dns",
-	    fieldDefaults: {
-		labelWidth: 120
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('Proxmox.node.HostsView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxNodeHostsView',
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-    },
-
-    tbar: [
-	{
-	    text: gettext('Save'),
-	    disabled: true,
-	    itemId: 'savebtn',
-	    handler: function() {
-		var me = this.up('panel');
-		Proxmox.Utils.API2Request({
-		    params: {
-			digest: me.digest,
-			data: me.down('#hostsfield').getValue()
-		    },
-		    method: 'POST',
-		    url: '/nodes/' + me.nodename + '/hosts',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			me.reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	{
-	    text: gettext('Revert'),
-	    disabled: true,
-	    itemId: 'resetbtn',
-	    handler: function() {
-		var me = this.up('panel');
-		me.down('#hostsfield').reset();
-	    }
-	}
-    ],
-
-	    layout: 'fit',
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'hostsfield',
-	    fieldStyle: {
-		'font-family': 'monospace',
-		'white-space': 'pre'
-	    },
-	    listeners: {
-		dirtychange: function(ta, dirty) {
-		    var me = this.up('panel');
-		    me.down('#savebtn').setDisabled(!dirty);
-		    me.down('#resetbtn').setDisabled(!dirty);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/hosts",
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.store);
-
-	me.mon(me.store, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    me.digest = records[0].data.digest;
-	    var data = records[0].data.data;
-	    me.down('#hostsfield').setValue(data);
-	    me.down('#hostsfield').resetOriginalValue();
-	});
-
-	me.reload();
-    }
-});
-Ext.define('Proxmox.node.DNSView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeDNSView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.DNSEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/dns",
-	    cwidth1: 130,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		search: {
-		    header: 'Search domain',
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns1: {
-		    header: gettext('DNS server') + " 1",
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns2: {
-		    header: gettext('DNS server') + " 2",
-		    renderer: Ext.htmlEncode
-		},
-		dns3: {
-		    header: gettext('DNS server') + " 3",
-		    renderer: Ext.htmlEncode
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
-Ext.define('Proxmox.node.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeTasks'],
-    stateful: true,
-    stateId: 'grid-node-tasks',
-    loadMask: true,
-    sortableColumns: false,
-    vmidFilter: 0,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.BufferedStore', {
-	    pageSize: 500,
-	    autoLoad: true,
-	    remoteFilter: true,
-	    model: 'proxmox-tasks',
-	    proxy: {
-                type: 'proxmox',
-		startParam: 'start',
-		limitParam: 'limit',
-                url: "/api2/json/nodes/" + me.nodename + "/tasks"
-	    }
-	});
-
-	var userfilter = '';
-	var filter_errors = 0;
-
-	var updateProxyParams = function() {
-	    var params = {
-		errors: filter_errors
-	    };
-	    if (userfilter) {
-		params.userfilter = userfilter;
-	    }
-	    if (me.vmidFilter) {
-		params.vmid = me.vmidFilter;
-	    }
-	    store.proxy.extraParams = params;
-	};
-
-	updateProxyParams();
-
-	var reload_task = Ext.create('Ext.util.DelayedTask',function() {
-	    updateProxyParams();
-	    store.reload();
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	var view_btn = new Ext.Button({
-	    text: gettext('View'),
-	    disabled: true,
-	    handler: run_task_viewer
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	Ext.apply(me, {
-	    store: store,
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: false, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    tbar: [
-		view_btn, '->', gettext('User name') +':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: userfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    userfilter = field.getValue();
-			    reload_task.delay(500);
-			}
-		    }
-		}, ' ', gettext('Only Errors') + ':', ' ',
-		{
-		    xtype: 'checkbox',
-		    hideLabel: true,
-		    checked: filter_errors,
-		    listeners: {
-			change: function(field, checked) {
-			    filter_errors = checked ? 1 : 0;
-			    reload_task.delay(10);
-			}
-		    }
-		}, ' '
-	    ],
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 100,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 100,
-		    renderer: function(value, metaData, record) {
-			return Ext.Date.format(value,"M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return "ERROR: " + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		selectionchange: function(v, selections) {
-		    view_btn.setDisabled(!(selections && selections[0]));
-		},
-		show: function() { reload_task.delay(10); },
-		destroy: function() { reload_task.cancel(); }
-	    }
-	});
-
-	me.callParent();
-
-    }
-});
-Ext.define('proxmox-services', {
-    extend: 'Ext.data.Model',
-    fields: [ 'service', 'name', 'desc', 'state' ],
-    idProperty: 'service'
-});
-
-Ext.define('Proxmox.node.ServiceView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeServiceView'],
-
-    startOnlyServices: {},
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 1000,
-	    storeid: 'proxmox-services' + me.nodename,
-	    model: 'proxmox-services',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/services"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sortAfterUpdate: true,
-	    sorters: [
-		{
-		    property : 'name',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var view_service_log = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + rec.data.service,
-		modal: true,
-		items: {
-		    xtype: 'proxmoxLogView',
-		    width: 800,
-		    height: 400,
-		    url: "/api2/extjs/nodes/" + me.nodename + "/syslog?service=" +
-			rec.data.service,
-		    log_select_timespan: 1
-		}
-	    });
-	    win.show();
-	};
-
-	var service_cmd = function(cmd) {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/services/" + rec.data.service + "/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.loading = true;
-		},
-		success: function(response, opts) {
-		    rstore.startUpdate();
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid
-		    });
-		    win.show();
-		}
-	    });
-	};
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var syslog_btn = new Ext.Button({
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: view_service_log
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		start_btn.disable();
-		stop_btn.disable();
-		restart_btn.disable();
-		syslog_btn.disable();
-		return;
-	    }
-	    var service = rec.data.service;
-	    var state = rec.data.state;
-
-	    syslog_btn.enable();
-
-	    if (me.startOnlyServices[service]) {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		}
-		stop_btn.disable();
-	    } else {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		    stop_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		    stop_btn.disable();
-		}
-	    }
-	};
-
-	me.mon(store, 'refresh', set_button_status);
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    tbar: [ start_btn, stop_btn, restart_btn, syslog_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Description'),
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'desc',
-		    flex: 2
-		}
-	    ],
-	    listeners: {
-		selectionchange: set_button_status,
-		itemdblclick: view_service_log,
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeTimeEdit'],
-
-    subject: gettext('Time zone'),
-
-    width: 400,
-
-    autoLoad: true,
-
-    fieldDefaults: {
-	labelWidth: 70
-    },
-
-    items: {
-	xtype: 'combo',
-	fieldLabel: gettext('Time zone'),
-	name: 'timezone',
-	queryMode: 'local',
-	store: Ext.create('Proxmox.data.TimezoneStore'),
-	displayField: 'zone',
-	forceSelection: true,
-	editable: false,
-	allowBlank: false
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/time";
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeTimeView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var tzoffset = (new Date()).getTimezoneOffset()*60000;
-	var renderlocaltime = function(value) {
-	    var servertime = new Date((value * 1000) + tzoffset);
-	    return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-	};
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.TimeEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/time",
-	    cwidth1: 150,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		timezone: { 
-		    header: gettext('Time zone'), 
-		    required: true
-		},
-		localtime: { 
-		    header: gettext('Server time'), 
-		    required: true, 
-		    renderer: renderlocaltime 
-		}
-	    },
-	    tbar: [ 
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
diff --git a/serverside/jsmod/5.4-3/pvemanagerlib.js b/serverside/jsmod/5.4-3/pvemanagerlib.js
deleted file mode 100644
index e62acdec179ec766f50bff197acac9510aa722df..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/pvemanagerlib.js
+++ /dev/null
@@ -1,38347 +0,0 @@
-var pveOnlineHelpInfo = {
-   "ceph_rados_block_devices" : {
-      "link" : "/pve-docs/chapter-pvesm.html#ceph_rados_block_devices",
-      "title" : "Ceph RADOS Block Devices (RBD)"
-   },
-   "chapter_ha_manager" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#chapter_ha_manager",
-      "title" : "High Availability"
-   },
-   "chapter_lvm" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_lvm",
-      "title" : "Logical Volume Manager (LVM)"
-   },
-   "chapter_pct" : {
-      "link" : "/pve-docs/chapter-pct.html#chapter_pct",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "chapter_pve_firewall" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#chapter_pve_firewall",
-      "title" : "Proxmox VE Firewall"
-   },
-   "chapter_pveceph" : {
-      "link" : "/pve-docs/chapter-pveceph.html#chapter_pveceph",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "chapter_pvecm" : {
-      "link" : "/pve-docs/chapter-pvecm.html#chapter_pvecm",
-      "title" : "Cluster Manager"
-   },
-   "chapter_pvesr" : {
-      "link" : "/pve-docs/chapter-pvesr.html#chapter_pvesr",
-      "title" : "Storage Replication"
-   },
-   "chapter_storage" : {
-      "link" : "/pve-docs/chapter-pvesm.html#chapter_storage",
-      "title" : "Proxmox VE Storage"
-   },
-   "chapter_system_administration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_system_administration",
-      "title" : "Host System Administration"
-   },
-   "chapter_user_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#chapter_user_management",
-      "title" : "User Management"
-   },
-   "chapter_virtual_machines" : {
-      "link" : "/pve-docs/chapter-qm.html#chapter_virtual_machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "chapter_vzdump" : {
-      "link" : "/pve-docs/chapter-vzdump.html#chapter_vzdump",
-      "title" : "Backup and Restore"
-   },
-   "chapter_zfs" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_zfs",
-      "title" : "ZFS on Linux"
-   },
-   "datacenter_configuration_file" : {
-      "link" : "/pve-docs/pve-admin-guide.html#datacenter_configuration_file",
-      "title" : "Datacenter Configuration"
-   },
-   "getting_help" : {
-      "link" : "/pve-docs/pve-admin-guide.html#getting_help",
-      "title" : "Getting Help"
-   },
-   "gui_my_settings" : {
-      "link" : "/pve-docs/chapter-pve-gui.html#gui_my_settings",
-      "subtitle" : "My Settings",
-      "title" : "Graphical User Interface"
-   },
-   "ha_manager_fencing" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_fencing",
-      "subtitle" : "Fencing",
-      "title" : "High Availability"
-   },
-   "ha_manager_groups" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_groups",
-      "subtitle" : "Groups",
-      "title" : "High Availability"
-   },
-   "ha_manager_resource_config" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resource_config",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_resources" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resources",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "pct_configuration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_configuration",
-      "subtitle" : "Configuration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_images" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_images",
-      "subtitle" : "Container Images",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_network" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_network",
-      "subtitle" : "Network",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_storage" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_storage",
-      "subtitle" : "Container Storage",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_cpu" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_cpu",
-      "subtitle" : "CPU",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_general" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_general",
-      "subtitle" : "General Settings",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_memory" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_memory",
-      "subtitle" : "Memory",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_migration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_migration",
-      "subtitle" : "Migration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_options" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_options",
-      "subtitle" : "Options",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_snapshots" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_snapshots",
-      "subtitle" : "Snapshots",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Containers",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pve_admin_guide" : {
-      "link" : "/pve-docs/pve-admin-guide.html",
-      "title" : "Proxmox VE Administration Guide"
-   },
-   "pve_ceph_install" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_install",
-      "subtitle" : "Installation of Ceph Packages",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_monitors" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_monitors",
-      "subtitle" : "Creating Ceph Monitors",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_osds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_osds",
-      "subtitle" : "Creating Ceph OSDs",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_pools" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_pools",
-      "subtitle" : "Creating Ceph Pools",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_documentation_index" : {
-      "link" : "/pve-docs/index.html",
-      "title" : "Proxmox VE Documentation Index"
-   },
-   "pve_firewall_cluster_wide_setup" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_cluster_wide_setup",
-      "subtitle" : "Cluster Wide Setup",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_host_specific_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_host_specific_configuration",
-      "subtitle" : "Host Specific Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_aliases" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_aliases",
-      "subtitle" : "IP Aliases",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_sets" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_sets",
-      "subtitle" : "IP Sets",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_vm_container_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_vm_container_configuration",
-      "subtitle" : "VM/Container Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_service_daemons" : {
-      "link" : "/pve-docs/index.html#_service_daemons",
-      "title" : "Service Daemons"
-   },
-   "pveceph_fs" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs",
-      "subtitle" : "CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_create" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_create",
-      "subtitle" : "Create a CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_mds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_mds",
-      "subtitle" : "Metadata Server (MDS)",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pvesr_schedule_time_format" : {
-      "link" : "/pve-docs/chapter-pvesr.html#pvesr_schedule_time_format",
-      "subtitle" : "Schedule Format",
-      "title" : "Storage Replication"
-   },
-   "pveum_authentication_realms" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_authentication_realms",
-      "subtitle" : "Authentication Realms",
-      "title" : "User Management"
-   },
-   "pveum_groups" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_groups",
-      "subtitle" : "Groups",
-      "title" : "User Management"
-   },
-   "pveum_permission_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_permission_management",
-      "subtitle" : "Permission Management",
-      "title" : "User Management"
-   },
-   "pveum_pools" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_pools",
-      "subtitle" : "Pools",
-      "title" : "User Management"
-   },
-   "pveum_roles" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_roles",
-      "subtitle" : "Roles",
-      "title" : "User Management"
-   },
-   "pveum_tfa_auth" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_tfa_auth",
-      "subtitle" : "Two factor authentication",
-      "title" : "User Management"
-   },
-   "pveum_users" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_users",
-      "subtitle" : "Users",
-      "title" : "User Management"
-   },
-   "qm_bios_and_uefi" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_bios_and_uefi",
-      "subtitle" : "BIOS and UEFI",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cloud_init" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cloud_init",
-      "title" : "Cloud-Init Support"
-   },
-   "qm_copy_and_clone" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_copy_and_clone",
-      "subtitle" : "Copies and Clones",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cpu" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cpu",
-      "subtitle" : "CPU",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_general_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_general_settings",
-      "subtitle" : "General Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_hard_disk" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_hard_disk",
-      "subtitle" : "Hard Disk",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_memory" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_memory",
-      "subtitle" : "Memory",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_migration" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_migration",
-      "subtitle" : "Migration",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_network_device" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_network_device",
-      "subtitle" : "Network Device",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_options" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_options",
-      "subtitle" : "Options",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_os_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_os_settings",
-      "subtitle" : "OS Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_pci_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_pci_passthrough",
-      "title" : "PCI(e) Passthrough"
-   },
-   "qm_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Virtual Machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_system_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_system_settings",
-      "subtitle" : "System Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_usb_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_usb_passthrough",
-      "subtitle" : "USB Passthrough",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_virtual_machines_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_virtual_machines_settings",
-      "subtitle" : "Virtual Machines Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "storage_cephfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cephfs",
-      "title" : "Ceph Filesystem (CephFS)"
-   },
-   "storage_cifs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cifs",
-      "title" : "CIFS Backend"
-   },
-   "storage_directory" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_directory",
-      "title" : "Directory Backend"
-   },
-   "storage_glusterfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_glusterfs",
-      "title" : "GlusterFS Backend"
-   },
-   "storage_lvm" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvm",
-      "title" : "LVM Backend"
-   },
-   "storage_lvmthin" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvmthin",
-      "title" : "LVM thin Backend"
-   },
-   "storage_nfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_nfs",
-      "title" : "NFS Backend"
-   },
-   "storage_open_iscsi" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_open_iscsi",
-      "title" : "Open-iSCSI initiator"
-   },
-   "storage_zfspool" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_zfspool",
-      "title" : "Local ZFS Pool Backend"
-   },
-   "sysadmin_certificate_management" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_certificate_management",
-      "title" : "Certificate Management"
-   },
-   "sysadmin_network_configuration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_network_configuration",
-      "title" : "Network Configuration"
-   }
-};
-Ext.ns('PVE');
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	log: function() {}
-    };
-}
-console.log("Starting PVE Manager");
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-/*jslint confusion: true */
-Ext.define('PVE.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js
-
-    bus_match: /^(ide|sata|virtio|scsi)\d+$/,
-
-    log_severity_hash: {
-	0: "panic",
-	1: "alert",
-	2: "critical",
-	3: "error",
-	4: "warning",
-	5: "notice",
-	6: "info",
-	7: "debug"
-    },
-
-    support_level_hash: {
-	'c': gettext('Community'),
-	'b': gettext('Basic'),
-	's': gettext('Standard'),
-	'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-	'Linux': [
-	    { desc: '4.X/3.X/2.6 Kernel', val: 'l26' },
-	    { desc: '2.4 Kernel', val: 'l24' }
-	],
-	'Microsoft Windows': [
-	    { desc: '10/2016', val: 'win10' },
-	    { desc: '8.x/2012/2012r2', val: 'win8' },
-	    { desc: '7/2008r2', val: 'win7' },
-	    { desc: 'Vista/2008', val: 'w2k8' },
-	    { desc: 'XP/2003', val: 'wxp' },
-	    { desc: '2000', val: 'w2k' }
-	],
-	'Solaris Kernel': [
-	    { desc: '-', val: 'solaris'}
-	],
-	'Other': [
-	    { desc: '-', val: 'other'}
-	]
-    },
-
-    get_health_icon: function(state, circle) {
-	if (circle === undefined) {
-	    circle = false;
-	}
-
-	if (state === undefined) {
-	    state = 'uknown';
-	}
-
-	var icon = 'faded fa-question';
-	switch(state) {
-	    case 'good':
-		icon = 'good fa-check';
-		break;
-	    case 'warning':
-		icon = 'warning fa-exclamation';
-		break;
-	    case 'critical':
-		icon = 'critical fa-times';
-		break;
-	    default: break;
-	}
-
-	if (circle) {
-	    icon += '-circle';
-	}
-
-	return icon;
-    },
-
-    map_ceph_health: {
-	'HEALTH_OK':'good',
-	'HEALTH_WARN':'warning',
-	'HEALTH_ERR':'critical'
-    },
-
-    render_ceph_health: function(healthObj) {
-	var state = {
-	    iconCls: PVE.Utils.get_health_icon(),
-	    text: ''
-	};
-
-	if (!healthObj || !healthObj.status) {
-	    return state;
-	}
-
-	var health = PVE.Utils.map_ceph_health[healthObj.status];
-
-	state.iconCls = PVE.Utils.get_health_icon(health, true);
-	state.text = healthObj.status;
-
-	return state;
-    },
-
-    render_zfs_health: function(value) {
-	if (typeof value == 'undefined'){
-	    return "";
-	}
-	var iconCls = 'question-circle';
-	switch (value) {
-	    case 'AVAIL':
-	    case 'ONLINE':
-		iconCls = 'check-circle good';
-		break;
-	    case 'REMOVED':
-	    case 'DEGRADED':
-		iconCls = 'exclamation-circle warning';
-		break;
-	    case 'UNAVAIL':
-	    case 'FAULTED':
-	    case 'OFFLINE':
-		iconCls = 'times-circle critical';
-		break;
-	    default: //unknown
-	}
-
-	return '<i class="fa fa-' + iconCls + '"></i> ' + value;
-
-    },
-
-    get_kvm_osinfo: function(value) {
-	var info = { base: 'Other' }; // default
-	if (value) {
-	    Ext.each(Object.keys(PVE.Utils.kvm_ostypes), function(k) {
-		Ext.each(PVE.Utils.kvm_ostypes[k], function(e) {
-		    if (e.val === value) {
-			info = { desc: e.desc, base: k };
-		    }
-		});
-	    });
-	}
-	return info;
-    },
-
-    render_kvm_ostype: function (value) {
-	var osinfo = PVE.Utils.get_kvm_osinfo(value);
-	if (osinfo.desc && osinfo.desc !== '-') {
-	    return osinfo.base + ' ' + osinfo.desc;
-	} else {
-	    return osinfo.base;
-	}
-    },
-
-    render_hotplug_features: function (value) {
-	var fa = [];
-
-	if (!value || (value === '0')) {
-	    return gettext('Disabled');
-	}
-
-	if (value === '1') {
-	    value = 'disk,network,usb';
-	}
-
-	Ext.each(value.split(','), function(el) {
-	    if (el === 'disk') {
-		fa.push(gettext('Disk'));
-	    } else if (el === 'network') {
-		fa.push(gettext('Network'));
-	    } else if (el === 'usb') {
-		fa.push('USB');
-	    } else if (el === 'memory') {
-		fa.push(gettext('Memory'));
-	    } else if (el === 'cpu') {
-		fa.push(gettext('CPU'));
-	    } else {
-		fa.push(el);
-	    }
-	});
-
-	return fa.join(', ');
-    },
-
-    render_qga_features: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText  + ')';
-	}
-	var props = PVE.Parser.parsePropertyString(value, 'enabled');
-	if (!PVE.Parser.parseBoolean(props.enabled)) {
-	    return Proxmox.Utils.disabledText;
-	}
-
-	delete props.enabled;
-	var agentstring = Proxmox.Utils.enabledText;
-
-	Ext.Object.each(props, function(key, value) {
-	    var keystring = '' ;
-	    agentstring += ', ' + key + ': ';
-
-	    if (PVE.Parser.parseBoolean(value)) {
-		agentstring += Proxmox.Utils.enabledText;
-	    } else {
-		agentstring += Proxmox.Utils.disabledText;
-	    }
-	});
-
-	return agentstring;
-    },
-
-    render_qemu_machine: function(value) {
-	return value || (Proxmox.Utils.defaultText + ' (i440fx)');
-    },
-
-    render_qemu_bios: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (SeaBIOS)';
-	} else if (value === 'seabios') {
-	    return "SeaBIOS";
-	} else if (value === 'ovmf') {
-	    return "OVMF (UEFI)";
-	} else {
-	    return value;
-	}
-    },
-
-    render_dc_ha_opts: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	} else {
-	    return PVE.Parser.printPropertyString(value);
-	}
-    },
-    render_as_property_string: function(value) {
-	return (!value) ? Proxmox.Utils.defaultText
-	    : PVE.Parser.printPropertyString(value);
-    },
-
-    render_scsihw: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (LSI 53C895A)';
-	} else if (value === 'lsi') {
-	    return 'LSI 53C895A';
-	} else if (value === 'lsi53c810') {
-	    return 'LSI 53C810';
-	} else if (value === 'megasas') {
-	    return 'MegaRAID SAS 8708EM2';
-	} else if (value === 'virtio-scsi-pci') {
-	    return 'VirtIO SCSI';
-	} else if (value === 'virtio-scsi-single') {
-	    return 'VirtIO SCSI single';
-	} else if (value === 'pvscsi') {
-	    return 'VMware PVSCSI';
-	} else {
-	    return value;
-	}
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-	//ar: 'Arabic',
-	da: 'Danish',
-	de: 'German',
-	'de-ch': 'German (Swiss)',
-	'en-gb': 'English (UK)',
-	'en-us': 'English (USA)',
-	es: 'Spanish',
-	//et: 'Estonia',
-	fi: 'Finnish',
-	//fo: 'Faroe Islands',
-	fr: 'French',
-	'fr-be': 'French (Belgium)',
-	'fr-ca': 'French (Canada)',
-	'fr-ch': 'French (Swiss)',
-	//hr: 'Croatia',
-	hu: 'Hungarian',
-	is: 'Icelandic',
-	it: 'Italian',
-	ja: 'Japanese',
-	lt: 'Lithuanian',
-	//lv: 'Latvian',
-	mk: 'Macedonian',
-	nl: 'Dutch',
-	//'nl-be': 'Dutch (Belgium)',
-	no: 'Norwegian',
-	pl: 'Polish',
-	pt: 'Portuguese',
-	'pt-br': 'Portuguese (Brazil)',
-	//ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	//th: 'Thai',
-	tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-	std: gettext('Standard VGA'),
-	vmware: gettext('VMware compatible'),
-	qxl: 'SPICE',
-	qxl2: 'SPICE dual monitor',
-	qxl3: 'SPICE three monitors',
-	qxl4: 'SPICE four monitors',
-	serial0: gettext('Serial terminal') + ' 0',
-	serial1: gettext('Serial terminal') + ' 1',
-	serial2: gettext('Serial terminal') + ' 2',
-	serial3: gettext('Serial terminal') + ' 3',
-	virtio: 'VirtIO-GPU',
-	none: Proxmox.Utils.noneText
-    },
-
-    render_kvm_language: function (value) {
-	if (!value || value === '__default__') {
-	    return Proxmox.Utils.defaultText;
-	}
-	var text = PVE.Utils.kvm_keymaps[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_keymap_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_language('')]];
-	Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_language(value)]);
-	});
-
-	return data;
-    },
-
-    console_map: {
-	'__default__': Proxmox.Utils.defaultText + ' (HTML5)',
-	'vv': 'SPICE (remote-viewer)',
-	'html5': 'HTML5 (noVNC)',
-	'xtermjs': 'xterm.js'
-    },
-
-    render_console_viewer: function(value) {
-	value = value || '__default__';
-	if (PVE.Utils.console_map[value]) {
-	    return PVE.Utils.console_map[value];
-	}
-	return value;
-    },
-
-    console_viewer_array: function() {
-	return Ext.Array.map(Object.keys(PVE.Utils.console_map), function(v) {
-	    return [v, PVE.Utils.render_console_viewer(v)];
-	});
-    },
-
-    render_kvm_vga_driver: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	}
-	var vga = PVE.Parser.parsePropertyString(value, 'type');
-	var text = PVE.Utils.kvm_vga_drivers[vga.type];
-	if (!vga.type) {
-	    text = Proxmox.Utils.defaultText;
-	}
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_vga_driver_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_vga_driver('')]];
-	Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-	});
-
-	return data;
-    },
-
-    render_kvm_startup: function(value) {
-	var startup = PVE.Parser.parseStartup(value);
-
-	var res = 'order=';
-	if (startup.order === undefined) {
-	    res += 'any';
-	} else {
-	    res += startup.order;
-	}
-	if (startup.up !== undefined) {
-	    res += ',up=' + startup.up;
-	}
-	if (startup.down !== undefined) {
-	    res += ',down=' + startup.down;
-	}
-
-	return res;
-    },
-
-    extractFormActionError: function(action) {
-	var msg;
-	switch (action.failureType) {
-	case Ext.form.action.Action.CLIENT_INVALID:
-	    msg = gettext('Form fields may not be submitted with invalid values');
-	    break;
-	case Ext.form.action.Action.CONNECT_FAILURE:
-	    msg = gettext('Connection error');
-	    var resp = action.response;
-	    if (resp.status && resp.statusText) {
-		msg += " " + resp.status + ": " + resp.statusText;
-	    }
-	    break;
-	case Ext.form.action.Action.LOAD_FAILURE:
-	case Ext.form.action.Action.SERVER_INVALID:
-	    msg = Proxmox.Utils.extractRequestError(action.result, true);
-	    break;
-	}
-	return msg;
-    },
-
-    format_duration_short: function(ut) {
-
-	if (ut < 60) {
-	    return ut.toFixed(1) + 's';
-	}
-
-	if (ut < 3600) {
-	    var mins = ut / 60;
-	    return mins.toFixed(1) + 'm';
-	}
-
-	if (ut < 86400) {
-	    var hours = ut / 3600;
-	    return hours.toFixed(1) + 'h';
-	}
-
-	var days = ut / 86400;
-	return days.toFixed(1) + 'd';
-    },
-
-    contentTypes: {
-	'images': gettext('Disk image'),
-	'backup': gettext('VZDump backup file'),
-	'vztmpl': gettext('Container template'),
-	'iso': gettext('ISO image'),
-	'rootdir': gettext('Container'),
-	'snippets': gettext('Snippets')
-    },
-
-    storageSchema: {
-	dir: {
-	    name: Proxmox.Utils.directoryText,
-	    ipanel: 'DirInputPanel',
-	    faIcon: 'folder'
-	},
-	lvm: {
-	    name: 'LVM',
-	    ipanel: 'LVMInputPanel',
-	    faIcon: 'folder'
-	},
-	lvmthin: {
-	    name: 'LVM-Thin',
-	    ipanel: 'LvmThinInputPanel',
-	    faIcon: 'folder'
-	},
-	nfs: {
-	    name: 'NFS',
-	    ipanel: 'NFSInputPanel',
-	    faIcon: 'building'
-	},
-	cifs: {
-	    name: 'CIFS',
-	    ipanel: 'CIFSInputPanel',
-	    faIcon: 'building'
-	},
-	glusterfs: {
-	    name: 'GlusterFS',
-	    ipanel: 'GlusterFsInputPanel',
-	    faIcon: 'building'
-	},
-	iscsi: {
-	    name: 'iSCSI',
-	    ipanel: 'IScsiInputPanel',
-	    faIcon: 'building'
-	},
-	sheepdog: {
-	    name: 'Sheepdog',
-	    ipanel: 'SheepdogInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	cephfs: {
-	    name: 'CephFS',
-	    ipanel: 'CephFSInputPanel',
-	    faIcon: 'building'
-	},
-	pvecephfs: {
-	    name: 'CephFS (PVE)',
-	    ipanel: 'CephFSInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	rbd: {
-	    name: 'RBD',
-	    ipanel: 'RBDInputPanel',
-	    faIcon: 'building'
-	},
-	pveceph: {
-	    name: 'RBD (PVE)',
-	    ipanel: 'RBDInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	zfs: {
-	    name: 'ZFS over iSCSI',
-	    ipanel: 'ZFSInputPanel',
-	    faIcon: 'building'
-	},
-	zfspool: {
-	    name: 'ZFS',
-	    ipanel: 'ZFSPoolInputPanel',
-	    faIcon: 'folder'
-	},
-	drbd: {
-	    name: 'DRBD',
-	    hideAdd: true
-	}
-    },
-
-    format_storage_type: function(value, md, record) {
-	if (value === 'rbd') {
-	    value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
-	} else if (value === 'cephfs') {
-	    value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
-	}
-
-	var schema = PVE.Utils.storageSchema[value];
-	if (schema) {
-	    return schema.name;
-	}
-	return Proxmox.Utils.unknownText;
-    },
-
-    format_ha: function(value) {
-	var text = Proxmox.Utils.noneText;
-
-	if (value.managed) {
-	    text = value.state || Proxmox.Utils.noneText;
-
-	    text += ', ' +  Proxmox.Utils.groupText + ': ';
-	    text += value.group || Proxmox.Utils.noneText;
-	}
-
-	return text;
-    },
-
-    format_content_types: function(value) {
-	return value.split(',').sort().map(function(ct) {
-	    return PVE.Utils.contentTypes[ct] || ct;
-	}).join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-	var data = record.data;
-	if (Ext.isNumber(data.channel) &&
-	    Ext.isNumber(data.id) &&
-	    Ext.isNumber(data.lun)) {
-	    return "CH " +
-		Ext.String.leftPad(data.channel,2, '0') +
-		" ID " + data.id + " LUN " + data.lun;
-	}
-	return data.volid.replace(/^.*:(.*\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-	return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	if (!(record.data.uptime && Ext.isNumeric(value))) {
-	    return '';
-	}
-
-	var maxcpu = record.data.maxcpu || 1;
-
-	if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-	    return '';
-	}
-
-	var per = value * 100;
-
-	return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-	/*jslint confusion: true */
-
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value);
-    },
-
-    render_bandwidth: function(value) {
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value) + '/s';
-    },
-
-    render_timestamp_human_readable: function(value) {
-	return Ext.Date.format(new Date(value * 1000), 'l d F Y H:i:s');
-    },
-
-    render_duration: function(value) {
-	if (value === undefined) {
-	    return '-';
-	}
-	return PVE.Utils.format_duration_short(value);
-    },
-
-    calculate_mem_usage: function(data) {
-	if (!Ext.isNumeric(data.mem) ||
-	    data.maxmem === 0 ||
-	    data.uptime < 1) {
-	    return -1;
-	}
-
-	return (data.mem / data.maxmem);
-    },
-
-    render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-	if (value > 1 ) {
-	    // we got no percentage but bytes
-	    var mem = value;
-	    var maxmem = record.data.maxmem;
-	    if (!record.data.uptime ||
-		maxmem === 0 ||
-		!Ext.isNumeric(mem)) {
-		return '';
-	    }
-
-	    return ((mem*100)/maxmem).toFixed(1) + " %";
-	}
-	return (value*100).toFixed(1) + " %";
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var mem = value;
-	var maxmem = record.data.maxmem;
-
-	if (!record.data.uptime) {
-	    return '';
-	}
-
-	if (!(Ext.isNumeric(mem) && maxmem)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    calculate_disk_usage: function(data) {
-
-	if (!Ext.isNumeric(data.disk) ||
-	    data.type === 'qemu' ||
-	    (data.type === 'lxc' && data.uptime === 0) ||
-	    data.maxdisk === 0) {
-	    return -1;
-	}
-
-	return (data.disk / data.maxdisk);
-    },
-
-    render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-
-	return (value * 100).toFixed(1) + " %";
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var disk = value;
-	var maxdisk = record.data.maxdisk;
-	var type = record.data.type;
-
-	if (!Ext.isNumeric(disk) ||
-	    type === 'qemu' ||
-	    maxdisk === 0 ||
-	    (type === 'lxc' && record.data.uptime === 0)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    get_object_icon_class: function(type, record) {
-	var status = '';
-	var objType = type;
-
-	if (type === 'type') {
-	    // for folder view
-	    objType = record.groupbyid;
-	} else if (record.template) {
-	    // templates
-	    objType = 'template';
-	    status = type;
-	} else {
-	    // everything else
-	    status = record.status + ' ha-' + record.hastate;
-	}
-
-	var defaults = PVE.tree.ResourceTree.typeDefaults[objType];
-	if (defaults && defaults.iconCls) {
-	    var retVal = defaults.iconCls + ' ' + status;
-	    return retVal;
-	}
-
-	return '';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
-	var fa = '<i class="fa-fw x-grid-icon-custom ' + cls  + '"></i> ';
-	return fa + value;
-    },
-
-    render_support_level: function(value, metaData, record) {
-	return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    /* render functions for new status panel */
-
-    render_usage: function(val) {
-	return (val*100).toFixed(2) + '%';
-    },
-
-    render_cpu_usage: function(val, max) {
-	return Ext.String.format(gettext('{0}% of {1}') +
-	    ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
-    },
-
-    render_size_usage: function(val, max) {
-	if (max === 0) {
-	    return gettext('N/A');
-	}
-	return (val*100/max).toFixed(2) + '% '+ '(' +
-	    Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
-    },
-
-    /* this is different for nodes */
-    render_node_cpu_usage: function(value, record) {
-	return PVE.Utils.render_cpu_usage(value, record.cpus);
-    },
-
-    /* this is different for nodes */
-    render_node_size_usage: function(record) {
-	return PVE.Utils.render_size_usage(record.used, record.total);
-    },
-
-    render_optional_url: function(value) {
-	var match;
-	if (value && (match = value.match(/^https?:\/\//)) !== null) {
-	    return '<a target="_blank" href="' + value + '">' + value + '</a>';
-	}
-	return value;
-    },
-
-    render_san: function(value) {
-	var names = [];
-	if (Ext.isArray(value)) {
-	    value.forEach(function(val) {
-		if (!Ext.isNumber(val)) {
-		    names.push(val);
-		}
-	    });
-	    return names.join('<br>');
-	}
-	return value;
-    },
-
-    render_full_name: function(firstname, metaData, record) {
-	var first = firstname || '';
-	var last = record.data.lastname || '';
-	return Ext.htmlEncode(first + " " + last);
-    },
-
-    render_u2f_error: function(error) {
-	var ErrorNames = {
-	    '1': gettext('Other Error'),
-	    '2': gettext('Bad Request'),
-	    '3': gettext('Configuration Unsupported'),
-	    '4': gettext('Device Ineligible'),
-	    '5': gettext('Timeout')
-	};
-	return "U2F Error: "  + ErrorNames[error] || Proxmox.Utils.unknownText;
-    },
-
-    windowHostname: function() {
-	return window.location.hostname.replace(Proxmox.Utils.IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-
-    openDefaultConsoleWindow: function(consoles, vmtype, vmid, nodename, vmname, cmd) {
-	var dv = PVE.Utils.defaultViewer(consoles);
-	PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname, cmd);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname, cmd) {
-	// kvm, lxc, shell, upgrade
-
-	if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-	    throw "missing vmid";
-	}
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (viewer === 'html5') {
-	    PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'xtermjs') {
-	    Proxmox.Utils.openXtermJsViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'vv') {
-	    var url;
-	    var params = { proxy: PVE.Utils.windowHostname() };
-	    if (vmtype === 'kvm') {
-		url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'lxc') {
-		url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'shell') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'upgrade') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.upgrade = 1;
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'cmd') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.cmd = cmd;
-		PVE.Utils.openSpiceViewer(url, params);
-	    }
-	} else {
-	    throw "unknown viewer type";
-	}
-    },
-
-    defaultViewer: function(consoles) {
-
-	var allowSpice, allowXtermjs;
-
-	if (consoles === true) {
-	    allowSpice = true;
-	    allowXtermjs = true;
-	} else if (typeof consoles === 'object') {
-	    allowSpice = consoles.spice;
-	    allowXtermjs = !!consoles.xtermjs;
-	}
-	var vncdefault = 'html5';
-	var dv = PVE.VersionInfo.console || vncdefault;
-	if ((dv === 'vv' && !allowSpice) || (dv === 'xtermjs' && !allowXtermjs)) {
-	    dv = vncdefault;
-	}
-
-	return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    novnc: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    resize: 'off',
-	    cmd: cmd
-	});
-	var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-	if (nw) {
-	    nw.focus();
-	}
-    },
-
-    openSpiceViewer: function(url, params){
-
-	var downloadWithName = function(uri, name) {
-	    var link = Ext.DomHelper.append(document.body, {
-		tag: 'a',
-		href: uri,
-		css : 'display:none;visibility:hidden;height:0px;'
-	    });
-
-	    // Note: we need to tell android the correct file name extension
-	    // but we do not set 'download' tag for other environments, because
-	    // It can have strange side effects (additional user prompt on firefox)
-	    var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-	    if (andriod) {
-		link.download = name;
-	    }
-
-	    if (link.fireEvent) {
-		link.fireEvent('onclick');
-	    } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-		link.dispatchEvent(evt);
-	    }
-	};
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    params: params,
-	    method: 'POST',
-	    failure: function(response, opts){
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, opts){
-		var raw = "[virt-viewer]\n";
-		Ext.Object.each(response.result.data, function(k, v) {
-		    raw += k + "=" + v + "\n";
-		});
-		var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-		    encodeURIComponent(raw);
-
-		downloadWithName(url, "pve-spice.vv");
-	    }
-	});
-    },
-
-    openTreeConsole: function(tree, record, item, index, e) {
-	e.stopEvent();
-	var nodename = record.data.node;
-	var vmid = record.data.vmid;
-	var vmname = record.data.name;
-	if (record.data.type === 'qemu' && !record.data.template) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var allowSpice = !!response.result.data.spice;
-		    PVE.Utils.openDefaultConsoleWindow(allowSpice, 'kvm', vmid, nodename, vmname);
-		}
-	    });
-	} else if (record.data.type === 'lxc' && !record.data.template) {
-	    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-	}
-    },
-
-    // test automation helper
-    call_menu_handler: function(menu, text) {
-
-	var list = menu.query('menuitem');
-
-	Ext.Array.each(list, function(item) {
-	    if (item.text === text) {
-		if (item.handler) {
-		    item.handler();
-		    return 1;
-		} else {
-		    return undefined;
-		}
-	    }
-	});
-    },
-
-    createCmdMenu: function(v, record, item, index, event) {
-	event.stopEvent();
-	if (!(v instanceof Ext.tree.View)) {
-	    v.select(record);
-	}
-	var menu;
-	var template = !!record.data.template;
-	var type = record.data.type;
-
-	if (template) {
-	    if (type === 'qemu' || type == 'lxc') {
-		menu = Ext.create('PVE.menu.TemplateMenu', {
-		    pveSelNode: record
-		});
-	    }
-	} else if (type === 'qemu' ||
-		   type === 'lxc' ||
-		   type === 'node') {
-	    menu = Ext.create('PVE.' + type + '.CmdMenu', {
-		pveSelNode: record,
-		nodename: record.data.node
-	    });
-	} else {
-	    return;
-	}
-
-	menu.showAt(event.getXY());
-	return menu;
-    },
-
-    // helper for deleting field which are set to there default values
-    delete_if_default: function(values, fieldname, default_val, create) {
-	if (values[fieldname] === '' || values[fieldname] === default_val) {
-	    if (!create) {
-		if (values['delete']) {
-		    values['delete'] += ',' + fieldname;
-		} else {
-		    values['delete'] = fieldname;
-		}
-	    }
-
-	    delete values[fieldname];
-	}
-    },
-
-    loadSSHKeyFromFile: function(file, callback) {
-	// ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-	// a user@host comment, 1420 for 8192 bits; current max is 16kbit
-	// assume: 740*8 for max. 32kbit (5920 byte file)
-	// round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
-	if (file.size > 8192) {
-	    Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
-	    return;
-	}
-	/*global
-	  FileReader
-	*/
-	var reader = new FileReader();
-	reader.onload = function(evt) {
-	    callback(evt.target.result);
-	};
-	reader.readAsText(file);
-    },
-
-    bus_counts: { ide: 4, sata: 6, scsi: 16, virtio: 16 },
-
-    // types is either undefined (all busses), an array of busses, or a single bus
-    forEachBus: function(types, func) {
-	var busses = Object.keys(PVE.Utils.bus_counts);
-	var i, j, count, cont;
-
-	if (Ext.isArray(types)) {
-	    busses = types;
-	} else if (Ext.isDefined(types)) {
-	    busses = [ types ];
-	}
-
-	// check if we only have valid busses
-	for (i = 0; i < busses.length; i++) {
-	    if (!PVE.Utils.bus_counts[busses[i]]) {
-		throw "invalid bus: '" + busses[i] + "'";
-	    }
-	}
-
-	for (i = 0; i < busses.length; i++) {
-	    count = PVE.Utils.bus_counts[busses[i]];
-	    for (j = 0; j < count; j++) {
-		cont = func(busses[i], j);
-		if (!cont && cont !== undefined) {
-		    return;
-		}
-	    }
-	}
-    },
-
-    mp_counts: { mps: 256, unused: 256 },
-
-    forEachMP: function(func, includeUnused) {
-	var i, cont;
-	for (i = 0; i < PVE.Utils.mp_counts.mps; i++) {
-	    cont = func('mp', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-
-	if (!includeUnused) {
-	    return;
-	}
-
-	for (i = 0; i < PVE.Utils.mp_counts.unused; i++) {
-	    cont = func('unused', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-    },
-
-    cleanEmptyObjectKeys: function (obj) {
-	var propName;
-	for (propName in obj) {
-	    if (obj.hasOwnProperty(propName)) {
-		if (obj[propName] === null || obj[propName] === undefined) {
-		    delete obj[propName];
-		}
-	    }
-	}
-    },
-
-    handleStoreErrorOrMask: function(me, store, regex, callback) {
-
-	me.mon(store, 'load', function (proxy, response, success, operation) {
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-	    var msg;
-
-	    if (operation.error.statusText) {
-		if (operation.error.statusText.match(regex)) {
-		    callback(me, operation.error);
-		    return;
-		} else {
-		    msg = operation.error.statusText + ' (' + operation.error.status + ')';
-		}
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    showCephInstallOrMask: function(container, msg, nodename, callback){
-	var regex = new RegExp("not (installed|initialized)", "i");
-	if (msg.match(regex)) {
-	    if (Proxmox.UserName === 'root@pam') {
-		container.el.mask();
-		if (!container.down('pveCephInstallWindow')){
-		    var isInstalled = msg.match(/not initialized/i) ? true : false;
-		    var win = Ext.create('PVE.ceph.Install', {
-			nodename: nodename
-		    });
-		    win.getViewModel().set('isInstalled', isInstalled);
-		    container.add(win);
-		    win.show();
-		    callback(win);
-		}
-	    } else {
-		container.mask(Ext.String.format(gettext('{0} not installed.') +
-		    ' ' + gettext('Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
-	    }
-	    return true;
-	} else {
-	    return false;
-	}
-    }
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-    }
-
-});
-
-// ExtJS related things
-
-Proxmox.Utils.toolkit = 'extjs';
-
-// custom PVE specific VTypes
-Ext.apply(Ext.form.field.VTypes, {
-
-    QemuStartDate: function(v) {
-	return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-    IP64AddressList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == '') {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.IP64_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    IP64AddressListText: gettext('Example') + ': 192.168.1.1,192.168.1.2',
-    IP64AddressListMask: /[A-Fa-f0-9\,\:\.\;\ ]/
-});
-
-Ext.define('PVE.form.field.Display', {
-    override: 'Ext.form.field.Display',
-
-    setSubmitValue: function(value) {
-	// do nothing, this is only to allow generalized  bindings for the:
-	// `me.isCreate ? 'textfield' : 'displayfield'` cases we have.
-    }
-});
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseACME: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-	var errors = false;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; //continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
-		res.domains = match_res[1].split(/[;, ]/);
-	    } else {
-		errors = true;
-		return false;
-	    }
-	});
-
-	if (errors || !res) {
-	    return;
-	}
-
-	return res;
-    },
-
-    parseBoolean: function(value, default_value) {
-	if (!Ext.isDefined(value)) {
-	    return default_value;
-	}
-	value = value.toLowerCase();
-	return value === '1' ||
-	       value === 'on' ||
-	       value === 'yes' ||
-	       value === 'true';
-    },
-
-    parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
-		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	});
-
-	if (error !== undefined) {
-	    console.error(error);
-	    return;
-	}
-
-	return res;
-    },
-
-    printPropertyString: function(data, defaultKey) {
-	var stringparts = [];
-
-	Ext.Object.each(data, function(key, value) {
-	    if (defaultKey !== undefined && key === defaultKey) {
-		stringparts.unshift(value);
-	    } else {
-		stringparts.push(key + '=' + value);
-	    }
-	});
-
-	return stringparts.join(',');
-    },
-
-    parseQemuNetwork: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-		res.model = match_res[1].toLowerCase();
-		if (match_res[3]) {
-		    res.macaddr = match_res[3];
-		}
-	    } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-		res.bridge = match_res[1];
-	    } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-		res.rate = match_res[1];
-	    } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-		res.tag = match_res[1];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		res.firewall = match_res[1];
-	    } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-		res.disconnect = match_res[1];
-	    } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-		res.queues = match_res[1];
-	    } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
-		res.trunks = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors || !res.model) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-	var netstr = net.model;
-	if (net.macaddr) {
-	    netstr += "=" + net.macaddr;
-	}
-	if (net.bridge) {
-	    netstr += ",bridge=" + net.bridge;
-	    if (net.tag) {
-		netstr += ",tag=" + net.tag;
-	    }
-	    if (net.firewall) {
-		netstr += ",firewall=" + net.firewall;
-	    }
-	}
-	if (net.rate) {
-	    netstr += ",rate=" + net.rate;
-	}
-	if (net.queues) {
-	    netstr += ",queues=" + net.queues;
-	}
-	if (net.disconnect) {
-	    netstr += ",link_down=" + net.disconnect;
-	}
-	if (net.trunks) {
-	    netstr += ",trunks=" + net.trunks;
-	}
-	return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var match_res = key.match(/^([a-z]+)(\d+)$/);
-	if (!match_res) {
-	    return;
-	}
-	res['interface'] = match_res[1];
-	res.index = match_res[2];
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    if (k === 'cache' && v === 'off') {
-		v = 'none';
-	    }
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-	var drivestr = drive.file;
-
-	Ext.Object.each(drive, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'index' || key === 'interface') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseIPConfig: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
-		res.ip = match_res[1];
-	    } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
-		res.gw = match_res[1];
-	    } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
-		res.ip6 = match_res[1];
-	    } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
-		res.gw6 = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printIPConfig: function(cfg) {
-	var c = "";
-	var str = "";
-	if (cfg.ip) {
-	    str += "ip=" + cfg.ip;
-	    c = ",";
-	}
-	if (cfg.gw) {
-	    str += c + "gw=" + cfg.gw;
-	    c = ",";
-	}
-	if (cfg.ip6) {
-	    str += c + "ip6=" + cfg.ip6;
-	    c = ",";
-	}
-	if (cfg.gw6) {
-	    str += c + "gw6=" + cfg.gw6;
-	    c = ",";
-	}
-	return str;
-    },
-
-    parseOpenVZNetIf: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(';'), function(item) {
-	    if (!item || item.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var data = {};
-	    Ext.Array.each(item.split(','), function(p) {
-		if (!p || p.match(/^\s*$/)) {
-		    return; // continue
-		}
-		var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-		if (!match_res) {
-		    errors = true;
-		    return false; // break
-		}
-		if (match_res[1] === 'bridge'){
-		    var bridgevlanf = match_res[2];
-		    var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-		    if (!bridge_res) {
-			errors = true;
-			return false; // break
-		    }
-		    data.bridge = bridge_res[1];
-		    data.tag = bridge_res[4];
-		    /*jslint confusion: true*/
-		    data.firewall = bridge_res[5] ? 1 : 0;
-		    /*jslint confusion: false*/
-		} else {
-		    data[match_res[1]] = match_res[2];
-		}
-	    });
-
-	    if (errors || !data.ifname) {
-		errors = true;
-		return false; // break
-	    }
-
-	    data.raw = item;
-
-	    res[data.ifname] = data;
-	});
-
-	return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-	var netarray = [];
-
-	Ext.Object.each(netif, function(iface, data) {
-	    var tmparray = [];
-	    Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-		var value = data[key];
-		if (key === 'bridge'){
-		    if(data.tag){
-			value = value + 'v' + data.tag;
-		    }
-		    if (data.firewall){
-			value = value + 'f';
-		    }
-		}
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-
-	    });
-	    netarray.push(tmparray.join(','));
-	});
-
-	return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var data = {};
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
-	    if (match_res) {
-		data[match_res[1]] = match_res[2];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		data.firewall = PVE.Parser.parseBoolean(match_res[1]);
-	    } else {
-		// todo: simply ignore errors ?
-		return; // continue
-	    }
-	});
-
-	return data;
-    },
-
-    printLxcNetwork: function(data) {
-	var tmparray = [];
-	Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-			'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-		var value = data[key];
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-	});
-
-	/*jslint confusion: true*/
-	if (data.rate > 0) {
-	    tmparray.push('rate=' + data.rate);
-	}
-	/*jslint confusion: false*/
-	return tmparray.join(',');
-    },
-
-    parseLxcMountPoint: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(.+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
-	if (m) {
-	    res.storage = m[1];
-	    res.type = 'volume';
-	} else if (res.file.match(/^\/dev\//)) {
-	    res.type = 'device';
-	} else {
-	    res.type = 'bind';
-	}
-
-	return res;
-    },
-
-    printLxcMountPoint: function(mp) {
-	var drivestr = mp.file;
-
-	Ext.Object.each(mp, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'type' || key === 'storage') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseStartup: function(value) {
-	if (value === undefined) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-		res.order = match_res[2];
-	    } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-		res.up = match_res[1];
-	    } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printStartup: function(startup) {
-	var arr = [];
-	if (startup.order !== undefined && startup.order !== '') {
-	    arr.push('order=' + startup.order);
-	}
-	if (startup.up !== undefined && startup.up !== '') {
-	    arr.push('up=' + startup.up);
-	}
-	if (startup.down !== undefined && startup.down !== '') {
-	    arr.push('down=' + startup.down);
-	}
-
-	return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-	var datastr = '';
-
-	Ext.Object.each(data, function(key, value) {
-	    if (value === '') { return; }
-	    datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-	});
-
-	return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    parseQemuCpu: function(value) {
-	if (!value) {
-	    return {};
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    if (!p.match(/\=/)) {
-		if (Ext.isDefined(res.cpu)) {
-		    errors = true;
-		    return false; // break
-		}
-		res.cputype = p;
-		return; // continue
-	    }
-
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var k = match_res[1];
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    res[k] = match_res[2];
-	});
-
-	if (errors || !res.cputype) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuCpu: function(cpu) {
-	var cpustr = cpu.cputype;
-	var optstr = '';
-
-	Ext.Object.each(cpu, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'cputype') {
-		return; // continue
-	    }
-	    optstr += ',' + key + '=' + value;
-	});
-
-	if (!cpustr) {
-	    if (optstr) {
-		return 'kvm64' + optstr;
-	    }
-	    return;
-	}
-
-	return cpustr + optstr;
-    },
-
-    parseSSHKey: function(key) {
-	//                |--- options can have quotes--|     type    key        comment
-	var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
-	var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
-
-	var m = key.match(keyre);
-	if (!m) {
-	    return null;
-	}
-	if (m.length < 3 || !m[2]) { // [2] is always either type or key
-	    return null;
-	}
-	if (m[1] && m[1].match(typere)) {
-	    return {
-		type: m[1],
-		key: m[2],
-		comment: m[3]
-	    };
-	}
-	if (m[2].match(typere)) {
-	    return {
-		options: m[1],
-		type: m[2],
-		key: m[3],
-		comment: m[4]
-	    };
-	}
-	return null;
-    }
-}});
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-	var me = this;
-
-	var changes = false;
-	var oldtext = Ext.encode(me.UIState[name]);
-	var newtext = Ext.encode(newvalue);
-	if (newtext != oldtext) {
-	    changes = true;
-	    me.UIState[name] = newvalue;
-	    //console.log("changed old " + name + " " + oldtext);
-	    //console.log("changed new " + name + " " + newtext);
-	    if (fireEvents) {
-		me.fireEvent("statechange", me, name, { value: newvalue });
-	    }
-	}
-	return changes;
-    },
-
-    // private
-    hslist: [
-	// order is important for notifications
-	// [ name, default ]
-	['view', 'server'],
-	['rid', 'root'],
-	['ltab', 'tasks'],
-	['nodetab', ''],
-	['storagetab', ''],
-	['pooltab', ''],
-	['kvmtab', ''],
-	['lxctab', ''],
-	['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-	cloudinit: 52,
-	replication: 51,
-	system: 50,
-	monitor: 49,
-	'ha-fencing': 48,
-	'ha-groups': 47,
-	'ha-resources': 46,
-	'ceph-log': 45,
-	'ceph-crushmap':44,
-	'ceph-pools': 43,
-	'ceph-osdtree': 42,
-	'ceph-disklist': 41,
-	'ceph-monlist': 40,
-	'ceph-config': 39,
-	ceph: 38,
-	'firewall-fwlog': 37,
-	'firewall-options': 36,
-	'firewall-ipset': 35,
-	'firewall-aliases': 34,
-	'firewall-sg': 33,
-	firewall: 32,
-	apt: 31,
-	members: 30,
-	snapshot: 29,
-	ha: 28,
-	support: 27,
-	pools: 26,
-	syslog: 25,
-	ubc: 24,
-	initlog: 23,
-	openvz: 22,
-	backup: 21,
-	resources: 20,
-	content: 19,
-	root: 18,
-	domains: 17,
-	roles: 16,
-	groups: 15,
-	users: 14,
-	time: 13,
-	dns: 12,
-	network: 11,
-	services: 10,
-	options: 9,
-	console: 8,
-	hardware: 7,
-	permissions: 6,
-	summary: 5,
-	tasks: 4,
-	clog: 3,
-	storage: 2,
-	folder: 1,
-	server: 0
-    },
-
-    decodeHToken: function(token) {
-	var me = this;
-
-	var state = {};
-	if (!token) {
-	    Ext.Array.each(me.hslist, function(rec) {
-		state[rec[0]] = rec[1];
-	    });
-	    return state;
-	}
-
-	// return Ext.urlDecode(token);
-
-	var items = token.split(':');
-	var prefix = items.shift();
-
-	if (prefix != me.hprefix) {
-	    return me.decodeHToken();
-	}
-
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = items.shift();
-	    if (value) {
-		if (value[0] === '=') {
-		    value = decodeURIComponent(value.slice(1));
-		} else {
-		    Ext.Object.each(me.compDict, function(key, cv) {
-			if (value == cv) {
-			    value = key;
-			    return false;
-			}
-		    });
-		}
-	    }
-	    state[rec[0]] = value;
-	});
-
-	return state;
-    },
-
-    encodeHToken: function(state) {
-	var me = this;
-
-	// return Ext.urlEncode(state);
-
-	var ctoken = me.hprefix;
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = state[rec[0]];
-	    if (!Ext.isDefined(value)) {
-		value = rec[1];
-	    }
-	    value = encodeURIComponent(value);
-	    if (!value) {
-		ctoken += ':';
-	    } else {
-		var comp = me.compDict[value];
-		if (Ext.isDefined(comp)) {
-		    ctoken += ":" + comp;
-		} else {
-		    ctoken += ":=" + value;
-		}
-	    }
-	});
-
-	return ctoken;
-    },
-
-    constructor: function(config){
-	var me = this;
-
-	me.callParent([config]);
-
-	me.UIState = me.decodeHToken(); // set default
-
-	var history_change_cb = function(token) {
-	    //console.log("HC " + token);
-	    if (!token) {
-		var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-		if (res){
-		    // process text value and close...
-		    Ext.History.back();
-		} else {
-		    Ext.History.forward();
-		}
-		return;
-	    }
-
-	    var newstate = me.decodeHToken(token);
-	    Ext.Array.each(me.hslist, function(rec) {
-		if (typeof newstate[rec[0]] == "undefined") {
-		    return;
-		}
-		me.setHV(rec[0], newstate[rec[0]], true);
-	    });
-	};
-
-	var start_token = Ext.History.getToken();
-	if (start_token) {
-	    history_change_cb(start_token);
-	} else {
-	    var htext = me.encodeHToken(me.UIState);
-	    Ext.History.add(htext);
-	}
-
-	Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-	/*jslint confusion: true */
-	var me = this;
-	var data;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    data = { value: me.UIState[name] };
-	} else {
-	    data = me.callParent(arguments);
-	    if (!data && name === 'GuiCap') {
-		data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-	    }
-	}
-
-	//console.log("GET " + name + " " + Ext.encode(data));
-	return data;
-    },
-
-    clear: function(name){
-	var me = this;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    me.UIState[name] = null;
-	}
-
-	me.callParent(arguments);
-    },
-
-    set: function(name, value){
-        var me = this;
-
-	//console.log("SET " + name + " " + Ext.encode(value));
-	if (typeof me.UIState[name] != "undefined") {
-	    var newvalue = value ? value.value : null;
-	    if (me.setHV(name, newvalue, false)) {
-		var htext = me.encodeHToken(me.UIState);
-		Ext.History.add(htext);
-	    }
-	} else {
-	    me.callParent(arguments);
-	}
-    }
-});
-Ext.define('PVE.menu.Item', {
-    extend: 'Ext.menu.Item',
-    alias: 'widget.pveMenuItem',
-
-    // set to wrap the handler callback in a confirm dialog  showing this text
-    confirmMsg: false,
-
-    // set to focus 'No' instead of 'Yes' button and show a warning symbol
-    dangerous: false,
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.handler) {
-	    me.setHandler(me.handler, me.scope);
-	}
-
-	me.callParent();
-    },
-
-    setHandler: function(fn, scope) {
-	var me = this;
-	me.scope = scope;
-	me.handler = function(button, e) {
-	    var rec, msg;
-	    if (me.confirmMsg) {
-		msg = me.confirmMsg;
-		Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: msg,
-		    buttons: Ext.Msg.YESNO,
-		    defaultFocus: me.dangerous ? 'no' : 'yes',
-		    callback: function(btn) {
-			if (btn === 'yes') {
-			    Ext.callback(fn, me.scope, [me, e], 0, me);
-			}
-		    }
-		});
-	    } else {
-		Ext.callback(fn, me.scope, [me, e], 0, me);
-	    }
-	};
-    }
-});
-Ext.define('PVE.menu.TemplateMenu', {
-    extend: 'Ext.menu.Menu',
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var guestType = me.pveSelNode.data.type;
-	if (guestType !== 'qemu' && guestType != 'lxc') {
-	    throw "invalid guest type";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var template = me.pveSelNode.data.template;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	me.title = (guestType === 'qemu' ? 'VM ' : 'CT ') + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: guestType,
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: template
-		    });
-		    win.show();
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade', 'cmd'
-
-    cmd: undefined,
-
-    consoleName: undefined,
-
-    iconCls: 'fa fa-terminal',
-
-    enableSpice: true,
-    enableXtermjs: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    text: gettext('Console'),
-
-    setEnableSpice: function(enable){
-	var me = this;
-
-	me.enableSpice = enable;
-	me.down('#spicemenu').setDisabled(!enable);
-    },
-
-    setEnableXtermJS: function(enable){
-	var me = this;
-
-	me.enableXtermjs = enable;
-	me.down('#xtermjs').setDisabled(!enable);
-    },
-
-    handler: function() {
-	var me = this;
-	var consoles = {
-	    spice: me.enableSpice,
-	    xtermjs: me.enableXtermjs
-	};
-	PVE.Utils.openDefaultConsoleWindow(consoles, me.consoleType, me.vmid,
-					   me.nodename, me.consoleName, me.cmd);
-    },
-
-    menu: [
-	{
-	    xtype:'menuitem',
-	    text: 'noVNC',
-	    iconCls: 'pve-itype-icon-novnc',
-	    type: 'html5',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    xterm: 'menuitem',
-	    itemId: 'spicemenu',
-	    text: 'SPICE',
-	    type: 'vv',
-	    iconCls: 'pve-itype-icon-virt-viewer',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    text: 'xterm.js',
-	    itemId: 'xtermjs',
-	    iconCls: 'pve-itype-icon-xtermjs',
-	    type: 'xtermjs',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- *
- *   does this for the button and every menu item
- */
-Ext.define('PVE.button.Split', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveSplitButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    handlerWrapper: function(button, event) {
-	var me = this;
-	var rec, msg;
-	if (me.selModel) {
-	    rec = me.selModel.getSelection()[0];
-	    if (!rec || (me.enableFn(rec) === false)) {
-		return;
-	    }
-	}
-
-	if (me.confirmMsg) {
-	    msg = me.confirmMsg;
-	    // confirMsg can be boolean or function
-	    /*jslint confusion: true*/
-	    if (Ext.isFunction(me.confirmMsg)) {
-		msg = me.confirmMsg(rec);
-	    }
-	    /*jslint confusion: false*/
-	    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-	    Ext.Msg.show({
-		title: gettext('Confirm'),
-		icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		msg: msg,
-		buttons: Ext.Msg.YESNO,
-		callback: function(btn) {
-		    if (btn !== 'yes') {
-			return;
-		    }
-		    me.realHandler(button, event, rec);
-		}
-	    });
-	} else {
-	    me.realHandler(button, event, rec);
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-	    me.realHandler = me.handler;
-	    me.handler = me.handlerWrapper;
-	}
-
-	if (me.menu && me.menu.items) {
-	    me.menu.items.forEach(function(item) {
-		if (item.handler) {
-		    item.realHandler = item.handler;
-		    item.handler = me.handlerWrapper;
-		}
-
-		if (item.selModel) {
-		    me.mon(item.selModel, "selectionchange", function() {
-			var rec = item.selModel.getSelection()[0];
-			if (!rec || (item.enableFn(rec) === false )) {
-			    item.setDisabled(true);
-			} else {
-			    item.setDisabled(false);
-			}
-		    });
-		}
-	    });
-	}
-
-	me.callParent();
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.controller.StorageEdit', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.storageEdit',
-    control: {
-	'field[name=content]': {
-	    change: function(field, value) {
-		var hasBackups = Ext.Array.contains(value, 'backup');
-		var maxfiles = this.lookupReference('maxfiles');
-		if (!maxfiles) {
-		    return;
-		}
-
-		if (!hasBackups) {
-		// clear values which will never be submitted
-		    maxfiles.reset();
-		}
-		maxfiles.setDisabled(!hasBackups);
-	    }
-	}
-    }
-});
-Ext.define('PVE.qemu.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'suspended':
-		stopped = false;
-		suspended = true;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = "VM " + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: running || suspended,
-		disabled: running || suspended,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-	    {
-		text: gettext('Pause'),
-		iconCls: 'fa fa-fw fa-pause',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmpause', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Hibernate'),
-		iconCls: 'fa fa-fw fa-download',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		tooltip: gettext('Suspend to disk'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmsuspend', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend', { todisk: 1 });
-		    });
-		}
-	    },
-	    {
-		text: gettext('Resume'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: !suspended,
-		handler: function() {
-		    vm_command('resume');
-		}
-	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'qemu',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'qemu');
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		hidden: !caps.vms['VM.Allocate'],
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmtemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			     url: '/nodes/' + nodename + '/qemu/' + vmid + '/template',
-			     method: 'POST',
-			     failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			     }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    Proxmox.Utils.API2Request({
-			url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-			failure: function(response, opts) {
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, opts) {
-			    var allowSpice = response.result.data.spice;
-			    var allowXtermjs = response.result.data.serial;
-			    var consoles = {
-				spice: allowSpice,
-				xtermjs: allowXtermjs
-			    };
-			    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-			}
-		    });
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no CT ID specified";
-	}
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/lxc/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = 'CT ' + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		disabled: running,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-//	    {
-//		text: gettext('Suspend'),
-//		iconCls: 'fa fa-fw fa-pause',
-//		hidde: suspended,
-//		disabled: stopped || suspended,
-//		handler: function() {
-//		    var msg = Proxmox.Utils.format_task_description('vzsuspend', vmid);
-//		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-//			if (btn !== 'yes') {
-//			    return;
-//			}
-//
-//			vm_command('suspend');
-//		    });
-//		}
-//	    },
-//	    {
-//		text: gettext('Resume'),
-//		iconCls: 'fa fa-fw fa-play',
-//		hidden: !suspended,
-//		handler: function() {
-//		    vm_command('resume');
-//		}
-//	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: standalone || !caps.vms['VM.Migrate']
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'lxc');
-		}
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'lxc',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vztemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/lxc/' + vmid + '/template',
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-    xtype: 'nodeCmdMenu',
-
-    showSeparator: false,
-
-    items: [
-	{
-	    text: gettext('Create VM'),
-	    itemId: 'createvm',
-	    iconCls: 'fa fa-desktop',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{
-	    text: gettext('Create CT'),
-	    itemId: 'createct',
-	    iconCls: 'fa fa-cube',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Bulk Start'),
-	    itemId: 'bulkstart',
-	    iconCls: 'fa fa-fw fa-play',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Start'),
-		    btnText: gettext('Start'),
-		    action: 'startall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Stop'),
-	    itemId: 'bulkstop',
-	    iconCls: 'fa fa-fw fa-stop',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Stop'),
-		    btnText: gettext('Stop'),
-		    action: 'stopall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Migrate'),
-	    itemId: 'bulkmigrate',
-	    iconCls: 'fa fa-fw fa-send-o',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Migrate'),
-		    btnText: gettext('Migrate'),
-		    action: 'migrateall'
-		});
-		win.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Shell'),
-	    itemId: 'shell',
-	    iconCls: 'fa fa-fw fa-terminal',
-	    handler: function() {
-		var me = this.up('menu');
-		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, me.nodename, undefined);
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Wake-on-LAN'),
-	    itemId: 'wakeonlan',
-	    iconCls: 'fa fa-fw fa-power-off',
-	    handler: function() {
-		var me = this.up('menu');
-		Proxmox.Utils.API2Request({
-		    param: {},
-		    url: '/nodes/' + me.nodename + '/wakeonlan',
-		    method: 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, opts) {
-			Ext.Msg.show({
-			    title: 'Success',
-			    icon: Ext.Msg.INFO,
-			    msg: Ext.String.format(gettext("Wake on LAN packet send for '{0}': '{1}'"), me.nodename, response.result.data)
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no nodename specified';
-	}
-
-	me.title = gettext('Node') + " '" + me.nodename + "'";
-	me.callParent();
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	// disable not allowed options
-	if (!caps.vms['VM.Allocate']) {
-	    me.getComponent('createct').setDisabled(true);
-	    me.getComponent('createvm').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.PowerMgmt']) {
-	    me.getComponent('bulkstart').setDisabled(true);
-	    me.getComponent('bulkstop').setDisabled(true);
-	    me.getComponent('bulkmigrate').setDisabled(true);
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.Console']) {
-	    me.getComponent('shell').setDisabled(true);
-	}
-
-	if (me.pveSelNode.data.running) {
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-    }
-});
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-
-    vmid: undefined,
-
-    cmd: undefined,
-
-    consoleType: undefined, // lxc, kvm, shell, cmd
-
-    layout: 'fit',
-
-    xtermjs: false,
-
-    border: false,
-
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.consoleType) {
-	    throw "no console type specified";
-	}
-
-	if (!me.vmid && me.consoleType !== 'shell' && me.consoleType !== 'cmd') {
-	    throw "no VM ID specified";
-	}
-
-	// always use same iframe, to avoid running several noVnc clients
-	// at same time (to avoid performance problems)
-	var box = Ext.create('Ext.ux.IFrame', { itemid : "vncconsole" });
-
-	var type = me.xtermjs ? 'xtermjs' : 'novnc';
-	Ext.apply(me, {
-	    items: box,
-	    listeners: {
-		activate: function() {
-		    var queryDict = {
-			console: me.consoleType, // kvm, lxc, upgrade or shell
-			vmid: me.vmid,
-			node: me.nodename,
-			cmd: me.cmd,
-			resize: 'scale'
-		    };
-		    queryDict[type] = 1;
-		    PVE.Utils.cleanEmptyObjectKeys(queryDict);
-		    var url = '/?' + Ext.Object.toQueryString(queryDict);
-		    box.load(url);
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.on('afterrender', function() {
-	    me.focus();
-	});
-    }
-});
-
-Ext.define('PVE.data.PermPathStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.pvePermPath',
-    fields: [ 'value' ],
-    autoLoad: false,
-    data: [
-	{'value':  '/'},
-	{'value':  '/access'},
-	{'value': '/nodes'},
-	{'value': '/pool'},
-	{'value': '/storage'},
-	{'value': '/vms'}
-    ],
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	me.callParent([config]);
-
-	me.suspendEvents();
-	PVE.data.ResourceStore.each(function(record) {
-	    switch (record.get('type')) {
-		case 'node':
-		    me.add({value: '/nodes/' + record.get('text')});
-		    break;
-
-		case 'qemu':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'lxc':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'storage':
-		    me.add({value: '/storage/' + record.get('storage')});
-		    break;
-		case 'pool':
-		    me.add({value: '/pool/' + record.get('pool')});
-		    break;
-	    }
-	});
-	me.resumeEvents();
-
-	me.fireEvent('refresh', me);
-	me.fireEvent('datachanged', me);
-
-	me.sort({
-	    property: 'value',
-	    direction: 'ASC'
-	});
-    }
-});
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-	var me = this, i;
-
-	return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-
-    // returns the cached data from all nodes
-    getNodes: function() {
-	var me = this;
-
-	var nodes = [];
-	me.each(function(record) {
-	    if (record.get('type') == "node") {
-		nodes.push( record.getData() );
-	    }
-	});
-
-	return nodes;
-    },
-
-    storageIsShared: function(storage_path) {
-	var me = this;
-
-	var index = me.findExact('id', storage_path);
-
-	return me.getAt(index).data.shared;
-    },
-
-    guestNode: function(vmid) {
-	var me = this;
-
-	var index = me.findExact('vmid', parseInt(vmid, 10));
-
-	return me.getAt(index).data.node;
-    },
-
-    constructor: function(config) {
-	// fixme: how to avoid those warnings
-	/*jslint confusion: true */
-
-	var me = this;
-
-	config = config || {};
-
-	var field_defaults = {
-	    type: {
-		header: gettext('Type'),
-		type: 'string',
-		renderer: PVE.Utils.render_resource_type,
-		sortable: true,
-		hideable: false,
-		width: 100
-	    },
-	    id: {
-		header: 'ID',
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    running: {
-		header: gettext('Online'),
-		type: 'boolean',
-		renderer: Proxmox.Utils.format_boolean,
-		hidden: true,
-		convert: function(value, record) {
-		    var info = record.data;
-		    return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-		}
-	    },
-	    text: {
-		header: gettext('Description'),
-		type: 'string',
-		sortable: true,
-		width: 200,
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-
-		    if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
-			text = String(info.vmid);
-			if (info.name) {
-			    text += " (" + info.name + ')';
-			}
-		    } else { // node, pool, storage
-			text = info[info.type] || info.id;
-			if (info.node && info.type !== 'node') {
-			    text += " (" + info.node + ")";
-			}
-		    }
-
-		    return text;
-		}
-	    },
-	    vmid: {
-		header: 'VMID',
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    name: {
-		header: gettext('Name'),
-		hidden: true,
-		sortable: true,
-		type: 'string'
-	    },
-	    disk: {
-		header: gettext('Disk usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_disk_usage,
-		sortable: true,
-		width: 100,
-		hidden: true
-	    },
-	    diskuse: {
-		header: gettext('Disk usage') + " %",
-		type: 'number',
-		sortable: true,
-		renderer: PVE.Utils.render_disk_usage_percent,
-		width: 100,
-		calculate: PVE.Utils.calculate_disk_usage,
-		sortType: 'asFloat'
-	    },
-	    maxdisk: {
-		header: gettext('Disk size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    mem: {
-		header: gettext('Memory usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_mem_usage,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    memuse: {
-		header: gettext('Memory usage') + " %",
-		type: 'number',
-		renderer: PVE.Utils.render_mem_usage_percent,
-		calculate: PVE.Utils.calculate_mem_usage,
-		sortType: 'asFloat',
-		sortable: true,
-		width: 100
-	    },
-	    maxmem: {
-		header: gettext('Memory size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		hidden: true,
-		sortable: true,
-		width: 100
-	    },
-	    cpu: {
-		header: gettext('CPU usage'),
-		type: 'float',
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100
-	    },
-	    maxcpu: {
-		header: gettext('maxcpu'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    diskread: {
-		header: gettext('Total Disk Read'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    diskwrite: {
-		header: gettext('Total Disk Write'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netin: {
-		header: gettext('Total NetIn'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netout: {
-		header: gettext('Total NetOut'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    template: {
-		header: gettext('Template'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    uptime: {
-		header: gettext('Uptime'),
-		type: 'integer',
-		renderer: Proxmox.Utils.render_uptime,
-		sortable: true,
-		width: 110
-	    },
-	    node: {
-		header: gettext('Node'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    storage: {
-		header: gettext('Storage'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    pool: {
-		header: gettext('Pool'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    hastate: {
-		header: gettext('HA State'),
-		type: 'string',
-		defaultValue: 'unmanaged',
-		hidden: true,
-		sortable: true
-	    },
-	    status: {
-		header: gettext('Status'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    }
-	};
-
-	var fields = [];
-	var fieldNames = [];
-	Ext.Object.each(field_defaults, function(key, value) {
-	    var field = {name: key, type: value.type};
-	    if (Ext.isDefined(value.convert)) {
-		field.convert = value.convert;
-	    }
-
-	    if (Ext.isDefined(value.calculate)) {
-		field.calculate = value.calculate;
-	    }
-
-	    if (Ext.isDefined(value.defaultValue)) {
-		field.defaultValue = value.defaultValue;
-	    }
-
-	    fields.push(field);
-	    fieldNames.push(key);
-	});
-
-	Ext.define('PVEResources', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/resources'
-	    }
-	});
-
-	Ext.define('PVETree', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: { type: 'memory' }
-	});
-
-	Ext.apply(config, {
-	    storeid: 'PVEResources',
-	    model: 'PVEResources',
-	    defaultColumns: function() {
-		var res = [];
-		Ext.Object.each(field_defaults, function(field, info) {
-		    var fi = Ext.apply({ dataIndex: field }, info);
-		    res.push(fi);
-		});
-		return res;
-	    },
-	    fieldNames: fieldNames
-	});
-
-	me.callParent([config]);
-    }
-});
-Ext.define('pve-domains', {
-    extend: "Ext.data.Model",
-    fields: [
-	'realm', 'type', 'comment', 'default', 'tfa',
-	{
-	    name: 'descr',
-	    // Note: We use this in the RealmComboBox.js (see Bug #125)
-	    convert: function(value, record) {
-		if (value) {
-		    return value;
-		}
-
-		var info = record.data;
-		// return realm if there is no comment
-		var text = info.comment || info.realm;
-
-		if (info.tfa) {
-		    text += " (+ " + info.tfa + ")";
-		}
-
-		return Ext.String.htmlEncode(text);
-	    }
-	}
-    ],
-    idProperty: 'realm',
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/domains"
-    }
-});
-Ext.define('pve-rrd-node', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	{
-	    name:'iowait',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'loadavg',
-	'maxcpu',
-	'memtotal',
-	'memused',
-	'netin',
-	'netout',
-	'roottotal',
-	'rootused',
-	'swaptotal',
-	'swapused',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-guest', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'maxcpu',
-	'netin',
-	'netout',
-	'mem',
-	'maxmem',
-	'disk',
-	'maxdisk',
-	'diskread',
-	'diskwrite',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-storage', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'used',
-	'total',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    minValue: 1,
-	    maxValue: 4094
-	});
-
-	me.callParent();
-    }
-});
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-    comboItems: [
-	['__default__', gettext('Default')],
-	[1, gettext('Yes')],
-	[0, gettext('No')]
-    ]
-});
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['0', Proxmox.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-    valueField: 'poolid',
-    displayField: 'poolid',
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: 'poolid'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    autoSelect: false,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Pool'),
-			sortable: true,
-			dataIndex: 'poolid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-	extend: 'Ext.data.Model',
-	fields: [ 'poolid', 'comment' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/pools"
-	},
-	idProperty: 'poolid'
-    });
-
-});
-Ext.define('PVE.form.PrivilegesSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'pvePrivilegesSelector',
-
-    multiSelect: true,
-
-    initComponent: function() {
-	var me = this;
-
-	// So me.store is available.
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/roles/Administrator',
-	    method: 'GET',
-	    success: function(response, options) {
-		var data = [], key;
-		/*jslint forin: true */
-		for (key in response.result.data) {
-		    data.push([key, key]);
-		}
-		/*jslint forin: false */
-
-		me.store.setData(data);
-
-		me.store.sort({
-		    property: 'key',
-		    direction: 'ASC'
-		});
-	    },
-
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-Ext.define('pve-groups', {
-    extend: 'Ext.data.Model',
-    fields: [ 'groupid', 'comment' ],
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/groups"
-    },
-    idProperty: 'groupid'
-});
-
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveGroupSelector',
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'groupid',
-    displayField: 'groupid',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		sortable: true,
-		dataIndex: 'groupid',
-		flex: 1
-	    },
-	    {
-		header: gettext('Comment'),
-		sortable: false,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: [{
-		property: 'groupid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-Ext.define('PVE.form.UserSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'userid',
-    displayField: 'userid',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-users',
-	    sorters: [{
-		property: 'userid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('User'),
-			sortable: true,
-			dataIndex: 'userid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Name'),
-			sortable: true,
-			renderer: PVE.Utils.render_full_name,
-			dataIndex: 'firstname',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'userid', 'firstname', 'lastname' , 'email', 'comment',
-	    { type: 'boolean', name: 'enable' },
-	    { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/users"
-	},
-	idProperty: 'userid'
-    });
-
-});
-
-
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'roleid',
-    displayField: 'roleid',
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: [{
-		property: 'roleid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Role'),
-			sortable: true,
-			dataIndex: 'roleid',
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-	extend: 'Ext.data.Model',
-	fields: [ 'roleid', 'privs' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/roles"
-	},
-	idProperty: 'roleid'
-    });
-
-});
-Ext.define('PVE.form.GuestIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveGuestIDSelector',
-
-    allowBlank: false,
-
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeID: false,
-
-    guestType: undefined,
-
-    validator: function(value) {
-	var me = this;
-
-	if (!Ext.isNumeric(value) ||
-	    value < me.minValue ||
-	    value > me.maxValue) {
-	    // check is done by ExtJS
-	    return true;
-	}
-
-	if (me.validateExists === true && !me.exists) {
-	    return me.unknownID;
-	}
-
-	if (me.validateExists === false && me.exists) {
-	    return me.inUseID;
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var label = '{0} ID';
-	var unknownID = gettext('This {0} ID does not exists');
-	var inUseID = gettext('This {0} ID is already in use');
-	var type = 'CT/VM';
-
-	if (me.guestType === 'lxc') {
-	    type = 'CT';
-	} else if (me.guestType === 'qemu') {
-	    type = 'VM';
-	}
-
-	me.label = Ext.String.format(label, type);
-	me.unknownID = Ext.String.format(unknownID, type);
-	me.inUseID = Ext.String.format(inUseID, type);
-
-	Ext.apply(me, {
-	    fieldLabel: me.label,
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    if (!Ext.isDefined(me.validateExists)) {
-			return;
-		    }
-		    Proxmox.Utils.API2Request({
-			params: { vmid: newValue },
-			url: '/cluster/nextid',
-			method: 'GET',
-			success: function(response, opts) {
-			    me.exists = false;
-			    me.validate();
-			},
-			failure: function(response, opts) {
-			    me.exists = true;
-			    me.validate();
-			}
-		    });
-		}
-	    }
-	});
-
-        me.callParent();
-
-	if (me.loadNextFreeID) {
-	    Proxmox.Utils.API2Request({
-		url: '/cluster/nextid',
-		method: 'GET',
-		success: function(response, opts) {
-		    me.setRawValue(response.result.data);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    allowDecimals: false,
-
-    allowExponential: false,
-
-    computeUpDown: function(value) {
-	var me = this;
-
-	if (!me.hotplug) {
-	    return { up: value + me.step, down: value - me.step };
-	}
-	
-	var dimm_size = 512;
-	var prev_dimm_size = 0;
-	var min_size = 1024;
-	var current_size = min_size;
-	var value_up = min_size;
-	var value_down = min_size;
-	var value_start = min_size;
-
-	var i, j;
-	for (j = 0; j < 9; j++) {
-	    for (i = 0; i < 32; i++) {
-		if ((value >= current_size) && (value < (current_size + dimm_size))) {
-		    value_start = current_size;
-		    value_up = current_size + dimm_size;
-		    value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-		}
-		current_size += dimm_size;				
-	    }
-	    prev_dimm_size = dimm_size;
-	    dimm_size = dimm_size*2;
-	}
-
-	return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-	}
-    },
-
-    onSpinDown: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.hotplug) {
-	    me.minValue = 1024;
-
-	    me.on('blur', function(field) {
-		var value = me.getValue();
-		var res = me.computeUpDown(value);
-		if (value === res.start || value === res.up || value === res.down) {
-		    return;
-		}
-		field.setValue(res.up);
-	    });
-	}
-
-        me.callParent();
-    }
-});
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveNetworkCardSelector',
-    comboItems: [
-	['e1000', 'Intel E1000'],
-	['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-	['rtl8139', 'Realtek RTL8139'],
-	['vmxnet3', 'VMware vmxnet3']
-    ]
-});
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveDiskFormatSelector',
-    comboItems:  [
-	['raw', gettext('Raw disk image') + ' (raw)'],
-	['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-	['vmdk', gettext('VMware image format') + ' (vmdk)']
-    ]
-});
-Ext.define('PVE.form.DiskSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveDiskSelector',
-
-    // can be
-    // undefined: all
-    // unused: only unused
-    // journal_disk: all disks with gpt
-    diskType: undefined,
-
-    valueField: 'devpath',
-    displayField: 'devpath',
-    emptyText: gettext('No Disks unused'),
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Device'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'devpath'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 60,
-		sortable: false,
-		renderer: Proxmox.Utils.format_size,
-		dataIndex: 'size'
-	    },
-	    {
-		header: gettext('Serial'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'serial'
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    filterOnLoad: true,
-	    model: 'pve-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list",
-		extraParams: { type: me.diskType }
-	    },
-	    sorters: [
-		{
-		    property : 'devpath',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-}, function() {
-
-    Ext.define('pve-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial'],
-	idProperty: 'devpath'
-    });
-});
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveBusSelector',
-  
-    noVirtIO: false,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [['ide', 'IDE'], ['sata', 'SATA']];
-
-	if (!me.noVirtIO) {
-	    me.comboItems.push(['virtio', 'VirtIO Block']);
-	}
-
-	me.comboItems.push(['scsi', 'SCSI']);
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveControllerSelector',
-   
-    statics: {
-	maxIds: {
-	    ide: 3,
-	    sata: 5,
-	    virtio: 15,
-	    scsi: 13
-	}
-    },
-
-    noVirtIO: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    sortByPreviousUsage: function(vmconfig, controllerList) {
-
-	var usedControllers = Ext.clone(PVE.form.ControllerSelector.maxIds);
-
-	var type;
-	for (type in usedControllers) {
-	    if(usedControllers.hasOwnProperty(type)) {
-		usedControllers[type] = 0;
-	    }
-	}
-
-	var property;
-	for (property in vmconfig) {
-	    if (vmconfig.hasOwnProperty(property)) {
-		if (property.match(PVE.Utils.bus_match) && !vmconfig[property].match(/media=cdrom/)) {
-		    var foundController = property.match(PVE.Utils.bus_match)[1];
-		    usedControllers[foundController]++;
-		}
-	    }
-	}
-
-	var vmDefaults = PVE.qemu.OSDefaults[vmconfig.ostype];
-
-	var sortPriority = vmDefaults && vmDefaults.busPriority
-	    ? vmDefaults.busPriority : PVE.qemu.OSDefaults.generic;
-
-	var sortedList = Ext.clone(controllerList);
-	sortedList.sort(function(a,b) {
-	    if (usedControllers[b] == usedControllers[a]) {
-		return sortPriority[b] - sortPriority[a];
-	    }
-	    return usedControllers[b] - usedControllers[a];
-	});
-	
-	return sortedList;
-    },
-
-    setVMConfig: function(vmconfig, autoSelect) {
-	var me = this;
-
-	me.vmconfig = Ext.apply({}, vmconfig);
-
-	var clist = ['ide', 'virtio', 'scsi', 'sata'];
-	var bussel = me.down('field[name=controller]');
-	var deviceid = me.down('field[name=deviceid]');
-
-	if (autoSelect === 'cdrom') {
-	    clist = ['ide', 'scsi', 'sata'];
-	    if (!Ext.isDefined(me.vmconfig.ide2)) {
-		bussel.setValue('ide');
-		deviceid.setValue(2);
-		return;
-	    }
-	} else  {
-	    // in most cases we want to add a disk to the same controller
-	    // we previously used
-	    clist = me.sortByPreviousUsage(me.vmconfig, clist);
-	}
-
-	Ext.Array.each(clist, function(controller) {
-	    var confid, i;
-	    bussel.setValue(controller);
-	    for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
-		confid = controller + i.toString();
-		if (!Ext.isDefined(me.vmconfig[confid])) {
-		    deviceid.setValue(i);
-		    return false; // break
-		}
-	    }
-	});
-	deviceid.validate();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    fieldLabel: gettext('Bus/Device'),
-	    layout: 'hbox',
-	    defaults: {
-                hideLabel: true
-	    },
-	    items: [
-		{
-		    xtype: 'pveBusSelector',
-		    name: 'controller',
-		    value: PVE.qemu.OSDefaults.generic.busType,
-		    noVirtIO: me.noVirtIO,
-		    allowBlank: false,
-		    flex: 2,
-		    listeners: {
-			change: function(t, value) {
-			    if (!value) {
-				return;
-			    }
-			    var field = me.down('field[name=deviceid]');
-			    field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
-			    field.validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'deviceid',
-		    minValue: 0,
-		    maxValue: PVE.form.ControllerSelector.maxIds.ide,
-		    value: '0',
-		    flex: 1,
-		    allowBlank: false,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.rendered) {
-			    return;
-			}
-			var field = me.down('field[name=controller]');
-			var controller = field.getValue();
-			var confid = controller + value;
-			if (Ext.isDefined(me.vmconfig[confid])) {
-			    return "This device is already in use.";
-			}
-			return true;
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
-/*global Proxmox*/
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    view.store.on('load', this.onLoad, view);
-	},
-
-	onLoad: function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-	    var me = this;
-	    var val = me.getValue();
-	    if (!val || !me.store.findRecord('realm', val)) {
-		var def = 'pam';
-		Ext.each(records, function(rec) {
-		    if (rec.data && rec.data['default']) {
-			def = rec.data.realm;
-		    }
-		});
-		me.setValue(def);
-	    }
-	}
-    },
-
-    fieldLabel: gettext('Realm'),
-    name: 'realm',
-    queryMode: 'local',
-    allowBlank: false,
-    editable: false,
-    forceSelection: true,
-    autoSelect: false,
-    triggerAction: 'all',
-    valueField: 'realm',
-    displayField: 'descr',
-    getState: function() {
-	return { value: this.getValue() };
-    },
-    applyState : function(state) {
-	if (state && state.value) {
-	    this.setValue(state.value);
-	}
-    },
-    stateEvents: [ 'select' ],
-    stateful: true, // last chosen auth realm is saved between page reloads
-    id: 'pveloginrealm', // We need stable ids when using stateful, not autogenerated
-    stateID: 'pveloginrealm',
-
-    needOTP: function(realm) {
-	var me = this;
-	// use exact match
-	var rec = me.store.findRecord('realm', realm, 0, false, false, true);
-	return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    store: {
-	model: 'pve-domains',
-	autoLoad: true
-    }
-});
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    editable: false,
-    allowBlank: false,
-    forceSelection: true,
-    autoSelect: false,
-    valueField: 'key',
-    displayField: 'value',
-    hideLabel: true,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	var default_views = {
-	    server: {
-		text: gettext('Server View'),
-		groups: ['node']
-	    },
-	    folder: {
-		text: gettext('Folder View'),
-		groups: ['type']
-	    },
-	    storage: {
-		text: gettext('Storage View'),
-		groups: ['node'],
-		filterfn: function(node) {
-		    return node.data.type === 'storage' || node.data.type === 'node';
-		}
-	    },
-	    pool: { 
-		text: gettext('Pool View'), 
-		groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-			node.data.type === 'pool';
-                }
-	    }
-	};
-
-	var groupdef = [];
-	Ext.Object.each(default_views, function(viewname, value) {
-	    groupdef.push([viewname, value.text]);
-	});
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-            proxy: {
-		type: 'memory',
-		reader: 'array'
-            },
-	    data: groupdef,
-	    autoload: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    value: groupdef[0][0],
-	    getViewFilter: function() {
-		var view = me.getValue();
-		return Ext.apply({ id: view }, default_views[view] || default_views.server);
-	    },
-
-	    getState: function() {
-		return { value: me.getValue() };
-	    },
-
-	    applyState : function(state, doSelect) {
-		var view = me.getValue();
-		if (state && state.value && (view != state.value)) {
-		    var record = store.findRecord('key', state.value);
-		    if (record) {
-			me.setValue(state.value, true);
-			if (doSelect) {
-			    me.fireEvent('select', me, [record]);
-			}
-		    }
-		}
-	    },
-	    stateEvents: [ 'select' ],
-	    stateful: true,
-	    stateId: 'pveview',
-	    id: 'view'
-	});
-
-	me.callParent();
-
-	var statechange = function(sp, key, value) {
-	    if (key === me.id) {
-		me.applyState(value, true);
-	    }
-	};
-
-	var sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', statechange, me);
-    }
-});
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveNodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // do not allow those nodes (array)
-    disallowedNodes: undefined,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'node',
-    displayField: 'node',
-    store: {
-	    fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes'
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		},
-		{
-		    property : 'mem',
-		    direction: 'DESC'
-		}
-	    ]
-	},
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node',
-		sortable: true,
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Memory usage') + " %",
-		renderer: PVE.Utils.render_mem_usage_percent,
-		sortable: true,
-		width: 100,
-		dataIndex: 'mem'
-	    },
-	    {
-		header: gettext('CPU usage'),
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100,
-		dataIndex: 'cpu'
-	    }
-	]
-    },
-
-    validator: function(value) {
-	/*jslint confusion: true */
-	var me = this;
-	if (!me.onlineValidator || (me.allowBlank && !value)) {
-	    return true;
-	}
-
-	var offline = [];
-	var notAllowed = [];
-
-	Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-	    var rec = me.store.findRecord(me.valueField, node);
-	    if (!(rec && rec.data) || !Ext.isNumeric(rec.data.mem)) {
-		offline.push(node);
-	    } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-		notAllowed.push(node);
-	    }
-	});
-
-	if (value && notAllowed.length !== 0) {
-	    return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-	}
-
-	if (value && offline.length !== 0) {
-	    return "Node " + offline.join(', ') + " seems to be offline!";
-	}
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-        me.getStore().load();
-
-	// filter out disallowed nodes
-	me.getStore().addFilter(new Ext.util.Filter({
-	    filterFn: function(item) {
-		if (Ext.isArray(me.disallowedNodes)) {
-		    return !Ext.Array.contains(me.disallowedNodes, item.data.node);
-		} else {
-		    return true;
-		}
-	    }
-	}));
-
-	me.mon(me.getStore(), 'load', function(){
-	    me.isValid();
-	});
-    }
-});
-Ext.define('PVE.form.FileSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFileSelector',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    listeners: {
-	afterrender: function() {
-	    var me = this;
-	    if (!me.disabled) {
-		me.setStorage(me.storage, me.nodename);
-	    }
-	}
-    },
-
-    setStorage: function(storage, nodename) {
-	var me = this;
-
-	var change = false;
-	if (storage && (me.storage !== storage)) {
-	    me.storage = storage;
-	    change = true;
-	}
-
-	if (nodename && (me.nodename !== nodename)) {
-	    me.nodename = nodename;
-	    change = true;
-	}
-
-	if (!(me.storage && me.nodename && change)) {
-	    return;
-	}
-
-	var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-	if (me.storageContent) {
-	    url += '?content=' + me.storageContent;
-	}
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url
-	});
-
-	me.store.removeAll();
-	me.store.load();
-    },
-
-    setNodename: function(nodename) {
-	this.setStorage(undefined, nodename);
-    },
-
-    store: {
-	model: 'pve-storage-content'
-    },
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'volid',
-    displayField: 'text',
-
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'text',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Format'),
-		width: 60,
-		dataIndex: 'format'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 100,
-		dataIndex: 'size',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveStorageSelector',
-
-    allowBlank: false,
-    valueField: 'storage',
-    displayField: 'storage',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'storage',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Type'),
-		width: 60,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Avail'),
-		width: 80,
-		dataIndex: 'avail',
-		renderer: Proxmox.Utils.format_size
-	    },
-	    {
-		header: gettext('Capacity'),
-		width: 80,
-		dataIndex: 'total',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    },
-
-    reloadStorageList: function() {
-	var me = this;
-	if (!me.nodename) {
-	    return;
-	}
-
-	var params = {
-	    format: 1
-	};
-	var url = '/api2/json/nodes/' + me.nodename + '/storage';
-	if (me.storageContent) {
-	    params.content = me.storageContent;
-	}
-	if (me.targetNode) {
-	    params.target = me.targetNode;
-	    params.enabled = 1; // skip disabled storages
-	}
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url,
-	    extraParams: params
-	});
-
-	me.store.load();
- 
-    },
-
-    setTargetNode: function(targetNode) {
-	var me = this;
-
-	if (!targetNode || (me.targetNode === targetNode)) {
-	    return;
-	}
-
-	me.targetNode = targetNode;
-
-	me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.reloadStorageList();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-status',
-	    sorters: {
-		property: 'storage', 
-		order: 'DESC' 
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	if (nodename) {
-	    me.setNodename(nodename);
-	}
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-	idProperty: 'storage'
-    });
-
-});
-Ext.define('PVE.form.DiskStorageSelector', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveDiskStorageSelector',
-
-    layout: 'fit',
-    defaults: {
-	margin: '0 0 5 0'
-    },
-
-    // the fieldLabel for the storageselector
-    storageLabel: gettext('Storage'),
-
-    // the content to show (e.g., images or rootdir)
-    storageContent: undefined,
-
-    // if true, selects the first available storage
-    autoSelect: false,
-
-    allowBlank: false,
-    emptyText: '',
-
-    // hides the selection field
-    // this is always hidden on creation,
-    // and only shown when the storage needs a selection and
-    // hideSelection is not true
-    hideSelection: undefined,
-
-    // hides the size field (e.g, for the efi disk dialog)
-    hideSize: false,
-
-    // sets the intial size value
-    // string because else we get a type confusion
-    defaultSize: '32',
-
-    changeStorage: function(f, value) {
-	var me = this;
-	var formatsel = me.getComponent('diskformat');
-	var hdfilesel = me.getComponent('hdimage');
-	var hdsizesel = me.getComponent('disksize');
-
-	// initial store load, and reset/deletion of the storage
-	if (!value) {
-	    hdfilesel.setDisabled(true);
-	    hdfilesel.setVisible(false);
-
-	    formatsel.setDisabled(true);
-	    return;
-	}
-
-	var rec = f.store.getById(value);
-	// if the storage is not defined, or valid,
-	// we cannot know what to enable/disable
-	if (!rec) {
-	    return;
-	}
-
-	var selectformat = false;
-	if (rec.data.format) {
-	    var format = rec.data.format[0]; // 0 is the formats, 1 the default in the backend
-	    delete format.subvol; // we never need subvol in the gui
-	    selectformat = (Ext.Object.getSize(format) > 1);
-	}
-
-	var select = !!rec.data.select_existing && !me.hideSelection;
-
-	formatsel.setDisabled(!selectformat);
-	formatsel.setValue(selectformat ? 'qcow2' : 'raw');
-
-	hdfilesel.setDisabled(!select);
-	hdfilesel.setVisible(select);
-	if (select) {
-	    hdfilesel.setStorage(value);
-	}
-
-	hdsizesel.setDisabled(select || me.hideSize);
-	hdsizesel.setVisible(!select && !me.hideSize);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-	var hdfilesel = me.getComponent('hdimage');
-
-	hdstorage.setNodename(nodename);
-	hdfilesel.setNodename(nodename);
-    },
-
-    setDisabled: function(value) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-
-	// reset on disable
-	if (value) {
-	    hdstorage.setValue();
-	}
-	hdstorage.setDisabled(value);
-
-	// disabling does not always fire this event and we do not need
-	// the value of the validity
-	hdstorage.fireEvent('validitychange');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'pveStorageSelector',
-		itemId: 'hdstorage',
-		name: 'hdstorage',
-		reference: 'hdstorage',
-		fieldLabel: me.storageLabel,
-		nodename: me.nodename,
-		storageContent: me.storageContent,
-		disabled: me.disabled,
-		autoSelect: me.autoSelect,
-		allowBlank: me.allowBlank,
-		emptyText: me.emptyText,
-		listeners: {
-		    change: {
-			fn: me.changeStorage,
-			scope: me
-		    }
-		}
-	    },
-	    {
-		xtype: 'pveFileSelector',
-		name: 'hdimage',
-		reference: 'hdimage',
-		itemId: 'hdimage',
-		fieldLabel: gettext('Disk image'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: true
-	    },
-	    {
-		xtype: 'numberfield',
-		itemId: 'disksize',
-		reference: 'disksize',
-		name: 'disksize',
-		fieldLabel: gettext('Disk size') + ' (GiB)',
-		hidden: me.hideSize,
-		disabled: me.hideSize,
-		minValue: 0.001,
-		maxValue: 128*1024,
-		decimalPrecision: 3,
-		value: me.defaultSize,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveDiskFormatSelector',
-		itemId: 'diskformat',
-		reference: 'diskformat',
-		name: 'diskformat',
-		fieldLabel: gettext('Format'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: me.storageContent === 'rootdir',
-		value: 'qcow2',
-		allowBlank: false
-	    }
-	];
-
-	// use it to disable the children but not ourself
-	me.disabled = false;
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    store: {
-	fields: [ 'iface', 'active', 'type' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	]
-    },
-    valueField: 'iface',
-    displayField: 'iface',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Bridge'),
-		dataIndex: 'iface',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Active'),
-		width: 60,
-		dataIndex: 'active',
-		renderer: Proxmox.Utils.format_boolean
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comments',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-		me.bridgeType
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-        me.callParent();
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.PCISelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pvePCISelector',
-
-    store: {
-	fields: [ 'id','vendor_name', 'device_name', 'vendor', 'device', 'iommugroup', 'mdev' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'id',
-		direction: 'ASC'
-	    }
-	]
-    },
-
-    autoSelect: false,
-    valueField: 'id',
-    displayField: 'id',
-
-    // can contain a load callback for the store
-    // useful to determine the state of the IOMMU
-    onLoadCallBack: undefined,
-
-    listConfig: {
-	width: 800,
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'id',
-		width: 80
-	    },
-	    {
-		header: gettext('IOMMU Group'),
-		dataIndex: 'iommugroup',
-		width: 50
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor_name',
-		flex: 2
-	    },
-	    {
-		header: gettext('Device'),
-		dataIndex: 'device_name',
-		flex: 6
-	    },
-	    {
-		header: gettext('Mediated Devices'),
-		dataIndex: 'mdev',
-		flex: 1,
-		renderer: function(val) {
-		    return Proxmox.Utils.format_boolean(!!val);
-		}
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined;
-
-        me.callParent();
-
-	if (me.onLoadCallBack !== undefined) {
-	    me.mon(me.getStore(), 'load', me.onLoadCallBack);
-	}
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.MDevSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveMDevSelector',
-
-    store: {
-	fields: [ 'type','available', 'description' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'type',
-		direction: 'ASC'
-	    }
-	]
-    },
-    autoSelect: false,
-    valueField: 'type',
-    displayField: 'type',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		flex: 1
-	    },
-	    {
-		header: gettext('Available'),
-		dataIndex: 'available',
-		width: 80
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'description',
-		flex: 1,
-		renderer: function(value) {
-		    if (!value) {
-			return '';
-		    }
-
-		    return value.split('\n').join('<br>');
-		}
-	    }
-	]
-    },
-
-    setPciID: function(pciid, force) {
-	var me = this;
-
-	if (!force && (!pciid || (me.pciid === pciid))) {
-	    return;
-	}
-
-	me.pciid = pciid;
-	me.updateProxy();
-    },
-
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-	me.updateProxy();
-    },
-
-    updateProxy: function() {
-	var me = this;
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci/' + me.pciid + '/mdev'
-	});
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no node name specified';
-	}
-
-        me.callParent();
-
-	if (me.pciid) {
-	    me.setPciID(me.pciid, true);
-	}
-    }
-});
-
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    valueField: 'group',
-    displayField: 'group',
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'group', 'comment' ],
-	    idProperty: 'group',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/groups"
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Security Group'),
-			dataIndex: 'group',
-			hideable: false,
-			width: 100
-		    },
-		    {
-			header: gettext('Comment'),  
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    valueField: 'ref',
-    displayField: 'ref',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-
-	var url = "/api2/json" + me.base_url;
-	if (me.ref_type) {
-	    url += "?type=" + me.ref_type;
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'type', 'name', 'ref', 'comment' ],
-	    idProperty: 'ref',
-	    proxy: {
-		type: 'proxmox',
-		url: url
-	    },
-	    sorters: {
-		property: 'ref',
-		order: 'DESC'
-	    }
-	});
-
-	var disable_query_for_ips = function(f, value) {
-	    if (value === null || 
-		value.match(/^\d/)) { // IP address starts with \d
-		f.queryDelay = 9999999999; // hack: disbale with long delay
-	    } else {
-		f.queryDelay = 10;
-	    }
-	};
-
-	var columns = [];
-
-	if (!me.ref_type) {
-	    columns.push({
-		header: gettext('Type'),
-		dataIndex: 'type',
-		hideable: false,
-		width: 60
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Name'),
-		dataIndex: 'ref',
-		hideable: false,
-		width: 140
-	    },
-	    {
-		header: gettext('Comment'),  
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: { columns: columns }
-	});
-
-	me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-    valueField: 'p',
-    displayField: 'p',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'p',
-		hideable: false,
-		sortable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Number'),
-		dataIndex: 'n',
-		hideable: false,
-		sortable: false,
-		width: 50
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'd',
-		hideable: false,
-		sortable: false,
-		flex: 1
-	    }
-	]
-    },
-    store: {
-	    fields: [ 'p', 'd', 'n'],
-	    data: [
-		{ p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-		{ p: 'udp', n: 17, d: 'User Datagram Protocol' },
-		{ p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-		{ p: 'igmp', n: 2,  d: 'Internet Group Management' },
-		{ p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-		{ p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-		{ p: 'st', n: 5, d: 'ST datagram mode' },
-		{ p: 'egp', n: 8, d: 'exterior gateway protocol' },
-		{ p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-		{ p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-		{ p: 'hmp', n: 20, d: 'host monitoring protocol' },
-		{ p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-		{ p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-		{ p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-		{ p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-		{ p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-		{ p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-		{ p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-		{ p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-		{ p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-		{ p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-		{ p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-		{ p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-		{ p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-		{ p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-		{ p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-		{ p: 'skip', n: 57, d: 'SKIP' },
-		{ p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-		{ p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-		{ p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-		{ p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-		{ p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-		{ p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-		{ p: 'ax.25', n: 93, d: 'AX.25 frames' },
-		{ p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-		{ p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-		{ p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-		{ p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-		{ p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-		{ p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-		{ p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-		{ p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-		{ p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-		{ p: 'fc', n: 133, d: 'Fibre Channel' },
-		{ p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-		{ p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-		{ p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-		{ p: 'hip', n: 139, d: 'Host Identity Protocol' },
-		{ p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-		{ p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-		{ p: 'rohc', n: 142, d: 'Robust Header Compression' }
-	    ]
-	}
-});
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CPUModelSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + ' (kvm64)'],
-	['486', '486'],
-	['athlon', 'athlon'],
-	['core2duo', 'core2duo'],
-	['coreduo', 'coreduo'],
-	['kvm32', 'kvm32'],
-	['kvm64', 'kvm64'],
-	['pentium', 'pentium'],
-	['pentium2', 'pentium2'],
-	['pentium3', 'pentium3'],
-	['phenom', 'phenom'],
-	['qemu32', 'qemu32'],
-	['qemu64', 'qemu64'],
-	['Conroe', 'Conroe'],
-	['Penryn', 'Penryn'],
-	['Nehalem', 'Nehalem'],
-	['Westmere', 'Westmere'],
-	['SandyBridge', 'SandyBridge'],
-	['IvyBridge', 'IvyBridge'],
-	['Haswell', 'Haswell'],
-	['Haswell-noTSX','Haswell-noTSX'],
-	['Broadwell', 'Broadwell'],
-	['Broadwell-noTSX','Broadwell-noTSX'],
-	['Skylake-Client','Skylake-Client'],
-	['Opteron_G1', 'Opteron_G1'],
-	['Opteron_G2', 'Opteron_G2'],
-	['Opteron_G3', 'Opteron_G3'],
-	['Opteron_G4', 'Opteron_G4'],
-	['Opteron_G5', 'Opteron_G5'],
-	['EPYC', 'EPYC'],
-	['host', 'host']
-
-    ]
-});
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + " (" + gettext('No cache') + ")"],
-	['directsync', 'Direct sync'],
-	['writethrough', 'Write through'],
-	['writeback', 'Write back'],
-	['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-	['none', gettext('No cache')]
-    ]
-});
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    valueField: 'name',
-    displayField: 'name',
-
-    loadStore: function(nodename, vmid) {
-	var me = this;
-
-	if (!nodename) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-        if (!vmid) {
-	    return;
-        }
-
-	me.vmid = vmid;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid +'/snapshot'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-	if (!me.guestType) {
-	    throw "no guest type specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'name'],
-	    filterOnLoad: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Snapshot'),
-			dataIndex: 'name',
-			hideable: false,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	me.loadStore(me.nodename, me.vmid);
-    }
-});
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-
-    cts: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [];
-
-	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'snippets'];
-	}
-
-	Ext.Array.each(me.cts, function(ct) {
-	    me.comboItems.push([ct, PVE.Utils.format_content_types(ct)]);
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'Ext.form.CheckboxGroup',
-    alias: 'widget.pveHotplugFeatureSelector',
-
-    columns: 1,
-    vertical: true,
-
-    defaults: {
-	name: 'hotplug',
-	submitValue: false
-    },
-    items: [
-	{
-	    boxLabel: gettext('Disk'),
-	    inputValue: 'disk',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Network'),
-	    inputValue: 'network',
-	    checked: true
-	},
-	{
-	    boxLabel: 'USB',
-	    inputValue: 'usb',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Memory'),
-	    inputValue: 'memory'
-	},
-	{
-	    boxLabel: gettext('CPU'),
-	    inputValue: 'cpu'
-	}
-    ],
-
-    setValue: function(value) {
-	var me = this;
-	var newVal = [];
-	if (value === '1') {
-	    newVal = ['disk', 'network', 'usb'];
-	} else if (value !== '0') {
-	    newVal = value.split(',');
-	}
-	me.callParent([{ hotplug: newVal }]);
-    },
-
-    // overide framework function to
-    // assemble the hotplug value
-    getSubmitData: function() {
-	var me = this,
-	boxes = me.getBoxes(),
-	data = [];
-	Ext.Array.forEach(boxes, function(box){
-	    if (box.getValue()) {
-		data.push(box.inputValue);
-	    }
-	});
-
-	/* because above is hotplug an array */
-	/*jslint confusion: true*/
-	if (data.length === 0) {
-	    return { 'hotplug':'0' };
-	} else {
-	    return { 'hotplug': data.join(',') };
-	}
-    }
-
-});
-Ext.define('PVE.form.AgentFeatureSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: ['widget.pveAgentFeatureSelector'],
-
-    initComponent: function() {
-	var me = this;
-	me.items= [
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Qemu Agent'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		listeners: {
-		    change: function(f, value, old) {
-			var gtcb = me.down('proxmoxcheckbox[name=fstrim_cloned_disks]');
-			if (value) {
-			    gtcb.setDisabled(false);
-			} else {
-			    gtcb.setDisabled(true);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Run guest-trim after clone disk'),
-		name: 'fstrim_cloned_disks',
-		disabled: true
-	    }
-	];
-	me.callParent();
-    },
-
-    onGetValues: function(values) {
-	var agentstr = PVE.Parser.printPropertyString(values, 'enabled');
-	return { agent: agentstr };
-    },
-
-    setValues: function(values) {
-	var agent = values.agent || '';
-	var res = PVE.Parser.parsePropertyString(agent, 'enabled');
-	this.callParent([res]);
-    }
-});
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-    comboItems: [
-	['comstar', 'Comstar'],
-	[ 'istgt', 'istgt'],
-	[ 'iet', 'IET'],
-	[ 'LIO', 'LIO']
-    ]
-});
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems:[],
-    initComponent: function(){
-	var me = this;
-	me.comboItems = [
-	    ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-	    ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-	    ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-	    ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-	    ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-	    ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])],
-	    ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])]
-	];
-	this.callParent();
-    }
-});
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-    comboItems: [
-	['__default__', PVE.Utils.render_scsihw('')],
-	['lsi', PVE.Utils.render_scsihw('lsi')],
-	['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-	['megasas', PVE.Utils.render_scsihw('megasas')],
-	['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-	['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-	['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-    ]
-});
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-    comboItems: [
-	    ['ACCEPT', 'ACCEPT'],
-	    ['REJECT', 'REJECT'],
-	    [ 'DROP', 'DROP']
-	]
-});
-/*
- *  This is a global search field
- *  it loads the /cluster/resources on focus
- *  and displays the result in a floating grid
- *
- *  it filters and sorts the objects by the algorithm in
- *  the customFilter function
- *
- *  also it does accept key up/down and enter for input
- *  and it opens to ctrl+shift+f and ctrl+space
- */
-Ext.define('PVE.form.GlobalSearchField', {
-    extend: 'Ext.form.field.Text',
-    alias: 'widget.pveGlobalSearchField',
-
-    emptyText: gettext('Search'),
-    enableKeyEvents: true,
-    selectOnFocus: true,
-    padding: '0 5 0 5',
-
-    grid: {
-	xtype: 'gridpanel',
-	focusOnToFront: false,
-	floating: true,
-	emptyText: Proxmox.Utils.noneText,
-	width: 600,
-	height: 400,
-	scrollable: {
-	    xtype: 'scroller',
-	    y: true,
-	    x:false
-	},
-	store: {
-	    model: 'PVEResources',
-	    proxy:{
-		type: 'proxmox',
-		url: '/api2/extjs/cluster/resources'
-	    }
-	},
-	plugins: {
-	    ptype: 'bufferedrenderer',
-	    trailingBufferZone: 20,
-	    leadingBufferZone: 20
-	},
-
-	hideMe: function() {
-	    var me = this;
-	    if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
-		return;
-	    }
-	    me.hasFocus = false;
-	    if (!me.textfield.hasFocus) {
-		me.hide();
-	    }
-	},
-
-	setFocus: function() {
-	    var me = this;
-	    me.hasFocus = true;
-	},
-
-	listeners: {
-	    rowclick: function(grid, record) {
-		var me = this;
-		me.textfield.selectAndHide(record.id);
-	    },
-	    itemcontextmenu: function(v, record, item, index, event) {
-		var me = this;
-		me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
-	    },
-	    /* because of lint */
-	    focusleave: {
-		fn: 'hideMe'
-	    },
-	    focusenter: 'setFocus'
-	},
-
-	columns: [
-	    {
-		text: gettext('Type'),
-		dataIndex: 'type',
-		width: 100,
-		renderer: PVE.Utils.render_resource_type
-	    },
-	    {
-		text: gettext('Description'),
-		flex: 1,
-		dataIndex: 'text'
-	    },
-	    {
-		text: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		text: gettext('Pool'),
-		dataIndex: 'pool'
-	    }
-	]
-    },
-
-    customFilter: function(item) {
-	var me = this;
-	var match = 0;
-	var fieldArr = [];
-	var i,j, fields;
-
-	// different types of objects have different fields to search
-	// for example, a node will never have a pool and vice versa
-	switch (item.data.type) {
-	    case 'pool': fieldArr = ['type', 'pool', 'text']; break;
-	    case 'node': fieldArr = ['type', 'node', 'text']; break;
-	    case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
-	    default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
-	}
-	if (me.filterVal === '') {
-	    item.data.relevance = 0;
-	    return true;
-	}
-
-	// all text is case insensitive and each word is
-	// searched alone
-	// for every partial match, the row gets
-	// 1 match point, for every exact match
-	// it gets 2 points
-	//
-	// results gets sorted by points (descending)
-	fields = me.filterVal.split(/\s+/);
-	for(i = 0; i < fieldArr.length; i++) {
-	    var v = item.data[fieldArr[i]];
-	    if (v !== undefined) {
-		v = v.toString().toLowerCase();
-		for(j = 0; j < fields.length; j++) {
-		    if (v.indexOf(fields[j]) !== -1) {
-			match++;
-			if(v === fields[j]) {
-			    match++;
-			}
-		    }
-		}
-	    }
-	}
-	// give the row the 'relevance' value
-	item.data.relevance = match;
-	return (match > 0);
-    },
-
-    updateFilter: function(field, newValue, oldValue) {
-	var me = this;
-	// parse input and filter store,
-	// show grid
-	me.grid.store.filterVal = newValue.toLowerCase().trim();
-	me.grid.store.clearFilter(true);
-	me.grid.store.filterBy(me.customFilter);
-	me.grid.getSelectionModel().select(0);
-    },
-
-    selectAndHide: function(id) {
-	var me = this;
-	me.tree.selectById(id);
-	me.grid.hide();
-	me.setValue('');
-	me.blur();
-    },
-
-    onKey: function(field, e) {
-	var me = this;
-	var key = e.getKey();
-
-	switch(key) {
-	    case Ext.event.Event.ENTER:
-		// go to first entry if there is one
-		if (me.grid.store.getCount() > 0) {
-		    me.selectAndHide(me.grid.getSelection()[0].data.id);
-		}
-		break;
-	    case Ext.event.Event.UP:
-		me.grid.getSelectionModel().selectPrevious();
-		break;
-	    case Ext.event.Event.DOWN:
-		me.grid.getSelectionModel().selectNext();
-		break;
-	    case Ext.event.Event.ESC:
-		me.grid.hide();
-		me.blur();
-		break;
-	}
-    },
-
-    loadValues: function(field) {
-	var me = this;
-	var records = [];
-
-	me.hasFocus = true;
-	me.grid.textfield = me;
-	me.grid.store.load();
-	me.grid.showBy(me, 'tl-bl');
-    },
-
-    hideGrid: function() {
-	var me = this;
-
-	me.hasFocus = false;
-	if (!me.grid.hasFocus) {
-	    me.grid.hide();
-	}
-    },
-
-    listeners: {
-	change: {
-	    fn: 'updateFilter',
-	    buffer: 250
-	},
-	specialkey: 'onKey',
-	focusenter: 'loadValues',
-	focusleave: {
-	    fn: 'hideGrid',
-	    delay: 100
-	}
-    },
-
-    toggleFocus: function() {
-	var me = this;
-	if (!me.hasFocus) {
-	    me.focus();
-	} else {
-	    me.blur();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.tree) {
-	    throw "no tree given";
-	}
-
-	me.grid = Ext.create(me.grid);
-
-	me.callParent();
-
-	/*jslint confusion: true*/
-	/*because shift is also a function*/
-	// bind ctrl+shift+f and ctrl+space
-	// to open/close the search
-	me.keymap = new Ext.KeyMap({
-	    target: Ext.get(document),
-	    binding: [{
-		key:'F',
-		ctrl: true,
-		shift: true,
-		fn: me.toggleFocus,
-		scope: me
-	    },{
-		key:' ',
-		ctrl: true,
-		fn: me.toggleFocus,
-		scope: me
-	    }]
-	});
-
-	// always select first item and
-	// sort by relevance after load
-	me.mon(me.grid.store, 'load', function() {
-	    me.grid.getSelectionModel().select(0);
-	    me.grid.store.sort({
-		property: 'relevance',
-		direction: 'DESC'
-	    });
-	});
-    }
-
-});
-Ext.define('PVE.form.QemuBiosSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveQemuBiosSelector'],
-
-    initComponent: function() {
-	var me = this;
-
-        me.comboItems = [
-	    ['__default__', PVE.Utils.render_qemu_bios('')],
-	    ['seabios', PVE.Utils.render_qemu_bios('seabios')],
-	    ['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-/* filter is a javascript builtin, but extjs calls it also filter */
-Ext.define('PVE.form.VMSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    allowBlank: true,
-    selectAll: false,
-    isFormField: true,
-
-    plugins: 'gridfilters',
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-    columns: [
-	{
-	    header: 'ID',
-	    dataIndex: 'vmid',
-	    width: 80,
-	    filter: {
-		type: 'number'
-	    }
-	},
-	{
-	    header: gettext('Node'),
-	    dataIndex: 'node'
-	},
-	{
-	    header: gettext('Status'),
-	    dataIndex: 'status',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1,
-	    filter: {
-		type: 'string'
-	    }
-	},
-	{
-	    header: gettext('Pool'),
-	    dataIndex: 'pool',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Type'),
-	    dataIndex: 'type',
-	    width: 120,
-	    renderer: function(value) {
-		if (value === 'qemu') {
-		    return gettext('Virtual Machine');
-		} else if (value === 'lxc') {
-		    return gettext('LXC Container');
-		}
-
-		return '';
-	    },
-	    filter: {
-		type: 'list',
-		store: {
-		    data: [
-			{id: 'qemu', text: gettext('Virtual Machine')},
-			{id: 'lxc', text: gettext('LXC Container')}
-		    ],
-		    // due to EXTJS-18711
-		    // we have to do a static list via a store
-		    // but to avoid creating an object,
-		    // we have to have a pseudo un function
-		    un: function(){}
-		}
-	    }
-	},
-	{
-	    header: 'HA ' + gettext('Status'),
-	    dataIndex: 'hastate',
-	    flex: 1,
-	    filter: {
-		type: 'list'
-	    }
-	}
-    ],
-
-    selModel: {
-	selType: 'checkboxmodel',
-	mode: 'SIMPLE'
-    },
-
-    checkChangeEvents: [
-	'selectionchange',
-	'change'
-    ],
-
-    listeners: {
-	selectionchange: function() {
-	    // to trigger validity and error checks
-	    this.checkChange();
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	var selection = sm.getSelection();
-	var values = [];
-	var store = me.getStore();
-	selection.forEach(function(item) {
-	    // only add if not filtered
-	    if (store.findExact('vmid', item.data.vmid) !== -1) {
-		values.push(item.data.vmid);
-	    }
-	});
-	return values;
-    },
-
-    setValue: function(value) {
-	console.log(value);
-	var me = this;
-	var sm = me.getSelectionModel();
-	if (!Ext.isArray(value)) {
-	    value = value.split(',');
-	}
-	var selection = [];
-	var store = me.getStore();
-
-	value.forEach(function(item) {
-	    var rec = store.findRecord('vmid',item, 0, false, true, true);
-	    console.log(store);
-
-	    if (rec) {
-		console.log(rec);
-		selection.push(rec);
-	    }
-	});
-
-	sm.select(selection);
-
-	return me.mixins.field.setValue.call(me, value);
-    },
-
-    getErrors: function(value) {
-	var me = this;
-	if (me.allowBlank ===  false &&
-	    me.getSelectionModel().getCount() === 0) {
-	    me.addBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	    return [gettext('No VM selected')];
-	}
-
-	me.removeBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	return [];
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.nodename) {
-	    me.store.filters.add({
-		property: 'node',
-		exactMatch: true,
-		value: me.nodename
-	    });
-	}
-
-	// only show the relevant guests by default
-	if (me.action) {
-	    var statusfilter = '';
-	    switch (me.action) {
-		case 'startall':
-		    statusfilter = 'stopped';
-		    break;
-		case 'stopall':
-		    statusfilter = 'running';
-		    break;
-	    }
-	    if (statusfilter !== '') {
-		me.store.filters.add({
-		    property: 'template',
-		    value: 0
-		},{
-		    id: 'x-gridfilter-status',
-		    operator: 'in',
-		    property: 'status',
-		    value: [statusfilter]
-		});
-	    }
-	}
-
-	var store = me.getStore();
-	var sm = me.getSelectionModel();
-
-	if (me.selectAll) {
-	    me.mon(store,'load', function(){
-		me.getSelectionModel().selectAll(false);
-	    });
-	}
-    }
-});
-
-
-Ext.define('PVE.form.VMComboSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.vmComboSelector',
-
-    valueField: 'vmid',
-    displayField: 'vmid',
-
-    autoSelect: false,
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-
-    listConfig: {
-	width: 600,
-	plugins: 'gridfilters',
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'vmid',
-		width: 80,
-		filter: {
-		    type: 'number'
-		}
-	    },
-	    {
-		header: gettext('Name'),
-		dataIndex: 'name',
-		flex: 1,
-		filter: {
-		    type: 'string'
-		}
-	    },
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		header: gettext('Status'),
-		dataIndex: 'status',
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Pool'),
-		dataIndex: 'pool',
-		hidden: true,
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		width: 120,
-		renderer: function(value) {
-		    if (value === 'qemu') {
-			return gettext('Virtual Machine');
-		    } else if (value === 'lxc') {
-			return gettext('LXC Container');
-		    }
-
-		    return '';
-		},
-		filter: {
-		    type: 'list',
-		    store: {
-			data: [
-			    {id: 'qemu', text: gettext('Virtual Machine')},
-			    {id: 'lxc', text: gettext('LXC Container')}
-			],
-			un: function(){} // due to EXTJS-18711
-		    }
-		}
-	    },
-	    {
-		header: 'HA ' + gettext('Status'),
-		dataIndex: 'hastate',
-		hidden: true,
-		flex: 1,
-		filter: {
-		    type: 'list'
-		}
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.USBSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUSBSelector'],
-    allowBlank: false,
-    autoSelect: false,
-    displayField: 'usbid',
-    valueField: 'usbid',
-    editable: true,
-
-    getUSBValue: function() {
-	var me = this;
-	var rec = me.store.findRecord('usbid', me.value);
-	var val = 'host='+ me.value;
-	if (rec && rec.data.speed === "5000") {
-	    val = 'host=' + me.value + ",usb3=1";
-	}
-	return val;
-    },
-
-    validator: function(value) {
-	var me = this;
-	if (me.type === 'device') {
-	    return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
-	} else if (me.type === 'port') {
-	    return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
-	}
-	return false;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (me.type !== 'device' && me.type !== 'port') {
-	    throw "no valid type specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-usb-' + me.type,
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/scan/usb"
-	    },
-	    filters: [
-		function (item) {
-		    return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: (me.type === 'device')?gettext('Device'):gettext('Port'),
-			sortable: true,
-			dataIndex: 'usbid',
-			width: 80
-		    },
-		    {
-			header: gettext('Manufacturer'),
-			sortable: true,
-			dataIndex: 'manufacturer',
-			width: 100
-		    },
-		    {
-			header: gettext('Product'),
-			sortable: true,
-			dataIndex: 'product',
-			flex: 1
-		    },
-		    {
-			header: gettext('Speed'),
-			width: 70,
-			sortable: true,
-			dataIndex: 'speed',
-			renderer: function(value) {
-			    if (value === "5000") {
-				return "USB 3.0";
-			    } else if (value === "480") {
-				return "USB 2.0";
-			    } else {
-				return "USB 1.x";
-			    }
-			}
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-usb-device', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val, data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('vendid') + ':' + data.get('prodid');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-
-    Ext.define('pve-usb-port', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val,data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('busnum') + '-' + data.get('usbpath');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-});
-Ext.define('PVE.form.CalendarEvent', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pveCalendarEvent',
-
-    editable: true,
-
-    valueField: 'value',
-    displayField: 'text',
-    queryMode: 'local',
-
-    store: {
-	field: [ 'value', 'text'],
-	data: [
-	    { value: '*/30', text: Ext.String.format(gettext("Every {0} minutes"), 30) },
-	    { value: '*/2:00', text: gettext("Every two hours")},
-	    { value: '2,22:30', text: gettext("Every day") + " 02:30, 22:30"},
-	    { value: 'mon..fri', text: gettext("Monday to Friday") + " 00:00"},
-	    { value: 'mon..fri */1:00', text: gettext("Monday to Friday") + ': ' +  gettext("hourly")},
-	    { value: 'sun 01:00', text: gettext("Sunday") + " 01:00"}
-	]
-    },
-
-    tpl: [
-	'<ul class="x-list-plain"><tpl for=".">',
-	    '<li role="option" class="x-boundlist-item">{text}</li>',
-	'</tpl></ul>'
-    ],
-
-    displayTpl: [
-	'<tpl for=".">',
-	'{value}',
-	'</tpl>'
-    ]
-
-});
-Ext.define('PVE.form.CephPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephPoolSelector',
-
-    allowBlank: false,
-    valueField: 'pool_name',
-    displayField: 'pool_name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/pools'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.form.PermPathSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pvePermPathSelector',
-
-    valueField: 'value',
-    displayField: 'value',
-    typeAhead: true,
-    queryMode: 'local',
-    store: {
-	type: 'pvePermPath'
-    }
-});
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-	var me = this;
-
-	var taskstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-tasks',
-	    model: 'proxmox-tasks',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/tasks'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: taskstore,
-	    sortAfterUpdate: true,
-	    appendAtStart: true,
-	    sorters: [
-		{
-		    property : 'pid',
-		    direction: 'DESC'
-		},
-		{
-		    property : 'starttime',
-		    direction: 'DESC'
-		}
-	    ]
-
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 150,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type == "vncproxy" ||
-				record.data.type == "vncshell" ||
-				record.data.type == "spiceproxy") {
-				metaData.tdCls =  "x-grid-row-console";
-			    } else {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type != "vncproxy") {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return Proxmox.Utils.errorText + ': ' + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		show: taskstore.startUpdate,
-		destroy: taskstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-	var me = this;
-
-	var logstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-log',
-	    model: 'proxmox-cluster-log',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/log'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: logstore,
-	    appendAtStart: true 
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true,
- 
-		getRowClass: function(record, index) {
-		    var pri = record.get('pri');
-
-		    if (pri && pri <= 3) {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{ 
-		    header: gettext("Time"), 
-		    dataIndex: 'time',
-		    width: 150,
-		    renderer: function(value) { 
-			return Ext.Date.format(value, "M d H:i:s"); 
-		    }
-		},
-		{ 
-		    header: gettext("Node"), 
-		    dataIndex: 'node',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Service"), 
-		    dataIndex: 'tag',
-		    width: 100
-		},
-		{ 
-		    header: "PID", 
-		    dataIndex: 'pid',
-		    width: 100 
-		},
-		{ 
-		    header: gettext("User name"), 
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Severity"), 
-		    dataIndex: 'pri',
-		    renderer: PVE.Utils.render_serverity,
-		    width: 100 
-		},
-		{ 
-		    header: gettext("Message"), 
-		    dataIndex: 'msg',
-		    flex: 1	  
-		}
-	    ],
-	    listeners: {
-		activate: logstore.startUpdate,
-		deactivate: logstore.stopUpdate,
-		destroy: logstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = 'ltab';
-	var sp = Ext.state.Manager.getProvider();
-
-	var state = sp.get(stateid);
-	if (state && state.value) {
-	    me.activeTab = state.value;
-	}
-
-	Ext.apply(me, {
-	    listeners: {
-		tabchange: function() {
-		    var atab = me.getActiveTab().itemId;
-		    var state = { value: atab };
-		    sp.set(stateid, state);
-		}
-	    },
-	    items: [
-		{
-		    itemId: 'tasks',
-		    title: gettext('Tasks'),
-		    xtype: 'pveClusterTasks'
-		},
-		{
-		    itemId: 'clog',
-		    title: gettext('Cluster log'),
-		    xtype: 'pveClusterLog'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.items.get(0).fireEvent('show', me.items.get(0));
-
-	var statechange = function(sp, key, state) {
-	    if (key === stateid) {
-		var atab = me.getActiveTab().itemId;
-		var ntab = state.value;
-		if (state && ntab && (atab != ntab)) {
-		    me.setActiveTab(ntab);
-		}
-	    }
-	};
-
-	sp.on('statechange', statechange);
-	me.on('destroy', function() {
-	    sp.un('statechange', statechange);		    
-	});
-
-    }
-});
-Ext.define('PVE.panel.StatusView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStatusView',
-
-    layout: {
-	type: 'column'
-    },
-
-    title: gettext('Status'),
-
-    getRecordValue: function(key, store) {
-	if (!key) {
-	    throw "no key given";
-	}
-	var me = this;
-
-	if (store === undefined) {
-	    store = me.getStore();
-	}
-
-	var rec = store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-
-	return '';
-    },
-
-    fieldRenderer: function(val,max) {
-	if (max === undefined) {
-	    return val;
-	}
-
-	if (!Ext.isNumeric(max) || max === 1) {
-	    return PVE.Utils.render_usage(val);
-	}
-	return PVE.Utils.render_size_usage(val,max);
-    },
-
-    fieldCalculator: function(used, max) {
-	if (!Ext.isNumeric(max) && Ext.isNumeric(used)) {
-	    return used;
-	} else if(!Ext.isNumeric(used)) {
-	    /* we come here if the field is from a node
-	     * where the records are not mem and maxmem
-	     * but mem.used and mem.total
-	     */
-	    if (used.used !== undefined &&
-		used.total !== undefined) {
-		return used.used/used.total;
-	    }
-	}
-
-	return used/max;
-    },
-
-    updateField: function(field) {
-	var me = this;
-	var text = '';
-	var renderer = me.fieldRenderer;
-	if (Ext.isFunction(field.renderer)) {
-	    renderer = field.renderer;
-	}
-	if (field.multiField === true) {
-	    field.updateValue(renderer.call(field, me.getStore().getRecord()));
-	} else if (field.textField !== undefined) {
-	    field.updateValue(renderer.call(field, me.getRecordValue(field.textField)));
-	} else if(field.valueField !== undefined) {
-	    var used = me.getRecordValue(field.valueField);
-	    /*jslint confusion: true*/
-	    /* string and int */
-	    var max = field.maxField !== undefined ? me.getRecordValue(field.maxField) : 1;
-
-	    var calculate = me.fieldCalculator;
-
-	    if (Ext.isFunction(field.calculate)) {
-		calculate = field.calculate;
-	    }
-	    field.updateValue(renderer.call(field, used,max), calculate(used,max));
-	}
-    },
-
-    getStore: function() {
-	var me = this;
-	if (!me.rstore) {
-	    throw "there is no rstore";
-	}
-
-	return me.rstore;
-    },
-
-    updateTitle: function() {
-	var me = this;
-	me.setTitle(me.getRecordValue('name'));
-    },
-
-    updateValues: function(store, records, success) {
-	if (!success) {
-	    return; // do not update if store load was not successful
-	}
-	var me = this;
-	var itemsToUpdate = me.query('pveInfoWidget');
-
-	itemsToUpdate.forEach(me.updateField, me);
-
-	me.updateTitle(store);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	if (!me.title) {
-	    throw "no title given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', 'updateValues');
-    }
-
-});
-Ext.define('PVE.panel.GuestStatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveGuestStatusView',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    height: 300,
-
-    cbindData: function (initialConfig) {
-	var me = this;
-	return {
-	    isQemu: me.pveSelNode.data.type === 'qemu',
-	    isLxc: me.pveSelNode.data.type === 'lxc'
-	};
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'status',
-	    title: gettext('Status'),
-	    iconCls: 'fa fa-info fa-fw',
-	    printBar: false,
-	    multiField: true,
-	    renderer: function(record) {
-		var me = this;
-		var text = record.data.status;
-		var qmpstatus = record.data.qmpstatus;
-		if (qmpstatus && qmpstatus !== record.data.status) {
-		    text += ' (' + qmpstatus + ')';
-		}
-		return text;
-	    }
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    xtype: 'pveInfoWidget',
-	    itemId: 'node',
-	    iconCls: 'fa fa-building fa-fw',
-	    title: gettext('Node'),
-	    cbind: {
-		text: '{pveSelNode.data.node}'
-	    },
-	    printBar: false
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpus',
-	    renderer: PVE.Utils.render_cpu_usage,
-	    // in this specific api call
-	    // we already have the correct value for the usage
-	    calculate: Ext.identityFn
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory usage'),
-	    valueField: 'mem',
-	    maxField: 'maxmem'
-	},
-	{
-	    itemId: 'swap',
-	    xtype: 'pveInfoWidget',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'maxswap',
-	    cbind: {
-		hidden: '{isQemu}',
-		disabled: '{isQemu}'
-	    }
-	},
-	{
-	    itemId: 'rootfs',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    valueField: 'disk',
-	    maxField: 'maxdisk',
-	    printBar: false,
-	    renderer: function(used, max) {
-		var me = this;
-		me.setPrintBar(used > 0);
-		if (used === 0) {
-		    return PVE.Utils.render_size(max);
-		} else {
-		    return PVE.Utils.render_size_usage(used,max);
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'ips',
-	    xtype: 'pveAgentIPView',
-	    cbind: {
-		rstore: '{rstore}',
-		pveSelNode: '{pveSelNode}',
-		hidden: '{isLxc}',
-		disabled: '{isLxc}'
-	    }
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = me.getRecordValue('uptime');
-
-	var text = "";
-	if (Number(uptime) > 0) {
-	    text = " (" + gettext('Uptime') + ': ' + Proxmox.Utils.format_duration_long(uptime)
-		+ ')';
-	}
-
-	me.setTitle(me.getRecordValue('name') + text);
-    }
-});
-/*
- * This is a running chart widget
- * you add time datapoints to it,
- * and we only show the last x of it
- * used for ceph performance charts
- */
-Ext.define('PVE.widget.RunningChart', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveRunningChart',
-
-    layout: {
-	type: 'hbox',
-	align: 'center'
-    },
-    items: [
-	{
-	    width: 80,
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}:</h3>'
-	},
-	{
-	    flex: 1,
-	    xtype: 'cartesian',
-	    height: '100%',
-	    itemId: 'chart',
-	    border: false,
-	    axes: [
-		{
-		    type: 'numeric',
-		    position: 'left',
-		    hidden: true,
-		    minimum: 0
-		},
-		{
-		    type: 'numeric',
-		    position: 'bottom',
-		    hidden: true
-		}
-	    ],
-
-	    store: {
-		data: {}
-	    },
-
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '0 B/s',
-		textAlign: 'end',
-		textBaseline: 'middle',
-		fontSize: 14
-	    }],
-
-	    series: [{
-		type: 'line',
-		xField: 'time',
-		yField: 'val',
-		fill: 'true',
-		colors: ['#cfcfcf'],
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function( tooltip, record, ctx) {
-			var me = this.getChart();
-			var date = new Date(record.data.time);
-			var value = me.up().renderer(record.data.val);
-			tooltip.setHtml(
-			    me.up().title + ': ' + value + '<br />' +
-			    Ext.Date.format(date, 'H:i:s')
-			);
-		    }
-		},
-		style: {
-		    lineWidth: 1.5,
-		    opacity: 0.60
-		},
-		marker: {
-		    opacity: 0,
-		    scaling: 0.01,
-		    fx: {
-			duration: 200,
-			easing: 'easeOut'
-		    }
-		},
-		highlightCfg: {
-		    opacity: 1,
-		    scaling: 1.5
-		}
-	    }]
-	}
-    ],
-
-    // the renderer for the tooltip and last value,
-    // default just the value
-    renderer: Ext.identityFn,
-
-    // show the last x seconds
-    // default is 5 minutes
-    timeFrame: 5*60,
-
-    addDataPoint: function(value, time) {
-	var me = this.chart;
-	var panel = me.up();
-	var now = new Date();
-	var begin = new Date(now.getTime() - (1000*panel.timeFrame));
-
-	me.store.add({
-	    time: time || now.getTime(),
-	    val: value || 0
-	});
-
-	// delete all old records when we have 20 times more datapoints
-	// than seconds in our timeframe (so even a subsecond graph does
-	// not trigger this often)
-	//
-	// records in the store do not take much space, but like this,
-	// we prevent a memory leak when someone has the site open for a long time
-	// with minimal graphical glitches
-	if (me.store.count() > panel.timeFrame * 20) {
-	    var oldData = me.store.getData().createFiltered(function(item) {
-		return item.data.time < begin.getTime();
-	    });
-
-	    me.store.remove(oldData.getRange());
-	}
-
-	me.timeaxis.setMinimum(begin.getTime());
-	me.timeaxis.setMaximum(now.getTime());
-	me.valuesprite.setText(panel.renderer(value || 0).toString());
-	me.valuesprite.setAttributes({
-	    x: me.getWidth() - 15,
-	    y: me.getHeight()/2
-	}, true);
-	me.redraw();
-    },
-
-    setTitle: function(title) {
-	this.title = title;
-	var me = this.getComponent('title');
-	me.update({title: title});
-    },
-
-    initComponent: function(){
-	var me = this;
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.chart = me.getComponent('chart');
-	me.chart.timeaxis = me.chart.getAxes()[1];
-	me.chart.valuesprite = me.chart.getSurface('chart').get('valueSprite');
-	if (me.color) {
-	    me.chart.series[0].setStyle({
-		fill: me.color,
-		stroke: me.color
-	    });
-	}
-    }
-});
-Ext.define('PVE.widget.Info',{
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveInfoWidget',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    value: 0,
-    maximum: 1,
-    printBar: true,
-    items: [
-	{
-	    xtype: 'component',
-	    itemId: 'label',
-	    data: {
-		title: '',
-		usage: '',
-		iconCls: undefined
-	    },
-	    tpl: [
-		'<div class="left-aligned">',
-		'<tpl if="iconCls">',
-		'<i class="{iconCls}"></i> ',
-		'</tpl>',
-		'{title}</div>&nbsp;<div class="right-aligned">{usage}</div>'
-	    ]
-	},
-	{
-	    height: 2,
-	    border: 0
-	},
-	{
-	    xtype: 'progressbar',
-	    itemId: 'progress',
-	    height: 5,
-	    value: 0,
-	    animate: true
-	}
-    ],
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-
-    setPrintBar: function(enable) {
-	var me = this;
-	me.printBar = enable;
-	me.getComponent('progress').setVisible(enable);
-    },
-
-    setIconCls: function(iconCls) {
-	var me = this;
-	me.getComponent('label').data.iconCls = iconCls;
-    },
-
-    updateValue: function(text, usage) {
-	var me = this;
-	var label = me.getComponent('label');
-	label.update(Ext.apply(label.data, {title: me.title, usage:text}));
-
-	if (usage !== undefined &&
-	    me.printBar &&
-	    Ext.isNumeric(usage) &&
-	    usage >= 0) {
-	    var progressBar = me.getComponent('progress');
-	    progressBar.updateProgress(usage, '');
-	    if (usage > me.criticalThreshold) {
-		progressBar.removeCls('warning');
-		progressBar.addCls('critical');
-	    } else if (usage > me.warningThreshold) {
-		progressBar.removeCls('critical');
-		progressBar.addCls('warning');
-	    } else {
-		progressBar.removeCls('warning');
-		progressBar.removeCls('critical');
-	    }
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.title) {
-	    throw "no title defined";
-	}
-
-	me.callParent();
-
-	me.getComponent('progress').setVisible(me.printBar);
-
-	me.updateValue(me.text, me.value);
-	me.setIconCls(me.iconCls);
-    }
-
-});
-Ext.define('PVE.panel.TemplateStatusView',{
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveTemplateStatusView',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	printBar: false,
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    itemId: 'node',
-	    iconCls: 'fa fa-fw fa-building',
-	    title: gettext('Node')
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'cpus',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('Processors'),
-	    textField: 'cpus'
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory'),
-	    textField: 'maxmem',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'swap',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('Swap'),
-	    textField: 'maxswap',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'disk',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    textField: 'maxdisk',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var name = me.pveSelNode.data.name;
-	if (!name) {
-	    throw "no name specified";
-	}
-
-	me.title = name;
-
-	me.callParent();
-	if (me.pveSelNode.data.type !== 'lxc') {
-	    me.remove(me.getComponent('swap'));
-	}
-	me.getComponent('node').updateValue(me.pveSelNode.data.node);
-    }
-});
-Ext.define('PVE.widget.HealthWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveHealthWidget',
-
-    data: {
-	iconCls: PVE.Utils.get_health_icon(undefined, true),
-	text: '',
-	title: ''
-    },
-
-    style: {
-	'text-align':'center'
-    },
-
-    tpl: [
-	'<h3>{title}</h3>',
-	'<i class="fa fa-5x {iconCls}"></i>',
-	'<br /><br/>',
-	'{text}'
-    ],
-
-    updateHealth: function(data) {
-	var me = this;
-	me.update(Ext.apply(me.data, data));
-    },
-
-    initComponent: function(){
-	var me = this;
-
-	if (me.title) {
-	    me.config.data.title = me.title;
-	}
-
-	me.callParent();
-    }
-
-});
-/*global u2f*/
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onLogon: function() {
-	    var me = this;
-
-	    var form = this.lookupReference('loginForm');
-	    var unField = this.lookupReference('usernameField');
-	    var saveunField = this.lookupReference('saveunField');
-	    var view = this.getView();
-
-	    if (!form.isValid()) {
-		return;
-	    }
-
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
-	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
-
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
-
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
-
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
-			} else {
-			    me.perform_otp();
-			}
-		    } else {
-			me.success(data);
-		    }
-		}
-	    });
-
-	},
-	failure: function(resp) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.unmask();
-	    var handler = function() {
-		var uf = me.lookupReference('usernameField');
-		uf.focus(true, true);
-	    };
-
-	    Ext.MessageBox.alert(gettext('Error'),
-				 gettext("Login failed. Please try again"),
-				 handler);
-	},
-	success: function(data) {
-	    var me = this;
-	    var view = me.getView();
-	    var handler = view.handler || Ext.emptyFn;
-	    handler.call(me, data);
-	    view.close();
-	},
-
-	perform_otp: function() {
-	    var me = this;
-	    var win = Ext.create('PVE.window.TFALoginWindow', {
-		onLogin: function(value) {
-		    me.finish_tfa(value);
-		},
-		onCancel: function() {
-		    Proxmox.LoggedOut = false;
-		    Proxmox.Utils.authClear();
-		    me.getView().show();
-		}
-	    });
-	    win.show();
-	},
-
-	perform_u2f: function(data) {
-	    var me = this;
-	    // Show the message:
-	    var msg = Ext.Msg.show({
-		title: 'U2F: '+gettext('Verification'),
-		message: gettext('Please press the button on your U2F Device'),
-		buttons: []
-	    });
-	    var chlg = data.U2FChallenge;
-	    var key = {
-		version: chlg.version,
-		keyHandle: chlg.keyHandle
-	    };
-	    u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
-		msg.close();
-		if (res.errorCode) {
-		    Proxmox.Utils.authClear();
-		    Ext.Msg.alert(gettext('Error'), PVE.Utils.render_u2f_error(res.errorCode));
-		    return;
-		}
-		delete res.errorCode;
-		me.finish_tfa(JSON.stringify(res));
-	    });
-	},
-	finish_tfa: function(res) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-	    var params = { response: res };
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'POST',
-		timeout: 5000, // it'll delay both success & failure
-		success: function(resp, opts) {
-		    view.el.unmask();
-		    // Fill in what we copy over from the 1st factor:
-		    var data = resp.result.data;
-		    data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-		    data.username = Proxmox.UserName;
-		    // Finish logging in:
-		    me.success(data);
-		},
-		failure: function(resp, opts) {
-		    Proxmox.Utils.authClear();
-		    me.failure(resp);
-		}
-	    });
-	},
-
-	control: {
-	    'field[name=username]': {
-		specialkey: function(f, e) {
-		    if (e.getKey() === e.ENTER) {
-			var pf = this.lookupReference('passwordField');
-			if (!pf.getValue()) {
-			    pf.focus(false);
-			}
-		    }
-		}
-	    },
-	    'field[name=lang]': {
-		change: function(f, value) {
-		    var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-		    Ext.util.Cookies.set('PVELangCookie', value, dt);
-		    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
-		    window.location.reload();
-		}
-	    },
-            'button[reference=loginButton]': {
-		click: 'onLogon'
-            },
-	    '#': {
-		show: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var checkboxField = this.lookupReference('saveunField');
-		    var unField = this.lookupReference('usernameField');
-
-		    var checked = sp.get(checkboxField.getStateId());
-		    checkboxField.setValue(checked);
-
-		    if(checked === true) {
-			var username = sp.get(unField.getStateId());
-			unField.setValue(username);
-			var pwField = this.lookupReference('passwordField');
-			pwField.focus();
-		    }
-		}
-	    }
-	}
-    },
-
-    width: 400,
-
-    modal: true,
-
-    border: false,
-
-    draggable: true,
-
-    closable: false,
-
-    resizable: false,
-
-    layout: 'auto',
-
-    title: gettext('Proxmox VE Login'),
-
-    defaultFocus: 'usernameField',
-
-    defaultButton: 'loginButton',
-
-    items: [{
-	xtype: 'form',
-	layout: 'form',
-	url: '/api2/extjs/access/ticket',
-	reference: 'loginForm',
-
-	fieldDefaults: {
-	    labelAlign: 'right',
-	    allowBlank: false
-	},
-
-	items: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('User name'),
-		name: 'username',
-		itemId: 'usernameField',
-		reference: 'usernameField',
-		stateId: 'login-username'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		fieldLabel: gettext('Password'),
-		name: 'password',
-		reference: 'passwordField'
-	    },
-	    {
-		xtype: 'pveRealmComboBox',
-		name: 'realm'
-	    },
-	    {
-		xtype: 'proxmoxLanguageSelector',
-		fieldLabel: gettext('Language'),
-		value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
-		name: 'lang',
-		reference: 'langField',
-		submitValue: false
-	    }
-	],
-	buttons: [
-	    {
-		xtype: 'checkbox',
-		fieldLabel: gettext('Save User name'),
-		name: 'saveusername',
-		reference: 'saveunField',
-		stateId: 'login-saveusername',
-		labelWidth: 'auto',
-		labelAlign: 'right',
-		submitValue: false
-	    },
-	    {
-		text: gettext('Login'),
-		reference: 'loginButton'
-	    }
-	]
-    }]
- });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	login: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onLogin(me.lookup('otpField').value);
-	    view.close();
-	},
-	cancel: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onCancel();
-	    view.close();
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Please enter your OTP verification code:'),
-	    name: 'otp',
-	    itemId: 'otpField',
-	    reference: 'otpField',
-	    allowBlank: false
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Login'),
-	    reference: 'loginButton',
-	    handler: 'login'
-	},
-	{
-	    text: gettext('Cancel'),
-	    handler: 'cancel'
-	}
-    ]
-});
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-
-    activeTitle: '', // used for automated testing
-
-    width: 700,
-    height: 510,
-
-    modal: true,
-    border: false,
-
-    draggable: true,
-    closable: true,
-    resizable: false,
-
-    layout: 'border',
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var tabs = me.items || [];
-	delete me.items;
-	
-	/* 
-	 * Items may have the following functions:
-	 * validator(): per tab custom validation
-	 * onSubmit(): submit handler
-	 * onGetValues(): overwrite getValues results
-	 */
-
-	Ext.Array.each(tabs, function(tab) {
-	    tab.disabled = true;
-	});
-	tabs[0].disabled = false;
-
-	var maxidx = 0;
-	var curidx = 0;
-
-	var check_card = function(card) {
-	    var valid = true;
-	    var fields = card.query('field, fieldcontainer');
-	    if (card.isXType('fieldcontainer')) {
-		fields.unshift(card);
-	    }
-	    Ext.Array.each(fields, function(field) {
-		// Note: not all fielcontainer have isValid()
-		if (Ext.isFunction(field.isValid) && !field.isValid()) {
-		    valid = false;
-		}
-	    });
-
-	    if (Ext.isFunction(card.validator)) {
-		return card.validator();
-	    }
-
-	    return valid;
-	};
-
-	var disable_at = function(card) {
-	    var tp = me.down('#wizcontent');
-	    var idx = tp.items.indexOf(card);
-	    for(;idx < tp.items.getCount();idx++) {
-		var nc = tp.items.getAt(idx);
-		if (nc) {
-		    nc.disable();
-		}
-	    }
-	};
-
-	var tabchange = function(tp, newcard, oldcard) {
-	    if (newcard.onSubmit) {
-		me.down('#next').setVisible(false);
-		me.down('#submit').setVisible(true); 
-	    } else {
-		me.down('#next').setVisible(true);
-		me.down('#submit').setVisible(false); 
-	    }
-	    var valid = check_card(newcard);
-	    me.down('#next').setDisabled(!valid);    
-	    me.down('#submit').setDisabled(!valid);    
-	    me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-	    var idx = tp.items.indexOf(newcard);
-	    if (idx > maxidx) {
-		maxidx = idx;
-	    }
-	    curidx = idx;
-
-	    var next = idx + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (valid && ntab && !newcard.onSubmit) {
-		ntab.enable();
-	    }
-	};
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, true, false);
-	}
-
-	var sp = Ext.state.Manager.getProvider();
-	var advchecked = sp.get('proxmox-advanced-cb');
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'form',
-		    region: 'center',
-		    layout: 'fit',
-		    border: false,
-		    margins: '5 5 0 5',
-		    fieldDefaults: {
-			labelWidth: 100,
-			anchor: '100%'
-		    },
-		    items: [{
-			itemId: 'wizcontent',
-			xtype: 'tabpanel',
-			activeItem: 0,
-			bodyPadding: 10,
-			listeners: {
-			    afterrender: function(tp) {
-				var atab = this.getActiveTab();
-				tabchange(tp, atab);
-			    },
-			    tabchange: function(tp, newcard, oldcard) {
-				tabchange(tp, newcard, oldcard);
-			    }
-			},
-			items: tabs
-		    }]
-		}
-	    ],
-	    fbar: [
-		{
-		    xtype: 'proxmoxHelpButton',
-		    itemId: 'help'
-		},
-		'->',
-		{
-		    xtype: 'proxmoxcheckbox',
-		    boxLabelAlign: 'before',
-		    boxLabel: gettext('Advanced'),
-		    value: advchecked,
-		    listeners: {
-			change: function(cb, val) {
-			    var tp = me.down('#wizcontent');
-			    tp.query('inputpanel').forEach(function(ip) {
-				ip.setAdvancedVisible(val);
-			    });
-
-			    sp.set('proxmox-advanced-cb', val);
-			}
-		    }
-		},
-		{
-		    text: gettext('Back'),
-		    disabled: true,
-		    itemId: 'back',
-		    minWidth: 60,
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			var prev = tp.items.indexOf(atab) - 1;
-			if (prev < 0) {
-			    return;
-			}
-			var ntab = tp.items.getAt(prev);
-			if (ntab) {
-			    tp.setActiveTab(ntab);
-			}
-		    }
-		},
-		{
-		    text: gettext('Next'),
-		    disabled: true,
-		    itemId: 'next',
-		    minWidth: 60,
-		    handler: function() {
-
-			var form = me.down('form').getForm();
-
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			if (!check_card(atab)) {
-			    return;
-			}
-
-			var next = tp.items.indexOf(atab) + 1;
-			var ntab = tp.items.getAt(next);
-			if (ntab) {
-			    ntab.enable();
-			    tp.setActiveTab(ntab);
-			}
-
-		    }
-		},
-		{
-		    text: gettext('Finish'),
-		    minWidth: 60,
-		    hidden: true,
-		    itemId: 'submit',
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			atab.onSubmit();
-		    }
-		}
-	    ]
-	});
-	me.callParent();
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setAdvancedVisible(advchecked);
-	});
-
-	Ext.Array.each(me.query('field'), function(field) {
-	    var validcheck = function() {
-		var tp = me.down('#wizcontent');
-
-		// check tabs from current to the last enabled for validity
-		// since we might have changed a validity on a later one
-		var i;
-		for (i = curidx; i <= maxidx && i < tp.items.getCount(); i++) {
-		    var tab = tp.items.getAt(i);
-		    var valid = check_card(tab);
-
-		    // only set the buttons on the current panel
-		    if (i === curidx) {
-			me.down('#next').setDisabled(!valid);
-			me.down('#submit').setDisabled(!valid);
-		    }
-
-		    // if a panel is invalid, then disable it and all following,
-		    // else enable it and go to the next
-		    var ntab = tp.items.getAt(i + 1);
-		    if (!valid) {
-			disable_at(ntab);
-			return;
-		    } else if (ntab && !tab.onSubmit) {
-			ntab.enable();
-		    }
-		}
-	    };
-	    field.on('change', validcheck);
-	    field.on('validitychange', validcheck);
-	});
-    }
-});
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    title: gettext('Notes'),
-	    width: 600,
-	    height: '400px',
-	    resizable: true,
-	    layout: 'fit',
-	    defaultButton: undefined,
-	    items: {
-		xtype: 'textarea',
-		name: 'description',
-		height: '100%',
-		value: '',
-		hideLabel: true
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: me.storage,
-	    fieldLabel: gettext('Storage'),
-	    storageContent: 'backup',
-	    allowBlank: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		storagesel,
-		{
-		    xtype: 'pveBackupModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    value: 'snapshot',
-		    name: 'mode'
-		},
-		{
-		    xtype: 'pveCompressionSelector',
-		    name: 'compress',
-		    value: 'lzo',
-		    fieldLabel: gettext('Compression')
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Send email to'),
-		    name: 'mailto',
-		    emptyText: Proxmox.Utils.noneText
-		}
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Backup'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid,
-		    mode: values.mode,
-		    remove: 0
-		};
-
-		if ( values.mailto ) {
-		    params.mailto = values.mailto;
-		}
-
-		if (values.compress) {
-		    params.compress = values.compress;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/vzdump',
-		    params: params,
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			// close later so we reload the grid
-			// after the task has completed
-			me.hide();
-
-			var upid = response.result.data;
-			
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				close: function() {
-				    me.close();
-				}
-			    }
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var helpBtn = Ext.create('Proxmox.button.Help', {
-	    onlineHelp: 'chapter_vzdump',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	});
-
-	var title = gettext('Backup') + " " + 
-	    ((me.vmtype === 'lxc') ? "CT" : "VM") +
-	    " " + me.vmid;
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 350,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ helpBtn, '->', submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: Proxmox.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.volid) {
-	    throw "no volume ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no vmtype specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: '',
-	    fieldLabel: gettext('Storage'),
-	    storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-	    allowBlank: true
-	});
-
-	var IDfield;
-	if (me.vmid) {
-	    IDfield = Ext.create('Ext.form.field.Display', {
-		name: 'vmid',
-		value: me.vmid,
-		fieldLabel: (me.vmtype === 'lxc') ? 'CT' : 'VM'
-	    });
-	} else {
-	    IDfield = Ext.create('PVE.form.GuestIDSelector', {
-		name: 'vmid',
-		guestType: me.vmtype,
-		loadNextFreeID: true,
-		validateExists: false
-	    });
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		value: me.volidText || me.volid,
-		fieldLabel: gettext('Source')
-	    },
-	    storagesel,
-	    IDfield,
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'bwlimit',
-		fieldLabel: gettext('Read Limit (MiB/s)'),
-		minValue: 0,
-		emptyText: gettext('Defaults to target storage restore limit'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext("Use '0' to disable all bandwidth limits.")
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'unique',
-		fieldLabel: gettext('Unique'),
-		hidden: !!me.vmid,
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext('Autogenerate unique properties, e.g., MAC addresses')
-		},
-		checked: false
-	    }
-	];
-
-	/*jslint confusion: true*/
-	if (me.vmtype === 'lxc') {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'unprivileged',
-		value: true,
-		fieldLabel: gettext('Unprivileged container')
-	    });
-	}
-	/*jslint confusion: false*/
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doRestore = function(url, params) {
-	    Proxmox.Utils.API2Request({
-		url: url,
-		params: params,
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.close();
-		}
-	    });
-	};
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Restore'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid || values.vmid,
-		    force: me.vmid ? 1 : 0
-		};
-		if (values.unique) { params.unique = 1; }
-
-		if (values.bwlimit !== undefined) {
-		    params.bwlimit = values.bwlimit * 1024;
-		}
-
-		var url;
-		var msg;
-		if (me.vmtype === 'lxc') {
-		    url = '/nodes/' + me.nodename + '/lxc';
-		    params.ostemplate = me.volid;
-		    params.restore = 1;
-		    if (values.unprivileged) { params.unprivileged = 1; }
-		    msg = Proxmox.Utils.format_task_description('vzrestore', params.vmid);
-		} else if (me.vmtype === 'qemu') {
-		    url = '/nodes/' + me.nodename + '/qemu';
-		    params.archive = me.volid;
-		    msg = Proxmox.Utils.format_task_description('qmrestore', params.vmid);
-		} else {
-		    throw 'unknown VM type';
-		}
-
-		if (me.vmid) {
-		    msg += '. ' + gettext('This will permanently erase current VM data.');
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRestore(url, params);
-		    });
-		} else {
-		    doRestore(url, params);
-		}
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-	var title =  gettext('Restore') + ": " + (
-	    (me.vmtype === 'lxc') ? 'CT' : 'VM');
-
-	if (me.vmid) {
-	    title += " " + me.vmid;
-	}
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 500,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-/* Popup a message window
- * where the user has to manually enter the ressource ID
- * to enable the destroy button
- */
-Ext.define('PVE.window.SafeDestroy', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSafeDestroy',
-
-    title: gettext('Confirm'),
-    modal: true,
-    buttonAlign: 'center',
-    bodyPadding: 10,
-    width: 450,
-    layout: { type:'hbox' },
-    defaultFocus: 'confirmField',
-    showProgress: false,
-
-    config: {
-	item: {
-	    id: undefined,
-	    type: undefined
-	},
-	url: undefined,
-	params: {}
-    },
-
-    getParams: function() {
-	var me = this;
-	if (Ext.Object.isEmpty(me.params)) {
-	    return '';
-	}
-	return '?' + Ext.Object.toQueryString(me.params);
-    },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=confirm]': {
-		change: function(f, value) {
-		    var view = this.getView();
-		    var removeButton = this.lookupReference('removeButton');
-		    if (value === view.getItem().id.toString()) {
-			removeButton.enable();
-		    } else {
-			removeButton.disable();
-		    }
-		},
-		specialkey: function (field, event) {
-		    var removeButton = this.lookupReference('removeButton');
-		    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
-			removeButton.fireEvent('click', removeButton, event);
-		    }
-		}
-	    },
-           'button[reference=removeButton]': {
-		click: function() {
-		    var view = this.getView();
-		    Proxmox.Utils.API2Request({
-			url: view.getUrl() + view.getParams(),
-			method: 'DELETE',
-			waitMsgTarget: view,
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var hasProgressBar = view.showProgress &&
-				response.result.data ? true : false;
-
-			    if (hasProgressBar) {
-				// stay around so we can trigger our close events
-				// when background action is completed
-				view.hide();
-
-				var upid = response.result.data;
-				var win = Ext.create('Proxmox.window.TaskProgress', {
-				    upid: upid,
-				    listeners: {
-					destroy: function () {
-					    view.close();
-					}
-				    }
-				});
-				win.show();
-			    } else {
-				view.close();
-			    }
-			}
-		    });
-		}
-            }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    cls: [ Ext.baseCSSPrefix + 'message-box-icon',
-		   Ext.baseCSSPrefix + 'message-box-warning',
-		   Ext.baseCSSPrefix + 'dlg-icon']
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    xtype: 'component',
-		    reference: 'messageCmp'
-		},
-		{
-		    itemId: 'confirmField',
-		    reference: 'confirmField',
-		    xtype: 'textfield',
-		    name: 'confirm',
-		    labelWidth: 300,
-		    hideTrigger: true,
-		    allowBlank: false
-		}
-	    ]
-	}
-    ],
-    buttons: [
-	{
-	    reference: 'removeButton',
-	    text: gettext('Remove'),
-	    disabled: true
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	var item = me.getItem();
-
-	if (!Ext.isDefined(item.id)) {
-	    throw "no ID specified";
-	}
-
-	if (!Ext.isDefined(item.type)) {
-	    throw "no VM type specified";
-	}
-
-	var messageCmp = me.lookupReference('messageCmp');
-	var msg;
-
-	if (item.type === 'VM') {
-	    msg = Proxmox.Utils.format_task_description('qmdestroy', item.id);
-	} else if (item.type === 'CT') {
-	    msg = Proxmox.Utils.format_task_description('vzdestroy', item.id);
-	} else if (item.type === 'CephPool') {
-	    msg = Proxmox.Utils.format_task_description('cephdestroypool', item.id);
-	} else if (item.type === 'Image') {
-	    msg = Proxmox.Utils.format_task_description('unknownimgdel', item.id);
-	} else {
-	    throw "unknown item type specified";
-	}
-
-	messageCmp.setHtml(msg);
-
-	var confirmField = me.lookupReference('confirmField');
-	msg = gettext('Please enter the ID to confirm') +
-	    ' (' + item.id + ')';
-	confirmField.setFieldLabel(msg);
-    }
-});
-Ext.define('PVE.window.BackupConfig', {
-    extend: 'Ext.window.Window',
-    title: gettext('Configuration'),
-    width: 600,
-    height: 400,
-    layout: 'fit',
-    modal: true,
-    items: {
-	xtype: 'component',
-	itemId: 'configtext',
-	autoScroll: true,
-	style: {
-	    'background-color': 'white',
-	    'white-space': 'pre',
-	    'font-family': 'monospace',
-	    padding: '5px'
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.volume) {
-	    throw "no volume specified";
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + nodename + "/vzdump/extractconfig",
-	    method: 'GET',
-	    params: {
-		volume: me.volume
-	    },
-	    failure: function(response, opts) {
-		me.close();
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response,options) {
-		me.show();
-		me.down('#configtext').update(Ext.htmlEncode(response.result.data));
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.Settings', {
-    extend: 'Ext.window.Window',
-
-    width: '800px',
-    title: gettext('My Settings'),
-    iconCls: 'fa fa-gear',
-    modal: true,
-    bodyPadding: 10,
-    resizable: false,
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    onlineHelp: 'gui_my_settings',
-	    hidden: false
-	},
-	'->',
-	{
-	    text: gettext('Close'),
-	    handler: function() {
-		this.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    var me = this;
-	    var sp = Ext.state.Manager.getProvider();
-
-	    var username = sp.get('login-username') || Proxmox.Utils.noneText;
-	    me.lookupReference('savedUserName').setValue(username);
-
-	    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-	    settings.forEach(function(setting) {
-		var val = localStorage.getItem('pve-xterm-' + setting);
-		if (val !== undefined && val !== null) {
-		    var field = me.lookup(setting);
-		    field.setValue(val);
-		    field.resetOriginalValue();
-		}
-	    });
-	},
-
-	set_button_status: function() {
-	    var me = this;
-
-	    var form = me.lookup('xtermform');
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-
-	    var hasvalues = false;
-	    var values = form.getValues();
-	    Ext.Object.eachValue(values, function(value) {
-		if (value) {
-		    hasvalues = true;
-		    return false;
-		}
-	    });
-
-	    me.lookup('xtermsave').setDisabled(!dirty || !valid);
-	    me.lookup('xtermreset').setDisabled(!hasvalues);
-	},
-
-	control: {
-	    '#xtermjs form': {
-		dirtychange: 'set_button_status',
-		validitychange: 'set_button_status'
-	    },
-	    '#xtermjs button': {
-		click: function(button) {
-		    var me = this;
-		    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-		    settings.forEach(function(setting) {
-			var field = me.lookup(setting);
-			if (button.reference === 'xtermsave') {
-			    var value = field.getValue();
-			    if (value) {
-				localStorage.setItem('pve-xterm-' + setting, value);
-			    } else {
-				localStorage.removeItem('pve-xterm-' + setting);
-			    }
-			} else if (button.reference === 'xtermreset') {
-			    field.setValue(undefined);
-			    localStorage.removeItem('pve-xterm-' + setting);
-			}
-			field.resetOriginalValue();
-		    });
-		    me.set_button_status();
-		}
-	    },
-	    'button[name=reset]': {
-		click: function () {
-		    var blacklist = ['GuiCap', 'login-username', 'dash-storages'];
-		    var sp = Ext.state.Manager.getProvider();
-		    var state;
-		    for (state in sp.state) {
-			if (sp.state.hasOwnProperty(state)) {
-			    if (blacklist.indexOf(state) !== -1) {
-				continue;
-			    }
-
-			    sp.clear(state);
-			}
-		    }
-
-		    window.location.reload();
-		}
-	    },
-	    'button[name=clear-username]': {
-		click: function () {
-		    var me = this;
-		    var usernamefield = me.lookupReference('savedUserName');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    usernamefield.setValue(Proxmox.Utils.noneText);
-		    sp.clear('login-username');
-		}
-	    },
-	    'grid[reference=dashboard-storages]': {
-		selectionchange: function(grid, selected) {
-		    var me = this;
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // saves the selected storageids as
-		    // "id1,id2,id3,..."
-		    // or clears the variable
-		    if (selected.length > 0) {
-			sp.set('dash-storages',
-			    Ext.Array.pluck(selected, 'id').join(','));
-		    } else {
-			sp.clear('dash-storages');
-		    }
-		},
-		afterrender: function(grid) {
-		    var me = grid;
-		    var sp = Ext.state.Manager.getProvider();
-		    var store = me.getStore();
-		    var items = [];
-		    me.suspendEvent('selectionchange');
-		    var storages = sp.get('dash-storages') || '';
-		    storages.split(',').forEach(function(storage){
-			// we have to get the records
-			// to be able to select them
-			if (storage !== '') {
-			    var item = store.getById(storage);
-			    if (item) {
-				items.push(item);
-			    }
-			}
-		    });
-		    me.getSelectionModel().select(items);
-		    me.resumeEvent('selectionchange');
-		}
-	    }
-	}
-    },
-
-    items: [{
-	    xtype: 'fieldset',
-	    width: '50%',
-	    title: gettext('Webinterface Settings'),
-	    margin: '5',
-	    layout: {
-		type: 'vbox',
-		align: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Dashboard Storages'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'grid',
-		    maxHeight: 150,
-		    reference: 'dashboard-storages',
-		    selModel: {
-			selType: 'checkboxmodel'
-		    },
-		    columns: [{
-			header: gettext('Name'),
-			dataIndex: 'storage',
-			flex: 1
-		    },{
-			header: gettext('Node'),
-			dataIndex: 'node',
-			flex: 1
-		    }],
-		    store: {
-			type: 'diff',
-			field: ['type', 'storage', 'id', 'node'],
-			rstore: PVE.data.ResourceStore,
-			filters: [{
-			    property: 'type',
-			    value: 'storage'
-			}],
-			sorters: [ 'node','storage']
-		    }
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Saved User name'),
-		    labelAlign: 'left',
-		    labelWidth: '50%',
-		    stateId: 'login-username',
-		    reference: 'savedUserName',
-		    value: ''
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Clear User name'),
-		    width: 'auto',
-		    name: 'clear-username'
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Layout'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Reset Layout'),
-		    width: 'auto',
-		    name: 'reset'
-		}
-	    ]
-    },{
-	xtype: 'fieldset',
-	itemId: 'xtermjs',
-	width: '50%',
-	margin: '5',
-	title: gettext('xterm.js Settings'),
-	items: [{
-	    xtype: 'form',
-	    reference: 'xtermform',
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		algin: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'textfield',
-		    name: 'fontFamily',
-		    reference: 'fontFamily',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Font-Family')
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    emptyText: Proxmox.Utils.defaultText,
-		    name: 'fontSize',
-		    reference: 'fontSize',
-		    minValue: 1,
-		    fieldLabel: gettext('Font-Size')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'letterSpacing',
-		    reference: 'letterSpacing',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Letter Spacing')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'lineHeight',
-		    minValue: 0.1,
-		    reference: 'lineHeight',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Line Height')
-		},
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'hbox',
-			pack: 'end'
-		    },
-		    items: [
-			{
-			    xtype: 'button',
-			    reference: 'xtermreset',
-			    disabled: true,
-			    text: gettext('Reset')
-			},
-			{
-			    xtype: 'button',
-			    reference: 'xtermsave',
-			    disabled: true,
-			    text: gettext('Save')
-			}
-		    ]
-		}
-	    ]
-	}]
-    }],
-
-    onShow: function() {
-	var me = this;
-	me.callParent();
-    }
-});
-Ext.define('PVE.panel.StartupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'qm_startup_and_shutdown',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = PVE.Parser.printStartup(values);
-
-	if (res === undefined || res === '') {
-	    return { 'delete': 'startup' };
-	}
-
-	return { startup: res };
-    },
-
-    setStartup: function(value) {
-	var me = this;
-
-	var startup = PVE.Parser.parseStartup(value);
-	if (startup) {
-	    me.setValues(startup);
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		name: 'order',
-		defaultValue: '',
-		emptyText: 'any',
-		fieldLabel: gettext('Start/Shutdown order')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'up',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Startup delay')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'down',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Shutdown timeout')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.window.StartupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveWindowStartupEdit',
-    onlineHelp: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-	var ipanelConfig = me.onlineHelp ? {onlineHelp: me.onlineHelp} : {};
-	var ipanel = Ext.create('PVE.panel.StartupInputPanel', ipanelConfig);
-
-	Ext.applyIf(me, {
-	    subject: gettext('Start/Shutdown order'),
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		ipanel.setStartup(me.vmconfig.startup);		    
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.Install', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveCephInstallWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 220,
-    header: false,
-    resizable: false,
-    draggable: false,
-    modal: true,
-    nodename: undefined,
-    shadow: false,
-    border: false,
-    bodyBorder: false,
-    closable: false,
-    cls: 'install-mask',
-    bodyCls: 'install-mask',
-    layout: {
-        align: 'stretch',
-        pack: 'center',
-	type: 'vbox'
-    },
-    viewModel: {
-	data: {
-	      cephVersion: 'luminous',
-	      isInstalled: false
-	},
-	formulas: {
-	    buttonText: function (get){
-		if (get('isInstalled')) {
-		    return gettext('Configure Ceph');
-		} else {
-		    return gettext('Install Ceph-') + get('cephVersion');
-		}
-	    },
-	    windowText: function (get) {
-		if (get('isInstalled')) {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not initialized.'), 'Ceph') + ' '+
-		    gettext('You need to create a initial config once.') + '</p>';
-		} else {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '<br>' +
-		    gettext('Would you like to install it now?') + '</p>';
-		}
-	    }
-	}
-    },
-    items: [
-	{
-	    bind: {
-		html: '{windowText}'
-	    },
-	    border: false,
-	    padding: 5,
-	    bodyCls: 'install-mask'
-
-	},
-	{
-	    xtype: 'button',
-	    bind: {
-		text: '{buttonText}'
-	    },
-	    viewModel: {},
-	    cbind: {
-		nodename: '{nodename}'
-	    },
-	    handler: function() {
-		var me = this.up('pveCephInstallWindow');
-		var win = Ext.create('PVE.ceph.CephInstallWizard',{
-		    nodename: me.nodename
-		});
-		win.getViewModel().set('isInstalled', this.getViewModel().get('isInstalled'));
-		win.show();
-		me.mon(win,'beforeClose', function(){
-		    me.fireEvent("cephInstallWindowClosed");
-		    me.close();
-		});
-
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallEnableEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveFirewallEnableEdit'],
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    subject: gettext('Firewall'),
-    cbindData: {
-	defaultValue: 0
-    },
-    width: 350,
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    uncheckedValue: 0,
-	    cbind: {
-		defaultValue: '{defaultValue}',
-		checked: '{defaultValue}'
-	    },
-	    deleteDefaultValue: false,
-	    fieldLabel: gettext('Firewall')
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'warning',
-	    userCls: 'pve-hint',
-	    value: gettext('Warning: Firewall still disabled at datacenter level!'),
-	    hidden: true
-	}
-    ],
-
-    beforeShow: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/cluster/firewall/options',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		if (!response.result.data.enable) {
-		    me.down('displayfield[name=warning]').setVisible(true);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallLograteInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveFirewallLograteInputPanel',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    reference: 'enable',
-	    fieldLabel: gettext('Enable'),
-	    value: false
-	},
-	{
-	    layout: 'hbox',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'numberfield',
-		    name: 'rate',
-		    fieldLabel: gettext('Log rate limit'),
-		    minValue: 1,
-		    maxValue: 99,
-		    allowBlank: false,
-		    flex: 2,
-		    value: 1
-		},
-		{
-		    html: '<div style="margin: auto; padding: 2.5px;"><b>/</b></div>'
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    name: 'unit',
-		    comboItems: [['second', 'second'], ['minute', 'minute'],
-			['hour', 'hour'], ['day', 'day']],
-		    allowBlank: false,
-		    flex: 1,
-		    value: 'second'
-		}
-	    ]
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'burst',
-	    fieldLabel: gettext('Log burst limit'),
-	    minValue: 1,
-	    maxValue: 99,
-	    value: 5
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var vals = {};
-	vals.enable = values.enable !== undefined ? 1 : 0;
-	vals.rate = values.rate + '/' + values.unit;
-	vals.burst = values.burst;
-	var properties = PVE.Parser.printPropertyString(vals, undefined);
-	if (properties == '') {
-	    return { 'delete': 'log_ratelimit' };
-	}
-	return { log_ratelimit: properties };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var properties = {};
-	if (values.log_ratelimit !== undefined) {
-	    properties = PVE.Parser.parsePropertyString(values.log_ratelimit);
-	    var matches = properties.rate.match(/^(\d+)\/(second|minute|hour|day)$/);
-	    if (matches) {
-		properties.rate = matches[1];
-		properties.unit = matches[2];
-	    }
-	}
-	me.callParent([properties]);
-    }
-});
-
-Ext.define('PVE.FirewallLograteEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveFirewallLograteEdit',
-
-    subject: gettext('Log rate limit'),
-
-    items: [{
-	xtype: 'pveFirewallLograteInputPanel'
-    }],
-    autoLoad: true
-});
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNotesView',
-
-    title: gettext("Notes"),
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 10,
-    scrollable: true,
-
-    tbar: {
-	itemId: 'tbar',
-	hidden: true,
-	items: [
-	    {
-		text: gettext('Edit'),
-		handler: function() {
-		    var me = this.up('panel');
-		    me.run_editor();
-		}
-	    }
-	]
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create('PVE.window.NotesEdit', {
-	    pveSelNode: me.pveSelNode,
-	    url: me.url
-	});
-	win.show();
-	win.on('destroy', me.load, me);
-    },
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data.description || '';
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    listeners: {
-	render: function(c) {
-	    var me = this;
-	    me.getEl().on('dblclick', me.run_editor, me);
-	}
-    },
-
-    tools: [{
-	type: 'gear',
-	handler: function() {
-	    var me = this.up('panel');
-	    me.run_editor();
-	}
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	if (!Ext.Array.contains(['node', 'qemu', 'lxc'], type)) {
-	    throw 'invalid type specified';
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid && type !== 'node') {
-	    throw "no VM ID specified";
-	}
-
-	me.url = '/api2/extjs/nodes/' + nodename + '/';
-
-	// add the type specific path if qemu/lxc
-	if (type === 'qemu' || type === 'lxc') {
-	    me.url += type + '/' + vmid + '/';
-	}
-
-	me.url += 'config';
-
-	me.callParent();
-	if (type === 'node') {
-	    me.down('#tbar').setVisible(true);
-	}
-	me.load();
-    }
-});
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    border: false,
-    defaultSorter: {
-	property: 'type',
-	direction: 'ASC'
-    },
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	var coldef = rstore.defaultColumns();
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: me.defaultSorter,
-	    proxy: { type: 'memory' }
-	});
-
-	var textfilter = '';
-
-	var textfilter_match = function(item) {
-	    var match = false;
-	    Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-		var v = item.data[field];
-		if (v !== undefined) {
-		    v = v.toLowerCase();
-		    if (v.indexOf(textfilter) >= 0) {
-			match = true;
-			return false;
-		    }
-		}
-	    });
-	    return match;
-	};
-
-	var updateGrid = function() {
-
-	    var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-	    
-	    //console.log("START GRID UPDATE " +  me.viewFilter);
-
-	    store.suspendEvents();
-
-	    var nodeidx = {};
-	    var gather_child_nodes = function(cn) {
-		if (!cn) {
-		    return;
-		}
-                var cs = cn.childNodes;
-		if (!cs) {
-		    return;
-		}
-		var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-		    var child = cs[i];
-		    var orgnode = rstore.data.get(child.data.id);
-		    if (orgnode) {
-			if ((!filterfn || filterfn(child)) &&
-			    (!textfilter || textfilter_match(child))) {
-			    nodeidx[child.data.id] = orgnode;
-			}
-		    }
-		    gather_child_nodes(child);
-		}
-	    };
-	    gather_child_nodes(me.pveSelNode);
-
-	    // remove vanished items
-	    var rmlist = [];
-	    store.each(function(olditem) {
-		var item = nodeidx[olditem.data.id];
-		if (!item) {
-		    //console.log("GRID REM UID: " + olditem.data.id);
-		    rmlist.push(olditem);
-		}
-	    });
-
-	    if (rmlist.length) {
-		store.remove(rmlist);
-	    }
-
-	    // add new items
-	    var addlist = [];
-	    var key;
-	    for (key in nodeidx) {
-		if (nodeidx.hasOwnProperty(key)) {
-		    var item = nodeidx[key];
-		
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var olditem = store.getById(item.data.id);
-		    var olditem = store.data.get(item.data.id);
-
-		    if (!olditem) {
-			//console.log("GRID ADD UID: " + item.data.id);
-			var info = Ext.apply({}, item.data);
-			var child = Ext.create(store.model, info);
-			addlist.push(item);
-			continue;
-		    }
-		    // try to detect changes
-		    var changes = false;
-		    var fieldkeys = PVE.data.ResourceStore.fieldNames;
-		    var fieldcount = fieldkeys.length;
-		    var fieldind;
-		    for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-			var field = fieldkeys[fieldind];
-			if (field != 'id' && item.data[field] != olditem.data[field]) {
-			    changes = true;
-			    //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-			    olditem.beginEdit();
-			    olditem.set(field, item.data[field]);
-			}
-		    }
-		    if (changes) {
-			olditem.endEdit(true);
-			olditem.commit(true); 
-		    }
-		}
-	    }
-
-	    if (addlist.length) {
-		store.add(addlist);
-	    }
-
-	    store.sort();
-
-	    store.resumeEvents();
-
-	    store.fireEvent('refresh', store);
-
-	    //console.log("END GRID UPDATE");
-	};
-
-	var filter_task = new Ext.util.DelayedTask(function(){
-	    updateGrid();
-	});
-
-	var load_cb = function() { 
-	    updateGrid(); 
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-resource',
-	    tbar: [
-		'->', 
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: textfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    var v = field.getValue();
-			    textfilter = v.toLowerCase();
-			    filter_task.delay(500);
-			}
-		    }
-		}
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		destroy: function() {
-		    rstore.un("load", load_cb);
-		}
-	    },
-            columns: coldef
-	});
-	me.callParent();
-	updateGrid();
-	rstore.on("load", load_cb);
-    }
-});
-Ext.define('PVE.pool.AddVM', {
-    extend: 'Proxmox.window.Edit',
-    width: 600,
-    height: 400,
-    isAdd: true,
-    isCreate: true,
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	var vmsField = Ext.create('Ext.form.field.Text', {
-	    name: 'vms',
-	    hidden: true,
-	    allowBlank: false
-	});
-
-	var vmStore = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property: 'vmid',
-		    order: 'ASC'
-		}
-	    ],
-	    filters: [
-		function(item) {
-		    return ((item.data.type === 'lxc' || item.data.type === 'qemu') && item.data.pool === '');
-		}
-	    ]
-	});
-
-	var vmGrid = Ext.create('widget.grid',{
-	    store: vmStore,
-	    border: true,
-	    height: 300,
-	    scrollable: true,
-	    selModel: {
-		selType: 'checkboxmodel',
-		mode: 'SIMPLE',
-		listeners: {
-		    selectionchange: function(model, selected, opts) {
-			var selectedVms = [];
-			selected.forEach(function(vm) {
-			    selectedVms.push(vm.data.vmid);
-			});
-			vmsField.setValue(selectedVms);
-		    }
-		}
-	    },
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-	Ext.apply(me, {
-	    subject: gettext('Virtual Machine'),
-	    items: [ vmsField, vmGrid ]
-	});
-
-	me.callParent();
-	vmStore.load();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.isCreate = true;
-	me.isAdd = true;
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	Ext.apply(me, {
-	    subject: gettext('Storage'),
-	    width: 350,
-	    items: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'storage',
-		    nodename: 'localhost',
-		    autoSelect: false,
-		    value:  '',
-		    fieldLabel: gettext("Storage")
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    stateful: true,
-    stateId: 'grid-pool-members',
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property : 'type',
-		    direction: 'ASC'
-		}
-	    ],
-	    proxy: {
-		type: 'proxmox',
-		root: 'data.members',
-		url: "/api2/json/pools/" + me.pool
-	    }
-	});
-
-	var coldef = PVE.data.ResourceStore.defaultColumns();
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		var params = { 'delete': 1 };
-		if (rec.data.type === 'storage') {
-		    params.storage = rec.data.storage;
-		} else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-		    params.vms = rec.data.vmid;
-		} else {
-		    throw "unknown resource type";
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/pools/' + me.pool,
-		    method: 'PUT',
-		    params: params,
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Virtual Machine'),
-				iconCls: 'pve-itype-icon-qemu',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Storage'),
-				iconCls: 'pve-itype-icon-storage',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-            columns: coldef,
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-    allowBlank: true,
-    autoSelect: false,
-    valueField: 'macro',
-    displayField: 'macro',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Description'),
-		renderer: Ext.String.htmlEncode,
-		flex: 1,
-		dataIndex: 'descr'
-	    }
-	]
-    },
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'macro', 'descr' ],
-	    idProperty: 'macro',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/macros"
-	    },
-	    sorters: {
-		property: 'macro',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	// hack: editable ComboGrid returns nothing when empty, so we need to set ''
-	// Also, disabled text fields return nothing, so we need to set ''
-
-	Ext.Array.each(['source', 'dest', 'macro', 'proto', 'sport', 'dport', 'log'], function(key) {
-	    if (values[key] === undefined) {
-		values[key] = '';
-	    }
-	});
-
-	delete values.modified_marker;
- 
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.column1 = [
-	    {
-		// hack: we use this field to mark the form 'dirty' when the
-		// record has errors- so that the user can safe the unmodified 
-		// form again.
-		xtype: 'hiddenfield',
-		name: 'modified_marker',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'type',
-		value: 'in',
-		comboItems: [['in', 'in'], ['out', 'out']],
-		fieldLabel: gettext('Direction'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'action',
-		value: 'ACCEPT',
-		comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-		fieldLabel: gettext('Action'),
-		allowBlank: false
-	    }
-        ];
-
-	if (me.allow_iface) {
-	    me.column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		fieldLabel: '',
-		value: ''
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'source',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Source')
-
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'dest',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Destination')
-	    }
-	);
-
-	
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    },
-	    {
-		xtype: 'pveFWMacroSelector',
-		name: 'macro',
-		fieldLabel: gettext('Macro'),
-		editable: true,
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-                        if (value === null) {
-			    me.down('field[name=proto]').setDisabled(false);
-			    me.down('field[name=sport]').setDisabled(false);
-			    me.down('field[name=dport]').setDisabled(false);
-                        } else {
-			    me.down('field[name=proto]').setDisabled(true);
-			    me.down('field[name=proto]').setValue('');
-			    me.down('field[name=sport]').setDisabled(true);
-			    me.down('field[name=sport]').setValue('');
-			    me.down('field[name=dport]').setDisabled(true);
-			    me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-	    },
-	    {
-		xtype: 'pveIPProtocolSelector',
-		name: 'proto',
-		autoSelect: false,
-		editable: true,
-		value: '',
-		fieldLabel: gettext('Protocol')
-	    },
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'sport',
-		value: '',
-		fieldLabel: gettext('Source port')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'dport',
-		value: '',
-		fieldLabel: gettext('Dest. port')
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'pveFirewallLogLevels'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.FirewallRulePanel', {
-	    isCreate: me.isCreate,
-	    list_refs_url: me.list_refs_url,
-	    allow_iface: me.allow_iface,
-	    rule_pos: me.rule_pos
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		    if (values.errors) {
-			var field = me.query('[isFormField][name=modified_marker]')[0];
-			field.setValue(1);
-			Ext.Function.defer(function() {
-			    var form = ipanel.up('form').getForm();
-			    form.markInvalid(values.errors);
-			}, 100);
-		    }
-		}
-	    });
-	} else if (me.rec) {
-	    ipanel.setValues(me.rec.data);
-	}
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: 'group'
-	    },
-	    {
-		xtype: 'pveSecurityGroupsSelector',
-		name: 'action',
-		value: '',
-		fieldLabel: gettext('Security Group'),
-		allowBlank: false
-	    }
-	];
-
-	if (me.allow_iface) {
-	    column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'enable',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: gettext('Enable')
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    onlineHelp: 'chapter_pve_firewall',
-
-    stateful: true,
-    stateId: 'grid-firewall-rules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(true);
-	    }
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(false);
-	    }
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + "/" + from,
-	    method: 'PUT',
-	    params: { moveto: to },
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	rule.enable = rule.enable ? 1 : 0;
-
-	var pos = rule.pos;
-	delete rule.pos;
-	delete rule.errors;
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + '/' + pos.toString(),
-	    method: 'PUT',
-	    params: rule,
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-fw-rule'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-	    var editor;
-	    if (type === 'in' || type === 'out') {
-		editor = 'PVE.FirewallRuleEdit';
-	    } else if (type === 'group') {
-		editor = 'PVE.FirewallGroupRuleEdit';
-	    } else {
-		return;
-	    }
-
-	    var win = Ext.create(editor, {
-		digest: rec.data.digest,
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rule_pos: rec.data.pos
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallRuleEdit', {
-		    allow_iface: me.allow_iface,
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var run_copy_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-
-	    if (!(type === 'in' || type === 'out')) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallRuleEdit', {
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rec: rec
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.copyBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Copy'),
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return (rec.data.type === 'in' || rec.data.type === 'out');
-	    },
-	    disabled: true,
-	    handler: run_copy_editor
-	});
-
-	if (me.allow_groups) {
-	    me.groupBtn =  Ext.create('Ext.Button', {
-		text: gettext('Insert') + ': ' + 
-		    gettext('Security Group'),
-		disabled: true,
-		handler: function() {
-		    var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-			allow_iface: me.allow_iface,
-			base_url: me.base_url
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    confirmMsg: false,
-	    getRecordName: function(rec) {
-		var rule = rec.data;
-		return rule.pos.toString() +
-		    '?digest=' + encodeURIComponent(rule.digest);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-
-	var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-	tbar.push(me.addBtn, me.copyBtn);
-	if (me.groupBtn) {
-	    tbar.push(me.groupBtn);
-	}
-	tbar.push(me.removeBtn, me.editBtn);
-
-	var render_errors = function(name, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors && errors[name]) {
-		metaData.tdCls = 'proxmox-invalid-row';
-		var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-		metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-		    html.replace(/\"/g,'&quot;') + '"';
-	    }
-	    return value;
-	};
-
-	var columns = [
-	    {
-		// similar to xtype: 'rownumberer',
-		dataIndex: 'pos',
-		resizable: false,
-		width: 23,
-		sortable: false,
-		align: 'right',
-		hideable: false,
-		menuDisabled: true,
-		renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-		    metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-		    if (value >= 0) {
-			return value;
-		    }
-		    return '';
-		}
-	    },
-	    {
-		xtype: 'checkcolumn',
-		header: gettext('Enable'),
-		dataIndex: 'enable',
-		listeners: {
-		    checkchange: function(column, recordIndex, checked) {
-			var record = me.getStore().getData().items[recordIndex];
-			record.commit();
-			var data = {};
-			Ext.Array.forEach(record.getFields(), function(field) {
-			    data[field.name] = record.get(field.name);
-			});
-			if (!me.allow_iface || !data.iface) {
-			    delete data.iface;
-			}
-			me.updateRule(data);
-		    }
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		renderer: function(value, metaData, record) {
-		    return render_errors('type', value, metaData, record);
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Action'),
-		dataIndex: 'action',
-		renderer: function(value, metaData, record) {
-		    return render_errors('action', value, metaData, record);
-		},
-		width: 80
-	    },
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		renderer: function(value, metaData, record) {
-		    return render_errors('macro', value, metaData, record);
-		},
-		width: 80
-	    }
-	];
-
-	if (me.allow_iface) {
-	    columns.push({
-		header: gettext('Interface'),
-		dataIndex: 'iface',
-		renderer: function(value, metaData, record) {
-		    return render_errors('iface', value, metaData, record);
-		},
-		width: 80
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Source'),
-		dataIndex: 'source',
-		renderer: function(value, metaData, record) {
-		    return render_errors('source', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Destination'),
-		dataIndex: 'dest',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dest', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'proto',
-		renderer: function(value, metaData, record) {
-		    return render_errors('proto', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Dest. port'),
-		dataIndex: 'dport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Source port'),
-		dataIndex: 'sport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('sport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Log level'),
-		dataIndex: 'log',
-		renderer: function(value, metaData, record) {
-		    return render_errors('log', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comment',
-		flex: 1,
-		renderer: function(value, metaData, record) {
-		    return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-		}
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-            viewConfig: {
-		plugins: [
-		    {
-			ptype: 'gridviewdragdrop',
-			dragGroup: 'FWRuleDDGroup',
-			dropGroup: 'FWRuleDDGroup'
-		    }
-		],
-		listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-			if (!dropRec) {
-			    return false; // empty view
-			}
-			var moveto = dropRec.get('pos');
-			if (dropPosition === 'after') {
-			    moveto++;
-			}
-			var pos = data.records[0].get('pos');
-			me.moveRule(pos, moveto);
-			return 0;
-                    },
-		    itemdblclick: run_editor
-		}
-	    },
-	    sortableColumns: false,
-	    columns: columns
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'enable', type: 'boolean' },
-		  'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-		  'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-	idProperty: 'pos'
-    });
-
-});
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    
-    alias_name: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.alias_name === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-            me.method = 'PUT';
-        }
-
-	var items =  [
-	    {
-		xtype: 'textfield',
-		name: me.isCreate ? 'name' : 'rename',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'cidr',
-		fieldLabel: gettext('IP/CIDR'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    items: items
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Alias'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    values.rename = values.name;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('pve-fw-aliases', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'name', 'cidr', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    onlineHelp: 'pve_firewall_ip_aliases',
-
-    stateful: true,
-    stateId: 'grid-firewall-aliases',
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-aliases',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallAliasEdit', {
-		base_url: me.base_url,
-		alias_name: rec.data.name
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallAliasEdit', {
-		    base_url: me.base_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Name'), dataIndex: 'name', width: 100 },
-		{ header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-	me.on('activate', reload);
-    }
-});
-Ext.define('PVE.FirewallOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-	    if (me.fwtype === 'node') {
-		me.cwidth1 = 250;
-	    }
-	} else {
-	    throw "unknown firewall option type";
-	}
-
-	me.rows = {};
-
-	var add_boolean_row = function(name, text, defaultValue) {
-	    me.add_boolean_row(name, text, { defaultValue: defaultValue });
-	};
-	var add_integer_row = function(name, text, minValue, labelWidth) {
-	    me.add_integer_row(name, text, {
-		minValue: minValue,
-		deleteEmpty: true,
-		labelWidth: labelWidth,
-		renderer: function(value) {
-		    if (value === undefined) {
-			return Proxmox.Utils.defaultText;
-		    }
-
-		    return value;
-		}
-	    });
-	};
-
-	var add_log_row = function(name, labelWidth) {
-	    me.rows[name] = {
-		header: name,
-		required: true,
-		defaultValue: 'nolog',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: name,
-		    fieldDefaults: { labelWidth: labelWidth || 100 },
-		    items: {
-			xtype: 'pveFirewallLogLevels',
-			name: name,
-			fieldLabel: name
-		    }
-		}
-	    };
-	};
-
-	if (me.fwtype === 'node') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 1,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 1
-		}
-	    };
-	    add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-	    add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 32768, 120);
-	    add_integer_row('nf_conntrack_tcp_timeout_established',
-			    'nf_conntrack_tcp_timeout_established', 7875, 250);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	    add_log_row('tcp_flags_log_level', 120);
-	    add_log_row('smurf_log_level');
-	} else if (me.fwtype === 'vm') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 0,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 0
-		}
-	    };
-	    add_boolean_row('dhcp', 'DHCP', 1);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_boolean_row('radv', gettext('Router Advertisement'), 0);
-	    add_boolean_row('macfilter', gettext('MAC filter'), 1);
-	    add_boolean_row('ipfilter', gettext('IP filter'), 0);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	} else if (me.fwtype === 'dc') {
-	    add_boolean_row('enable', gettext('Firewall'), 0);
-	    add_boolean_row('ebtables', 'ebtables', 1);
-	    me.rows.log_ratelimit = {
-		header: gettext('Log rate limit'),
-		required: true,
-		defaultValue: 'enable=0',
-		editor: {
-		    xtype: 'pveFirewallLograteEdit'
-		}
-	    };
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-	    me.rows.policy_in = {
-		header: gettext('Input Policy'),
-		required: true,
-		defaultValue: 'DROP',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Input Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_in',
-			value: 'DROP',
-			fieldLabel: gettext('Input Policy')
-		    }
-		}
-	    };
-
-	    me.rows.policy_out = {
-		header: gettext('Output Policy'),
-		required: true,
-		defaultValue: 'ACCEPT',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Output Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_out',
-			value: 'ACCEPT',
-			fieldLabel: gettext('Output Policy')
-		    }
-		}
-	    };
-	}
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = me.rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json" + me.base_url,
-	    tbar: [ edit_btn ],
-	    editorConfig: {
-		url: '/api2/extjs/' + me.base_url
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-
-
-Ext.define('PVE.FirewallLogLevels', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallLogLevels'],
-
-    name: 'log',
-    fieldLabel: gettext('Log level'),
-    value: 'nolog',
-    comboItems: [['nolog', 'nolog'], ['emerg', 'emerg'], ['alert', 'alert'],
-	['crit', 'crit'], ['err', 'err'], ['warning', 'warning'],
-	['notice', 'notice'], ['info', 'info'], ['debug', 'debug']]
-});
-/*
- * Left Treepanel, containing all the ressources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-	typeDefaults: {
-	    node: { 
-		iconCls: 'fa fa-building',
-		text: gettext('Nodes')
-	    },
-	    pool: { 
-		iconCls: 'fa fa-tags',
-		text: gettext('Resource Pool')
-	    },
-	    storage: {
-		iconCls: 'fa fa-database',
-		text: gettext('Storage')
-	    },
-	    qemu: {
-		iconCls: 'fa fa-desktop',
-		text: gettext('Virtual Machine')
-	    },
-	    lxc: {
-		//iconCls: 'x-tree-node-lxc',
-		iconCls: 'fa fa-cube',
-		text: gettext('LXC Container')
-	    },
-	    template: {
-		iconCls: 'fa fa-file-o'
-	    }
-	}
-    },
-
-    useArrows: true,
-
-    // private
-    nodeSortFn: function(node1, node2) {
-	var n1 = node1.data;
-	var n2 = node2.data;
-
-	if ((n1.groupbyid && n2.groupbyid) ||
-	    !(n1.groupbyid || n2.groupbyid)) {
-
-	    var tcmp;
-
-	    var v1 = n1.type;
-	    var v2 = n2.type;
-
-	    if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		return tcmp;
-	    }
-
-	    // numeric compare for VM IDs
-	    // sort templates after regular VMs
-	    if (v1 === 'qemu' || v1 === 'lxc') {
-		if (n1.template && !n2.template) {
-		    return 1;
-		} else if (n2.template && !n1.template) {
-		    return -1;
-		}
-		v1 = n1.vmid;
-		v2 = n2.vmid;
-		if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		    return tcmp;
-		}
-	    }
-
-	    return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
-	} else if (n1.groupbyid) {
-	    return -1;
-	} else if (n2.groupbyid) {
-	    return 1;
-	}
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-	var me = this;
-
-	var diff = end - start;
-
-	var mid = start + (diff>>1);
-
-	if (diff <= 0) {
-	    return start;
-	}
-
-	var res = me.nodeSortFn(child, node.childNodes[mid]);
-	if (res <= 0) {
-	    return me.findInsertIndex(node, child, start, mid);
-	} else {
-	    return me.findInsertIndex(node, child, mid + 1, end);
-	}
-    },
-
-    setIconCls: function(info) {
-	var me = this;
-
-	var cls = PVE.Utils.get_object_icon_class(info.type, info);
-
-	if (cls !== '') {
-	    info.iconCls = cls;
-	}
-    },
-
-    // add additional elements to text
-    // at the moment only the usage indicator for storages
-    setText: function(info) {
-	var me = this;
-
-	var status = '';
-	if (info.type === 'storage') {
-	    var maxdisk = info.maxdisk;
-	    var disk = info.disk;
-	    var usage = disk/maxdisk;
-	    var cls = '';
-	    if (usage <= 1.0 && usage >= 0.0) {
-		var height = (usage*100).toFixed(0);
-		var neg_height = (100-usage*100).toFixed(0);
-		status = '<div class="usage-wrapper">';
-		status += '<div class="usage-negative" style="height: ';
-		status += neg_height + '%"></div>';
-		status += '<div class="usage" style="height: '+ height +'%"></div>';
-		status += '</div> ';
-	    }
-	}
-
-	info.text = status + info.text;
-    },
-
-    setToolTip: function(info) {
-	if (info.type === 'pool' || info.groupbyid !== undefined) {
-	    return;
-	}
-
-	var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
-	if (info.hastate != 'unmanaged') {
-	    qtips.push(gettext('HA State') + ": " + info.hastate);
-	}
-
-	info.qtip = qtips.join(', ');
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-	var me = this;
-
-	me.setIconCls(info);
-	me.setText(info);
-	me.setToolTip(info);
-
-	var defaults;
-	if (info.groupbyid) {
-	    info.text = info.groupbyid;
-	    if (info.type === 'type') {
-		defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-		if (defaults && defaults.text) {
-		    info.text = defaults.text;
-		}
-	    }
-	}
-	var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-	var pos;
-	if (cs) {
-	    pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-	}
-
-	node.insertBefore(child, pos);
-
-	return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-	var me = this;
-
-	var groupby = groups[level];
-	var v = info[groupby];
-
-	if (v) {
-            var group = node.findChild('groupbyid', v);
-	    if (!group) {
-		var groupinfo;
-		if (info.type === groupby) {
-		    groupinfo = info;
-		} else {
-		    groupinfo = {
-			type: groupby,
-			id : groupby + "/" + v
-		    };
-		    if (groupby !== 'type') {
-			groupinfo[groupby] = v;
-		    }
-		}
-		groupinfo.leaf = false;
-		groupinfo.groupbyid = v; 
-		group = me.addChildSorted(node, groupinfo);
-	    }
-	    if (info.type === groupby) {
-		return group;
-	    }
-	    if (group) {
-		return me.groupChild(group, info, groups, level + 1);
-	    }
-	}
-
-	return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	if (!me.viewFilter) {
-	    me.viewFilter = {};
-	}
-
-	var pdata = {
-	    dataIndex: {},
-	    updateCount: 0
-	};
-
-	var store = Ext.create('Ext.data.TreeStore', {
-	    model: 'PVETree',
-	    root: {
-		expanded: true,
-		id: 'root',
-		text: gettext('Datacenter'),
-		iconCls: 'fa fa-server'
-	    }
-	});
-
-	var stateid = 'rid';
-
-	var updateTree = function() {
-	    var tmp;
-
-	    store.suspendEvents();
-
-	    var rootnode = me.store.getRootNode();
-	    // remember selected node (and all parents)
-	    var sm = me.getSelectionModel();
-
-	    var lastsel = sm.getSelection()[0];
-	    var reselect = false;
-	    var parents = [];
-	    var p = lastsel;
-	    while (p && !!(p = p.parentNode)) {
-		parents.push(p);
-	    }
-
-	    var index = pdata.dataIndex;
-
-	    var groups = me.viewFilter.groups || [];
-	    var filterfn = me.viewFilter.filterfn;
-
-	    // remove vanished or moved items
-	    // update in place changed items
-	    var key;
-	    for (key in index) {
-		if (index.hasOwnProperty(key)) {
-		    var olditem = index[key];
-
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var item = rstore.getById(olditem.data.id);
-		    var item = rstore.data.get(olditem.data.id);
-
-		    var changed = false;
-		    var moved = false;
-		    if (item) {
-			// test if any grouping attributes changed
-			// this will also catch migrated nodes
-			// in server view
-			var i, len;
-			for (i = 0, len = groups.length; i < len; i++) {
-			    var attr = groups[i];
-			    if (item.data[attr] != olditem.data[attr]) {
-				//console.log("changed " + attr);
-				moved = true;
-				break;
-			    }
-			}
-
-			// explicitely check for node, since
-			// in some views, node is not a grouping
-			// attribute
-			if (!moved && item.data.node !== olditem.data.node) {
-			    moved = true;
-			}
-
-			// tree item has been updated
-			if ((item.data.text !== olditem.data.text) ||
-			    (item.data.running !== olditem.data.running) ||
-			    (item.data.template !== olditem.data.template) ||
-			    (item.data.status !== olditem.data.status) ||
-			    (item.data.hastate!== olditem.data.hastate)) {
-			    //console.log("changed node/text/running " + olditem.data.id);
-			    changed = true;
-			}
-
-			// fixme: also test filterfn()?
-		    }
-
-		    if (changed) {
-			olditem.beginEdit();
-			//console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-			var info = olditem.data;
-			Ext.apply(info, item.data);
-			me.setIconCls(info);
-			me.setText(info);
-			me.setToolTip(info);
-			olditem.commit();
-		    }
-		    if ((!item || moved) && olditem.isLeaf()) {
-			//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-			delete index[key];
-			var parentNode = olditem.parentNode;
-			// when the selected item disappears,
-			// we have to deselect it here, and reselect it
-			// later
-			if (lastsel && olditem.data.id === lastsel.data.id) {
-			    reselect = true;
-			    sm.deselect(olditem);
-			}
-			// since the store events are suspended, we
-			// manually remove the item from the store also
-			store.remove(olditem);
-			parentNode.removeChild(olditem, true);
-		    }
-		}
-	    }
-
-	    // add new items
-            rstore.each(function(item) {
-		var olditem = index[item.data.id];
-		if (olditem) {
-		    return;
-		}
-
-		if (filterfn && !filterfn(item)) {
-		    return;
-		}
-
-		//console.log("ADD UID: " + item.data.id);
-
-		var info = Ext.apply({ leaf: true }, item.data);
-
-		var child = me.groupChild(rootnode, info, groups, 0);
-		if (child) {
-		    index[item.data.id] = child;
-		}
-	    });
-
-	    store.resumeEvents();
-	    store.fireEvent('refresh', store);
-
-	    // select parent node is selection vanished
-	    if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-		lastsel = rootnode;
-		while (!!(p = parents.shift())) {
-		    if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-			lastsel = tmp;
-			break;
-		    }
-		}
-		me.selectById(lastsel.data.id);
-	    } else if (lastsel && reselect) {
-		me.selectById(lastsel.data.id);
-	    }
-
-	    // on first tree load set the selection from the stateful provider
-	    if (!pdata.updateCount) {
-		rootnode.expand();
-		me.applyState(sp.get(stateid));
-	    }
-
-	    pdata.updateCount++;
-	};
-
-	var statechange = function(sp, key, value) {
-	    if (key === stateid) {
-		me.applyState(value);
-	    }
-	};
-
-	sp.on('statechange', statechange);
-
-	Ext.apply(me, {
-	    allowSelection: true,
-	    store: store,
-	    viewConfig: {
-		// note: animate cause problems with applyState
-		animate: false
-	    },
-	    //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		destroy: function() {
-		    rstore.un("load", updateTree);
-		},
-		beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
-		    var sm = me.getSelectionModel();
-		    // disable selection when right clicking
-		    // except the record is already selected
-		    me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
-		},
-		beforeselect: function (tree, record, index, eopts) {
-		    var allow = me.allowSelection;
-		    me.allowSelection = true;
-		    return allow;
-		},
-		itemdblclick: PVE.Utils.openTreeConsole
-	    },
-	    setViewFilter: function(view) {
-		me.viewFilter = view;
-		me.clearTree();
-		updateTree();
-	    },
-	    setDatacenterText: function(clustername) {
-		var rootnode = me.store.getRootNode();
-
-		var rnodeText = gettext('Datacenter');
-		if (clustername !== undefined) {
-		    rnodeText += ' (' + clustername + ')';
-		}
-
-		rootnode.beginEdit();
-		rootnode.data.text = rnodeText;
-		rootnode.commit();
-	    },
-	    clearTree: function() {
-		pdata.updateCount = 0;
-		var rootnode = me.store.getRootNode();
-		rootnode.collapse();
-		rootnode.removeAll();
-		pdata.dataIndex = {};
-		me.getSelectionModel().deselectAll();
-	    },
-	    selectExpand: function(node) {
-		var sm = me.getSelectionModel();
-		if (!sm.isSelected(node)) {
-		    sm.select(node);
-		    var cn = node;
-		    while (!!(cn = cn.parentNode)) {
-			if (!cn.isExpanded()) {
-			    cn.expand();
-			}
-		    }
-		    me.getView().focusRow(node);
-		}
-	    },
-	    selectById: function(nodeid) {
-		var rootnode = me.store.getRootNode();
-		var sm = me.getSelectionModel();
-		var node;
-		if (nodeid === 'root') {
-		    node = rootnode;
-		} else {
-		    node = rootnode.findChild('id', nodeid, true);
-		}
-		if (node) {
-		    me.selectExpand(node);
-		}
-		return node;
-	    },
-	    applyState : function(state) {
-		var sm = me.getSelectionModel();
-		if (state && state.value) {
-		    me.selectById(state.value);
-		} else {
-		    sm.deselectAll();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	var sm = me.getSelectionModel();
-	sm.on('select', function(sm, n) {		    
-	    sp.set(stateid, { value: n.data.id});
-	});
-
-	rstore.on("load", updateTree);
-	rstore.startUpdate();
-	//rstore.stopUpdate();
-    }
-
-});
-Ext.define('pve-fw-ipsets', {
-    extend: 'Ext.data.Model',
-    fields: [ 'name', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsetlist',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-
-        var me = this;
-
-	if (me.ipset_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-ipsets',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('Proxmox.window.Edit', {
-		subject: "IPSet '" + rec.data.name + "'",
-		url: me.base_url,
-		method: 'POST',
-		digest: rec.data.digest,
-		items: [
-		    {
-			xtype: 'hiddenfield',
-			name: 'rename',
-			value: rec.data.name
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'name',
-			value: rec.data.name,
-			fieldLabel: gettext('Name'),
-			allowBlank: false
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'comment',
-			value: rec.data.comment,
-			fieldLabel: gettext('Comment')
-		    }
-		]
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('Proxmox.window.Edit', {
-		    subject: 'IPSet',
-		    url: me.base_url,
-		    method: 'POST',
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'name',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'textfield',
-			    name: 'comment',
-			    value: '',
-			    fieldLabel: gettext('Comment')
-			}
-		    ]
-		});
-		win.show();
-		win.on('destroy', reload);
-
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: 'IPSet', dataIndex: 'name', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = me.base_url + '/' + rec.data.name;
-		    me.ipset_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.ipset_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.cidr === undefined);
-
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-	var column1 = [];
-
-	if (me.isCreate) {
-	    if (!me.list_refs_url) {
-		throw "no alias_base_url specified";
-	    }
-
-	    column1.push({
-		xtype: 'pveIPRefSelector',
-		name: 'cidr',
-		ref_type: 'alias',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	} else {
-	    column1.push({
-		xtype: 'displayfield',
-		name: 'cidr',
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'nomatch',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: 'nomatch'
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('IP/CIDR'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsets',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no1 list_refs_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ipset'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.IPSetCidrEdit', {
-		base_url: me.base_url,
-		cidr: rec.data.cidr
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		if (!me.base_url) {
-		    return;
-		}
-		var win = Ext.create('PVE.IPSetCidrEdit', {
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	var render_errors = function(value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors.cidr || errors.nomatch;
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	Ext.apply(me, {
-	    tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    store: store,
-	    selModel: sm,
-	    listeners: {
-		itemdblclick: run_editor
-	    },
-	    columns: [
-		{
-		    xtype: 'rownumberer'
-		},
-		{
-		    header: gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			value = render_errors(value, metaData, record);
-			if (record.data.nomatch) {
-			    return '<b>! </b>' + value;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    flex: 1,
-		    renderer: function(value) {
-			return Ext.util.Format.htmlEncode(value);
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'nomatch', type: 'boolean' },
-		  'cidr', 'comment', 'errors' ],
-	idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    onlineHelp: 'pve_firewall_ip_sets',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-	    region: 'center',
-	    list_refs_url: me.list_refs_url,
-	    border: false
-	});
-
-	var ipset_list = Ext.createWidget('pveIPSetList', {
-	    region: 'west',
-	    ipset_panel: ipset_panel,
-	    base_url: me.base_url,
-	    width: '50%',
-	    border: false,
-	    split: true
-	});
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-	    listeners: {
-		show: function() {
-		    ipset_list.fireEvent('show', ipset_list);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Base class for all the multitab config panels
- *
- * How to use this:
- *
- * You create a subclass of this, and then define your wanted tabs
- * as items like this:
- *
- * items: [{
- *  title: "myTitle",
- *  xytpe: "somextype",
- *  iconCls: 'fa fa-icon',
- *  groups: ['somegroup'],
- *  expandedOnInit: true,
- *  itemId: 'someId'
- * }]
- *
- * this has to be in the declarative syntax, else we
- * cannot save them for later
- * (so no Ext.create or Ext.apply of an item in the subclass)
- *
- * the groups array expects the itemids of the items
- * which are the parents, which have to come before they
- * are used
- *
- * if you want following the tree:
- *
- * Option1
- * Option2
- *   -> SubOption1
- *	-> SubSubOption1
- *
- * the suboption1 group array has to look like this:
- * groups: ['itemid-of-option2']
- *
- * and of subsuboption1:
- * groups: ['itemid-of-option2', 'itemid-of-suboption1']
- *
- * setting the expandedOnInit determines if the item/group is expanded
- * initially (false by default)
- */
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    showSearch: true, // add a ressource grid with a search button as first tab
-    viewFilter: undefined, // a filter to pass to that ressource grid
-
-    tbarSpacing: true, // if true, adds a spacer after the title in tbar
-
-    dockedItems: [{
-	// this is needed for the overflow handler
-	xtype: 'toolbar',
-	overflowHandler: 'scroller',
-	dock: 'left',
-	style: {
-	    backgroundColor: '#f5f5f5',
-	    padding: 0,
-	    margin: 0
-	},
-	items: {
-	    xtype: 'treelist',
-	    itemId: 'menu',
-	    ui: 'nav',
-	    expanderOnly: true,
-	    expanderFirst: false,
-	    animation: false,
-	    singleExpand: false,
-	    listeners: {
-		selectionchange: function(treeList, selection) {
-		    var me = this.up('panel');
-		    me.suspendLayout = true;
-		    me.activateCard(selection.data.id);
-		    me.suspendLayout = false;
-		    me.updateLayout();
-		},
-		itemclick: function(treelist, info) {
-		    var olditem = treelist.getSelection();
-		    var newitem = info.node;
-
-		    // when clicking on the expand arrow,
-		    // we dont select items, but still want
-		    // the original behaviour
-		    if (info.select === false) {
-			return;
-		    }
-
-		    // if you click on a different item which is open,
-		    // leave it open
-		    // else toggle the clicked item
-		    if (olditem.data.id !== newitem.data.id &&
-			newitem.data.expanded === true) {
-			info.toggle = false;
-		    } else {
-			info.toggle = true;
-		    }
-		}
-	    }
-	}
-    },
-    {
-	xtype: 'toolbar',
-	itemId: 'toolbar',
-	dock: 'top',
-	height: 36,
-	overflowHandler: 'scroller'
-    }],
-
-    firstItem: '',
-    layout: 'card',
-    border: 0,
-
-    // used for automated test
-    selectById: function(cardid) {
-	var me = this;
-
-	var root = me.store.getRoot();
-	var selection = root.findChild('id', cardid, true);
-
-	if (selection) {
-	    selection.expand();
-	    var menu = me.down('#menu');
-	    menu.setSelection(selection);
-	    return cardid;
-	}
-    },
-
-    activateCard: function(cardid) {
-	var me = this;
-	if (me.savedItems[cardid]) {
-	    var curcard = me.getLayout().getActiveItem();
-	    var newcard = me.add(me.savedItems[cardid]);
-	    me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp);
-	    if (curcard) {
-		me.setActiveItem(cardid);
-		me.remove(curcard, true);
-
-		// trigger state change
-
-		var ncard = cardid;
-		// Note: '' is alias for first tab.
-		// First tab can be 'search' or something else
-		if (cardid === me.firstItem) {
-		    ncard = '';
-		}
-		if (me.hstateid) {
-		   me.sp.set(me.hstateid, { value: ncard });
-		}
-	    }
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = me.hstateid;
-
-	me.sp = Ext.state.Manager.getProvider();
-
-	var activeTab; // leaving this undefined means items[0] will be the default tab
-
-	if (stateid) {
-	    var state = me.sp.get(stateid);
-	    if (state && state.value) {
-		// if this tab does not exists, it chooses the first
-		activeTab = state.value;
-	    }
-	}
-
-	// get title
-	var title = me.title || me.pveSelNode.data.text;
-	me.title = undefined;
-
-	// create toolbar
-	var tbar = me.tbar || [];
-	me.tbar = undefined;
-
-	if (!me.onlineHelp) {
-	    switch(me.pveSelNode.data.id) {
-		case 'type/storage':me.onlineHelp = 'chapter-pvesm.html'; break;
-		case 'type/qemu':me.onlineHelp = 'chapter-qm.html'; break;
-		case 'type/lxc':me.onlineHelp = 'chapter-pct.html'; break;
-		case 'type/pool':me.onlineHelp = 'chapter-pveum.html#_pools'; break;
-		case 'type/node':me.onlineHelp = 'chapter-sysadmin.html'; break;
-	    }
-	}
-
-	if (me.tbarSpacing) {
-	    tbar.unshift('->');
-	}
-	tbar.unshift({
-	    xtype: 'tbtext',
-	    text: title,
-	    baseCls: 'x-panel-header-text'
-	});
-
-	me.helpButton = Ext.create('Proxmox.button.Help', {
-	    hidden: false,
-	    listenToGlobalEvent: false,
-	    onlineHelp: me.onlineHelp || undefined
-	});
-
-	tbar.push(me.helpButton);
-
-	me.dockedItems[1].items = tbar;
-
-	// include search tab
-	me.items = me.items || [];
-	if (me.showSearch) {
-	    me.items.unshift({
-		itemId: 'search',
-		title: gettext('Search'),
-		iconCls: 'fa fa-search',
-		xtype: 'pveResourceGrid',
-		pveSelNode: me.pveSelNode
-	    });
-	}
-
-	me.savedItems = {};
-	/*jslint confusion:true*/
-	if (me.items[0]) {
-	    me.firstItem = me.items[0].itemId;
-	}
-	/*jslint confusion:false*/
-
-	me.store = Ext.create('Ext.data.TreeStore', {
-	    root: {
-		expanded: true
-	    }
-	});
-	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
-
-	delete me.items;
-	me.defaults = me.defaults || {};
-	Ext.apply(me.defaults, {
-	    pveSelNode: me.pveSelNode,
-	    viewFilter: me.viewFilter,
-	    workspace: me.workspace,
-	    border: 0
-	});
-
-	me.callParent();
-
-	var menu = me.down('#menu');
-	var selection = root.findChild('id', activeTab, true) || root.firstChild;
-	var node = selection;
-	while (node !== root) {
-	    node.expand();
-	    node = node.parentNode;
-	}
-	menu.setStore(me.store);
-	menu.setSelection(selection);
-
-	// on a state change,
-	// select the new item
-	var statechange = function(sp, key, state) {
-	    // it the state change is for this panel
-	    if (stateid && (key === stateid) && state) {
-		// get active item
-		var acard = me.getLayout().getActiveItem().itemId;
-		// get the itemid of the new value
-		var ncard = state.value || me.firstItem;
-		if (ncard && (acard != ncard)) {
-		    // select the chosen item
-		    menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
-		}
-	    }
-	};
-
-	if (stateid) {
-	    me.mon(me.sp, 'statechange', statechange);
-	}
-    }
-});
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    stateful: true,
-    stateId: 'grid-guest-backup',
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmtype = me.pveSelNode.data.type;
-	if (!vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var vmtypeFilter;
-	if (vmtype === 'openvz') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-openvz-');
-	    };
-	} else if (vmtype === 'lxc') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-lxc-');
-	    };
-	} else if (vmtype === 'qemu') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-qemu-');
-	    };
-	} else {
-	    throw "unsupported VM type '" + vmtype + "'";
-	}
-
-	var searchFilter = {
-	    property: 'volid',
-	// on initial store display only our vmid backups
-	// surround with minus sign to prevent the 2016 VMID bug
-	    value: vmtype + '-' + vmid + '-',
-	    anyMatch: true,
-	    caseSensitive: false
-	};
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-content',
-	    sorters: { 
-		property: 'volid', 
-		order: 'DESC' 
-	    },
-	    filters: [
-	        vmtypeFilter,
-		searchFilter
-		]
-	});
-
-	var reload = Ext.Function.createBuffered(function() {
-	    if (me.store) {
-		me.store.load();
-	    }
-	}, 100);
-
-	var setStorage = function(storage) {
-	    var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-	    url += '?content=backup';
-
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: url
-	    });
-
-	    reload();
-	};
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    setStorage(value);
-		}
-	    }
-	});
-
-	var storagefilter = Ext.create('Ext.form.field.Text', {
-	    fieldLabel: gettext('Search'),
-	    labelWidth: 50,
-	    labelAlign: 'right',
-	    enableKeyEvents: true,
-	    value: searchFilter.value,
-	    listeners: {
-		buffer: 500,
-		keyup: function(field) {
-		    me.store.clearFilter(true);
-		    searchFilter.value = field.getValue();
-		    me.store.filter([
-			vmtypeFilter,
-			searchFilter
-		    ]);
-		}
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var backup_btn = Ext.create('Ext.button.Button', {
-	    text: gettext('Backup now'),
-	    handler: function() {
-		var win = Ext.create('PVE.window.Backup', { 
-		    nodename: nodename,
-		    vmid: vmid,
-		    vmtype: vmtype,
-		    storage: storagesel.getValue(),
-		    listeners : {
-			close: function() {
-			    reload();
-			}
-		    }
-		});
-		win.show();
-	    }
-	});
-
-	var restore_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Restore'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var volid = rec.data.volid;
-
-		var win = Ext.create('PVE.window.Restore', {
-		    nodename: nodename,
-		    vmid: vmid,
-		    volid: rec.data.volid,
-		    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-		    vmtype: vmtype
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var delete_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.volid + "'");
-		msg += " " + gettext('This will permanently erase all data.');
-
-		return msg;
-	    },
-	    getUrl: function(rec) {
-		var storage = storagesel.getValue();
-		return '/nodes/' + nodename + '/storage/' + storage + '/content/' + rec.data.volid;
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	var config_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show Configuration'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var storage = storagesel.getValue();
-		if (!storage) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.window.BackupConfig', {
-		    volume: rec.data.volid,
-		    pveSelNode: me.pveSelNode
-		});
-
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    tbar: [ backup_btn, restore_btn, delete_btn,config_btn, '->', storagesel, storagefilter ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'volid'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.CephCreateFS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateFS',
-
-    showTaskViewer: true,
-    onlineHelp: 'pveceph_fs_create',
-
-    subject: 'Ceph FS',
-    isCreate: true,
-    method: 'POST',
-
-    setFSName: function(fsName) {
-	var me = this;
-
-	if (fsName === '' || fsName === undefined) {
-	    fsName = 'cephfs';
-	}
-
-	me.url = "/nodes/" + me.nodename + "/ceph/fs/" + fsName;
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    value: 'cephfs',
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateFS').setFSName(value);
-		}
-	    },
-	    submitValue: false, // already encoded in apicall URL
-	    emptyText: 'cephfs'
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'Placement Groups',
-	    name: 'pg_num',
-	    value: 128,
-	    emptyText: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add Storage'),
-	    value: true,
-	    name: 'add-storage'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setFSName();
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.CephCreateMDS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateMDS',
-
-    showProgress: true,
-    onlineHelp: 'pveceph_fs_mds',
-
-    subject: 'Ceph MDS',
-    isCreate: true,
-    method: 'POST',
-
-    setNode: function(nodename) {
-	var me = this;
-
-	me.nodename = nodename;
-	me.url = "/nodes/" + nodename + "/ceph/mds/" + nodename;
-    },
-
-    items: [
-	{
-	    xtype: 'pveNodeSelector',
-	    fieldLabel: gettext('Node'),
-	    selectCurNode: true,
-	    submitValue: false,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateMDS').setNode(value);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setNode(me.nodename);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.NodeCephFSPanel', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNodeCephFSPanel',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    title: gettext('CephFS'),
-    onlineHelp: 'pveceph_fs',
-
-    border: false,
-    defaults: {
-	border: false,
-	cbind: {
-	    nodename: '{nodename}'
-	}
-    },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    cephfsConfigured: false,
-	    mdsCount: 0
-	},
-	formulas: {
-	    canCreateFS: function(get) {
-		return (!get('cephfsConfigured') && get('mdsCount') > 0);
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'CephFS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-fs',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/' + view.nodename + '/ceph/fs'
-			},
-			model: 'pve-ceph-fs'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'name',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateFS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!(success && records && records.length > 0)) {
-			vm.set('cephfsConfigured', false);
-			return;
-		    }
-		    vm.set('cephfsConfigured', true);
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create CephFS'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			// only one CephFS per Ceph cluster makes sense for now
-			disabled: '{!canCreateFS}'
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: 'Data Pool',
-		    flex: 1,
-		    dataIndex: 'data_pool'
-		},
-		{
-		    header: 'Metadata Pool',
-		    flex: 1,
-		    dataIndex: 'metadata_pool'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Metadata Servers'),
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'MDS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 3 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-mds',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/'+ view.nodename +'/ceph/mds'
-			},
-			model: 'pve-ceph-mds'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'id',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('mdsCount', 0);
-			return;
-		    }
-		    vm.set('mdsCount', records.length);
-		},
-		onCreateMDS: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateMDS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create MDS'),
-		    reference: 'createButton',
-		    handler: 'onCreateMDS'
-		},
-		{
-		    text: gettext('Destroy MDS'),
-		    xtype: 'proxmoxStdRemoveButton',
-		    getUrl: function(rec) {
-			if (!rec.data.host) {
-			    Ext.Msg.alert(gettext('Error'), "entry has no host");
-			    return;
-			}
-			return "/nodes/" + rec.data.host + "/ceph/mds/" + rec.data.name;
-		    },
-		    callback: function(options, success, response) {
-			if (!success) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    return;
-			}
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Host'),
-		    flex: 1,
-		    dataIndex: 'host'
-		},
-		{
-		    header: gettext('Address'),
-		    flex: 1,
-		    dataIndex: 'addr'
-		},
-		{
-		    header: gettext('State'),
-		    flex: 1,
-		    dataIndex: 'state'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-}, function() {
-    Ext.define('pve-ceph-mds', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'host', 'addr', 'state' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/mds"
-	},
-	idProperty: 'name'
-    });
-    Ext.define('pve-ceph-fs', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'data_pool', 'metadata_pool' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/fs"
-	},
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.CephCreatePool', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreatePool',
-
-    showProgress: true,
-    onlineHelp: 'pve_ceph_pools',
-
-    subject: 'Ceph Pool',
-    isCreate: true,
-    method: 'POST',
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Size'),
-	    name: 'size',
-	    value: 3,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Min. Size'),
-	    name: 'min_size',
-	    value: 2,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'pveCephRuleSelector',
-	    fieldLabel: 'Crush Rule', // do not localize
-	    name: 'crush_rule',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'pg_num',
-	    name: 'pg_num',
-	    value: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add Storage'),
-	    name: 'add_storages'
-	}
-    ],
-    initComponent : function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.apply(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/pools",
-	    defaults: {
-		nodename: me.nodename
-	    }
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephPoolList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeCephPoolList',
-
-    onlineHelp: 'chapter_pveceph',
-    stateful: true,
-    stateId: 'grid-ceph-pools',
-    bufferedRenderer: false,
-    features: [ { ftype: 'summary'} ],
-    columns: [
-	{
-	    header: gettext('Name'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'pool_name'
-	},
-	{
-	    header: gettext('Size') + '/min',
-	    width: 80,
-	    sortable: false,
-	    renderer: function(v, meta, rec) {
-		return v + '/' + rec.data.min_size;
-	    },
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'pg_num',
-	    width: 100,
-	    sortable: false,
-	    dataIndex: 'pg_num'
-	},
-	{
-	    header: 'rule',
-	    width: 50,
-	    sortable: false,
-	    dataIndex: 'crush_rule'
-	},
-	{
-	    header: 'rule_name',
-	    width: 50,
-	    sortable: false,
-	    dataIndex: 'crush_rule_name'
-	},
-	{
-	    header: gettext('Used'),
-	    columns: [
-		{
-		    header: '%',
-		    width: 80,
-		    sortable: true,
-		    align: 'right',
-		    renderer: Ext.util.Format.numberRenderer('0.00'),
-		    dataIndex: 'percent_used',
-		    summaryType: 'sum',
-		    summaryRenderer: Ext.util.Format.numberRenderer('0.00')
-		},
-		{
-		    header: gettext('Total'),
-		    width: 100,
-		    sortable: true,
-		    renderer: PVE.Utils.render_size,
-		    align: 'right',
-		    dataIndex: 'bytes_used',
-		    summaryType: 'sum',
-		    summaryRenderer: PVE.Utils.render_size
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-pool-list' + nodename,
-	    model: 'ceph-pool-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/pools"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		var win = Ext.create('PVE.CephCreatePool', {
-                    nodename: nodename
-		});
-		win.show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	var destroy_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Destroy'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.pool_name) {
-		    return;
-		}
-		var base_url = '/nodes/' + nodename + '/ceph/pools/' +
-		    rec.data.pool_name;
-
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    showProgress: true,
-		    url: base_url,
-		    params: {
-			remove_storages: 1
-		    },
-		    item: { type: 'CephPool', id: rec.data.pool_name }
-		}).show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ create_btn, destroy_btn ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-pool-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'pool_name',
-		  { name: 'pool', type: 'integer'},
-		  { name: 'size', type: 'integer'},
-		  { name: 'min_size', type: 'integer'},
-		  { name: 'pg_num', type: 'integer'},
-		  { name: 'bytes_used', type: 'integer'},
-		  { name: 'percent_used', type: 'number'},
-		  { name: 'crush_rule', type: 'integer'},
-		  { name: 'crush_rule_name', type: 'string'}
-		],
-	idProperty: 'pool_name'
-    });
-});
-
-Ext.define('PVE.form.CephRuleSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephRuleSelector',
-
-    allowBlank: false,
-    valueField: 'name',
-    displayField: 'name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/rules'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.CephCreateOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephCreateOsd'],
-
-    subject: 'Ceph OSD',
-
-    showProgress: true,
-
-    onlineHelp: 'pve_ceph_osds',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'dev',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'journal_dev',
-		    nodename: me.nodename,
-		    diskType: 'journal_disks',
-		    fieldLabel: gettext('Journal/DB Disk'),
-		    value: '',
-		    autoSelect: false,
-		    allowBlank: true,
-		    emptyText: 'use OSD disk'
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'bluestore',
-		    fieldLabel: 'Bluestore',
-		    uncheckedValue: '0',
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.CephRemoveOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephRemoveOsd'],
-
-    isRemove: true,
-
-    showProgress: true,
-    method: 'DELETE',
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cleanup',
-	    checked: true,
-	    labelWidth: 130,
-	    fieldLabel: gettext('Remove Partitions')
-	}
-    ],
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (me.osdid === undefined || me.osdid < 0) {
-	    throw "no osdid specified";
-	}
-
-	me.isCreate = true;
-
-	me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephOsdTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveNodeCephOsdTree'],
-    onlineHelp: 'chapter_pveceph',
-    stateful: true,
-    stateId: 'grid-ceph-osd',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: 'Name',
-	    dataIndex: 'name',
-	    width: 150
-	},
-	{
-	    text: 'Type',
-	    dataIndex: 'type',
-	    align: 'right',
-	    width: 60
-	},
-	{
-	    text: gettext("Class"),
-	    dataIndex: 'device_class',
-	    align: 'right',
-	    width: 40
-	},
-	{
-	    text: "OSD Type",
-	    dataIndex: 'osdtype',
-	    align: 'right',
-	    width: 40
-	},
-	{
-	    text: "Bluestore Device",
-	    dataIndex: 'blfsdev',
-	    align: 'right',
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: "DB Device",
-	    dataIndex: 'dbdev',
-	    align: 'right',
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: "WAL Device",
-	    dataIndex: 'waldev',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (!value &&
-		    rec.data.osdtype === 'bluestore' &&
-		    rec.data.type === 'osd') {
-		    return 'N/A';
-		}
-		return value;
-	    },
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: 'Status',
-	    dataIndex: 'status',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (!value) {
-		    return value;
-		}
-		var inout = rec.data['in'] ? 'in' : 'out';
-		var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
-						  'critical fa-arrow-circle-down';
-
-		var inouticon = rec.data['in'] ? 'good fa-circle' :
-						 'warning fa-circle-o';
-
-		var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
-			   inout + ' <i class="fa ' + inouticon + '"></i>';
-
-		return text;
-	    },
-	    width: 80
-	},
-	{
-	    text: 'weight',
-	    dataIndex: 'crush_weight',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return value;
-	    },
-	    width: 80
-	},
-	{
-	    text: 'reweight',
-	    dataIndex: 'reweight',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return value;
-	    },
-	    width: 90
-	},
-	{
-	    header: gettext('Used'),
-	    columns: [
-		{
-		    text: '%',
-		    dataIndex: 'percent_used',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return Ext.util.Format.number(value, '0.00');
-		    },
-		    width: 80
-		},
-		{
-		    text: gettext('Total'),
-		    dataIndex: 'total_space',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return PVE.Utils.render_size(value);
-		    },
-		    width: 100
-		}
-	    ]
-	},
-	{
-	    header: gettext('Latency (ms)'),
-	    columns: [
-		{
-		    text: 'Apply',
-		    dataIndex: 'apply_latency_ms',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return value;
-		    },
-		    width: 60
-		},
-		{
-		    text: 'Commit',
-		    dataIndex: 'commit_latency_ms',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return value;
-		    },
-		    width: 60
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	// we expect noout to be not set by default
-	var noout = false;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	var set_button_status; // defined later
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + nodename + "/ceph/osd",
-		waitMsgTarget: me,
-		method: 'GET',
-		failure: function(response, opts) {
-		    var msg = response.htmlStatus;
-		    PVE.Utils.showCephInstallOrMask(me, msg, me.pveSelNode.data.node,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', function(){
-				reload();
-			    });
-			}
-		    );
-		},
-		success: function(response, opts) {
-		    sm.deselectAll();
-		    me.setRootNode(response.result.data.root);
-		    me.expandAll();
-		    // extract noout flag
-		    if (response.result.data.flags &&
-			response.result.data.flags.search(/noout/) !== -1) {
-			noout = true;
-		    } else {
-			noout = false;
-		    }
-		    set_button_status();
-		}
-	    });
-	};
-
-	var osd_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + rec.data.host + "/ceph/osd/" +
-		    rec.data.id + '/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		success: reload,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var service_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!(rec && rec.data.name && rec.data.host)) {
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		params: { service: rec.data.name },
-		waitMsgTarget: me,
-		method: 'POST',
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		    win.show();
-		    me.mon(win, 'close', reload, me);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var create_btn = new Proxmox.button.Button({
-	    text: gettext('Create') + ': OSD',
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.CephCreateOsd', {
-                    nodename: nodename
-		});
-		win.show();
-		me.mon(win, 'close', reload, me);
-	    }
-	});
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){ service_cmd('start'); }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){ service_cmd('stop'); }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){ service_cmd('restart'); }
-	});
-
-	var osd_out_btn = new Ext.Button({
-	    text: 'Out',
-	    disabled: true,
-	    handler: function(){ osd_cmd('out'); }
-	});
-
-	var osd_in_btn = new Ext.Button({
-	    text: 'In',
-	    disabled: true,
-	    handler: function(){ osd_cmd('in'); }
-	});
-
-	var remove_btn = new Ext.Button({
-	    text: gettext('Destroy'),
-	    disabled: true,
-	    handler: function(){
-		var rec = sm.getSelection()[0];
-		if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.CephRemoveOsd', {
-                    nodename: rec.data.host,
-		    osdid: rec.data.id
-		});
-		win.show();
-		me.mon(win, 'close', reload, me);
-	    }
-	});
-
-	var noout_btn = new Ext.Button({
-	    text: gettext('Set noout'),
-	    handler: function() {
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + nodename + "/ceph/flags/noout",
-		    waitMsgTarget: me,
-		    method: noout ? 'DELETE' : 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: reload
-		});
-	    }
-	});
-
-	var osd_label = new Ext.toolbar.TextItem({
-	    data: {
-		osd: undefined
-	    },
-	    tpl: [
-		'<tpl if="osd">',
-		'{osd}:',
-		'<tpl else>',
-		gettext('No OSD selected'),
-		'</tpl>'
-	    ]
-	});
-
-	set_button_status = function() {
-	    var rec = sm.getSelection()[0];
-	    noout_btn.setText(noout?gettext('Unset noout'):gettext('Set noout'));
-
-	    if (!rec) {
-		start_btn.setDisabled(true);
-		stop_btn.setDisabled(true);
-		restart_btn.setDisabled(true);
-		remove_btn.setDisabled(true);
-		osd_out_btn.setDisabled(true);
-		osd_in_btn.setDisabled(true);
-		return;
-	    }
-
-	    var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
-
-	    start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
-	    stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
-	    restart_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
-	    remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
-
-	    osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
-	    osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
-
-	    osd_label.update(isOsd?{osd:rec.data.name}:undefined);
-	};
-
-	sm.on('selectionchange', set_button_status);
-
-	var reload_btn = new Ext.Button({
-	    text: gettext('Reload'),
-	    handler: reload
-	});
-
-	Ext.apply(me, {
-	    tbar: [ create_btn, reload_btn, noout_btn, '->', osd_label, start_btn, stop_btn, restart_btn, osd_out_btn, osd_in_btn, remove_btn ],
-	    rootVisible: false,
-	    useArrows: true,
-	    fields: ['name', 'type', 'status', 'host', 'in', 'id' ,
-		     { type: 'number', name: 'reweight' },
-		     { type: 'number', name: 'percent_used' },
-		     { type: 'integer', name: 'bytes_used' },
-		     { type: 'integer', name: 'total_space' },
-		     { type: 'integer', name: 'apply_latency_ms' },
-		     { type: 'integer', name: 'commit_latency_ms' },
-		     { type: 'string', name: 'device_class' },
-		     { type: 'string', name: 'osdtype' },
-		     { type: 'string', name: 'blfsdev' },
-		     { type: 'string', name: 'dbdev' },
-		     { type: 'string', name: 'waldev' },
-		     { type: 'string', name: 'iconCls', calculate: function(data) {
-			 var iconCls = 'fa x-fa-tree fa-';
-			 switch (data.type) {
-			    case 'host':
-				 iconCls += 'building';
-				 break;
-			    case 'osd':
-				 iconCls += 'hdd-o';
-				 break;
-			    case 'root':
-				 iconCls += 'server';
-				 break;
-			    default:
-				 return undefined;
-			 }
-			 return iconCls;
-		     } },
-		     { type: 'number', name: 'crush_weight' }],
-	    selModel: sm,
-
-	    listeners: {
-		activate: function() {
-		    reload();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	reload();
-    }
-});
-Ext.define('PVE.CephCreateMon', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephCreateMon'],
-
-    subject: 'Ceph Monitor/Manager',
-    onlineHelp: 'pve_ceph_monitors',
-
-    showProgress: true,
-
-    setNode: function(nodename) {
-        var me = this;
-
-	me.nodename = nodename;
-        me.url = "/nodes/" + nodename + "/ceph/mon";
-    },
-
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.setNode(me.nodename);
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-            method: 'POST',
-            items: [
-               {
-		   xtype: 'pveNodeSelector',
-		   submitValue: false,
-		   fieldLabel: gettext('Host'),
-		   selectCurNode: true,
-		   allowBlank: false,
-		   listeners: {
-		       change: function(f, value) {
-			   me.setNode(value);
-		       }
-		   }
-	       }
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephMonList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveNodeCephMonList'],
-
-    onlineHelp: 'chapter_pveceph',
-
-    stateful: true,
-    stateId: 'grid-ceph-monitor',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-mon-list' + nodename,
-	    model: 'ceph-mon-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/mon"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sorters: [{ property: 'name'}]
-	});
-
-
-	var service_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!rec.data.host) {
-		Ext.Msg.alert(gettext('Error'), "entry has no host");
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		method: 'POST',
-		params: { service: "mon." + rec.data.name },
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var start_btn = new Proxmox.button.Button({
-	    text: gettext('Start'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Proxmox.button.Button({
-	    text: gettext('Stop'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Proxmox.button.Button({
-	    text: gettext('Restart'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function(){
-		var win = Ext.create('PVE.CephCreateMon', {
-                    nodename: nodename
-		});
-		win.show();
-	    }
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.host) {
-		    Ext.Msg.alert(gettext('Error'), "entry has no host");
-		    return;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + rec.data.host + "/ceph/mon/" +
-			rec.data.name,
-		    method: 'DELETE',
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ start_btn, stop_btn, restart_btn, '-', create_btn, remove_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) { return "mon." + v; },
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Host'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'unknown';
-		    },
-		    dataIndex: 'host'
-		},
-		{
-		    header: gettext('Quorum'),
-		    width: 70,
-		    sortable: false,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'quorum'
-		},
-		{
-		    header: gettext('Address'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'addr'
-		}
-	    ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-mon-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'addr', 'name', 'rank', 'host', 'quorum' ],
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.node.CephCrushMap', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveNodeCephCrushMap'],
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    stateful: true,
-    stateId: 'layout-ceph-crush',
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/crush',
-
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.node.CephStatus', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephStatus',
-
-    onlineHelp: 'chapter_pveceph',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: {
-	type: 'column'
-    },
-
-    defaults: {
-	padding: 5
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Health'),
-	    bodyPadding: 10,
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5
-		}
-	    },
-	    minHeight: 210,
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    itemId: 'overallhealth',
-		    xtype: 'pveHealthWidget',
-		    title: gettext('Status')
-		},
-		{
-		    flex: 2,
-		    itemId: 'warnings',
-		    stateful: true,
-		    stateId: 'ceph-status-warnings',
-		    xtype: 'grid',
-		    // since we load the store manually,
-		    // to show the emptytext, we have to
-		    // specify an empty store
-		    store: { data:[] },
-		    emptyText: gettext('No Warnings/Errors'),
-		    columns: [
-			{
-			    dataIndex: 'severity',
-			    header: gettext('Severity'),
-			    align: 'center',
-			    width: 70,
-			    renderer: function(value) {
-				var health = PVE.Utils.map_ceph_health[value];
-				var classes = PVE.Utils.get_health_icon(health);
-
-				return '<i class="fa fa-fw ' + classes + '"></i>';
-			    },
-			    sorter: {
-				sorterFn: function(a,b) {
-				    var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-				    return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-				}
-			    }
-			},
-			{
-			    dataIndex: 'summary',
-			    header: gettext('Summary'),
-			    flex: 1
-			},
-			{
-			    xtype: 'actioncolumn',
-			    width: 40,
-			    align: 'center',
-			    tooltip: gettext('Detail'),
-			    items: [
-				{
-				    iconCls: 'x-fa fa-info-circle',
-				    handler: function(grid, rowindex, colindex, item, e, record) {
-					var win = Ext.create('Ext.window.Window', {
-					    title: gettext('Detail'),
-					    resizable: true,
-					    modal: true,
-					    width: 650,
-					    height: 400,
-					    layout: {
-						type: 'fit'
-					    },
-					    items: [{
-						scrollable: true,
-						padding: 10,
-						xtype: 'box',
-						html: [
-						    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-						    '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-						]
-					    }]
-					});
-					win.show();
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveCephStatusDetail',
-	    itemId: 'statusdetail',
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5
-		}
-	    },
-	    title: gettext('Status')
-	},
-	{
-	    xtype: 'panel',
-	    title: gettext('Performance'),
-	    columnWidth: 1,
-	    bodyPadding: 5,
-	    layout: {
-		type: 'hbox',
-		align: 'center'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    xtype: 'proxmoxGauge',
-		    itemId: 'space',
-		    title: gettext('Usage')
-		},
-		{
-		    flex: 2,
-		    xtype: 'container',
-		    defaults: {
-			padding: 0,
-			height: 100
-		    },
-		    items: [
-			{
-			    itemId: 'reads',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Reads'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'writes',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Writes'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'iops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS', // do not localize
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'readiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Reads'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'writeiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Writes'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			}
-		    ]
-		}
-	    ]
-	}
-    ],
-
-    generateCheckData: function(health) {
-	var result = [];
-	var checks = health.checks || {};
-	var keys = Ext.Object.getKeys(checks).sort();
-
-	Ext.Array.forEach(keys, function(key) {
-	    var details = checks[key].detail || [];
-	    result.push({
-		id: key,
-		summary: checks[key].summary.message,
-		detail: Ext.Array.reduce(
-			    checks[key].detail,
-			    function(first, second) {
-				return first + '\n' + second.message;
-			    },
-			    ''
-			),
-		severity: checks[key].severity
-	    });
-	});
-
-	return result;
-    },
-
-    updateAll: function(store, records, success) {
-	if (!success || records.length === 0) {
-	    return;
-	}
-
-	var me = this;
-	var rec = records[0];
-
-	// add health panel
-	me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
-	// add errors to gridstore
-	me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
-
-	// update detailstatus panel
-	me.getComponent('statusdetail').updateAll(
-	    rec.data.health || {},
-	    rec.data.monmap || {},
-	    rec.data.pgmap || {},
-	    rec.data.osdmap || {},
-	    rec.data.quorum_names || []);
-
-	// add performance data
-	var used = rec.data.pgmap.bytes_used;
-	var total = rec.data.pgmap.bytes_total;
-
-	var text = Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(used),
-	    PVE.Utils.render_size(total)
-	);
-
-	// update the usage widget
-	me.down('#space').updateValue(used/total, text);
-
-	// TODO: logic for jewel (iops splitted in read/write)
-
-	var iops = rec.data.pgmap.op_per_sec;
-	var readiops = rec.data.pgmap.read_op_per_sec;
-	var writeiops = rec.data.pgmap.write_op_per_sec;
-	var reads = rec.data.pgmap.read_bytes_sec || 0;
-	var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-	if (iops !== undefined && me.version !== 'hammer') {
-	    me.change_version('hammer');
-	} else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-	    me.change_version('jewel');
-	}
-	// update the graphs
-	me.reads.addDataPoint(reads);
-	me.writes.addDataPoint(writes);
-	me.iops.addDataPoint(iops);
-	me.readiops.addDataPoint(readiops);
-	me.writeiops.addDataPoint(writeiops);
-    },
-
-    change_version: function(version) {
-	var me = this;
-	me.version = version;
-	me.sp.set('ceph-version', version);
-	me.iops.setVisible(version === 'hammer');
-	me.readiops.setVisible(version === 'jewel');
-	me.writeiops.setVisible(version === 'jewel');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-	me.store = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-status-' + nodename,
-	    interval: 5000,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/ceph/status'
-	    }
-	});
-
-	// save references for the updatefunction
-	me.iops = me.down('#iops');
-	me.readiops = me.down('#readiops');
-	me.writeiops = me.down('#writeiops');
-	me.reads = me.down('#reads');
-	me.writes = me.down('#writes');
-
-	// get ceph version
-	me.sp = Ext.state.Manager.getProvider();
-	me.version = me.sp.get('ceph-version');
-	me.change_version(me.version);
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-	    me.store.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.mon(me.store, 'load', me.updateAll, me);
-	me.on('destroy', me.store.stopUpdate);
-	me.store.startUpdate();
-    }
-
-});
-Ext.define('PVE.ceph.StatusDetail', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephStatusDetail',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5 20',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [{
-	flex: 1,
-	itemId: 'monitors',
-	xtype: 'container',
-	items: [
-	    {
-		xtype: 'box',
-		width: '100%',
-		html: '<h3>' + gettext('Monitors') + '</h3>'
-	    }
-	]
-    },{
-	flex: 1,
-	itemId: 'osds',
-	data: {
-	    total: 0,
-	    upin: 0,
-	    upout: 0,
-	    downin: 0,
-	    downout: 0
-	},
-	tpl: [
-	    '<h3>' + 'OSDs' + '</h3>',
-	    '<table class="osds">',
-	    '<tr><td></td>',
-	    '<td><i class="fa fa-fw good fa-circle"></i>',
-	    gettext('In'),
-	    '</td>',
-	    '<td><i class="fa fa-fw warning fa-circle-o"></i>',
-	    gettext('Out'),
-	    '</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
-	    gettext('Up'),
-	    '</td>',
-	    '<td>{upin}</td>',
-	    '<td>{upout}</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
-	    gettext('Down'),
-	    '</td>',
-	    '<td>{downin}</td>',
-	    '<td>{downout}</td>',
-	    '</tr>',
-	    '</table>',
-	    '<br /><div>',
-	    gettext('Total'),
-	    ': {total}',
-	    '</div>'
-	]
-    },
-    {
-	flex: 1.6,
-	itemId: 'pgs',
-	padding: '0 10',
-	data: {
-	    states: []
-	},
-	tpl: [
-	    '<h3>' + 'PGs' + '</h3>',
-	    '<tpl for="states">',
-	    '<div class="left-aligned">{state_name}:</div>',
-	    '<div class="right-aligned">{count}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateAll: function(health, monmap, pgmap, osdmap, quorum_names) {
-	var me = this;
-	me.suspendLayout = true;
-
-	// update pgs sorted
-	var pgs_by_state = pgmap.pgs_by_state || [];
-	pgs_by_state.sort(function(a,b){
-	    return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
-	});
-	me.getComponent('pgs').update({states: pgs_by_state});
-
-	var downinregex = /(\d+) osds down/;
-	var monnameregex = /^mon.(\S+) /;
-	var downin_osds = 0;
-	var monmsgs = {};
-
-	// we collect monitor/osd information from the checks
-	Ext.Object.each(health.checks, function(key, value, obj) {
-	    var found = null;
-	    if (key === 'OSD_DOWN') {
-		found = value.summary.message.match(downinregex);
-		if (found !== null) {
-		    downin_osds = parseInt(found[1],10);
-		}
-	    }
-	    else if (Ext.String.startsWith(key, 'MON_')) {
-		if (!value.detail) {
-		    return;
-		}
-		found = value.detail[0].message.match(monnameregex);
-		if (found !== null) {
-		    if (!monmsgs[found[1]]) {
-			monmsgs[found[1]] = [];
-		    }
-		    monmsgs[found[1]].push({
-			text: Ext.Array.reduce(value.detail, function(first, second) {
-			    return first + '\n' + second.message;
-			}, ''),
-			severity: value.severity
-		    });
-		}
-	    }
-	});
-
-	// update osds counts
-
-	var total_osds = osdmap.osdmap.num_osds || 0;
-	var in_osds = osdmap.osdmap.num_in_osds || 0;
-	var up_osds = osdmap.osdmap.num_up_osds || 0;
-	var out_osds = total_osds - in_osds;
-	var down_osds = total_osds - up_osds;
-
-	var downout_osds = down_osds - downin_osds;
-	var upin_osds = in_osds - downin_osds;
-	var upout_osds = up_osds - upin_osds;
-	var osds = {
-	    total: total_osds,
-	    upin: upin_osds,
-	    upout: upout_osds,
-	    downin: downin_osds,
-	    downout: downout_osds
-	};
-	me.getComponent('osds').update(osds);
-
-	// update the monitors
-	var mons = monmap.mons.sort(function(a,b) {
-	    return (a.name < b.name)?-1:(a.name > b.name)?1:0;
-	});
-
-	var monContainer = me.getComponent('monitors');
-
-	var i;
-	for (i = 0; i < mons.length; i++) {
-	    var monitor = monContainer.getComponent('mon.' + mons[i].name);
-	    if (!monitor) {
-		// since mons are already sorted, and
-		// we always have a sorted list
-		// we can add it at the mons+1 position (because of the title)
-		monitor = monContainer.insert(i+1, {
-		    xtype: 'pveCephMonitorWidget',
-		    itemId: 'mon.' + mons[i].name
-		});
-	    }
-	    monitor.updateMonitor(mons[i], monmsgs, quorum_names);
-	}
-	me.suspendLayout = false;
-	me.updateLayout();
-    }
-});
-
-Ext.define('PVE.ceph.MonitorWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveCephMonitorWidget',
-
-    userCls: 'monitor inline-block',
-    data: {
-	name: '0',
-	health: 'HEALTH_ERR',
-	text: '',
-	iconCls: PVE.Utils.get_health_icon(),
-	addr: ''
-    },
-
-    tpl: [
-	'{name}: ',
-	'<i class="fa fa-fw {iconCls}"></i>'
-    ],
-
-    // expects 3 variables which are
-    // timestate: the status from timechecks.mons
-    // data: the monmap.mons data
-    // quorum_names: the quorum_names array
-    updateMonitor: function(data, monmsgs, quorum_names) {
-	var me = this;
-	var state = 'HEALTH_ERR';
-	var text = '';
-	var healthstates = {
-	    'HEALTH_OK': 3,
-	    'HEALTH_WARN': 2,
-	    'HEALTH_ERR': 1
-	};
-
-	if (quorum_names &&
-	    quorum_names.indexOf(data.name) !== -1) {
-	    state = 'HEALTH_OK';
-	}
-
-	if (monmsgs[data.name]) {
-	    Ext.Array.forEach(monmsgs[data.name], function(msg) {
-		if (healthstates[msg.severity] < healthstates[state]) {
-		    state = msg.severity;
-		}
-
-		text += msg.text + "\n";
-	    });
-	}
-
-	me.update(Ext.apply(me.data, {
-	    health: state,
-	    text: text,
-	    addr: data.addr,
-	    name: data.name,
-	    iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
-	}));
-    },
-
-    listeners: {
-	mouseenter: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (!me) {
-		    return;
-		}
-		if (!me.tooltip) {
-		    me.tooltip = Ext.create('Ext.tip.ToolTip', {
-			target: me.el,
-			trackMouse: true,
-			renderTo: Ext.getBody(),
-			html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
-			      gettext('Address') + ': ' + me.data.addr + '<br />' +
-			      gettext('Health')  + ': ' + me.data.health + '<br />' + 
-			      me.data.text
-		    });
-		}
-		me.tooltip.show();
-	    }
-	},
-	mouseleave: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (me.tooltip) {
-		    me.tooltip.destroy();
-		    delete me.tooltip;
-		}
-	    }
-	}
-    }
-});
-Ext.define('PVE.node.CephConfig', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfig',
-
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/config',
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.CephConfigCrush', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfigCrush',
-
-    onlineHelp: 'chapter_pveceph',
-
-    layout: 'border',
-    items: [{
-	    title: gettext('Configuration'),
-	    xtype: 'pveNodeCephConfig',
-	    region: 'center'
-	},
-	{
-	    title: 'Crush Map', // do not localize
-	    xtype: 'pveNodeCephCrushMap',
-	    region: 'east',
-	    split: true,
-	    width: '50%'
-    }],
-
-    initComponent: function() {
-	var me = this;
-	me.defaults = {
-	    pveSelNode: me.pveSelNode
-	};
-	me.callParent();
-    }
-});
-Ext.define('PVE.ceph.Log', {
-    extend: 'Proxmox.panel.LogView',
-    xtype: 'cephLogView',
-    nodename: undefined,
-    failCallback: function(response) {
-	var me = this;
-	var msg = response.htmlStatus;
-	var windowShow = PVE.Utils.showCephInstallOrMask(me, msg, me.nodename,
-	    function(win){
-		me.mon(win, 'cephInstallWindowClosed', function(){
-		    me.loadTask.delay(200);
-		});
-	    }
-	);
-	if (!windowShow) {
-	    Proxmox.Utils.setErrorMask(me, msg);
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.CephInstallWizard', {
-	extend: 'PVE.window.Wizard',
-	alias: 'widget.pveCephInstallWizard',
-	mixins: ['Proxmox.Mixin.CBind'],
-	resizable: false,
-	nodename: undefined,
-	viewModel: {
-	    data: {
-		nodename: '',
-		configuration: true,
-		isInstalled: false
-	    }
-	},
-	cbindData: {
-	    nodename: undefined
-	},
-	title: gettext('Setup'),
-	navigateNext: function() {
-	    var tp = this.down('#wizcontent');
-	    var atab = tp.getActiveTab();
-
-	    var next = tp.items.indexOf(atab) + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (ntab) {
-		ntab.enable();
-		tp.setActiveTab(ntab);
-	    }
-	},
-	setInitialTab: function (index) {
-	    var tp = this.down('#wizcontent');
-	    var initialTab = tp.items.getAt(index);
-	    initialTab.enable();
-	    tp.setActiveTab(initialTab);
-	},
-	onShow: function() {
-		this.callParent(arguments);
-		var isInstalled = this.getViewModel().get('isInstalled');
-		if (isInstalled) {
-		    this.getViewModel().set('configuration', false);
-		    this.setInitialTab(2);
-		}
-	},
-	items: [
-	    {
-		title: gettext('Info'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'chapter_pveceph',
-		html: '<h3>Ceph?</h3>'+
-		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
-		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
-		' This wizard will guide you through the necessary steps, after the initial installation you will be offered to create a initial configuration.'+
-		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
-		'<p>Please take a look at our documentation, by clicking the help button below, before starting the installation, '+
-		'if you want to gain deeper knowledge about Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#back').hide(true);
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Start installation'));
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
-		    }
-		}
-	    },
-	    {
-		title: gettext('Installation'),
-		xtype: 'panel',
-		layout: 'fit',
-		cbind:{
-		    nodename: '{nodename}'
-		},
-		viewModel: {}, // needed to inherit parent viewModel data
-		listeners: {
-		    afterrender: function() {
-			var me = this;
-			if (this.getViewModel().get('isInstalled')) {
-			    this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
-			} else {
-			    me.down('pveNoVncConsole').fireEvent('activate');
-			}
-		    },
-		    activate: function() {
-			var me = this;
-			var nodename = me.nodename;
-			me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
-				storeid: 'ceph-status-' + nodename,
-				interval: 1000,
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + nodename + '/ceph/status'
-				},
-				listeners: {
-				    load: function(rec, response, success, operation) {
-
-					if (success) {
-					    me.updateStore.stopUpdate();
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("not initialized", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("rados_connect failed", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
-					    me.down('textfield').setValue('success');
-					} else if (!operation.error.statusText.match("not installed", "i")) {
-					    Proxmox.Utils.setErrorMask(me, operation.error.statusText);
-					}
-				    }
-				}
-			});
-			me.updateStore.startUpdate();
-		    },
-		    destroy: function() {
-			var me = this;
-			if (me.updateStore) {
-			    me.updateStore.stopUpdate();
-			}
-		    }
-		},
-		items: [
-		    {
-			itemId: 'jsconsole',
-			consoleType: 'cmd',
-			xtermjs: true,
-			xtype: 'pveNoVncConsole',
-			cbind:{
-			    nodename: '{nodename}'
-			},
-			cmd: 'ceph_install'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'installSuccess',
-			value: '',
-			allowBlank: false,
-			submitValue: false,
-			hidden: true
-		    }
-		]
-	    },
-	    {
-		xtype: 'inputpanel',
-		title: gettext('Configuration'),
-		onlineHelp: 'chapter_pveceph',
-		cbind: {
-		    nodename: '{nodename}'
-		},
-		viewModel: {
-		    data: {
-			replicas: undefined,
-			minreplicas: undefined
-		    }
-		},
-		listeners: {
-		    activate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
-		    },
-		    beforeshow: function() {
-			if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			    this.mask("Coniguration already initialized",['pve-static-mask']);
-			} else {
-			    this.unmask();
-			}
-		    },
-		    deactivate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
-		    }
-		},
-		column1: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('Ceph cluster configuration') + ':'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'network',
-			vtype: 'IPCIDRAddress',
-			value: '',
-			fieldLabel: 'Public Network IP/CIDR',
-			bind: {
-			    allowBlank: '{configuration}'
-			},
-			setAllowBlank: function(allowBlank) {
-			    this.allowBlank = allowBlank;
-			    this.validate();
-			}
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'cluster-network',
-			vtype: 'IPCIDRAddress',
-			fieldLabel: 'Cluster Network IP/CIDR',
-			allowBlank: true,
-			emptyText: gettext('Same as Public Network')
-		    }
-		    // FIXME: add hint about cluster network and/or reference user to docs??
-		],
-		column2: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('First Ceph monitor') + ':'
-		    },
-		    {
-			xtype: 'pveNodeSelector',
-			fieldLabel: gettext('Monitor node'),
-			name: 'mon-node',
-			selectCurNode: true,
-			allowBlank: false
-		    },
-		    {
-			xtype: 'displayfield',
-			value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
-			userCls: 'pve-hint'
-		    }
-		],
-		advancedColumn1: [
-		    {
-			xtype: 'numberfield',
-			name: 'size',
-			fieldLabel: 'Number of replicas',
-			bind: {
-			    value: '{replicas}'
-			},
-			maxValue: 7,
-			minValue: 2,
-			emptyText: '3'
-		    },
-		    {
-			xtype: 'numberfield',
-			name: 'min_size',
-			fieldLabel: 'Minimum replicas',
-			bind: {
-			    maxValue: '{replicas}',
-			    value: '{minreplicas}'
-			},
-			minValue: 2,
-			maxValue: 3,
-			setMaxValue: function(value) {
-			    this.maxValue = Ext.Number.from(value, 2);
-			    // allow enough to avoid split brains with max 'size', but more makes simply no sense
-			    if (this.maxValue > 4) {
-				this.maxValue = 4;
-			    }
-			    this.toggleSpinners();
-			    this.validate();
-			},
-			emptyText: '2'
-		    }
-		],
-		onGetValues: function(values) {
-		    ['cluster-network', 'size', 'min_size'].forEach(function(field) {
-			if (!values[field]) {
-			    delete values[field];
-			}
-		    });
-		    return values;
-		},
-		onSubmit: function() {
-		    var me = this;
-		    if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			var wizard = me.up('window');
-			var kv = wizard.getValues();
-			delete kv['delete'];
-			var monNode = kv['mon-node'];
-			delete kv['mon-node'];
-			var nodename = me.nodename;
-			delete kv.nodename;
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/ceph/init',
-			    waitMsgTarget: wizard,
-			    method: 'POST',
-			    params: kv,
-			    success: function() {
-				Proxmox.Utils.API2Request({
-				    url: '/nodes/' + monNode + '/ceph/mon',
-				    waitMsgTarget: wizard,
-				    method: 'POST',
-				    success: function() {
-					me.up('pveCephInstallWizard').navigateNext();
-				    },
-				    failure: function(response, opts) {
-					Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				    }
-				});
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-
-		    } else {
-			me.up('pveCephInstallWizard').navigateNext();
-		    }
-		}
-	    },
-	    {
-		title: gettext('Success'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'pve_ceph_install',
-		html: '<h3>Installation successful!</h3>'+
-		'<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
-		    '<ol><li>Install Ceph on other nodes</li>'+
-		    '<li>Create additional Ceph Monitors</li>'+
-		    '<li>Create Ceph OSDs</li>'+
-		    '<li>Create Ceph Pools</li></ol>'+
-		'<p>To learn more click on the help button below.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-
-			var tp = this.up('#wizcontent');
-			var idx = tp.items.indexOf(this)-1;
-			for(;idx >= 0;idx--) {
-			    var nc = tp.items.getAt(idx);
-			    if (nc) {
-				nc.disable();
-			    }
-			}
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-		    }
-		},
-		onSubmit: function() {
-		    var wizard = this.up('pveCephInstallWizard');
-		    wizard.close();
-		}
-	    }
-	]
-    });
-Ext.define('PVE.node.DiskList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeDiskList',
-    emptyText: gettext('No Disks found'),
-    stateful: true,
-    stateId: 'grid-node-disks',
-    columns: [
-	{
-	    header: gettext('Device'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'devpath'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 80,
-	    sortable: true,
-	    dataIndex: 'type',
-	    renderer: function(v) {
-		if (v === 'ssd') {
-		    return 'SSD';
-		} else if (v === 'hdd') {
-		    return 'Hard Disk';
-		} else if (v === 'usb'){
-		    return 'USB';
-		} else {
-		    return gettext('Unknown');
-		}
-	    }
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 80,
-	    sortable: false,
-	    renderer: function(v, metaData, rec) {
-		if (rec) {
-		    if (rec.data.osdid >= 0) {
-			var bluestore = '';
-			if (rec.data.bluestore === 1) {
-			    bluestore = ' (Bluestore)';
-			}
-			return "Ceph osd." + rec.data.osdid.toString() + bluestore;
-		    }
-
-		    var types = [];
-		    if (rec.data.journals > 0) {
-			types.push('Journal');
-		    }
-
-		    if (rec.data.db > 0) {
-			types.push('DB');
-		    }
-
-		    if (rec.data.wal > 0) {
-			types.push('WAL');
-		    }
-
-		    if (types.length > 0) {
-			return 'Ceph (' + types.join(', ') + ')';
-		    }
-		}
-
-		return v || Proxmox.Utils.noText;
-	    },
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'GPT',
-	    width: 60,
-	    align: 'right',
-	    renderer: function(value) {
-		if (value) {
-		    return Proxmox.Utils.yesText;
-		} else {
-		    return Proxmox.Utils.noText;
-		}
-	    },
-	    dataIndex: 'gpt'
-	},
-	{
-	    header: gettext('Vendor'),
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'vendor'
-	},
-	{
-	    header: gettext('Model'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'model'
-	},
-	{
-	    header: gettext('Serial'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'serial'
-	},
-	{
-	    header: 'S.M.A.R.T.',
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'health'
-	},
-	{
-	    header: 'Wearout',
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'wearout',
-	    renderer: function(value) {
-		if (Ext.isNumeric(value)) {
-		    return (100 - value).toString() + '%';
-		}
-		return 'N/A';
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var store = Ext.create('Ext.data.Store', {
-	    storeid: 'node-disk-list' + nodename,
-	    model: 'node-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list"
-	    },
-	    sorters: [
-		{
-		    property : 'dev',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reloadButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reload'),
-	    handler: function() {
-		me.store.load();
-	    }
-	});
-
-	var smartButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show S.M.A.R.T. values'),
-	    selModel: sm,
-	    enableFn: function() {
-		return !!sm.getSelection().length;
-	    },
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.DiskSmartWindow', {
-                    nodename: nodename,
-		    dev: rec.data.devpath
-		});
-		win.show();
-	    }
-	});
-
-	var initButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Initialize Disk with GPT'),
-	    selModel: sm,
-	    enableFn: function() {
-		var selection = sm.getSelection();
-
-		if (!selection.length || selection[0].data.used) {
-		    return false;
-		} else {
-		    return true;
-		}
-	    },
-	    disabled: true,
-
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
-		    waitMsgTarget: me,
-		    method: 'POST',
-		    params: { disk: rec.data.devpath},
-		    failure: function(response, options) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    upid: upid
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	me.loadCount = 1; // avoid duplicate loadmask
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ reloadButton, smartButton, initButton ],
-	    listeners: {
-		itemdblclick: function() {
-		    var rec = sm.getSelection()[0];
-
-		    var win = Ext.create('PVE.DiskSmartWindow', {
-			nodename: nodename,
-			dev: rec.data.devpath
-		    });
-		    win.show();
-		}
-	    }
-	});
-
-
-	me.callParent();
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('node-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
-	idProperty: 'devpath'
-    });
-});
-
-Ext.define('PVE.DiskSmartWindow', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSmartWindow',
-
-    modal: true,
-
-    items: [
-	{
-	    xtype: 'gridpanel',
-	    layout: {
-		type: 'fit'
-	    },
-	    emptyText: gettext('No S.M.A.R.T. Values'),
-	    scrollable: true,
-	    flex: 1,
-	    itemId: 'smarts',
-	    reserveScrollbar: true,
-	    columns: [
-	    { text: 'ID', dataIndex: 'id', width: 50 },
-	    { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Normalized'), dataIndex: 'value', width: 60},
-	    { text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
-	    { text: gettext('Worst'), dataIndex: 'worst', width: 60},
-	    { text: gettext('Flags'), dataIndex: 'flags'},
-	    { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
-	    ]
-	},
-	{
-	    xtype: 'component',
-	    itemId: 'text',
-	    layout: {
-		type: 'fit'
-	    },
-	    hidden: true,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Reload'),
-	    name: 'reload',
-	    handler: function() {
-		var me = this;
-		me.up('window').store.reload();
-	    }
-	},
-	{
-	    text: gettext('Close'),
-	    name: 'close',
-	    handler: function() {
-		var me = this;
-		me.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    width: 800,
-    height: 500,
-    minWidth: 600,
-    minHeight: 400,
-    bodyPadding: 5,
-    title: gettext('S.M.A.R.T. Values'),
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var dev = me.dev;
-	if (!dev) {
-	    throw "no device specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'disk-smart',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
-	    }
-	});
-
-	me.callParent();
-	var grid = me.down('#smarts');
-	var text = me.down('#text');
-
-	Proxmox.Utils.monStoreErrors(grid, me.store);
-	me.mon(me.store, 'load', function(s, records, success) {
-	    if (success && records.length > 0) {
-		var rec = records[0];
-		switch (rec.data.type) {
-		    case 'text':
-			grid.setVisible(false);
-			text.setVisible(true);
-			text.setHtml(Ext.String.htmlEncode(rec.data.text));
-			break;
-		    default:
-			// includes 'ata'
-			// cannot use empty case because
-			// of jslint
-			grid.setVisible(true);
-			text.setVisible(false);
-			grid.setStore(rec.attributes());
-			break;
-		}
-	    }
-	});
-
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('disk-smart', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'health'},
-	    { name:'type'},
-	    { name:'text'}
-	],
-	hasMany: {model: 'smart-attribute', name: 'attributes'}
-    });
-    Ext.define('smart-attribute', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
-	]
-    });
-});
-Ext.define('PVE.node.CreateLVM', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVM',
-
-    subject: 'LVM Volume Group',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMList', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveLVMList',
-    emptyText: gettext('No Volume Groups found'),
-    stateful: true,
-    stateId: 'grid-node-lvm',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Number of LVs'),
-	    dataIndex: 'lvcount',
-	    width: 150,
-	    align: 'right'
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Volume Group',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVM', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'size', 'free',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			txt += (data.leaf) ? 'hdd-o' : 'object-group';
-			return txt;
-		    }
-		},
-		{
-		    type: 'number',
-		    name: 'usage',
-		    calculate: function(data) {
-			return ((data.size-data.free)/data.size);
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateLVMThin', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVMThin',
-
-    subject: 'LVM Thinpool',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvmthin",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMThinList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveLVMThinList',
-
-    emptyText: gettext('No thinpools found'),
-    stateful: true,
-    stateId: 'grid-node-lvmthin',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'lv',
-	    flex: 1
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'lv_size'
-	},
-	{
-	    header: gettext('Used'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Metadata Usage'),
-	    width: 120,
-	    dataIndex: 'metadata_usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Metadata Size'),
-	    width: 120,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_size'
-	},
-	{
-	    header: gettext('Metadata Used'),
-	    width: 125,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_used'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Thinpool',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVMThin', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['lv', 'lv_size', 'used', 'metadata_size', 'metadata_used',
-		    {
-			type: 'number',
-			name: 'usage',
-			calculate: function(data) {
-			    return data.used/data.lv_size;
-			}
-		    },
-		    {
-			type: 'number',
-			name: 'metadata_usage',
-			calculate: function(data) {
-			    return data.metadata_used/data.metadata_size;
-			}
-		    }
-		],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/lvmthin'
-		},
-		sorters: 'lv'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateDirectory', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateDirectory',
-
-    subject: Proxmox.Utils.directoryText,
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/directory",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    comboItems: [
-			['ext4', 'ext4'],
-			['xfs', 'xfs']
-		    ],
-		    fieldLabel: gettext('Filesystem'),
-		    name: 'filesystem',
-		    value: '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.Directorylist', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveDirectoryList',
-
-    stateful: true,
-    stateId: 'grid-node-directory',
-    columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 100,
-	    dataIndex: 'type'
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options'
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateDirectory', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['path', 'device', 'type', 'options', 'unitfile' ],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/directory'
-		},
-		sorters: 'path'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.node.CreateZFS', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateZFS',
-
-    subject: 'ZFS',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_zfs',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-	var update_disklist = function() {
-	    var grid = me.down('#disklist');
-	    var disks = grid.getSelection();
-
-	    var val = [];
-	    disks.sort(function(a,b) {
-		var aorder = a.get('order') || 0;
-		var border = b.get('order') || 0;
-		return (aorder - border);
-	    });
-
-	    disks.forEach(function(disk) {
-		val.push(disk.get('devpath'));
-	    });
-
-	    me.down('field[name=devices]').setValue(val.join(','));
-	};
-
-	Ext.apply(me, {
-	    url: '/nodes/' + me.nodename + '/disks/zfs',
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'textfield',
-			    hidden: true,
-			    name: 'devices',
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxtextfield',
-			    name: 'name',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'add_storage',
-			    fieldLabel: gettext('Add Storage'),
-			    value: '1'
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('RAID Level'),
-			    name: 'raidlevel',
-			    value: 'single',
-			    comboItems: [
-				['single', gettext('Single Disk')],
-				['mirror', 'Mirror'],
-				['raid10', 'RAID10'],
-				['raidz', 'RAIDZ'],
-				['raidz2', 'RAIDZ2'],
-				['raidz3', 'RAIDZ3']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('Compression'),
-			    name: 'compression',
-			    value: 'on',
-			    comboItems: [
-				['on', 'on'],
-				['off', 'off'],
-				['gzip', 'gzip'],
-				['lz4', 'lz4'],
-				['lzjb', 'lzjb'],
-				['zle', 'zle']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    fieldLabel: gettext('ashift'),
-			    minValue: 9,
-			    maxValue: 16,
-			    value: '12',
-			    name: 'ashift'
-			}
-		    ],
-		    columnB: [
-			{
-			    xtype: 'grid',
-			    height: 200,
-			    emptyText: gettext('No Disks unused'),
-			    itemId: 'disklist',
-			    selModel: 'checkboxmodel',
-			    listeners: {
-				selectionchange: update_disklist
-			    },
-			    store: {
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + me.nodename + '/disks/list?type=unused'
-				}
-			    },
-			    columns: [
-				{
-				    text: gettext('Device'),
-				    dataIndex: 'devpath',
-				    flex: 1
-				},
-				{
-				    text: gettext('Serial'),
-				    dataIndex: 'serial'
-				},
-				{
-				    text: gettext('Size'),
-				    dataIndex: 'size',
-				    renderer: PVE.Utils.render_size
-				},
-				{
-				    header: gettext('Order'),
-				    xtype: 'widgetcolumn',
-				    dataIndex: 'order',
-				    sortable: true,
-				    widget: {
-					xtype: 'proxmoxintegerfield',
-					minValue: 1,
-					isFormField: false,
-					listeners: {
-					    change: function(numberfield, value, old_value) {
-						var record = numberfield.getWidgetRecord();
-						record.set('order', value);
-						update_disklist(record);
-					    }
-					}
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	});
-
-        me.callParent();
-	me.down('#disklist').getStore().load();
-    }
-});
-
-Ext.define('PVE.node.ZFSDevices', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveZFSDevices',
-    stateful: true,
-    stateId: 'grid-node-zfsstatus',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'state'
-	},
-	{
-	    text: 'READ',
-	    dataIndex: 'read'
-	},
-	{
-	    text: 'WRITE',
-	    dataIndex: 'write'
-	},
-	{
-	    text: 'CKSUM',
-	    dataIndex: 'cksum'
-	},
-	{
-	    text: gettext('Message'),
-	    dataIndex: 'msg'
-	}
-    ],
-
-    rootVisible: true,
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/zfs/" + me.zpool,
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'status',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			if (data.leaf) {
-			    return txt + 'hdd-o';
-			}
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSStatus', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveZFSStatus',
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/disks/zfs/" + me.zpool;
-
-	me.rows = {
-	    scan: {
-		header: gettext('Scan')
-	    },
-	    status: {
-		header: gettext('Status')
-	    },
-	    action: {
-		header: gettext('Action')
-	    },
-	    errors: {
-		header: gettext('Errors')
-	    }
-	};
-
-	me.callParent();
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveZFSList',
-
-    stateful: true,
-    stateId: 'grid-node-zfs',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    header: gettext('Size'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	},
-	{
-	    header: gettext('Allocated'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'alloc'
-	},
-	{
-	    header: gettext('Fragmentation'),
-	    renderer: function(value) {
-		return value.toString() + '%';
-	    },
-	    dataIndex: 'frag'
-	},
-	{
-	    header: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'health'
-	},
-	{
-	    header: gettext('Deduplication'),
-	    hidden: true,
-	    renderer: function(value) {
-		return value.toFixed(2).toString() + 'x';
-	    },
-	    dataIndex: 'dedup'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': ZFS',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateZFS', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	},
-	{
-	    text: gettext('Detail'),
-	    itemId: 'detailbtn',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('panel');
-		var selection = me.getSelection();
-		if (selection.length < 1) {
-		    return;
-		}
-		me.show_detail(selection[0].get('name'));
-	    }
-	}
-    ],
-
-    show_detail: function(zpool) {
-	var me = this;
-
-	var detailsgrid = Ext.create('PVE.node.ZFSStatus', {
-	    layout: 'fit',
-	    nodename: me.nodename,
-	    flex: 0,
-	    zpool: zpool
-	});
-
-	var devicetree = Ext.create('PVE.node.ZFSDevices', {
-	    title: gettext('Devices'),
-	    nodename: me.nodename,
-	    flex: 1,
-	    zpool: zpool
-	});
-
-
-	var win = Ext.create('Ext.window.Window', {
-	    modal: true,
-	    width: 800,
-	    height: 400,
-	    resizable: true,
-	    layout: 'fit',
-	    title: gettext('Status') + ': ' + zpool,
-	    items:[{
-		xtype: 'panel',
-		region: 'center',
-		layout: {
-		    type: 'vbox',
-		    align: 'stretch'
-		},
-		items: [detailsgrid, devicetree],
-		tbar: [{
-		    text: gettext('Reload'),
-		    iconCls: 'fa fa-refresh',
-		    handler: function() {
-
-			devicetree.reload();
-			detailsgrid.reload();
-		    }
-		}]
-	    }]
-	}).show();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var selection = me.getSelection();
-	me.down('#detailbtn').setDisabled(selection.length === 0);
-    },
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	},
-	selectionchange: function() {
-	    this.set_button_status();
-	},
-	itemdblclick: function(grid, record) {
-	    var me = this;
-	    me.show_detail(record.get('name'));
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/zfs'
-		},
-		sorters: 'name'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveNodeStatus',
-
-    height: 300,
-    bodyPadding: '20 15 20 15',
-
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 15 5 15'
-    },
-
-    items: [
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpuinfo',
-	    renderer: PVE.Utils.render_node_cpu_usage
-	},
-	{
-	    itemId: 'wait',
-	    iconCls: 'fa fa-fw fa-clock-o',
-	    title: gettext('IO delay'),
-	    valueField: 'wait',
-	    rowspan: 2
-	},
-	{
-	    itemId: 'load',
-	    iconCls: 'fa fa-fw fa-tasks',
-	    title: gettext('Load average'),
-	    printBar: false,
-	    textField: 'loadavg'
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    itemId: 'memory',
-	    title: gettext('RAM usage'),
-	    valueField: 'memory',
-	    maxField: 'memory',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    itemId: 'ksm',
-	    printBar: false,
-	    title: gettext('KSM sharing'),
-	    textField: 'ksm',
-	    renderer: function(record) {
-		return PVE.Utils.render_size(record.shared);
-	    },
-	    padding: '0 15 10 15'
-	},
-	{
-	    iconCls: 'fa fa-fw fa-hdd-o',
-	    itemId: 'rootfs',
-	    title: gettext('HD space') + '(root)',
-	    valueField: 'rootfs',
-	    maxField: 'rootfs',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    iconCls: 'fa fa-fw fa-refresh',
-	    itemId: 'swap',
-	    printSize: true,
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'swap',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    itemId: 'cpus',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('CPU(s)'),
-	    textField: 'cpuinfo',
-	    renderer: function(cpuinfo) {
-		return cpuinfo.cpus + " x " + cpuinfo.model + " (" +
-		cpuinfo.sockets.toString() + " " +
-		(cpuinfo.sockets > 1 ?
-		    gettext('Sockets') :
-		    gettext('Socket')
-		) + ")";
-	    },
-	    value: ''
-	},
-	{
-	    itemId: 'kversion',
-	    colspan: 2,
-	    title: gettext('Kernel Version'),
-	    printBar: false,
-	    textField: 'kversion',
-	    value: ''
-	},
-	{
-	    itemId: 'version',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('PVE Manager Version'),
-	    textField: 'pveversion',
-	    value: ''
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
-	me.setTitle(me.pveSelNode.data.node + ' (' + gettext('Uptime') + ': ' + uptime + ')');
-    }
-
-});
-Ext.define('PVE.node.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    showVersions: function() {
-	var me = this;
-
-	// Note: we use simply text/html here, because ExtJS grid has problems
-	// with cut&paste
-
-	var nodename = me.pveSelNode.data.node;
-
-	var view = Ext.createWidget('component', {
-	    autoScroll: true,
-	    padding: 5,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	});
-
-	var win = Ext.create('Ext.window.Window', {
-	    title: gettext('Package versions'),
-	    width: 600,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [ view ]
-	});
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: "/nodes/" + nodename + "/apt/versions",
-	    method: 'GET',
-	    failure: function(response, opts) {
-		win.close();
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		win.show();
-		var text = '';
-
-		Ext.Array.each(response.result.data, function(rec) {
-		    var version = "not correctly installed";
-		    var pkg = rec.Package;
-		    if (rec.OldVersion && rec.CurrentState === 'Installed') {
-			version = rec.OldVersion;
-		    }
-		    if (rec.RunningKernel) {
-			text += pkg + ': ' + version + ' (running kernel: ' +
-			    rec.RunningKernel + ')\n';
-		    } else if (rec.ManagerVersion) {
-			text += pkg + ': ' + version + ' (running version: ' +
-			    rec.ManagerVersion + ')\n';
-		    } else {
-			text += pkg + ': ' + version + '\n';
-		    }
-		});
-
-		view.update(Ext.htmlEncode(text));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var rstore = me.statusStore;
-
-	var version_btn = new Ext.Button({
-	    text: gettext('Package versions'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { me.showVersions(); });
-	    }
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl: "/api2/json/nodes/" + nodename + "/rrddata",
-	    model: 'pve-rrd-node'
-	});
-
-	Ext.apply(me, {
-	    tbar: [version_btn, '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: 'column',
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: [
-			{
-			    xtype: 'pveNodeStatus',
-			    rstore: rstore,
-			    width: 770,
-			    pveSelNode: me.pveSelNode
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('CPU usage'),
-			    fields: ['cpu','iowait'],
-			    fieldTitles: [gettext('CPU usage'), gettext('IO delay')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Server load'),
-			    fields: ['loadavg'],
-			    fieldTitles: [gettext('Load average')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Memory usage'),
-			    fields: ['memtotal','memused'],
-			    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Network traffic'),
-			    fields: ['netin','netout'],
-			    store: rrdstore
-			}
-		    ]
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*global Blob*/
-Ext.define('PVE.node.SubscriptionKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-    title: gettext('Upload Subscription Key'),
-    width: 300,
-    items: {
-	xtype: 'textfield',
-	name: 'key',
-	value: '',
-	fieldLabel: gettext('Subscription Key')
-    },
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.Subscription', {
-    extend: 'Proxmox.grid.ObjectGrid',
-
-    alias: ['widget.pveNodeSubscription'],
-
-    onlineHelp: 'getting_help',
-
-    viewConfig: {
-	enableTextSelection: true
-    },
-
-    showReport: function() {
-	var me = this;
-	var nodename = me.pveSelNode.data.node;
-
-	var getReportFileName = function() {
-	    var now = Ext.Date.format(new Date(), 'D-d-F-Y-G-i');
-	    return me.nodename + '-report-'  + now + '.txt';
-	};
-
-	var view = Ext.createWidget('component', {
-	    itemId: 'system-report-view',
-	    scrollable: true,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace',
-		padding: '5px'
-	    }
-	});
-
-	var reportWindow = Ext.create('Ext.window.Window', {
-	    title: gettext('System Report'),
-	    width: 1024,
-	    height: 600,
-	    layout: 'fit',
-	    modal: true,
-	    buttons: [
-		        '->',
-			{
-			    text: gettext('Download'),
-			    handler: function() {
-				var fileContent = reportWindow.getComponent('system-report-view').html;
-				var fileName = getReportFileName();
-
-				// Internet Explorer
-				if (window.navigator.msSaveOrOpenBlob) {
-				    navigator.msSaveOrOpenBlob(new Blob([fileContent]), fileName);
-				} else {
-				    var element = document.createElement('a');
-				    element.setAttribute('href', 'data:text/plain;charset=utf-8,'
-				      + encodeURIComponent(fileContent));
-				    element.setAttribute('download', fileName);
-				    element.style.display = 'none';
-				    document.body.appendChild(element);
-				    element.click();
-				    document.body.removeChild(element);
-				}
-			    }
-			}
-		],
-	    items: view
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/nodes/' + me.nodename + '/report',
-	    method: 'GET',
-	    waitMsgTarget: me,
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var report = Ext.htmlEncode(response.result.data);
-		reportWindow.show();
-		view.update(report);
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = '/nodes/' + me.nodename + '/subscription';
-
-	var render_status = function(value) {
-
-	    var message = me.getObjectValue('message');
-
-	    if (message) {
-		return value + ": " + message;
-	    }
-	    return value;
-	};
-
-	var rows = {
-	    productname: {
-		header: gettext('Type')
-	    },
-	    key: {
-		header: gettext('Subscription Key')
-	    },
-	    status: {
-		header: gettext('Status'),
-		renderer: render_status
-	    },
-	    message: {
-		visible: false
-	    },
-	    serverid: {
-		header: gettext('Server ID')
-	    },
-	    sockets: {
-		header: gettext('Sockets')
-	    },
-	    checktime: {
-		header: gettext('Last checked'),
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    nextduedate: {
-		header: gettext('Next due date')
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json' + baseurl,
-	    cwidth1: 170,
-	    tbar: [ 
-		{
-		    text: gettext('Upload Subscription Key'),
-		    handler: function() {
-			var win = Ext.create('PVE.node.SubscriptionKeyEdit', {
-			    url: '/api2/extjs/' + baseurl 
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		{
-		    text: gettext('Check'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    params: { force: 1 },
-			    url: baseurl,
-			    method: 'POST',
-			    waitMsgTarget: me,
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    },
-			    callback: reload
-			});
-		    }
-		},
-		{
-		    text: gettext('System Report'),
-		    handler: function() {
-			Proxmox.Utils.checked_command(function (){ me.showReport(); });
-		    }
-		}
-	    ],
-	    rows: rows,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CertificateView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCertificatesView',
-
-    onlineHelp: 'sysadmin_certificate_management',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    items: [
-	{
-	    xtype: 'pveCertView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveACMEView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.CertificateViewer', {
-    extend: 'Proxmox.window.Edit',
-
-    title: gettext('Certificate'),
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-    width: 800,
-    resizable: true,
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'filename'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Fingerprint'),
-	    name: 'fingerprint'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Issuer'),
-	    name: 'issuer'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject'),
-	    name: 'subject'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Valid Since'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notbefore'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Expires'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notafter'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject Alternative Names'),
-	    name: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    xtype: 'textarea',
-	    editable: false,
-	    grow: true,
-	    growMax: 200,
-	    fieldLabel: gettext('Certificate'),
-	    name: 'pem'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.cert) {
-	    throw "no cert given";
-	}
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/info';
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		if (Ext.isArray(response.result.data)) {
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.filename === me.cert) {
-			    me.setValues(item);
-			    return false;
-			}
-		    });
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CertUpload', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCertUpload',
-
-    title: gettext('Upload Custom Certificate'),
-    resizable: false,
-    isCreate: true,
-    submitText: gettext('Upload'),
-    method: 'POST',
-    width: 600,
-
-    apiCallDone: function(success, response, options) {
-	if (!success) {
-	    return;
-	}
-
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    items: [
-	{
-	    fieldLabel: gettext('Private Key (Optional)'),
-	    labelAlign: 'top',
-	    emptyText: gettext('No change'),
-	    name: 'key',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=key]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    autoEl: 'hr'
-	},
-	{
-	    fieldLabel: gettext('Certificate Chain'),
-	    labelAlign: 'top',
-	    allowBlank: false,
-	    name: 'certificates',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=certificates]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'restart',
-	    value: '1'
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'force',
-	    value: '1'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/custom';
-
-	me.callParent();
-    }
-});
-
-Ext.define('pve-certificate', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san' ],
-    idProperty: 'filename'
-});
-
-Ext.define('PVE.node.Certificates', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveCertView',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    text: gettext('Upload Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.CertUpload', {
-		    nodename: me.nodename
-		});
-		win.show();
-		win.on('destroy', me.reload, me);
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'deletebtn',
-	    text: gettext('Delete Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/certificates/custom?restart=1',
-		    method: 'DELETE',
-		    success: function(response, opt) {
-			var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-			Ext.getBody().mask(txt, ['pve-static-mask']);
-			// reload after 10 seconds automatically
-			Ext.defer(function() {
-			    window.location.reload(true);
-			}, 10000);
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    itemId: 'viewbtn',
-	    disabled: true,
-	    text: gettext('View Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		me.view_certificate();
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('File'),
-	    width: 150,
-	    dataIndex: 'filename'
-	},
-	{
-	    header: gettext('Issuer'),
-	    flex: 1,
-	    dataIndex: 'issuer'
-	},
-	{
-	    header: gettext('Subject'),
-	    flex: 1,
-	    dataIndex: 'subject'
-	},
-	{
-	    header: gettext('Valid Since'),
-	    width: 150,
-	    dataIndex: 'notbefore',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Expires'),
-	    width: 150,
-	    dataIndex: 'notafter',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Subject Alternative Names'),
-	    flex: 1,
-	    dataIndex: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    header: gettext('Fingerprint'),
-	    dataIndex: 'fingerprint',
-	    hidden: true
-	},
-	{
-	    header: gettext('PEM'),
-	    dataIndex: 'pem',
-	    hidden: true
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var rec = me.rstore.getById('pveproxy-ssl.pem');
-
-	me.down('#deletebtn').setDisabled(!rec);
-    },
-
-    view_certificate: function() {
-	var me = this;
-	var selection = me.getSelection();
-	if (!selection || selection.length < 1) {
-	    return;
-	}
-	var win = Ext.create('PVE.node.CertificateViewer', {
-	    cert: selection[0].data.filename,
-	    nodename : me.nodename
-	});
-	win.show();
-    },
-
-    listeners: {
-	itemdblclick: 'view_certificate'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'certs-' + me.nodename,
-	    model: 'pve-certificate',
-	    proxy: {
-		type: 'proxmox',
-		    url: '/api2/json/nodes/' + me.nodename + '/certificates/info'
-	    }
-	});
-
-	me.store = {
-	    type: 'diff',
-	    rstore: me.rstore
-	};
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-    }
-});
-Ext.define('PVE.node.ACMEEditor', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveACMEEditor',
-
-    subject: gettext('Domains'),
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    items: [
-		{
-		    xtype: 'textarea',
-		    fieldLabel: gettext('Domains'),
-		    emptyText: "domain1.example.com\ndomain2.example.com",
-		    name: 'domains'
-		}
-	    ],
-	    onGetValues: function(values) {
-		if (!values.domains) {
-		    return {
-			'delete': 'acme'
-		    };
-		}
-		var domains = values.domains.split(/\n/).join(';');
-		return {
-		    'acme': 'domains=' + domains
-		};
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		var res = PVE.Parser.parseACME(response.result.data.acme);
-		if (res) {
-		    res.domains = res.domains.join(' ');
-		    me.setValues(res);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACMEAccountCreate', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-    title: gettext('Register Account'),
-    isCreate: true,
-    method: 'POST',
-    submitText: gettext('Register'),
-    url: '/cluster/acme/account',
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'proxmoxComboGrid',
-	    name: 'directory',
-	    allowBlank: false,
-	    valueField: 'url',
-	    displayField: 'name',
-	    fieldLabel: gettext('ACME Directory'),
-	    store: {
-		autoLoad: true,
-		fields: ['name', 'url'],
-		idProperty: ['name'],
-		proxy: {
-		    type: 'proxmox',
-		    url: '/api2/json/cluster/acme/directories'
-		},
-		sorters: {
-		    property: 'name',
-		    order: 'ASC'
-		}
-	    },
-	    listConfig: {
-		columns: [
-		    {
-			header: gettext('Name'),
-			dataIndex: 'name',
-			flex: 1
-		    },
-		    {
-			header: gettext('URL'),
-			dataIndex: 'url',
-			flex: 1
-		    }
-		]
-	    },
-	    listeners: {
-		change: function(combogrid, value) {
-		    var me = this;
-		    if (!value) {
-			return;
-		    }
-
-		    var disp = me.up('window').down('#tos_url_display');
-		    var field = me.up('window').down('#tos_url');
-		    var checkbox = me.up('window').down('#tos_checkbox');
-
-		    disp.setValue(gettext('Loading'));
-		    field.setValue(undefined);
-		    checkbox.setValue(undefined);
-
-		    Proxmox.Utils.API2Request({
-			url: '/cluster/acme/tos',
-			method: 'GET',
-			params: {
-			    directory: value
-			},
-			success: function(response, opt) {
-			    me.up('window').down('#tos_url').setValue(response.result.data);
-			    me.up('window').down('#tos_url_display').setValue(response.result.data);
-			},
-			failure: function(response, opt) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-		}
-	    }
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'tos_url_display',
-	    fieldLabel: gettext('Terms of Service'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos_url_display'
-	},
-	{
-	    xtype: 'hidden',
-	    itemId: 'tos_url',
-	    name: 'tos_url'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'tos_checkbox',
-	    fieldLabel: gettext('Accept TOS'),
-	    submitValue: false,
-	    validateValue: function(value) {
-		if (value && this.checked) {
-		    return true;
-		}
-		return false;
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'contact',
-	    vtype: 'email',
-	    allowBlank: false,
-	    fieldLabel: gettext('E-Mail')
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.ACMEAccountView', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 600,
-    fieldDefaults: {
-	labelWidth: 140
-    },
-
-    title: gettext('Account'),
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('E-Mail'),
-	    name: 'email'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Created'),
-	    name: 'createdAt'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Status'),
-	    name: 'status'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Directory'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'directory'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Terms of Services'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.accountname) {
-	    throw "no account name defined";
-	}
-
-	me.url = '/cluster/acme/account/' + me.accountname;
-
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		var data = response.result.data;
-		data.email = data.account.contact[0];
-		data.createdAt = data.account.createdAt;
-		data.status = data.account.status;
-		me.setValues(data);
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACME', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveACMEView',
-
-    margin: '10 0 0 0',
-    title: 'ACME',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    itemId: 'edit',
-	    text: gettext('Edit Domains'),
-	    handler: function() {
-		this.up('grid').run_editor();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'createaccount',
-	    text: gettext('Register Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountCreate', {
-		    taskDone: function() {
-			me.load_account();
-			me.reload();
-		    }
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'viewaccount',
-	    text: gettext('View Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountView', {
-		    accountname: 'default'
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'order',
-	    text: gettext('Order Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-
-		Proxmox.Utils.API2Request({
-		    method: 'POST',
-		    params: {
-			force: 1
-		    },
-		    url: '/nodes/' + me.nodename + '/certificates/acme/certificate',
-		    success: function(response, opt) {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: response.result.data,
-			    taskDone: function(success) {
-				me.certificate_order_finished(success);
-			    }
-			});
-			win.show();
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ],
-
-    certificate_order_finished: function(success) {
-	if (!success) {
-	    return;
-	}
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    set_button_status: function() {
-	var me = this;
-
-	var account = !!me.account;
-	var acmeObj = PVE.Parser.parseACME(me.getObjectValue('acme'));
-	var domains = acmeObj ? acmeObj.domains.length : 0;
-
-	var order = me.down('#order');
-	order.setVisible(account);
-	order.setDisabled(!account || !domains);
-
-	me.down('#createaccount').setVisible(!account);
-	me.down('#viewaccount').setVisible(account);
-    },
-
-    load_account: function() {
-	var me = this;
-
-	// for now we only use the 'default' account
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/acme/account/default',
-	    success: function(response, opt) {
-		me.account = response.result.data;
-		me.set_button_status();
-	    },
-	    failure: function(response, opt) {
-		me.account = undefined;
-		me.set_button_status();
-	    }
-	});
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create(me.rows.acme.editor, me.editorConfig);
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    listeners: {
-	itemdblclick: 'run_editor'
-    },
-
-    // account data gets loaded here
-    account: undefined,
-
-    disableSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/api2/json/nodes/' + me.nodename + '/config';
-
-	me.editorConfig = {
-	    url: '/api2/extjs/nodes/' + me.nodename + '/config'
-	};
-	/*jslint confusion: true*/
-	/*acme is a string above*/
-	me.rows = {
-	    acme: {
-		defaultValue: '',
-		header: gettext('Domains'),
-		editor: 'PVE.node.ACMEEditor',
-		renderer: function(value) {
-		    var acmeObj = PVE.Parser.parseACME(value);
-		    if (acmeObj) {
-			return acmeObj.domains.join('<br>');
-		    }
-		    return Proxmox.Utils.noneText;
-		}
-	    }
-	};
-	/*jslint confusion: false*/
-
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-	me.load_account();
-    }
-});
-Ext.define('PVE.node.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.node.Config',
-
-    onlineHelp: 'chapter_system_administration',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/status",
-	    interval: 1000
-	});
-
-	var node_command = function(cmd) {
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/status',
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var actionBtn = Ext.create('Ext.Button', {
-	    text: gettext('Bulk Actions'),
-	    iconCls: 'fa fa-fw fa-ellipsis-v',
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    menu: new Ext.menu.Menu({
-		items: [
-		    {
-			text: gettext('Bulk Start'),
-			iconCls: 'fa fa-fw fa-play',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Start'),
-				btnText: gettext('Start'),
-				action: 'startall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Stop'),
-			iconCls: 'fa fa-fw fa-stop',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Stop'),
-				btnText: gettext('Stop'),
-				action: 'stopall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Migrate'),
-			iconCls: 'fa fa-fw fa-send-o',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Migrate'),
-				btnText: gettext('Migrate'),
-				action: 'migrateall'
-			    });
-			    win.show();
-			}
-		    }
-		]
-	    })
-	});
-
-	var restartBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reboot'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Reboot node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('reboot');
-	    },
-	    iconCls: 'fa fa-undo'
-	});
-
-	var shutdownBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Shutdown node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('shutdown');
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var shellBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.nodes['Sys.Console'],
-	    text: gettext('Shell'),
-	    consoleType: 'shell',
-	    nodename: nodename
-	});
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext('Node') + " '" + nodename + "'",
-	    hstateid: 'nodetab',
-	    defaults: { statusStore: me.statusStore },
-	    tbar: [ restartBtn, shutdownBtn, shellBtn, actionBtn]
-	});
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary',
-		    xtype: 'pveNodeSummary'
-		},
-		{
-		    title: gettext('Notes'),
-		    iconCls: 'fa fa-sticky-note-o',
-		    itemId: 'notes',
-		    xtype: 'pveNotesView'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Console']) {
-	    me.items.push(
-		{
-		    title: gettext('Shell'),
-		    iconCls: 'fa fa-terminal',
-		    itemId: 'jsconsole',
-		    xtype: 'pveNoVncConsole',
-		    consoleType: 'shell',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('System'),
-		    iconCls: 'fa fa-cogs',
-		    itemId: 'services',
-		    expandedOnInit: true,
-		    startOnlyServices: {
-			'pveproxy': true,
-			'pvedaemon': true,
-			'pve-cluster': true
-		    },
-		    nodename: nodename,
-		    onlineHelp: 'pve_service_daemons',
-		    xtype: 'proxmoxNodeServiceView'
-		},
-		{
-		    title: gettext('Network'),
-		    iconCls: 'fa fa-exchange',
-		    itemId: 'network',
-		    groups: ['services'],
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeNetworkView'
-		},
-		{
-		    title: gettext('Certificates'),
-		    iconCls: 'fa fa-certificate',
-		    itemId: 'certificates',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'pveCertificatesView'
-		},
-		{
-		    title: gettext('DNS'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'dns',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeDNSView'
-		},
-		{
-		    title: gettext('Hosts'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'hosts',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeHostsView'
-		},
-		{
-		    title: gettext('Time'),
-		    itemId: 'time',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'proxmoxNodeTimeView',
-		    iconCls: 'fa fa-clock-o'
-		});
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push({
-		title: 'Syslog',
-		iconCls: 'fa fa-list',
-		groups: ['services'],
-		disabled: !caps.nodes['Sys.Syslog'],
-		itemId: 'syslog',
-		xtype: 'proxmoxLogView',
-		url: "/api2/extjs/nodes/" + nodename + "/syslog",
-		log_select_timespan: 1
-	    });
-
-	    if (caps.nodes['Sys.Modify']) {
-		me.items.push({
-		    title: gettext('Updates'),
-		    iconCls: 'fa fa-refresh',
-		    disabled: !caps.nodes['Sys.Console'],
-		    // do we want to link to system updates instead?
-		    itemId: 'apt',
-		    xtype: 'proxmoxNodeAPT',
-		    upgradeBtn: {
-			xtype: 'pveConsoleButton',
-			disabled: Proxmox.UserName !== 'root@pam',
-			text: gettext('Upgrade'),
-			consoleType: 'upgrade',
-			nodename: nodename
-		    },
-		    nodename: nodename
-		});
-	    }
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    iconCls: 'fa fa-shield',
-		    title: gettext('Firewall'),
-		    allow_iface: true,
-		    base_url: '/nodes/' + nodename + '/firewall/rules',
-		    list_refs_url: '/cluster/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    title: gettext('Options'),
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_host_specific_configuration',
-		    groups: ['firewall'],
-		    base_url: '/nodes/' + nodename + '/firewall/options',
-		    fwtype: 'node',
-		    itemId: 'firewall-options'
-		});
-	}
-
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Disks'),
-		    itemId: 'storage',
-		    expandedOnInit: true,
-		    iconCls: 'fa fa-hdd-o',
-		    xtype: 'pveNodeDiskList'
-		},
-		{
-		    title: 'LVM',
-		    itemId: 'lvm',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square',
-		    groups: ['storage'],
-		    xtype: 'pveLVMList'
-		},
-		{
-		    title: 'LVM-Thin',
-		    itemId: 'lvmthin',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square-o',
-		    groups: ['storage'],
-		    xtype: 'pveLVMThinList'
-		},
-		{
-		    title: Proxmox.Utils.directoryText,
-		    itemId: 'directory',
-		    onlineHelp: 'chapter_storage',
-		    iconCls: 'fa fa-folder',
-		    groups: ['storage'],
-		    xtype: 'pveDirectoryList'
-		},
-		{
-		    title: 'ZFS',
-		    itemId: 'zfs',
-		    onlineHelp: 'chapter_zfs',
-		    iconCls: 'fa fa-th-large',
-		    groups: ['storage'],
-		    xtype: 'pveZFSList'
-		},
-		{
-		    title: 'Ceph',
-		    itemId: 'ceph',
-		    iconCls: 'fa fa-ceph',
-		    xtype: 'pveNodeCephStatus'
-		},
-		{
-		    xtype: 'pveReplicaView',
-		    iconCls: 'fa fa-retweet',
-		    title: gettext('Replication'),
-		    itemId: 'replication'
-		},
-		{
-		    xtype: 'pveNodeCephConfigCrush',
-		    title: gettext('Configuration'),
-		    iconCls: 'fa fa-gear',
-		    groups: ['ceph'],
-		    itemId: 'ceph-config'
-		},
-		{
-		    xtype: 'pveNodeCephMonList',
-		    title: gettext('Monitor'),
-		    iconCls: 'fa fa-tv',
-		    groups: ['ceph'],
-		    itemId: 'ceph-monlist'
-		},
-		{
-		    xtype: 'pveNodeCephOsdTree',
-		    title: 'OSD',
-		    iconCls: 'fa fa-hdd-o',
-		    groups: ['ceph'],
-		    itemId: 'ceph-osdtree'
-		},
-		{
-		    xtype: 'pveNodeCephFSPanel',
-		    title: 'CephFS',
-		    iconCls: 'fa fa-folder',
-		    groups: ['ceph'],
-		    nodename: nodename,
-		    itemId: 'ceph-cephfspanel'
-		},
-		{
-		    xtype: 'pveNodeCephPoolList',
-		    title: 'Pools',
-		    iconCls: 'fa fa-sitemap',
-		    groups: ['ceph'],
-		    itemId: 'ceph-pools'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push(
-		{
-		    xtype: 'proxmoxLogView',
-		    title: gettext('Log'),
-		    iconCls: 'fa fa-list',
-		    groups: ['firewall'],
-		    onlineHelp: 'chapter_pve_firewall',
-		    url: '/api2/extjs/nodes/' + nodename + '/firewall/log',
-		    itemId: 'firewall-fwlog'
-		},
-		{
-		    title: gettext('Log'),
-		    itemId: 'ceph-log',
-		    iconCls: 'fa fa-list',
-		    groups: ['ceph'],
-		    onlineHelp: 'chapter_pveceph',
-		    xtype: 'cephLogView',
-		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
-		    nodename: nodename
-		});
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Task History'),
-		iconCls: 'fa fa-list',
-		itemId: 'tasks',
-		nodename: nodename,
-		xtype: 'proxmoxNodeTasks'
-	    },
-	    {
-		title: gettext('Subscription'),
-		iconCls: 'fa fa-support',
-		itemId: 'support',
-		xtype: 'pveNodeSubscription',
-		nodename: nodename
-	    }
-	);
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var uptimerec = s.data.get('uptime');
-	    var powermgmt = uptimerec ? uptimerec.data.value : false;
-	    if (!caps.nodes['Sys.PowerMgmt']) {
-		powermgmt = false;
-	    }
-	    restartBtn.setDisabled(!powermgmt);
-	    shutdownBtn.setDisabled(!powermgmt);
-	    shellBtn.setDisabled(!powermgmt);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    config: {
-	vmtype: undefined,
-	nodename: undefined,
-	vmid: undefined
-    },
- // private, used to store the migration mode after checking if the guest runs
-    liveMode: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=formPanel]': {
-		validityChange: function(panel, isValid) {
-		    this.lookup('submitButton').setDisabled(!isValid);
-		}
-	    },
-	    'button[reference=submitButton]': {
-		click: function() {
-		    var me = this;
-		    var view = me.getView();
-
-		    var values = me.lookup('formPanel').getValues();
-		    var params = {
-			target: values.target
-		    };
-
-		    if (view.liveMode) {
-			params[view.liveMode] = 1;
-		    }
-
-		    Proxmox.Utils.API2Request({
-			params: params,
-			url: '/nodes/' + view.nodename + '/' + view.vmtype + '/' + view.vmid + '/migrate',
-			waitMsgTarget: view,
-			method: 'POST',
-			failure: function(response, opts) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var upid = response.result.data;
-			    var extraTitle = Ext.String.format(' ({0} ---> {1})', view.nodename, params.target);
-
-			    Ext.create('Proxmox.window.TaskViewer', {
-				upid: upid,
-				extraTitle: extraTitle
-			    }).show();
-
-			    view.close();
-			}
-		    });
-		}
-	    }
-	}
-    },
-
-    width: 350,
-    modal: true,
-    layout: 'auto',
-    border: false,
-    resizable: false,
-    items: [
-	{
-	    xtype: 'form',
-	    reference: 'formPanel',
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    xtype: 'pveNodeSelector',
-		    reference: 'pveNodeSelector',
-		    name: 'target',
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    disallowedNodes: undefined,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'displayfield',
-		    reference: 'migrationMode',
-		    fieldLabel: gettext('Mode'),
-		    value: gettext('Offline')
-		}
-		]
-	}
-    ],
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    reference: 'proxmoxHelpButton',
-	    onlineHelp: 'pct_migration',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	},
-	'->',
-	{
-	    xtype: 'button',
-	    reference: 'submitButton',
-	    text: gettext('Migrate')
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	me.callParent();
-
-	var title = gettext('Migrate') + (' CT ') + me.vmid;
-	me.liveMode = 'restart';
-
-	if (me.vmtype === 'qemu') {
-	    me.lookup('proxmoxHelpButton').setHelpConfig({
-		onlineHelp: 'qm_migration'
-	    });
-	    title = gettext('Migrate') + (' VM ') + me.vmid;
-	    me.liveMode = 'online';
-	}
-
-	var running = false;
-	var vmrec = PVE.data.ResourceStore.findRecord('vmid', me.vmid,
-	    0, false, false, true);
-	if (vmrec && vmrec.data && vmrec.data.running) {
-	    running = true;
-	}
-
-	if (running) {
-	    var displayField = me.lookup('migrationMode');
-	    if (me.vmtype === 'qemu') {
-		displayField.setValue(gettext('Online'));
-		me.liveMode = 'online';
-	    } else {
-		displayField.setValue(gettext('Restart Mode'));
-		me.liveMode = 'restart';
-	    }
-	}
-
-	me.setTitle(title);
-	me.lookup('pveNodeSelector').disallowedNodes = [me.nodename];
-	me.lookup('formPanel').isValid();
-    }
-});Ext.define('PVE.window.BulkAction', {
-    extend: 'Ext.window.Window',
-
-    resizable: true,
-    width: 800,
-    modal: true,
-    layout: {
-	type: 'fit'
-    },
-    border: false,
-
-    // the action to be set
-    // currently there are
-    // startall
-    // migrateall
-    // stopall
-    action: undefined,
-
-    submit: function(params) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.action,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		me.hide();
-		win.on('destroy', function() {
-		    me.close();
-		});
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.action) {
-	    throw "no action specified";
-	}
-
-	if (!me.btnText) {
-	    throw "no button text specified";
-	}
-
-	if (!me.title) {
-	    throw "no title specified";
-	}
-
-	var items = [];
-
-	if (me.action === 'migrateall') {
-	    /*jslint confusion: true*/
-	    /*value is string and number*/
-	    items.push(
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'target',
-		    disallowedNodes: [me.nodename],
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'maxworkers',
-		    minValue: 1,
-		    maxValue: 100,
-		    value: 1,
-		    fieldLabel: gettext('Parallel jobs'),
-		    allowBlank: false
-		},
-		{
-		    itemId: 'lxcwarning',
-		    xtype: 'displayfield',
-		    userCls: 'pve-hint',
-		    value: 'Warning: Running CTs will be migrated in Restart Mode.',
-		    hidden: true // only visible if running container chosen
-		}
-	    );
-	    /*jslint confusion: false*/
-	} else if (me.action === 'startall') {
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'force',
-		value: 1
-	    });
-	}
-
-	items.push({
-	    xtype: 'vmselector',
-	    itemId: 'vms',
-	    name: 'vms',
-	    flex: 1,
-	    height: 300,
-	    selectAll: true,
-	    allowBlank: false,
-	    nodename: me.nodename,
-	    action: me.action,
-	    listeners: {
-		selectionchange: function(vmselector, records) {
-		    if (me.action == 'migrateall') {
-			var showWarning = records.some(function(item) {
-			    return (item.data.type == 'lxc' &&
-				item.data.status == 'running');
-			});
-			me.down('#lxcwarning').setVisible(showWarning);
-		    }
-		}
-	    }
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    fieldDefaults: {
-		labelWidth: 300,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: me.btnText,
-	    handler: function() {
-		form.isValid();
-		me.submit(form.getValues());
-	    }
-	});
-
-	Ext.apply(me, {
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-
-	form.on('validitychange', function() {
-	    var valid = form.isValid();
-	    submitBtn.setDisabled(!valid);
-	});
-	form.isValid();
-    }
-});
-Ext.define('PVE.window.Clone', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    isTemplate: false,
-
-    onlineHelp: 'qm_copy_and_clone',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=cloneform]': {
-		validitychange: 'disableSubmit'
-	    }
-	},
-	disableSubmit: function(form) {
-	    this.lookupReference('submitBtn').setDisabled(!form.isValid());
-	}
-    },
-
-    statics: {
-	// display a snapshot selector only if needed
-	wrap: function(nodename, vmid, isTemplate, guestType) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var snapshotList = response.result.data;
-		    var hasSnapshots = snapshotList.length === 1 &&
-			snapshotList[0].name === 'current' ? false : true;
-
-		    Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: isTemplate,
-			hasSnapshots: hasSnapshots
-		    }).show();
-		}
-	    });
-	}
-    },
-
-    create_clone: function(values) {
-	var me = this;
-
-	var params = { newid: values.newvmid };
-
-	if (values.snapname && values.snapname !== 'current') {
-	    params.snapname = values.snapname;
-	}
-
-	if (values.pool) {
-	    params.pool = values.pool;
-	}
-
-	if (values.name) {
-	    if (me.guestType === 'lxc') {
-		params.hostname = values.name;
-	    } else {
-		params.name = values.name;
-	    }
-	}
-
-	if (values.target) {
-	    params.target = values.target;
-	}
-
-	if (values.clonemode === 'copy') {
-	    params.full = 1;
-	    if (values.hdstorage) {
-		params.storage = values.hdstorage;
-		if (values.diskformat && me.guestType !== 'lxc') {
-		    params.format = values.diskformat;
-		}
-	    }
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/clone',
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-
-    },
-
-    // disable the Storage selector when clone mode is linked clone
-    updateVisibility: function() {
-	var me = this;
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-	var disksel = me.lookup('diskselector');
-	disksel.setDisabled(clonemode === 'clone');
-    },
-
-    // add to the list of valid nodes each node where
-    // all the VM disks are available
-    verifyFeature: function() {
-	var me = this;
-
-	var snapname = me.lookupReference('snapshotsel').getValue();
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-
-	var params = { feature: clonemode };
-	if (snapname !== 'current') {
-	    params.snapname = snapname;
-	}
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/feature',
-	    params: params,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		me.lookupReference('submitBtn').setDisabled(true);
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var res = response.result.data;
-
-		me.lookupReference('targetsel').allowedNodes = res.nodes;
-		me.lookupReference('targetsel').validate();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.snapname) {
-	    me.snapname = 'current';
-	}
-
-	if (!me.guestType) {
-	    throw "no Guest Type specified";
-	}
-
-	var titletext = me.guestType === 'lxc' ? 'CT' : 'VM';
-	if (me.isTemplate) {
-	    titletext += ' Template';
-	}
-	me.title = "Clone " + titletext + " " + me.vmid;
-
-	var col1 = [];
-	var col2 = [];
-
-	col1.push({
-	    xtype: 'pveNodeSelector',
-	    name: 'target',
-	    reference: 'targetsel',
-	    fieldLabel: gettext('Target node'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    onlineValidator: true,
-	    listeners: {
-		change: function(f, value) {
-		    me.lookupReference('hdstorage').setTargetNode(value);
-		}
-	    }
-	});
-
-	var modelist = [['copy', gettext('Full Clone')]];
-	if (me.isTemplate) {
-	    modelist.push(['clone', gettext('Linked Clone')]);
-	}
-
-	col1.push({
-	    xtype: 'pveGuestIDSelector',
-	    name: 'newvmid',
-	    guestType: me.guestType,
-	    value: '',
-	    loadNextFreeID: true,
-	    validateExists: false
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'name',
-	    allowBlank: true,
-	    fieldLabel: me.guestType === 'lxc' ? gettext('Hostname') : gettext('Name')
-	},
-	{
-	    xtype: 'pvePoolSelector',
-	    fieldLabel: gettext('Resource Pool'),
-	    name: 'pool',
-	    value: '',
-	    allowBlank: true
-	}
-	);
-
-	col2.push({
-	    xtype: 'proxmoxKVComboBox',
-	    fieldLabel: gettext('Mode'),
-	    name: 'clonemode',
-	    reference: 'clonemodesel',
-	    allowBlank: false,
-	    hidden: !me.isTemplate,
-	    value: me.isTemplate ? 'clone' : 'copy',
-		    comboItems: modelist,
-		    listeners: {
-			change: function(t, value) {
-			    me.updateVisibility();
-			    me.verifyFeature();
-			}
-		    }
-	},
-	{
-	    xtype: 'PVE.form.SnapshotSelector',
-	    name: 'snapname',
-	    reference: 'snapshotsel',
-	    fieldLabel: gettext('Snapshot'),
-	    nodename: me.nodename,
-	    guestType: me.guestType,
-	    vmid: me.vmid,
-	    hidden: me.isTemplate || !me.hasSnapshots ? true : false,
-	    disabled: false,
-	    allowBlank: false,
-	    value : me.snapname,
-	    listeners: {
-		change: function(f, value) {
-		    me.verifyFeature();
-		}
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    reference: 'diskselector',
-	    nodename: me.nodename,
-	    autoSelect: false,
-	    hideSize: true,
-	    hideSelection: true,
-	    storageLabel: gettext('Target Storage'),
-	    allowBlank: true,
-	    storageContent: me.guestType === 'qemu' ? 'images' : 'rootdir',
-	    emptyText: gettext('Same as source'),
-	    disabled: me.isTemplate ? true : false // because default mode is clone for templates
-	});
-
-	var formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    reference: 'cloneform',
-	    border: false,
-	    layout: 'column',
-	    defaultType: 'container',
-	    columns: 2,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: col1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: col2
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 600,
-	    height: 250,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ {
-		xtype: 'proxmoxHelpButton',
-		listenToGlobalEvent: false,
-		hidden: false,
-		onlineHelp: me.onlineHelp
-	    },
-	    '->',
-	    {
-		reference: 'submitBtn',
-		text: gettext('Clone'),
-		disabled: true,
-		handler: function() {
-		    var cloneForm = me.lookupReference('cloneform');
-		    if (cloneForm.isValid()) {
-			me.create_clone(cloneForm.getValues());
-		    }
-		}
-	    } ],
-	    items: [ formPanel ]
-	});
-
-	me.callParent();
-
-	me.verifyFeature();
-    }
-});
-Ext.define('PVE.qemu.Monitor', {
-    extend: 'Ext.panel.Panel',
-
-    alias: 'widget.pveQemuMonitor',
-
-    maxLines: 500,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var history = [];
-	var histNum = -1;
-	var lines = [];
-
-	var textbox = Ext.createWidget('panel', {
-	    region: 'center',
-	    xtype: 'panel',
-	    autoScroll: true,
-	    border: true,
-	    margins: '5 5 5 5',
-	    bodyStyle: 'font-family: monospace;'
-	});
-
-	var scrollToEnd = function() {
-	    var el = textbox.getTargetEl();
-	    var dom = Ext.getDom(el);
-
-	    var clientHeight = dom.clientHeight;
-	    // BrowserBug: clientHeight reports 0 in IE9 StrictMode
-            // Instead we are using offsetHeight and hardcoding borders
-            if (Ext.isIE9 && Ext.isStrict) {
-		clientHeight = dom.offsetHeight + 2;
-            }
-	    dom.scrollTop = dom.scrollHeight - clientHeight;
-	};
-
-	var refresh = function() {
-	    textbox.update('<pre>' + lines.join('\n') + '</pre>');
-	    scrollToEnd();
-	};
-
-	var addLine = function(line) {
-	    lines.push(line);
-	    if (lines.length > me.maxLines) {
-		lines.shift();
-	    }
-	};
-
-	var executeCmd = function(cmd) {
-	    addLine("# " + Ext.htmlEncode(cmd));
-	    if (cmd) {
-		history.unshift(cmd);
-		if (history.length > 20) {
-		    history.splice(20);
-		}
-	    }
-	    histNum = -1;
-
-	    refresh();
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor",
-		method: 'POST',
-		waitMsgTarget: me,
-		success: function(response, opts) {
-		    var res = response.result.data; 
-		    Ext.Array.each(res.split('\n'), function(line) {
-			addLine(Ext.htmlEncode(line));
-		    });
-		    refresh();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		textbox,
-		{
-		    region: 'south',
-		    margins:'0 5 5 5',
-		    border: false,
-		    xtype: 'textfield',
-		    name: 'cmd',
-		    value: '',
-		    fieldStyle: 'font-family: monospace;',
-		    allowBlank: true,
-		    listeners: {
-			afterrender: function(f) {
-			    f.focus(false);
-			    addLine("Type 'help' for help.");
-			    refresh();
-			},
-			specialkey: function(f, e) {
-			    var key = e.getKey();
-			    switch (key) {
-				case e.ENTER:
-				    var cmd = f.getValue();
-				    f.setValue('');
-				    executeCmd(cmd);
-				    break;
-				case e.PAGE_UP:
-				    textbox.scrollBy(0, -0.9*textbox.getHeight(), false);
-				    break;
-				case e.PAGE_DOWN:
-				    textbox.scrollBy(0, 0.9*textbox.getHeight(), false);
-				    break;
-				case e.UP:
-				    if (histNum + 1 < history.length) {
-					f.setValue(history[++histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				case e.DOWN:
-				    if (histNum > 0) {
-					f.setValue(history[--histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				default:
-				    break;
-			    }
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		show: function() {
-		    var field = me.query('textfield[name="cmd"]')[0];
-		    field.focus(false, true);
-		}
-	    }
-	});		
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveQemuSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 330,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 330,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.qemu.OSTypeInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuOSTypePanel',
-    onlineHelp: 'qm_os_settings',
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'combobox[name=osbase]': {
-		change: 'onOSBaseChange'
-	    },
-	    'combobox[name=ostype]': {
-		afterrender: 'onOSTypeChange',
-		change: 'onOSTypeChange'
-	    }
-	},
-	onOSBaseChange: function(field, value) {
-	    this.lookup('ostype').getStore().setData(PVE.Utils.kvm_ostypes[value]);
-	},
-	onOSTypeChange: function(field) {
-	    var me = this, ostype = field.getValue();
-	    if (!me.getView().insideWizard) {
-		return;
-	    }
-	    var targetValues = PVE.qemu.OSDefaults.getDefaults(ostype);
-
-	    me.setWidget('pveBusSelector', targetValues.busType);
-	    me.setWidget('pveNetworkCardSelector', targetValues.networkCard);
-	    var scsihw = targetValues.scsihw || '__default__';
-	    this.getViewModel().set('current.scsihw', scsihw);
-	},
-	setWidget: function(widget, newValue) {
-	    // changing a widget is safe only if ComponentQuery.query returns us
-	    // a single value array
-	    var widgets = Ext.ComponentQuery.query('pveQemuCreateWizard ' + widget);
-	    if (widgets.length === 1) {
-		widgets[0].setValue(newValue);
-	    } else {
-		throw 'non unique widget :' + widget + ' in Wizard';
-	    }
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	/*jslint confusion: true */
-	me.items = [
-	    {
-		xtype: 'displayfield',
-		value: gettext('Guest OS') + ':',
-		hidden: !me.insideWizard
-	    },
-	    {
-		xtype: 'combobox',
-		submitValue: false,
-		name: 'osbase',
-		fieldLabel: gettext('Type'),
-		editable: false,
-		queryMode: 'local',
-		value: 'Linux',
-		store: Object.keys(PVE.Utils.kvm_ostypes)
-	    },
-	    {
-		xtype: 'combobox',
-		name: 'ostype',
-		reference: 'ostype',
-		fieldLabel: gettext('Version'),
-		value: 'l26',
-		allowBlank : false,
-		editable: false,
-		queryMode: 'local',
-		valueField: 'val',
-		displayField: 'desc',
-		store: {
-		    fields: ['desc', 'val'],
-		    data: PVE.Utils.kvm_ostypes.Linux,
-		    listeners: {
-			datachanged: function (store) {
-			    var ostype = me.lookup('ostype');
-			    var old_val = ostype.getValue();
-			    if (!me.insideWizard && old_val && store.find('val', old_val) != -1) {
-				ostype.setValue(old_val);
-			    } else {
-				ostype.setValue(store.getAt(0));
-			    }
-			}
-		    }
-		}
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.OSTypeEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: 'OS Type',
-
-    items: [{ xtype: 'pveQemuOSTypePanel' }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var value = response.result.data.ostype || 'other';
-		var osinfo = PVE.Utils.get_kvm_osinfo(value);
-		me.setValues({ ostype: value, osbase: osinfo.base });
-	    }
-	});
-    }
-});
-/*
- * This class holds performance *recommended* settings for the PVE Qemu wizards
- * the *mandatory* settings are set in the PVE::QemuServer
- * config_to_command sub
- * We store this here until we get the data from the API server
-*/
-
-// this is how you would add an hypothetic FreeBSD > 10 entry
-//
-//virtio-blk is stable but virtIO net still
-//   problematic as of 10.3
-// see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059
-//	addOS({
-//	    parent: 'generic', // inherits defaults
-//	    pveOS: 'freebsd10', // must match a radiofield in OSTypeEdit.js
-//	    busType: 'virtio' // must match a pveBusController value
-//			    // networkCard muss match a pveNetworkCardSelector
-
-
-Ext.define('PVE.qemu.OSDefaults', {
-    singleton: true, // will also force creation when loaded
-
-    constructor: function() {
-	var me = this;
-
-	var addOS = function(settings) {
-		if (me.hasOwnProperty(settings.parent)) {
-		    var child = Ext.clone(me[settings.parent]);
-		    me[settings.pveOS] = Ext.apply(child, settings);
-
-		} else {
-		    throw("Could not find your genitor");
-		}
-	    };
-
-	// default values
-	me.generic = {
-	    busType: 'ide',
-	    networkCard: 'e1000',
-	    busPriority: {
-		    ide: 4,
-		    sata: 3,
-		    scsi: 2,
-		    virtio: 1
-	    },
-	    scsihw: 'virtio-scsi-pci'
-	};
-
-       // virtio-net is in kernel since 2.6.25
-       // virtio-scsi since 3.2 but backported in RHEL with 2.6 kernel
-	addOS({
-	    pveOS: 'l26',
-	    parent : 'generic',
-	    busType: 'scsi',
-	    busPriority: {
-		    scsi: 4,
-		    virtio: 3,
-		    sata: 2,
-		    ide: 1
-	    },
-	    networkCard: 'virtio'
-	});
-
-	// recommandation from http://wiki.qemu.org/Windows2000
-	addOS({
-	    pveOS: 'w2k',
-	    parent : 'generic',
-	    networkCard: 'rtl8139',
-	    scsihw: ''
-	});
-	// https://pve.proxmox.com/wiki/Windows_XP_Guest_Notes
-	addOS({
-	    pveOS: 'wxp',
-	    parent : 'w2k'
-	});
-
-	me.getDefaults = function(ostype) {
-	    if (PVE.qemu.OSDefaults[ostype]) {
-		return PVE.qemu.OSDefaults[ostype];
-	    } else {
-		return PVE.qemu.OSDefaults.generic;
-	    }
-	};
-    }
-});
-Ext.define('PVE.qemu.ProcessorInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuProcessorPanel',
-    onlineHelp: 'qm_cpu',
-
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateCores: function() {
-	    var me = this.getView();
-	    var sockets = me.down('field[name=sockets]').getValue();
-	    var cores = me.down('field[name=cores]').getValue();
-	    me.down('field[name=totalcores]').setValue(sockets*cores);
-	    var vcpus = me.down('field[name=vcpus]');
-	    vcpus.setMaxValue(sockets*cores);
-	    vcpus.setEmptyText(sockets*cores);
-	    vcpus.validate();
-	},
-
-	control: {
-	    'field[name=sockets]': {
-		change: 'updateCores'
-	    },
-	    'field[name=cores]': {
-		change: 'updateCores'
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (Array.isArray(values['delete'])) {
-	    values['delete'] = values['delete'].join(',');
-	}
-
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	// build the cpu options:
-	me.cpu.cputype = values.cputype;
-
-	var flags = [];
-
-	['pcid', 'spec-ctrl'].forEach(function(flag) {
-	    if (values[flag]) {
-		flags.push('+' + flag.toString());
-	    }
-	    delete values[flag];
-	});
-
-	me.cpu.flags = flags.length ? flags.join(';') : undefined;
-
-	delete values.cputype;
-	delete values.flags;
-	var cpustring = PVE.Parser.printQemuCpu(me.cpu);
-
-	// remove cputype delete request:
-	var del = values['delete'];
-	delete values['delete'];
-	if (del) {
-	    del = del.split(',');
-	    Ext.Array.remove(del, 'cputype');
-	} else {
-	    del = [];
-	}
-
-	if (cpustring) {
-	    values.cpu = cpustring;
-	} else {
-	    del.push('cpu');
-	}
-
-	var delarr = del.join(',');
-	if (delarr) {
-	    values['delete'] = delarr;
-	}
-
-	return values;
-    },
-
-    cpu: {},
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'sockets',
-	    minValue: 1,
-	    maxValue: 4,
-	    value: '1',
-	    fieldLabel: gettext('Sockets'),
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cores',
-	    minValue: 1,
-	    maxValue: 128,
-	    value: '1',
-	    fieldLabel: gettext('Cores'),
-	    allowBlank: false
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'CPUModelSelector',
-	    name: 'cputype',
-	    value: '__default__',
-	    fieldLabel: gettext('Type')
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Total cores'),
-	    name: 'totalcores',
-	    value: '1'
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'vcpus',
-	    minValue: 1,
-	    maxValue: 1,
-	    value: '',
-	    fieldLabel: gettext('VCPUs'),
-	    deleteEmpty: true,
-	    allowBlank: true,
-	    emptyText: '1'
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    maxValue: 128, // api maximum
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    minValue: 8,
-	    maxValue: 500000,
-	    value: '1024',
-	    deleteEmpty: true,
-	    allowBlank: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Enable NUMA'),
-	    name: 'numa',
-	    uncheckedValue: 0
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'PCID',
-	    name: 'pcid',
-	    uncheckedValue: 0
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'SPEC-CTRL',
-	    name: 'spec-ctrl',
-	    uncheckedValue: 0
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.ProcessorEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.ProcessorInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Processors'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		var value = data.cpu;
-		if (value) {
-		    var cpu = PVE.Parser.parseQemuCpu(value);
-		    ipanel.cpu = cpu;
-		    data.cputype = cpu.cputype;
-		    if (cpu.flags) {
-			var flags = cpu.flags.split(';');
-			flags.forEach(function(flag) {
-			    var sign = flag.substr(0,1);
-			    flag = flag.substr(1);
-			    data[flag] = (sign === '+');
-			});
-		    }
-		}
-		me.setValues(data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuBootOrderPanel',
-    vmconfig: {}, // store loaded vm config
-
-    bootdisk: undefined,
-    selection: [],
-    list: [],
-    comboboxes: [],
-
-    isBootDisk: function(value) {
-	return PVE.Utils.bus_match.test(value);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-	var order = me.vmconfig.boot || 'cdn';
-	me.bootdisk = me.vmconfig.bootdisk || undefined;
-
-	// get the first 3 characters
-	// ignore the rest (there should never be more than 3)
-	me.selection = order.split('').slice(0,3);
-
-	// build bootdev list
-	me.list = [];
-	Ext.Object.each(me.vmconfig, function(key, value) {
-	    if (me.isBootDisk(key) &&
-		!(/media=cdrom/).test(value)) {
-		me.list.push([key, "Disk '" + key + "'"]);
-	    }
-	});
-
-	me.list.push(['d', 'CD-ROM']);
-	me.list.push(['n', gettext('Network')]);
-	me.list.push(['__none__', Proxmox.Utils.noneText]);
-
-	me.recomputeList();
-
-	me.comboboxes.forEach(function(box) {
-	    box.resetOriginalValue();
-	});
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var order = me.selection.join('');
-	var res = { boot: order };
-
-	if  (me.bootdisk && order.indexOf('c') !== -1) {
-	    res.bootdisk = me.bootdisk;
-	} else {
-	    res['delete'] = 'bootdisk';
-	}
-
-	return res;
-    },
-
-    recomputeSelection: function(combobox, newVal, oldVal) {
-	var me = this.up('#inputpanel');
-	me.selection = [];
-	me.comboboxes.forEach(function(item) {
-	    var val = item.getValue();
-
-	    // when selecting an already selected item,
-	    // switch it around
-	    if ((val === newVal || (me.isBootDisk(val) && me.isBootDisk(newVal))) &&
-		item.name !== combobox.name &&
-		newVal !== '__none__') {
-		// swap items
-		val = oldVal;
-	    }
-
-	    // push 'c','d' or 'n' in the array
-	    if (me.isBootDisk(val)) {
-		me.selection.push('c');
-		me.bootdisk = val;
-	    } else if (val === 'd' ||
-		       val === 'n') {
-		me.selection.push(val);
-	    }
-	});
-
-	me.recomputeList();
-    },
-
-    recomputeList: function(){
-	var me = this;
-	// set the correct values in the kvcomboboxes
-	var cnt = 0;
-	me.comboboxes.forEach(function(item) {
-	    if (cnt === 0) {
-		// never show 'none' on first combobox
-		item.store.loadData(me.list.slice(0, me.list.length-1));
-	    } else {
-		item.store.loadData(me.list);
-	    }
-	    item.suspendEvent('change');
-	    if (cnt < me.selection.length) {
-		item.setValue((me.selection[cnt] !== 'c')?me.selection[cnt]:me.bootdisk);
-	    } else if (cnt === 0){
-		item.setValue('');
-	    } else {
-		item.setValue('__none__');
-	    }
-	    cnt++;
-	    item.resumeEvent('change');
-	    item.validate();
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	// this has to be done here, because of
-	// the way our inputPanel class handles items
-	me.comboboxes = [
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 1",
-		labelWidth: 120,
-		name: 'bd1',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 2",
-		labelWidth: 120,
-		name: 'bd2',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 3",
-		labelWidth: 120,
-		name: 'bd3',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    })
-	];
-	Ext.apply(me, { items: me.comboboxes });
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    items: [{
-	xtype: 'pveQemuBootOrderPanel',
-	itemId: 'inputpanel'
-    }],
-
-    subject: gettext('Boot Order'),
-
-    initComponent : function() {
-	var me = this;
-	me.callParent();
-	me.load({
-	    success: function(response, options) {
-		me.down('#inputpanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuMemoryPanel',
-    onlineHelp: 'qm_memory',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = {};
-
-	res.memory = values.memory;
-	res.balloon = values.balloon;
-
-	if (!values.ballooning) {
-	    res.balloon = 0;
-	    res['delete'] = 'shares';
-	} else if (values.memory === values.balloon) {
-	    delete res.balloon;
-	    res['delete'] = 'balloon,shares';
-	} else if (Ext.isDefined(values.shares) && (values.shares !== "")) {
-	    res.shares = values.shares;
-	} else {
-	    res['delete'] = "shares";
-	}
-
-	return res;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var labelWidth = 160;
-
-	me.items= [
-	    {
-		xtype: 'pveMemoryField',
-		labelWidth: labelWidth,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		name: 'memory',
-		minValue: 1,
-		step: 32,
-		hotplug: me.hotplug,
-		listeners: {
-		    change: function(f, value, old) {
-			var bf = me.down('field[name=balloon]');
-			var balloon = bf.getValue();
-			bf.setMaxValue(value);
-			if (balloon === old) {
-			    bf.setValue(value);
-			}
-			bf.validate();
-		    }
-		}
-	    }
-	];
-
-	me.advancedItems= [
-	    {
-		xtype: 'pveMemoryField',
-		name: 'balloon',
-		minValue: 1,
-		step: 32,
-		fieldLabel: gettext('Minimum memory') + ' (MiB)',
-		hotplug: me.hotplug,
-		labelWidth: labelWidth,
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			var memory = me.down('field[name=memory]').getValue();
-			var shares = me.down('field[name=shares]');
-			shares.setDisabled(value === memory);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'shares',
-		disabled: true,
-		minValue: 0,
-		maxValue: 50000,
-		value: '',
-		step: 10,
-		fieldLabel: gettext('Shares'),
-		labelWidth: labelWidth,
-		allowBlank: true,
-		emptyText: Proxmox.Utils.defaultText + ' (1000)',
-		submitEmptyText: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		labelWidth: labelWidth,
-		value: '1',
-		name: 'ballooning',
-		fieldLabel: gettext('Ballooning Device'),
-		listeners: {
-		    change: function(f, value) {
-			var bf = me.down('field[name=balloon]');
-			var shares = me.down('field[name=shares]');
-			var memory = me.down('field[name=memory]');
-			bf.setDisabled(!value);
-			shares.setDisabled(!value || (bf.getValue() === memory.getValue()));
-		    }
-		}
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = me.items;
-	    me.items = undefined;
-	    me.advancedColumn1 = me.advancedItems;
-	    me.advancedItems = undefined;
-	}
-	me.callParent();
-    }
-
-});
-
-Ext.define('PVE.qemu.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent: function() {
-	var me = this;
-
-	var memoryhotplug;
-	if(me.hotplug) {
-	    Ext.each(me.hotplug.split(','), function(el) {
-		if (el === 'memory') {
-		    memoryhotplug = 1;
-	        }
-	    });
-	}
-
-	var ipanel = Ext.create('PVE.qemu.MemoryInputPanel', {
-	    hotplug: memoryhotplug
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: [ ipanel ],
-	    // uncomment the following to use the async configiguration API
-	    // backgroundDelay: 5, 
-	    width: 400
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-
-		var values = {
-		    ballooning: data.balloon === 0 ? '0' : '1',
-		    shares: data.shares,
-		    memory: data.memory || '512',
-		    balloon: data.balloon > 0 ? data.balloon : (data.memory || '512')
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuNetworkInputPanel',
-    onlineHelp: 'qm_network_device',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	me.network.model = values.model;
-	if (values.nonetwork) {
-	    return {};
-	} else {
-	    me.network.bridge = values.bridge;
-	    me.network.tag = values.tag;
-	    me.network.firewall = values.firewall;
-	}
-	me.network.macaddr = values.macaddr;
-	me.network.disconnect = values.disconnect;
-	me.network.queues = values.queues;
-
-	if (values.rate) {
-	    me.network.rate = values.rate;
-	} else {
-	    delete me.network.rate;
-	}
-
-	var params = {};
-
-	params[me.confid] = PVE.Parser.printQemuNetwork(me.network);
-
-	return params;
-    },
-
-    setNetwork: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data) {
-	    data.networkmode = data.bridge ? 'bridge' : 'nat';
-	} else {
-	    data = {};
-	    data.networkmode = 'bridge';
-	}
-	me.network = data;
-	
-	me.setValues(me.network);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.bridgesel.setNodename(nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.network = {};
-	me.confid = 'net0';
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.bridgesel = Ext.create('PVE.form.BridgeSelector', {
-	    name: 'bridge',
-	    fieldLabel: gettext('Bridge'),
-	    nodename: me.nodename,
-	    autoSelect: true,
-	    allowBlank: false
-	});
-
-	me.column1 = [
-	    me.bridgesel,
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		checked: (me.insideWizard || me.isCreate)
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Disconnect'),
-		name: 'disconnect'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1.unshift({
-		xtype: 'checkbox',
-		name: 'nonetwork',
-		inputValue: 'none',
-		boxLabel: gettext('No network device'),
-		listeners: {
-		    change: function(cb, value) {
-			var fields = [
-			    'disconnect',
-			    'bridge',
-			    'tag',
-			    'firewall',
-			    'model',
-			    'macaddr',
-			    'rate',
-			    'queues'
-			];
-			fields.forEach(function(fieldname) {
-			    me.down('field[name='+fieldname+']').setDisabled(value);
-			});
-			me.down('field[name=bridge]').validate();
-		    }
-		}
-	    });
-	    me.column2.unshift({
-		xtype: 'displayfield'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'pveNetworkCardSelector',
-		name: 'model',
-		fieldLabel: gettext('Model'),
-		value: PVE.qemu.OSDefaults.generic.networkCard,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'macaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		allowBlank: true,
-		emptyText: 'auto'
-	    });
-	me.advancedColumn2 = [
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: '',
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'queues',
-		fieldLabel: 'Multiqueue',
-		minValue: 1,
-		maxValue: 8,
-		value: '',
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";	    
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.NetworkInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: me.isCreate
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Device'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		if (!me.isCreate) {
-		    var value = me.vmconfig[me.confid];
-		    var network = PVE.Parser.parseQemuNetwork(me.confid, value);
-		    if (!network) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse network options');
-			me.close();
-			return;
-		    }
-		    ipanel.setNetwork(me.confid, network);
-		} else {
-		    for (i = 0; i < 100; i++) {
-			confid = 'net' + i.toString();
-			if (!Ext.isDefined(me.vmconfig[confid])) {
-			    me.confid = confid;
-			    break;
-			}
-		    }
-		    ipanel.setNetwork(me.confid);		    
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Smbios1InputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.PVE.qemu.Smbios1InputPanel',
-
-    insideWizard: false,
-
-    smbios1: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {
-	    smbios1: PVE.Parser.printQemuSmbios1(values)
-	};
-
-	return params;
-    },
-
-    setSmbios1: function(data) {
-	var me = this;
-
-	me.smbios1 = data;
-	
-	me.setValues(me.smbios1);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: 'UUID',
-		regex: /^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$/,
-		name: 'uuid'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Manufacturer'),
-		regex: /^\S+$/,
-		name: 'manufacturer'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Product'),
-		regex: /^\S+$/,
-		name: 'product'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Version'),
-		regex: /^\S+$/,
-		name: 'version'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Serial'),
-		regex: /^\S+$/,
-		name: 'serial'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: 'SKU',
-		regex: /^\S+$/,
-		name: 'sku'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Family'),
-		regex: /^\S+$/,
-		name: 'family'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.Smbios1Edit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.Smbios1InputPanel', {});
-
-	Ext.applyIf(me, {
-	    subject: gettext('SMBIOS settings (type1)'),
-	    width: 450,
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		var value = me.vmconfig.smbios1;
-		if (value) {
-		    var data = PVE.Parser.parseQemuSmbios1(value);
-		    if (!data) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse smbios options');
-			me.close();
-			return;
-		    }
-		    ipanel.setSmbios1(data);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.CDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuCDInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || (values.controller + values.deviceid);
-	
-	me.drive.media = 'cdrom';
-	if (values.mediaType === 'iso') {
-	    me.drive.file = values.cdimage;
-	} else if (values.mediaType === 'cdrom') {
-	    me.drive.file = 'cdrom';
-	} else {
-	    me.drive.file = 'none';
-	}
-
-	var params = {};
-		
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	
-	return params;	
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig, 'cdrom');
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	var values = {};
-	if (drive.file === 'cdrom') {
-	    values.mediaType = 'cdrom';
-	} else if (drive.file === 'none') {
-	    values.mediaType = 'none';
-	} else {
-	    values.mediaType = 'iso';
-	    var match = drive.file.match(/^([^:]+):/);
-	    if (match) {
-		values.cdstorage = match[1];
-		values.cdimage = drive.file;
-	    }
-	}
-
-	me.drive = drive;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.cdstoragesel.setNodename(nodename);
-	me.cdfilesel.setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	var items = [];
-
-	if (!me.confid) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		noVirtIO: true
-	    });
-	    items.push(me.bussel);
-	}
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'iso',
-	    boxLabel: gettext('Use CD/DVD disc image file (iso)'),
-	    checked: true,
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=cdstorage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').validate();
-		}
-	    }
-	});
-
-	me.cdfilesel = Ext.create('PVE.form.FileSelector', {
-	    name: 'cdimage',
-	    nodename: me.nodename,
-	    storageContent: 'iso',
-	    fieldLabel: gettext('ISO image'),
-	    labelAlign: 'right',
-	    allowBlank: false
-	});
-	
-	me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
-	    name: 'cdstorage',
-	    nodename: me.nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'iso',
-	    allowBlank: false,
-	    autoSelect: me.insideWizard,
-	    listeners: {
-		change: function(f, value) {
-		    me.cdfilesel.setStorage(value);
-		}
-	    }
-	});
-
-	items.push(me.cdstoragesel);
-	items.push(me.cdfilesel);
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'cdrom',
-	    boxLabel: gettext('Use physical CD/DVD Drive')
-	});
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'none',
-	    boxLabel: gettext('Do not use any media')
-	});
-
-	me.items = items;
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.CDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'CD/DVD Drive',
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-	
-	me.load({
-	    success:  function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert('Error', 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-/* 'change' property is assigned a string and then a function */
-Ext.define('PVE.qemu.HDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuHDInputPanel',
-    onlineHelp: 'qm_hard_disk',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onControllerChange: function(field) {
-	    var value = field.getValue();
-
-	    var allowIOthread = value.match(/^(virtio|scsi)/);
-	    this.lookup('iothread').setDisabled(!allowIOthread);
-	    if (!allowIOthread) {
-		this.lookup('iothread').setValue(false);
-	    }
-
-	    var virtio = value.match(/^virtio/);
-	    this.lookup('discard').setDisabled(virtio);
-	    this.lookup('ssd').setDisabled(virtio);
-	    if (virtio) {
-		this.lookup('discard').setValue(false);
-		this.lookup('ssd').setValue(false);
-	    }
-
-	    this.lookup('scsiController').setVisible(value.match(/^scsi/));
-	},
-
-	control: {
-	    'field[name=controller]': {
-		change: 'onControllerChange',
-		afterrender: 'onControllerChange'
-	    },
-	    'field[name=iothread]' : {
-		change: function(f, value) {
-		    if (!this.getView().insideWizard) {
-			return;
-		    }
-		    var vmScsiType = value ? 'virtio-scsi-single': 'virtio-scsi-pci';
-		    this.lookupReference('scsiController').setValue(vmScsiType);
-		}
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {};
-	var confid = me.confid || (values.controller + values.deviceid);
-
-	if (me.unused) {
-	    me.drive.file = me.vmconfig[values.unusedId];
-	    confid = values.controller + values.deviceid;
-	} else if (me.isCreate) {
-	    if (values.hdimage) {
-		me.drive.file = values.hdimage;
-	    } else {
-		me.drive.file = values.hdstorage + ":" + values.disksize;
-	    }
-	    me.drive.format = values.diskformat;
-	}
-
-	if (values.nobackup) {
-	    me.drive.backup = 'no';
-	} else {
-	    delete me.drive.backup;
-	}
-
-	if (values.noreplicate) {
-	    me.drive.replicate = 'no';
-	} else {
-	    delete me.drive.replicate;
-	}
-
-	if (values.discard) {
-	    me.drive.discard = 'on';
-	} else {
-	    delete me.drive.discard;
-	}
-
-	if (values.ssd) {
-	    me.drive.ssd = 'on';
-	} else {
-	    delete me.drive.ssd;
-	}
-
-	if (values.iothread) {
-	    me.drive.iothread = 'on';
-	} else {
-	    delete me.drive.iothread;
-	}
-
-	if (values.cache) {
-	    me.drive.cache = values.cache;
-	} else {
-	    delete me.drive.cache;
-	}
-
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            if (values[name]) {
-                me.drive[name] = values[name];
-            } else {
-                delete me.drive[name];
-            }
-            var burst_name = name + '_max';
-            if (values[burst_name] && values[name]) {
-                me.drive[burst_name] = values[burst_name];
-            } else {
-                delete me.drive[burst_name];
-            }
-        });
-
-
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
-	return params;
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	me.vmconfig = vmconfig;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig);
-	    me.scsiController.setValue(vmconfig.scsihw);
-	}
-	if (me.unusedDisks) {
-	    var disklist = [];
-	    Ext.Object.each(vmconfig, function(key, value) {
-		if (key.match(/^unused\d+$/)) {
-		    disklist.push([key, value]);
-		}
-	    });
-	    me.unusedDisks.store.loadData(disklist);
-	    me.unusedDisks.setValue(me.confid);
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	me.drive = drive;
-
-	var values = {};
-	var match = drive.file.match(/^([^:]+):/);
-	if (match) {
-	    values.hdstorage = match[1];
-	}
-
-	values.hdimage = drive.file;
-	values.nobackup = !PVE.Parser.parseBoolean(drive.backup, 1);
-	values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
-	values.diskformat = drive.format || 'raw';
-	values.cache = drive.cache || '__default__';
-	values.discard = (drive.discard === 'on');
-	values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-	values.iothread = PVE.Parser.parseBoolean(drive.iothread);
-
-	values.mbps_rd = drive.mbps_rd;
-	values.mbps_wr = drive.mbps_wr;
-	values.iops_rd = drive.iops_rd;
-	values.iops_wr = drive.iops_wr;
-	values.mbps_rd_max = drive.mbps_rd_max;
-	values.mbps_wr_max = drive.mbps_wr_max;
-	values.iops_rd_max = drive.iops_rd_max;
-	values.iops_wr_max = drive.iops_wr_max;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var labelWidth = 140;
-
-	me.drive = {};
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.advancedColumn1 = [];
-	me.advancedColumn2 = [];
-
-	if (!me.confid || me.unused) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
-	    });
-	    me.column1.push(me.bussel);
-
-	    me.scsiController = Ext.create('Ext.form.field.Display', {
-		fieldLabel: gettext('SCSI Controller'),
-		reference: 'scsiController',
-		bind: me.insideWizard ? {
-		    value: '{current.scsihw}'
-		} : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		submitValue: false,
-		hidden: true
-	    });
-	    me.column1.push(me.scsiController);
-	}
-
-	if (me.unused) {
-	    me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
-		name: 'unusedId',
-		fieldLabel: gettext('Disk image'),
-		matchFieldWidth: false,
-		listConfig: {
-		    width: 350
-		},
-		data: [],
-		allowBlank: false
-	    });
-	    me.column1.push(me.unusedDisks);
-	} else if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveDiskStorageSelector',
-		storageContent: 'images',
-		name: 'disk',
-		nodename: me.nodename,
-		autoSelect: me.insideWizard
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'textfield',
-		disabled: true,
-		submitValue: false,
-		fieldLabel: gettext('Disk image'),
-                name: 'hdimage'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'CacheTypeSelector',
-		name: 'cache',
-		value: '__default__',
-		fieldLabel: gettext('Cache')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Discard'),
-		disabled: me.confid && me.confid.match(/^virtio/),
-		reference: 'discard',
-		name: 'discard'
-	    }
-	);
-
-	me.advancedColumn1.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && me.confid.match(/^virtio/),
-		fieldLabel: gettext('SSD emulation'),
-		labelWidth: labelWidth,
-		name: 'ssd',
-		reference: 'ssd'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && !me.confid.match(/^(virtio|scsi)/),
-		fieldLabel: 'IO thread',
-		labelWidth: labelWidth,
-		reference: 'iothread',
-		name: 'iothread'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    }
-	);
-
-	me.advancedColumn2.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('No backup'),
-		labelWidth: labelWidth,
-		name: 'nobackup'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Skip replication'),
-		labelWidth: labelWidth,
-		name: 'noreplicate'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-/*jslint confusion: false */
-
-Ext.define('PVE.qemu.HDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    backgroundDelay: 5,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    me.subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
-	} else {
-           me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
-	}
-
-	me.items = [ ipanel ];
-
-	me.callParent();
-	/*jslint confusion: true*/
-	/* 'data' is assigned an empty array in same file, and here we
-	 * use it like an object
-	 */
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-	/*jslint confusion: false*/
-    }
-});
-Ext.define('PVE.window.HDResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 140,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 250,
-	    height: 150,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-Ext.define('PVE.window.HDMove', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-
-    move_disk: function(disk, storage, format, delete_disk) {
-	var me = this;
-	var qemu = (me.type === 'qemu');
-	var params = {};
-	params.storage = storage;
-	params[qemu ? 'disk':'volume'] = disk;
-
-	if (format && qemu) {
-	    params.format = format;
-	}
-
-	if (delete_disk) {
-	    params['delete'] = 1;
-	}
-
-	var url = '/nodes/' + me.nodename + '/' + me.type + '/' + me.vmid + '/';
-	url += qemu ? 'move_disk' : 'move_volume';
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: url,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		win.on('destroy', function() { me.close(); });
-	    }
-	});
-
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var diskarray = [];
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    me.type = 'qemu';
-	}
-
-	var qemu = (me.type === 'qemu');
-
-        var items = [
-            {
-                xtype: 'displayfield',
-                name: qemu ? 'disk' : 'volume',
-                value: me.disk,
-                fieldLabel: qemu ? gettext('Disk') : gettext('Mount Point'),
-                vtype: 'StorageId',
-                allowBlank: false
-            }
-        ];
-
-	items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    storageLabel: gettext('Target Storage'),
-	    nodename: me.nodename,
-	    storageContent: qemu ? 'images' : 'rootdir',
-	    hideSize: true
-	});
-
-	items.push({
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Delete source'),
-	    name: 'deleteDisk',
-	    uncheckedValue: 0,
-	    checked: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = qemu ? gettext("Move disk") : gettext('Move Volume');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: me.title,
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.move_disk(me.disk, values.hdstorage, values.diskformat,
-				 values.deleteDisk);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 350,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	me.mon(me.formPanel, 'validitychange', function(fp, isValid) {
-	    submitBtn.setDisabled(!isValid);
-	});
-
-	me.formPanel.isValid();
-    }
-});
-Ext.define('PVE.qemu.EFIDiskInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveEFIDiskInputPanel',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = 'efidisk0';
-
-	if (values.hdimage) {
-	    me.drive.file = values.hdimage;
-	} else {
-	    // we use 1 here, because for efi the size gets overridden from the backend
-	    me.drive.file = values.hdstorage + ":1";
-	}
-
-	me.drive.format = values.diskformat;
-	var params = {};
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items= [];
-
-	me.items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    nodename: me.nodename,
-	    hideSize: true
-	});
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.EFIDiskEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-    subject: gettext('EFI Disk'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveEFIDiskInputPanel',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: true
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.DisplayInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveDisplayInputPanel',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values, 'type');
-	if (ret === '') {
-	    return {
-		'delete': 'vga'
-	    };
-	}
-	return {
-	    vga: ret
-	};
-    },
-
-    items: [{
-	name: 'type',
-	xtype: 'proxmoxKVComboBox',
-	value: '__default__',
-	deleteEmpty: false,
-	fieldLabel: gettext('Graphic card'),
-	comboItems: PVE.Utils.kvm_vga_driver_array(),
-	validator: function() {
-	    var v = this.getValue();
-	    var cfg = this.up('proxmoxWindowEdit').vmconfig || {};
-
-	    if (v.match(/^serial\d+$/) && (!cfg[v] || cfg[v] !== 'socket')) {
-		var fmt = gettext("Serial interface '{0}' is not correctly configured.");
-		return Ext.String.format(fmt, v);
-	    }
-	    return true;
-	},
-	listeners: {
-	    change: function(cb, val) {
-		var me = this.up('panel');
-		if (!val) {
-		    return;
-		}
-		var disable = false;
-		var emptyText = Proxmox.Utils.defaultText;
-		switch (val) {
-		    case "cirrus":
-			emptyText = "4";
-			break;
-		    case "std":
-			emptyText = "16";
-			break;
-		    case "qxl":
-		    case "qxl2":
-		    case "qxl3":
-		    case "qxl4":
-			emptyText = "16";
-			break;
-		    case "vmware":
-			emptyText = "16";
-			break;
-		    case "none":
-		    case "serial0":
-		    case "serial1":
-		    case "serial2":
-		    case "serial3":
-			emptyText = 'N/A';
-			disable = true;
-			break;
-		    case "virtio":
-			emptyText = "256";
-			break;
-		    default:
-			break;
-		}
-		var memoryfield = me.down('field[name=memory]');
-		memoryfield.setEmptyText(emptyText);
-		memoryfield.setDisabled(disable);
-	    }
-	}
-    },{
-	xtype: 'proxmoxintegerfield',
-	emptyText: Proxmox.Utils.defaultText,
-	fieldLabel: gettext('Memory') + ' (MiB)',
-	minValue: 4,
-	maxValue: 512,
-	step: 4,
-	name: 'memory'
-    }]
-});
-
-Ext.define('PVE.qemu.DisplayEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Display'),
-    width: 350,
-
-    items: [{
-	xtype: 'pveDisplayInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-		var vga = me.vmconfig.vga || '__default__';
-		me.setValues(PVE.Parser.parsePropertyString(vga, 'type'));
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.KeyboardEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('Keyboard Layout'),
-	    items: {
-		xtype: 'VNCKeyboardSelector',
-		name: 'keyboard',
-		value: '__default__',
-		fieldLabel: gettext('Keyboard Layout')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.HardwareView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.HardwareView'],
-
-    onlineHelp: 'qm_virtual_machines_settings',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-	var iconCls = rowdef.iconCls;
-	var icon = '';
-	var txt = (rowdef.header || key);
-
-	metaData.tdAttr = "valign=middle";
-
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') { 
-		var value = me.getObjectValue(key, '', false);
-		if (value === '') {
-		    value = me.getObjectValue(key, '', true);
-		}
-		if (value.match(/vm-.*-cloudinit/)) {
-		    metaData.tdCls = 'pve-itype-icon-cloud';
-		    return rowdef.cloudheader;
-		} else if (value.match(/media=cdrom/)) {
-		    metaData.tdCls = 'pve-itype-icon-cdrom';
-		    return rowdef.cdheader;
-		}
-	    }
-	} else if (iconCls) {
-	    icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
-	    metaData.tdCls += " pve-itype-fa";
-	}
-	return icon + txt;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	/*jslint confusion: true */
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
-		never_delete: true,
-		defaultValue: '512',
-		tdCls: 'pve-itype-icon-memory',
-		group: 2,
-		multiKey: ['memory', 'balloon', 'shares'],
-		renderer: function(value, metaData, record, ri, ci, store, pending) {
-		    var res = '';
-
-		    var max = me.getObjectValue('memory', 512, pending);
-		    var balloon =  me.getObjectValue('balloon', undefined, pending);
-		    var shares = me.getObjectValue('shares', undefined, pending);
-
-		    res  = Proxmox.Utils.format_size(max*1024*1024);
-
-		    if (balloon !== undefined && balloon > 0) {
-			res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
-
-			if (shares) {
-			    res += ' [shares=' + shares +']';
-			}
-		    } else if (balloon === 0) {
-			res += ' [balloon=0]';
-		    }
-		    return res;
-		}
-	    },
-	    sockets: {
-		header: gettext('Processors'),
-		never_delete: true,
-		editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? 
-		    'PVE.qemu.ProcessorEdit' : undefined,
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		defaultValue: '1',
-		multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
-		renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
-
-		    var sockets = me.getObjectValue('sockets', 1, pending);
-		    var model = me.getObjectValue('cpu', undefined, pending);
-		    var cores = me.getObjectValue('cores', 1, pending);
-		    var numa = me.getObjectValue('numa', undefined, pending);
-		    var vcpus = me.getObjectValue('vcpus', undefined, pending);
-		    var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
-		    var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
-
-		    var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
-			sockets*cores, sockets, cores);
-
-		    if (model) {
-			res += ' [' + model + ']';
-		    }
-
-		    if (numa) {
-			res += ' [numa=' + numa +']';
-		    }
-
-		    if (vcpus) {
-			res += ' [vcpus=' + vcpus +']';
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit +']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits +']';
-		    }
-
-		    return res;
-		}
-	    },
-	    bios: {
-		header: 'BIOS',
-		group: 4,
-		never_delete: true,
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.BiosEdit' : undefined,
-		defaultValue: '',
-		iconCls: 'microchip',
-		renderer: PVE.Utils.render_qemu_bios
-	    },
-	    vga: {
-		header: gettext('Display'),
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
-		never_delete: true,
-		tdCls: 'pve-itype-icon-display',
-		group:5,
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_vga_driver		
-	    },
-	    machine: {
-		header: gettext('Machine'),
-		editor: caps.vms['VM.Config.HWType'] ?  {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Machine'),
-		    width: 350,
-		    items: [{
-			xtype: 'proxmoxKVComboBox',
-			name: 'machine',
-			value: '__default__',
-			fieldLabel: gettext('Machine'),
-			comboItems: [
-			    ['__default__', PVE.Utils.render_qemu_machine('')],
-			    ['q35', 'q35']
-			]
-		    }]} : undefined,
-		iconCls: 'cogs',
-		never_delete: true,
-		group: 6,
-		defaultValue: '',
-		renderer: PVE.Utils.render_qemu_machine
-	    },
-	    scsihw: {
-		header: gettext('SCSI Controller'),
-		iconCls: 'database',
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.ScsiHwEdit' : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		group: 7,
-		never_delete: true,
-		defaultValue: ''
-	    },
-	    cores: {
-		visible: false
-	    },
-	    cpu: {
-		visible: false
-	    },
-	    numa: {
-		visible: false
-	    },
-	    balloon: {
-		visible: false
-	    },
-	    hotplug: {
-		visible: false
-	    },
-	    vcpus: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    shares: {
-		visible: false
-	    }
-	};
-	/*jslint confusion: false */
-
-	PVE.Utils.forEachBus(undefined, function(type, id) {
-	    var confid = type + id;
-	    rows[confid] = {
-		group: 10,
-		tdCls: 'pve-itype-icon-storage',
-		editor: 'PVE.qemu.HDEdit',
-		never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-		header: gettext('Hard Disk') + ' (' + confid +')',
-		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
-		cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
-	    };
-	});
-	for (i = 0; i < 32; i++) {
-	    confid = "net" + i.toString();
-	    rows[confid] = {
-		group: 15,
-		order: i,
-		tdCls: 'pve-itype-icon-network',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
-		never_delete: caps.vms['VM.Config.Network'] ? false : true,
-		header: gettext('Network Device') + ' (' + confid +')'
-	    };
-	}
-	rows.efidisk0 = {
-	    group: 20,
-	    tdCls: 'pve-itype-icon-storage',
-	    editor: null,
-	    never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-	    header: gettext('EFI Disk')
-	};
-	for (i = 0; i < 5; i++) {
-	    confid = "usb" + i.toString();
-	    rows[confid] = {
-		group: 25,
-		order: i,
-		tdCls: 'pve-itype-icon-usb',
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('USB Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "hostpci" + i.toString();
-	    rows[confid] = {
-		group: 30,
-		order: i,
-		tdCls: 'pve-itype-icon-pci',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
-		header: gettext('PCI Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "serial" + i.toString();
-	    rows[confid] = {
-		group: 35,
-		order: i,
-		tdCls: 'pve-itype-icon-serial',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('Serial Port') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 256; i++) {
-	    rows["unused" + i.toString()] = {
-		group: 99,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
-		header: gettext('Unused Disk') + ' ' + i.toString()
-	    };
-	}
-
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-	    
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var editor = rowdef.editor;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') {
-		if (!diskCap) {
-		    return;
-		}
-		var value = me.getObjectValue(rec.data.key, '', true); 
-		if (value.match(/vm-.*-cloudinit/)) {
-		    return;
-		} else if (value.match(/media=cdrom/)) {
-		    editor = 'PVE.qemu.CDEdit';
-		}
-	    }
-
-	    var win;
-
-	    if (Ext.isString(editor)) {
-		win = Ext.create(editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var run_resize = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var run_move = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_editor
-        });
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_move
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    defaultText: gettext('Remove'),
-	    altText: gettext('Detach'),
-	    selModel: sm,
-	    disabled: true,
-	    dangerous: true,
-	    RESTMethod: 'PUT',
-	    confirmMsg: function(rec) {
-		var warn = gettext('Are you sure you want to remove entry {0}');
-		if (this.text === this.altText) {
-		    warn = gettext('Are you sure you want to detach entry {0}');
-		}
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		if (entry.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: function(b, e, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: b.RESTMethod,
-		    params: {
-			'delete': rec.data.key
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			if (b.RESTMethod === 'POST') {
-			    var upid = response.result.data;
-			    var win = Ext.create('Proxmox.window.TaskProgress', {
-				upid: upid,
-				listeners: {
-				    destroy: function () {
-					me.reload();
-				    }
-				}
-			    });
-			    win.show();
-			}
-		    }
-		});
-	    },
-	    listeners: {
-		render: function(btn) {
-		    // hack: calculate an optimal button width on first display
-		    // to prevent the whole toolbar to move when we switch
-		    // between the "Remove" and "Detach" labels
-		    var def = btn.getSize().width;
-
-		    btn.setText(btn.altText);
-		    var alt = btn.getSize().width;
-
-		    btn.setText(btn.defaultText);
-
-		    var optimal = alt > def ? alt : def;
-		    btn.setSize({ width: optimal });
-		}
-	    }
-	});
-
-	var revert_btn = new Proxmox.button.Button({
-	    text: gettext('Revert'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(b, e, rec) {
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: {
-			'revert': revert
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var efidisk_menuitem = Ext.create('Ext.menu.Item',{
-	    text: gettext('EFI Disk'),
-	    iconCls: 'pve-itype-icon-storage',
-	    disabled: !caps.vms['VM.Config.Disk'],
-	    handler: function() {
-
-		var rstoredata = me.rstore.getData().map;
-		// check if ovmf is configured
-		if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') {
-		    var win = Ext.create('PVE.qemu.EFIDiskEdit', {
-			url: '/api2/extjs/' + baseurl,
-			pveSelNode: me.pveSelNode
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		} else {
-		    Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
-		}
-
-	    }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    // disable button when we have an efidisk already
-	    // disable is ok in this case, because you can instantly
-	    // see that there is already one
-	    efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined);
-	    // en/disable usb add button
-	    var usbcount = 0;
-	    var pcicount = 0;
-	    var hasCloudInit = false;
-	    me.rstore.getData().items.forEach(function(item){
-		if (/^usb\d+/.test(item.id)) {
-		    usbcount++;
-		} else if (/^hostpci\d+/.test(item.id)) {
-		    pcicount++;
-		}
-		if (!hasCloudInit && /vm-.*-cloudinit/.test(item.data.value)) {
-		    hasCloudInit = true;
-		}
-	    });
-
-	    // heuristic only for disabling some stuff, the backend has the final word.
-	    var noSysConsolePerm = !caps.nodes['Sys.Console'];
-
-	    me.down('#addusb').setDisabled(noSysConsolePerm || (usbcount >= 5));
-	    me.down('#addpci').setDisabled(noSysConsolePerm || (pcicount >= 4));
-	    me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
-
-	    if (!rec) {
-		remove_btn.disable();
-		edit_btn.disable();
-		resize_btn.disable();
-		move_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isUnusedDisk = key.match(/^unused\d+/);
-	    var isUsedDisk = !isUnusedDisk &&
-		rowdef.tdCls == 'pve-itype-icon-storage' &&
-		(value && !value.match(/media=cdrom/));
-
-	    var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
-
-	    var isEfi = (key === 'efidisk0');
-
-	    remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true) || (isUnusedDisk && !diskCap));
-	    remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
-	    remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
-
-	    edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit || !diskCap);
-
-	    resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    move_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    revert_btn.setDisabled(!pending);
-
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
-	    interval: 5000,
-	    selModel: sm,
-	    run_editor: run_editor,
-	    tbar: [ 
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Hard Disk'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.HDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CD/DVD Drive'),
-				iconCls: 'pve-itype-icon-cdrom',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Network Device'),
-				iconCls: 'pve-itype-icon-network',
-				disabled: !caps.vms['VM.Config.Network'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.NetworkEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode,
-					isCreate: true
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    efidisk_menuitem,
-			    {
-				text: gettext('USB Device'),
-				itemId: 'addusb',
-				iconCls: 'pve-itype-icon-usb',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.USBEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('PCI Device'),
-				itemId: 'addpci',
-				iconCls: 'pve-itype-icon-pci',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.PCIEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Serial Port'),
-				itemId: 'addserial',
-				iconCls: 'pve-itype-icon-serial',
-				disabled: !caps.vms['VM.Config.Options'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.SerialEdit', {
-					url: '/api2/extjs/' + baseurl
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CloudInit Drive'),
-				itemId: 'addci',
-				iconCls: 'pve-itype-icon-cloud',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CIDriveEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn,
-		edit_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-	me.mon(me.rstore, 'refresh', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.qemu.ScsiHwEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('SCSI Controller Type'),
-	    items: {
-		xtype: 'pveScsiHwSelector',
-		name: 'scsihw',
-		value: '__default__',
-		fieldLabel: gettext('Type')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.BiosEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveQemuBiosEdit',
-
-    initComponent : function() {
-	var me = this;
-
-	var EFIHint = Ext.createWidget({
-	    xtype: 'displayfield', //submitValue is false, so we don't get submitted
-	    userCls: 'pve-hint',
-	    value: 'You need to add an EFI disk for storing the ' +
-	    'EFI settings. See the online help for details.',
-	    hidden: true
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'BIOS',
-	    items: [ {
-		xtype: 'pveQemuBiosSelector',
-		onlineHelp: 'qm_bios_and_uefi',
-		name: 'bios',
-		value: '__default__',
-		fieldLabel: 'BIOS',
-		listeners: {
-		    'change' : function(field, newValue) {
-			if (newValue == 'ovmf') {
-			    Proxmox.Utils.API2Request({
-				url : me.url,
-				method : 'GET',
-				failure : function(response, opts) {
-				    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				},
-				success : function(response, opts) {
-				    var vmConfig = response.result.data;
-				    // there can be only one
-				    if (!vmConfig.efidisk0) {
-					EFIHint.setVisible(true);
-				    }
-				}
-			    });
-			} else {
-			    if (EFIHint.isVisible()) {
-				EFIHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    EFIHint
-	    ] });
-
-	me.callParent();
-
-	me.load();
-
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.Options'],
-
-    onlineHelp: 'qm_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    name: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Name'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Name'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    xtype: 'textfield',
-			    name: 'name',
-			    vtype: 'DnsName',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: true
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.name === undefined ||
-				values.name === null ||
-				values.name === '') {
-				params = { 'delete':'name'};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ?
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'qm_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.OSTypeEdit' : undefined,
-		renderer: PVE.Utils.render_kvm_ostype,
-		defaultValue: 'other'
-	    },
-	    bootdisk: {
-		visible: false
-	    },
-	    boot: {
-		header: gettext('Boot Order'),
-		defaultValue: 'cdn',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.BootOrderEdit' : undefined,
-		multiKey: ['boot', 'bootdisk'],
-		renderer: function(order, metaData, record, rowIndex, colIndex, store, pending) {
-		    var i;
-		    var text = '';
-		    var bootdisk = me.getObjectValue('bootdisk', undefined, pending);
-		    order = order || 'cdn';
-		    for (i = 0; i < order.length; i++) {
-			var sel = order.substring(i, i + 1);
-			if (text) {
-			    text += ', ';
-			}
-			if (sel === 'c') {
-			    if (bootdisk) {
-				text += "Disk '" + bootdisk + "'";
-			    } else {
-				text += "Disk";
-			    }
-			} else if (sel === 'n') {
-			    text += 'Network';
-			} else if (sel === 'a') {
-			    text += 'Floppy';
-			} else if (sel === 'd') {
-			    text += 'CD-ROM';
-			} else {
-			    text += sel;
-			}
-		    }
-		    return text;
-		}
-	    },
-	    tablet: {
-		header: gettext('Use tablet for pointer'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use tablet for pointer'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'tablet',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hotplug: {
-		header: gettext('Hotplug'),
-		defaultValue: 'disk,network,usb',
-		renderer:  PVE.Utils.render_hotplug_features,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hotplug'),
-		    items: {
-			xtype: 'pveHotplugFeatureSelector',
-			name: 'hotplug',
-			value: '',
-			multiSelect: true,
-			fieldLabel: gettext('Hotplug'),
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    acpi: {
-		header: gettext('ACPI support'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('ACPI support'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'acpi',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    kvm: {
-		header: gettext('KVM hardware virtualization'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('KVM hardware virtualization'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'kvm',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    freeze: {
-		header: gettext('Freeze CPU at startup'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.PowerMgmt'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Freeze CPU at startup'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'freeze',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Freeze CPU at startup')
-		    }
-		} : undefined
-	    },
-	    localtime: {
-		header: gettext('Use local time for RTC'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use local time for RTC'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'localtime',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Use local time for RTC')
-		    }
-		} : undefined
-	    },
-	    startdate: {
-		header: gettext('RTC start date'),
-		defaultValue: 'now',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('RTC start date'),
-		    items: {
-			xtype: 'proxmoxtextfield',
-			name: 'startdate',
-			deleteEmpty: true,
-			value: 'now',
-			fieldLabel: gettext('RTC start date'),
-			vtype: 'QemuStartDate',
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    smbios1: {
-		header: gettext('SMBIOS settings (type1)'),
-		defaultValue: '',
-		renderer: Ext.String.htmlEncode,
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.Smbios1Edit' : undefined
-	    },
-	    agent: {
-		header: gettext('Qemu Agent'),
-		defaultValue: false,
-		renderer: PVE.Utils.render_qga_features,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Qemu Agent'),
-		    items: {
-			xtype: 'pveAgentFeatureSelector',
-			name: 'agent'
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-        var revert_btn = new Proxmox.button.Button({
-            text: gettext('Revert'),
-            disabled: true,
-            handler: function() {
-		var sm = me.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-
-                Proxmox.Utils.API2Request({
-                    url: '/api2/extjs/' + baseurl,
-                    waitMsgTarget: me,
-                    method: 'PUT',
-                    params: {
-                        'revert': revert
-                    },
-                    callback: function() {
-                        me.reload();
-                    },
-                    failure: function (response, opts) {
-                        Ext.Msg.alert('Error',response.htmlStatus);
-                    }
-                });
-            }
-        });
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/pending",
-	    interval: 5000,
-	    cwidth1: 250,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.rstore.on('datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-
-Ext.define('PVE.window.Snapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname, vmstate: vmstate ? 1 : 0 };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	} else {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'vmstate',
-		uncheckedValue: 0,
-		defaultValue: 0,
-		checked: 1,
-		fieldLabel: gettext('Include RAM')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description, values.vmstate);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}	 
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveQemuSnapshotTree'],
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-qemu-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-        var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-        Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-            method: 'GET',
-            success: function(response, options) {
-                var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-            }
-        });
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) { 
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		return Proxmox.Utils.format_task_description('qmrollback', me.vmid) +
-		    " '" +  rec.data.name + "'";
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', { 
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [ 
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-		{
-		    text: gettext('RAM'),
-		    align: 'center',
-		    resizable: false,
-		    dataIndex: 'vmstate',
-		    width: 50,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name !== 'current') {
-			    return Proxmox.Utils.format_boolean(value);
-			}
-		    }
-		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{ 
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true, // will work in 4.1?
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-
-Ext.define('PVE.qemu.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.qemu.Config',
-
-    onlineHelp: 'chapter_virtual_machines',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + "/qemu/" + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + '/status/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var resumeBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resume'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    hidden: true,
-	    handler: function() {
-		vm_command('resume');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'qemu',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    itemId: 'removeBtn',
-		    disabled: !caps.vms['VM.Allocate'],
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'VM', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items: [{
-		    text: gettext('Pause'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid),
-		    handler: function() {
-			vm_command("suspend");
-		    },
-		    iconCls: 'fa fa-pause'
-		},{
-		    text: gettext('Hibernate'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid),
-		    tooltip: gettext('Suspend to disk'),
-		    handler: function() {
-			vm_command("suspend", { todisk: 1 });
-		    },
-		    iconCls: 'fa fa-download'
-		},{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    dangerous: true,
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid),
-		    handler: function() {
-			vm_command("stop", { timeout: 30 });
-		    },
-		    iconCls: 'fa fa-stop'
-		},{
-		    text: gettext('Reset'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid),
-		    handler: function() {
-			vm_command("reset");
-		    },
-		    iconCls: 'fa fa-bolt'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    hidden: template,
-	    consoleType: 'kvm',
-	    consoleName: vm.name,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'kvmtab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveQemuSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push({
-		title: gettext('Console'),
-		itemId: 'console',
-		iconCls: 'fa fa-terminal',
-		xtype: 'pveNoVncConsole',
-		vmid: vmid,
-		consoleType: 'kvm',
-		nodename: nodename
-	    });
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Hardware'),
-		itemId: 'hardware',
-		iconCls: 'fa fa-desktop',
-		xtype: 'PVE.qemu.HardwareView'
-	    },
-	    {
-		title: 'Cloud-Init',
-		itemId: 'cloudinit',
-		iconCls: 'fa fa-cloud',
-		xtype: 'pveCiPanel'
-	    },
-	    {
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options',
-		xtype: 'PVE.qemu.Options'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		xtype: 'proxmoxNodeTasks',
-		iconCls: 'fa fa-list',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Monitor'] && !template) {
-	    me.items.push({
-		title: gettext('Monitor'),
-		iconCls: 'fa fa-eye',
-		itemId: 'monitor',
-		xtype: 'pveQemuMonitor'
-	    });
-	}
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveQemuSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-        me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var qmpstatus;
-	    var spice = false;
-	    var xtermjs = false;
-	    var lock;
-
-	    if (!success) {
-		status = qmpstatus = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('qmpstatus');
-		qmpstatus = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-
-		spice = s.data.get('spice') ? true : false;
-		xtermjs = s.data.get('serial') ? true : false;
-
-	    }
-
-	    if (template) {
-		return;
-	    }
-
-	    var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1);
-
-	    if (resume || lock === 'suspended') {
-		startBtn.setVisible(false);
-		resumeBtn.setVisible(true);
-	    } else {
-		startBtn.setVisible(true);
-		resumeBtn.setVisible(false);
-	    }
-
-	    consoleBtn.setEnableSpice(spice);
-	    consoleBtn.setEnableXtermJS(xtermjs);
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-   }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    alias: 'widget.pveQemuCreateWizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    current: {
-		scsihw: ''
-	    }
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('Virtual Machine'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'qm_general_settings',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid',
-		    guestType: 'qemu',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'name',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: true
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		}
-	    ],
-	    advancedColumn1: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'onboot',
-		    uncheckedValue: 0,
-		    defaultValue: 0,
-		    deleteDefaultValue: true,
-		    fieldLabel: gettext('Start at boot')
-		}
-	    ],
-	    advancedColumn2: [
-		{
-		    xtype: 'textfield',
-		    name: 'order',
-		    defaultValue: '',
-		    emptyText: 'any',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Start/Shutdown order')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'up',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Startup delay')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'down',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Shutdown timeout')
-		}
-	    ],
-	    onGetValues: function(values) {
-
-		['name', 'pool', 'onboot', 'agent'].forEach(function(field) {
-		    if (!values[field]) {
-			delete values[field];
-		    }
-		});
-
-		var res = PVE.Parser.printStartup({
-		    order: values.order,
-		    up: values.up,
-		    down: values.down
-		});
-
-		if (res) {
-		    values.startup = res;
-		}
-
-		delete values.order;
-		delete values.up;
-		delete values.down;
-
-		return values;
-	    }
-	},
-	{
-	    xtype: 'container',
-	    layout: 'hbox',
-	    defaults: {
-		flex: 1,
-		padding: '0 10'
-	    },
-	    title: gettext('OS'),
-	    items: [
-		{
-		    xtype: 'pveQemuCDInputPanel',
-		    bind: {
-			nodename: '{nodename}'
-		    },
-		    confid: 'ide2',
-		    insideWizard: true
-		},
-		{
-		    xtype: 'pveQemuOSTypePanel',
-		    insideWizard: true
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveQemuSystemPanel',
-	    title: gettext('System'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuHDInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Hard Disk'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuProcessorPanel',
-	    insideWizard: true,
-	    title: gettext('CPU')
-	},
-	{
-	    xtype: 'pveQemuMemoryPanel',
-	    insideWizard: true,
-	    title: gettext('Memory')
-	},
-	{
-	    xtype: 'pveQemuNetworkInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Network'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-			    property : 'key',
-			    direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var kv = this.up('window').getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete') { // ignore
-			    return;
-			}
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/qemu',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response){
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-
-Ext.define('PVE.qemu.USBInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    autoComplete: false,
-    onlineHelp: 'qm_usb_passthrough',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=usb]': {
-		change: function(field, newValue, oldValue) {
-		    var hwidfield = this.lookupReference('hwid');
-		    var portfield = this.lookupReference('port');
-		    var usb3field = this.lookupReference('usb3');
-		    if (field.inputValue === 'hostdevice') {
-			hwidfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'port') {
-			portfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'spice') {
-			usb3field.setDisabled(newValue);
-		    }
-		}
-	    },
-	    'pveUSBSelector': {
-		change: function(field, newValue, oldValue) {
-		    var usbval = field.getUSBValue();
-		    var usb3field = this.lookupReference('usb3');
-		    var usb3 = /usb3/.test(usbval);
-		    if(usb3 && !usb3field.isDisabled()) {
-			usb3field.savedVal = usb3field.getValue();
-			usb3field.setValue(true);
-			usb3field.setDisabled(true);
-		    } else if(!usb3 && usb3field.isDisabled()){
-			var val = (usb3field.savedVal === undefined)?usb3field.originalValue:usb3field.savedVal;
-			usb3field.setValue(val);
-			usb3field.setDisabled(false);
-		    }
-		}
-	    }
-	}
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 6; i++) {
-		if (!me.vmconfig['usb' +  i.toString()]) {
-		    me.confid = 'usb' + i.toString();
-		    break;
-		}
-	    }
-	}
-	var val = "";
-	var type = me.down('radiofield').getGroupValue();
-	switch (type) {
-	    case 'spice':
-		val = 'spice'; break;
-	    case 'hostdevice':
-	    case 'port':
-		val = me.down('pveUSBSelector[name=' + type + ']').getUSBValue();
-		if (!/usb3/.test(val) && me.down('field[name=usb3]').getValue() === true) {
-		    val += ',usb3=1';
-		}
-		break;
-	    default:
-		throw "invalid type selected";
-	}
-
-	values[me.confid] = val;
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'fieldcontainer',
-	    defaultType: 'radiofield',
-	    items:[
-		{
-		    name: 'usb',
-		    inputValue: 'spice',
-		    boxLabel: gettext('Spice Port'),
-		    submitValue: false,
-		    checked: true
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'hostdevice',
-		    boxLabel: gettext('Use USB Vendor/Device ID'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    type: 'device',
-		    name: 'hostdevice',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    reference: 'hwid',
-		    allowBlank: false,
-		    fieldLabel: 'Choose Device',
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'port',
-		    boxLabel: gettext('Use USB Port'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    name: 'port',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    type: 'port',
-		    reference: 'port',
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Port'),
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    xtype: 'checkbox',
-		    name: 'usb3',
-		    submitValue: false,
-		    reference: 'usb3',
-		    fieldLabel: gettext('Use USB3')
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.USBEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('USB Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var data = response.result.data[me.confid].split(',');
-		    var port, hostdevice, usb3 = false;
-		    var type = 'spice';
-		    var i;
-		    for (i = 0; i < data.length; i++) {
-			if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
-			    hostdevice = data[i];
-			    hostdevice = hostdevice.replace('host=', '').replace('0x','');
-			    type = 'hostdevice';
-			} else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
-			    port = data[i];
-			    port = port.replace('host=','');
-			    type = 'port';
-			}
-
-			if (/^usb3=(1|on|true)$/.test(data[i])) {
-			    usb3 = true;
-			}
-		    }
-		    var values = {
-			usb : type,
-			hostdevice: hostdevice,
-			port: port,
-			usb3: usb3
-		    };
-
-		    ipanel.setValues(values);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.PCIInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    onlineHelp: 'qm_pci_passthrough',
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-
-	var hostpci = me.vmconfig[me.confid] || '';
-
-	var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-	if (values.host && values.host.length < 6) { // 00:00 format not 00:00.0
-	    values.host += ".0";
-	    values.multifunction = true;
-	}
-	values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
-	values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
-	values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
-
-	me.setValues(values);
-	if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
-	    // machine is not set to some variant of q35, so we disable pcie
-	    var pcie = me.down('field[name=pcie]');
-	    pcie.setDisabled(true);
-	    pcie.setBoxLabel(gettext('Q35 only'));
-	}
-
-	if (values.romfile) {
-	    me.down('field[name=romfile]').setVisible(true);
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var ret = {};
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 5; i++) {
-		if (!me.vmconfig['hostpci' +  i.toString()]) {
-		    me.confid = 'hostpci' + i.toString();
-		    break;
-		}
-	    }
-	}
-	if (values.multifunction) {
-	    // modify host to skip the '.X'
-	    values.host = values.host.substring(0,5);
-	    delete values.multifunction;
-	}
-
-	if (values.rombar) {
-	    delete values.rombar;
-	} else {
-	    values.rombar = 0;
-	}
-
-	if (!values.romfile) {
-	    delete values.romfile;
-	}
-
-	ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-	return ret;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.column1 = [
-	    {
-		xtype: 'pvePCISelector',
-		fieldLabel: gettext('Device'),
-		name: 'host',
-		nodename: me.nodename,
-		allowBlank: false,
-		onLoadCallBack: function(store, records, success) {
-		    if (!success || !records.length) {
-			return;
-		    }
-
-		    var first = records[0];
-		    if (first.data.iommugroup === -1) {
-			// no iommu groups
-			var warning = Ext.create('Ext.form.field.Display', {
-			    columnWidth: 1,
-			    padding: '0 0 10 0',
-			    value: 'No IOMMU detected, please activate it.' +
-				   'See Documentation for further information.',
-			    userCls: 'pve-hint'
-			});
-			me.items.insert(0, warning);
-			me.updateLayout(); // insert does not trigger that
-		    }
-		},
-		listeners: {
-		    change: function(pcisel, value) {
-			if (!value) {
-			    return;
-			}
-			var pcidev = pcisel.getStore().getById(value);
-			var mdevfield = me.down('field[name=mdev]');
-			mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
-			if (!pcidev) {
-			    return;
-			}
-			var id = pcidev.data.id.substring(0,5); // 00:00
-			var iommu = pcidev.data.iommugroup;
-			// try to find out if there are more devices
-			// in that iommu group
-			if (iommu !== -1) {
-			    var count = 0;
-			    pcisel.getStore().each(function(record) {
-				if (record.data.iommugroup === iommu &&
-				    record.data.id.substring(0,5) !== id)
-				{
-				    count++;
-				    return false;
-				}
-			    });
-			    var warning = me.down('#iommuwarning');
-			    if (count && !warning) {
-				warning = Ext.create('Ext.form.field.Display', {
-				    columnWidth: 1,
-				    padding: '0 0 10 0',
-				    itemId: 'iommuwarning',
-				    value: 'The selected Device is not in a seperate' +
-					   'IOMMU group, make sure this is intended.',
-				    userCls: 'pve-hint'
-				});
-				me.items.insert(0, warning);
-				me.updateLayout(); // insert does not trigger that
-			    } else if (!count && warning) {
-				me.remove(warning);
-			    }
-			}
-			if (pcidev.data.mdev) {
-			    mdevfield.setPciID(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('All Functions'),
-		name: 'multifunction'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'pveMDevSelector',
-		name: 'mdev',
-		disabled: true,
-		fieldLabel: gettext('MDev Type'),
-		nodename: me.nodename,
-		listeners: {
-		    change: function(field, value) {
-			var mf = me.down('field[name=multifunction]');
-			if (!!value) {
-			    mf.setValue(false);
-			}
-			mf.setDisabled(!!value);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Primary GPU'),
-		name: 'x-vga'
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'ROM-Bar',
-		name: 'rombar'
-	    },
-	    {
-		xtype: 'displayfield',
-		submitValue: true,
-		hidden: true,
-		fieldLabel: 'ROM-File',
-		name: 'romfile'
-	    }
-	];
-
-	me.advancedColumn2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'PCI-Express',
-		name: 'pcie'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.PCIEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('PCI Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.SerialnputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    autoComplete: false,
-
-    setVMConfig: function(vmconfig) {
-	var me = this, i;
-	me.vmconfig = vmconfig;
-
-	for (i = 0; i < 4; i++) {
-	    var port = 'serial' +  i.toString();
-	    if (!me.vmconfig[port]) {
-		me.down('field[name=serialid]').setValue(i);
-		break;
-	    }
-	}
-
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id = 'serial' + values.serialid;
-	delete values.serialid;
-	values[id] = 'socket';
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'serialid',
-	    fieldLabel: gettext('Serial Port'),
-	    minValue: 0,
-	    maxValue: 3,
-	    allowBlank: false,
-	    validator: function(id) {
-		if (!this.rendered) {
-		    return true;
-		}
-		var me = this.up('panel');
-		if (me.vmconfig !== undefined && Ext.isDefined(me.vmconfig['serial' + id])) {
-			return "This device is already in use.";
-		}
-		return true;
-	    }
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.SerialEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('Serial Port'),
-
-    initComponent : function() {
-	var me = this;
-
-	// for now create of (socket) serial port only
-	me.isCreate = true;
-
-	var ipanel = Ext.create('PVE.qemu.SerialnputPanel', {});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.IPInfo', {
-    extend: 'Ext.window.Window',
-    width: 600,
-    title: gettext('Guest Agent Network Information'),
-    height: 300,
-    layout: {
-	type: 'fit'
-    },
-    modal: true,
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: gettext('No network information'),
-	    columns: [
-		{
-		    dataIndex: 'name',
-		    text: gettext('Name'),
-		    flex: 3
-		},
-		{
-		    dataIndex: 'hardware-address',
-		    text: gettext('MAC address'),
-		    width: 140
-		},
-		{
-		    dataIndex: 'ip-addresses',
-		    text: gettext('IP address'),
-		    align: 'right',
-		    flex: 4,
-		    renderer: function(val) {
-			if (!Ext.isArray(val)) {
-			    return '';
-			}
-			var ips = [];
-			val.forEach(function(ip) {
-			    var addr = ip['ip-address'];
-			    var pref = ip.prefix;
-			    if  (addr && pref) {
-				ips.push(addr + '/' + pref);
-			    }
-			});
-			return ips.join('<br>');
-		    }
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.AgentIPView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveAgentIPView',
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    nics: [],
-
-    items: [
-	{
-	    xtype: 'box',
-	    html: '<i class="fa fa-exchange"></i> IPs'
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'right',
-		pack: 'end'
-	    },
-	    items: [
-		{
-		    xtype: 'label',
-		    flex: 1,
-		    itemId: 'ipBox',
-		    style: {
-			'text-align': 'right'
-		    }
-		},
-		{
-		    xtype: 'button',
-		    itemId: 'moreBtn',
-		    hidden: true,
-		    ui: 'default-toolbar',
-		    handler: function(btn) {
-			var me = this.up('pveAgentIPView');
-
-			var win = Ext.create('PVE.window.IPInfo');
-			win.down('grid').getStore().setData(me.nics);
-			win.show();
-		    },
-		    text: gettext('More')
-		}
-	    ]
-	}
-    ],
-
-    getDefaultIps: function(nics) {
-	var me = this;
-	var ips = [];
-	nics.forEach(function(nic) {
-	    if (nic['hardware-address'] &&
-		nic['hardware-address'] != '00:00:00:00:00:00') {
-
-		var nic_ips = nic['ip-addresses'] || [];
-		nic_ips.forEach(function(ip) {
-		    var p = ip['ip-address'];
-		    // show 2 ips at maximum
-		    if (ips.length < 2) {
-			ips.push(p);
-		    }
-		});
-	    }
-	});
-
-	return ips;
-    },
-
-    startIPStore: function(store, records, success) {
-	var me = this;
-	var agentRec = store.getById('agent');
-	/*jslint confusion: true*/
-	/* value is number and string */
-	me.agent = (agentRec && agentRec.data.value === 1);
-	me.running = (store.getById('status').data.value === 'running');
-	/*jslint confusion: false*/
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!caps.vms['VM.Monitor']) {
-	    var errorText = gettext("Requires '{0}' Privileges");
-	    me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
-	    return;
-	}
-
-	if (me.agent && me.running && me.ipStore.isStopped) {
-	    me.ipStore.startUpdate();
-	} else if (me.ipStore.isStopped) {
-	    me.updateStatus();
-	}
-    },
-
-    updateStatus: function(unsuccessful, defaulttext) {
-	var me = this;
-	var text = defaulttext || gettext('No network information');
-	var more = false;
-	if (unsuccessful) {
-	    text = gettext('Guest Agent not running');
-	} else if (me.agent && me.running) {
-	    if (Ext.isArray(me.nics) && me.nics.length) {
-		more = true;
-		var ips = me.getDefaultIps(me.nics);
-		if (ips.length !== 0) {
-		    text = ips.join('<br>');
-		}
-	    } else if (me.nics && me.nics.error) {
-		var msg = gettext('Cannot get info from Guest Agent<br>Error: {0}');
-		text = Ext.String.format(text, me.nics.error.desc);
-	    }
-	} else if (me.agent) {
-	    text = gettext('Guest Agent not running');
-	} else {
-	    text = gettext('No Guest Agent configured');
-	}
-
-	var ipBox = me.down('#ipBox');
-	ipBox.update(text);
-
-	var moreBtn = me.down('#moreBtn');
-	moreBtn.setVisible(more);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw 'rstore not given';
-	}
-
-	if (!me.pveSelNode) {
-	    throw 'pveSelNode not given';
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	var vmid = me.pveSelNode.data.vmid;
-
-	me.ipStore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 10000,
-	    storeid: 'pve-qemu-agent-' + vmid,
-	    method: 'POST',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces'
-	    }
-	});
-
-	me.callParent();
-
-	me.mon(me.ipStore, 'load', function(store, records, success) {
-	    if (records && records.length) {
-		me.nics = records[0].data.result;
-	    } else {
-		me.nics = undefined;
-	    }
-	    me.updateStatus(!success);
-	});
-
-	me.on('destroy', me.ipStore.stopUpdate);
-
-	// if we already have info about the vm, use it immediately
-	if (me.rstore.getCount()) {
-	    me.startIPStore(me.rstore, me.rstore.getData(), false);
-	}
-
-	// check if the guest agent is there on every statusstore load
-	me.mon(me.rstore, 'load', me.startIPStore, me);
-    }
-});
-Ext.define('PVE.qemu.CloudInit', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    xtype: 'pveCiPanel',
-
-    onlineHelp: 'qm_cloud_init',
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var me = this.up('grid');
-		var warn = gettext('Are you sure you want to remove entry {0}');
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		return msg;
-	    },
-	    enableFn: function(record) {
-		var me = this.up('grid');
-		var caps = Ext.state.Manager.get('GuiCap');
-		if (me.rows[record.data.key].never_delete ||
-		    !caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-
-		if (record.data.key === 'cipassword' && !record.data.value) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		var records = me.getSelection();
-		if (!records ||  !records.length) {
-		    return;
-		}
-
-		var id = records[0].data.key;
-		var match = id.match(/^net(\d+)$/);
-		if (match) {
-		    id = 'ipconfig' + match[1];
-		}
-
-		var params = {};
-		params['delete'] = id;
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: params,
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    callback: function() {
-			me.reload();
-		    }
-		});
-	    },
-	    text: gettext('Remove')
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('grid');
-		me.run_editor();
-	    },
-	    text: gettext('Edit')
-	},
-	'-',
-	{
-	    xtype: 'button',
-	    itemId: 'savebtn',
-	    text: gettext('Regenerate Image'),
-	    handler: function() {
-		var me = this.up('grid');
-		var eject_params = {};
-		var insert_params = {};
-		var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
-		var storage = '';
-		var stormatch = disk.file.match(/^([^\:]+)\:/);
-		if (stormatch) {
-		    storage = stormatch[1];
-		}
-		eject_params[me.ciDriveId] = 'none,media=cdrom';
-		insert_params[me.ciDriveId] = storage + ':cloudinit';
-
-		var failure = function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		};
-
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: eject_params,
-		    failure: failure,
-		    callback: function() {
-			Proxmox.Utils.API2Request({
-			    url: me.baseurl + '/config',
-			    waitMsgTarget: me,
-			    method: 'PUT',
-			    params: insert_params,
-			    failure: failure,
-			    callback: function() {
-				me.reload();
-			    }
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    border: false,
-
-    set_button_status: function(rstore, records, success) {
-	if (!success || records.length < 1) {
-	    return;
-	}
-	var me = this;
-	var found;
-	records.forEach(function(record) {
-	    if (found) {
-		return;
-	    }
-	    var id = record.data.key;
-	    var value = record.data.value;
-	    var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
-		if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
-		    found = id;
-		    me.ciDriveId = found;
-		    me.ciDrive = value;
-		}
-	});
-
-	me.down('#savebtn').setDisabled(!found);
-	me.setDisabled(!found);
-	if (!found) {
-	    me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
-	} else {
-	    me.getView().unmask();
-	}
-    },
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-
-	var icon = "";
-	if (rowdef.iconCls) {
-	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
-	}
-	return icon + (rowdef.header || key);
-    },
-
-    listeners: {
-	activate: function () {
-	    var me = this;
-	    me.rstore.startUpdate();
-	},
-	itemdblclick: function() {
-	    var me = this;
-	    me.run_editor();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-	var caps = Ext.state.Manager.get('GuiCap');
-	me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
-	me.url =  me.baseurl + '/pending';
-	me.editorConfig.url = me.baseurl + '/config';
-	me.editorConfig.pveSelNode = me.pveSelNode;
-
-	/*jslint confusion: true*/
-	/* editor is string and object */
-	me.rows = {
-	    ciuser: {
-		header: gettext('User'),
-		iconCls: 'fa fa-user',
-		never_delete: true,
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('User'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('User'),
-			    name: 'ciuser'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.defaultText;
-		}
-	    },
-	    cipassword: {
-		header: gettext('Password'),
-		iconCls: 'fa fa-unlock',
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Password'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    inputType: 'password',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.noneText,
-			    fieldLabel: gettext('Password'),
-			    name: 'cipassword'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.noneText;
-		}
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    nameserver: {
-		header: gettext('DNS servers'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    sshkeys: {
-		header: gettext('SSH public key'),
-		iconCls: 'fa fa-key',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.SSHKeyEdit' : undefined,
-		never_delete: true,
-		renderer: function(value) {
-		    value = decodeURIComponent(value);
-		    var keys = value.split('\n');
-		    var text = [];
-		    keys.forEach(function(key) {
-			if (key.length) {
-			    // First erase all quoted strings (eg. command="foo"
-			    var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
-			    // Now try to detect the comment:
-			    var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
-			    if (res) {
-				key = Ext.String.htmlEncode(res[2]);
-				if (res[1]) {
-				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
-				}
-				text.push(key);
-				return;
-			    }
-			    // Most likely invalid at this point, so just stick to
-			    // the old value.
-			    text.push(Ext.String.htmlEncode(key));
-			}
-		    });
-		    if (text.length) {
-			return text.join('<br>');
-		    } else {
-			return Proxmox.Utils.noneText;
-		    }
-		},
-		defaultValue: ''
-	    }
-	};
-	var i;
-	var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
-	    var id = record.data.key;
-	    var match = id.match(/^net(\d+)$/);
-	    var val = '';
-	    if (match) {
-		val = me.getObjectValue('ipconfig'+match[1], '', pending);
-	    }
-	    return val;
-	};
-	for (i = 0; i < 32; i++) {
-	    // we want to show an entry for every network device
-	    // even if it is empty
-	    me.rows['net' + i.toString()] = {
-		multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
-		header: gettext('IP Config') + ' (net' + i.toString() +')',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
-		iconCls: 'fa fa-exchange',
-		renderer: ipconfig_renderer
-	    };
-	    me.rows['ipconfig' + i.toString()] = {
-		visible: false
-	    };
-	}
-	/*jslint confusion: false*/
-
-	PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
-	    me.rows[type+id] = {
-		visible: false
-	    };
-	});
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-    }
-});
-Ext.define('PVE.qemu.CIDriveInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveCIDriveInputPanel',
-
-    insideWizard: false,
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var drive = {};
-	var params = {};
-	drive.file = values.hdstorage + ":cloudinit";
-	drive.format = values.diskformat;
-	params[values.controller + values.deviceid] = PVE.Parser.printQemuDrive(drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.down('#drive').setVMConfig(config, 'cdrom');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items = [
-	    {
-		xtype: 'pveControllerSelector',
-		noVirtIO: true,
-		itemId: 'drive',
-		fieldLabel: gettext('CloudInit Drive'),
-		name: 'drive'
-	    },
-	    {
-		xtype: 'pveDiskStorageSelector',
-		itemId: 'storselector',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    }
-	];
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CIDriveEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCIDriveEdit',
-
-    isCreate: true,
-    subject: gettext('CloudInit Drive'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveCIDriveInputPanel',
-	    itemId: 'cipanel',
-	    nodename: nodename
-	}];
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		me.down('#cipanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SSHKeyInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSSHKeyInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-	if (values.sshkeys) {
-	    values.sshkeys.trim();
-	}
-	if (!values.sshkeys.length) {
-	    values = {};
-	    values['delete'] = 'sshkeys';
-	    return values;
-	} else {
-	    values.sshkeys = encodeURIComponent(values.sshkeys);
-	}
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'sshkeys',
-	    name: 'sshkeys',
-	    height: 250
-	},
-	{
-	    xtype: 'filebutton',
-	    itemId: 'filebutton',
-	    name: 'file',
-	    text: gettext('Load SSH Key File'),
-	    fieldLabel: 'test',
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('inputpanel');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    var keysField = me.down('#sshkeys');
-			    var old = keysField.getValue();
-			    keysField.setValue(old + res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-	if (!window.FileReader) {
-	    me.down('#filebutton').setVisible(false);
-	}
-
-    }
-});
-
-Ext.define('PVE.qemu.SSHKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 800,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.SSHKeyInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('SSH Keys'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.create) {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.sshkeys) {
-			data.sshkeys = decodeURIComponent(data.sshkeys);
-			ipanel.setValues(data);
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.qemu.IPConfigPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveIPConfigPanel',
-
-    insideWizard: false,
-
-    vmconfig: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-
-	var params = {};
-
-	var cfg = PVE.Parser.printIPConfig(values);
-	if (cfg === '') {
-	    params['delete'] = [me.confid];
-	} else {
-	    params[me.confid] = cfg;
-	}
-	return params;
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.vmconfig = config;
-    },
-
-    setIPConfig: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data.ip === 'dhcp') {
-	    data.ipv4mode = data.ip;
-	    data.ip = '';
-	} else {
-	    data.ipv4mode = 'static';
-	}
-	if (data.ip6 === 'dhcp' || data.ip6 === 'auto') {
-	    data.ipv6mode = data.ip6;
-	    data.ip6 = '';
-	} else {
-	    data.ipv6mode = 'static';
-	}
-
-	me.ipconfig = data;
-	me.setValues(me.ipconfig);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.ipconfig = {};
-
-	me.column1 = [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Network Device'),
-		value: me.netid
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv4') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('IPv4/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: '',
-		vtype: 'IPAddress',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv4') +')'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'displayfield'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv6') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: '',
-		vtype: 'IP6CIDRAddress',
-		disabled: true,
-		fieldLabel: gettext('IPv6/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv6') +')'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.IPConfigEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	// convert confid from netX to ipconfigX
-	var match = me.confid.match(/^net(\d+)$/);
-	if (match) {
-	    me.netid = me.confid;
-	    me.confid = 'ipconfig' + match[1];
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.IPConfigPanel', {
-	    confid: me.confid,
-	    netid: me.netid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Config'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		me.vmconfig = response.result.data;
-		var ipconfig = {};
-		var value = me.vmconfig[me.confid];
-		if (value) {
-		    ipconfig = PVE.Parser.parseIPConfig(me.confid, value);
-		    if (!ipconfig) {
-			Ext.Msg.alert(gettext('Error'), gettext('Unable to parse network configuration'));
-			me.close();
-			return;
-		    }
-		}
-		ipanel.setIPConfig(me.confid, ipconfig);
-		ipanel.setVMConfig(me.vmconfig);
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.SystemInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSystemPanel',
-
-    onlineHelp: 'qm_system_settings',
-
-    viewModel: {
-	data: {
-	    efi: false,
-	    addefi: true
-	},
-
-	formulas: {
-	    efidisk: function(get) {
-		return get('efi') && get('addefi');
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	if (values.vga && values.vga.substr(0,6) === 'serial') {
-	    values['serial' + values.vga.substr(6,1)] = 'socket';
-	}
-
-	var efidrive = {};
-	if (values.hdimage) {
-	    efidrive.file = values.hdimage;
-	} else if (values.hdstorage) {
-	    efidrive.file = values.hdstorage + ":1";
-	}
-
-	if (values.diskformat) {
-	    efidrive.format = values.diskformat;
-	}
-
-	delete values.hdimage;
-	delete values.hdstorage;
-	delete values.diskformat;
-
-	if (efidrive.file) {
-	    values.efidisk0 = PVE.Parser.printQemuDrive(efidrive);
-	}
-
-	return values;
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	scsihwChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('current.scsihw', value);
-	    }
-	},
-
-	biosChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('efi', value === 'ovmf');
-	    }
-	},
-
-	control: {
-	    'pveScsiHwSelector': {
-		change: 'scsihwChange'
-	    },
-	    'pveQemuBiosSelector': {
-		change: 'biosChange'
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: gettext('Graphic card'),
-	    name: 'vga',
-	    comboItems: PVE.Utils.kvm_vga_driver_array()
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'agent',
-	    uncheckedValue: 0,
-	    defaultValue: 0,
-	    deleteDefaultValue: true,
-	    fieldLabel: gettext('Qemu Agent')
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'pveScsiHwSelector',
-	    name: 'scsihw',
-	    value: '__default__',
-	    bind: {
-		value: '{current.scsihw}'
-	    },
-	    fieldLabel: gettext('SCSI Controller')
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    name: 'bios',
-	    value: '__default__',
-	    fieldLabel: 'BIOS'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    bind: {
-		value: '{addefi}',
-		hidden: '{!efi}',
-		disabled: '{!efi}'
-	    },
-	    hidden: true,
-	    submitValue: false,
-	    disabled: true,
-	    fieldLabel: gettext('Add EFI Disk')
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    bind: {
-		nodename: '{nodename}',
-		hidden: '{!efi}',
-		disabled: '{!efidisk}'
-	    },
-	    autoSelect: false,
-	    disabled: true,
-	    hidden: true,
-	    hideSize: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'machine',
-	    value: '__default__',
-	    fieldLabel: gettext('Machine'),
-	    comboItems: [
-		['__default__', PVE.Utils.render_qemu_machine('')],
-		['q35', 'q35']
-	    ]
-	}
-    ]
-
-});
-Ext.define('PVE.lxc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveLxcSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 320,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.lxc.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcNetworkInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_network',
-
-    setNodename: function(nodename) {
-	var me = this;
-	
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	var bridgesel = me.query("[isFormField][name=bridge]")[0];
-	bridgesel.setNodename(nodename);
-    },
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	var id;
-	if (me.isCreate) {
-	    id = values.id;
-	    delete values.id;
-	} else {
-	    id = me.ifname;
-	}
-
-	if (!id) {
-	    return {};
-	}
-
-	var newdata = {};
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-	newdata[id] = PVE.Parser.printLxcNetwork(values);
-	return newdata;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var cdata = {};
-
-	if (me.insideWizard) {
-	    me.ifname = 'net0';
-	    cdata.name = 'eth0';
-	    me.dataCache = {};
-	}
-	cdata.firewall =  (me.insideWizard || me.isCreate);
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.isCreate) {
-	    if (!me.ifname) {
-		throw "no interface name specified";
-	    }
-	    if (!me.dataCache[me.ifname]) {
-		throw "no such interface '" + me.ifname + "'";
-	    }
-
-	    cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
-	}
-
-	var i;
-	for (i = 0; i < 10; i++) {
-	    if (me.isCreate && !me.dataCache['net'+i.toString()]) {
-		me.ifname = 'net' + i.toString();
-		break;
-	    }
-	}
-
-	var idselector = {
-	    xtype: 'hidden',
-	    name: 'id',
-	    value: me.ifname
-	};
-
-	me.column1 = [
-	    idselector,
-	    {
-		xtype: 'textfield',
-		name: 'name',
-		fieldLabel: gettext('Name'),
-		emptyText: '(e.g., eth0)',
-		allowBlank: false,
-		value: cdata.name,
-		validator: function(value) {
-		    var result = '';
-		    Ext.Object.each(me.dataCache, function(key, netstr) {
-			if (!key.match(/^net\d+/) || key === me.ifname) {
-			    return; // continue
-			}
-			var net = PVE.Parser.parseLxcNetwork(netstr);
-			if (net.name === value) {
-			    result = "interface name already in use";
-			    return false;
-			}
-		    });
-		    if (result !== '') {
-			return result;
-		    }
-		    // validator can return bool/string
-		    /*jslint confusion:true*/
-		    return true;
-		}
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'hwaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		value: cdata.hwaddr,
-		allowBlank: true,
-		emptyText: 'auto'
-	    },
-	    {
-		xtype: 'PVE.form.BridgeSelector',
-		name: 'bridge',
-		nodename: me.nodename,
-		fieldLabel: gettext('Bridge'),
-		value: cdata.bridge,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: cdata.tag
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: cdata.rate,
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		value: cdata.firewall
-	    }
-	];
-
-	var dhcp4 = (cdata.ip === 'dhcp');
-	if (dhcp4) {
-	    cdata.ip = '';
-	    cdata.gw = '';
-	}
-
-	var auto6 = (cdata.ip6 === 'auto');
-	var dhcp6 = (cdata.ip6 === 'dhcp');
-	if (auto6 || dhcp6) {
-	    cdata.ip6 = '';
-	    cdata.gw6 = '';
-	}
-	
-	me.column2 = [
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv4:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: !dhcp4,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: dhcp4,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: cdata.ip,
-		disabled: dhcp4,
-		fieldLabel: 'IPv4/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: cdata.gw,
-		vtype: 'IPAddress',
-		disabled: dhcp4,
-		fieldLabel: gettext('Gateway') + ' (IPv4)',
-		margin: '0 0 3 0' // override bottom margin to account for the menuseparator
-	    },
-	    {
-		xtype: 'menuseparator',
-		height: '3',
-		margin: '0'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv6:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: !(auto6 || dhcp6),
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: dhcp6,
-			margin: '0 0 0 10'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'SLAAC', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'auto',
-			checked: auto6,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: cdata.ip6,
-		vtype: 'IP6CIDRAddress',
-		disabled: (dhcp6 || auto6),
-		fieldLabel: 'IPv6/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: cdata.gw6,
-		disabled: (dhcp6 || auto6),
-		fieldLabel: gettext('Gateway') + ' (IPv6)'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-	
-
-Ext.define('PVE.lxc.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
-	    ifname: me.ifname,
-	    nodename: me.nodename,
-	    dataCache: me.dataCache,
-	    isCreate: me.isCreate
-	});
-	   
-	Ext.apply(me, {
-	    subject: gettext('Network Device') + ' (veth)',
-	    digest: me.dataCache.digest,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveLxcNetworkView',
-
-    onlineHelp: 'pct_container_network',
-
-    dataCache: {}, // used to store result of last load
-
-    stateful: true,
-    stateId: 'grid-lxc-network',
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.setErrorMask(me, true);
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		me.dataCache = data;
-		var records = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (!key.match(/^net\d+/)) {
-			return; // continue
-		    }
-		    var net = PVE.Parser.parseLxcNetwork(value);
-		    net.id = key;
-		    records.push(net);
-		});
-		me.store.loadData(records);
-		me.down('button[name=addButton]').setDisabled((records.length >= 10));
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var store = new Ext.data.Store({
-	    model: 'pve-lxc-network',
-	    sorters: [
-		{
-		    property : 'id',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!caps.vms['VM.Config.Network'];
-	    },
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: me.url,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: { 'delete': rec.data.id,  digest: me.dataCache.digest },
-		    callback: function() {
-			me.load();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!caps.vms['VM.Config.Network']) {
-		return false;
-	    }
-
-	    var win = Ext.create('PVE.lxc.NetworkEdit', {
-		url: me.url,
-		nodename: nodename,
-		dataCache: me.dataCache,
-		ifname: rec.data.id
-	    });
-	    win.on('destroy', me.load, me);
-	    win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    name: 'addButton',
-		    disabled: !caps.vms['VM.Config.Network'],
-		    handler: function() {
-			var win = Ext.create('PVE.lxc.NetworkEdit', {
-			    url: me.url,
-			    nodename: nodename,
-			    isCreate: true,
-			    dataCache: me.dataCache
-			});
-			win.on('destroy', me.load, me);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 50,
-		    dataIndex: 'id'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 80,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Bridge'),
-		    width: 80,
-		    dataIndex: 'bridge'
-		},
-		{
-		    header: gettext('Firewall'),
-		    width: 80,
-		    dataIndex: 'firewall',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('VLAN Tag'),
-		    width: 80,
-		    dataIndex: 'tag'
-		},
-		{
-		    header: gettext('MAC address'),
-		    width: 110,
-		    dataIndex: 'hwaddr'
-		},
-		{
-		    header: gettext('IP address'),
-		    width: 150,
-		    dataIndex: 'ip',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.ip && rec.data.ip6) {
-			    return rec.data.ip + "<br>" + rec.data.ip6;
-			} else if (rec.data.ip6) {
-			    return rec.data.ip6;
-			} else {
-			    return rec.data.ip;
-			}
-		    }
-		},
-		{
-		    header: gettext('Gateway'),
-		    width: 150,
-		    dataIndex: 'gw',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.gw && rec.data.gw6) {
-			    return rec.data.gw + "<br>" + rec.data.gw6;
-			} else if (rec.data.gw6) {
-			    return rec.data.gw6;
-			} else {
-			    return rec.data.gw;
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: me.load,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-   }
-}, function() {
-
-    Ext.define('pve-lxc-network', {
-	extend: "Ext.data.Model",
-	proxy: { type: 'memory' },
-	fields: [ 'id', 'name', 'hwaddr', 'bridge',
-		  'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
-    });
-
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.RessourceView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcRessourceView'],
-
-    onlineHelp: 'pct_configuration',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rowdef = me.rows[key] || {};
-
-	metaData.tdAttr = "valign=middle";
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	}
-	return rowdef.header || key;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	var mpeditor = caps.vms['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
-
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-memory',
-		group: 1,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    swap: {
-		header: gettext('Swap'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-swap',
-		group: 2,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    cores: {
-		header: gettext('Cores'),
-		editor: caps.vms['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
-		defaultValue: '',
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		renderer: function(value) {
-		    var cpulimit = me.getObjectValue('cpulimit');
-		    var cpuunits = me.getObjectValue('cpuunits');
-		    var res;
-		    if (value) {
-			res = value;
-		    } else {
-			res = gettext('unlimited');
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit + ']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits + ']';
-		    }
-		    return res;
-		}
-	    },
-	    rootfs: {
-		header: gettext('Root Disk'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: mpeditor,
-		tdCls: 'pve-itype-icon-storage',
-		group: 4
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    unprivileged: {
-		visible: false
-	    }
-	};
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    confid = bus + i;
-	    var group = 5;
-	    var header;
-	    if (bus === 'mp') {
-		header = gettext('Mount Point') + ' (' + confid + ')';
-	    } else {
-		header = gettext('Unused Disk') + ' ' + i;
-		group += 1;
-	    }
-	    rows[confid] = {
-		group: group,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: mpeditor,
-		header: header
-	    };
-	}, true);
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	var run_resize = function() {
-	    var rec = me.selModel.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.MPResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-	};
-
-	var run_remove = function(b, e, rec) {
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/' + baseurl,
-		waitMsgTarget: me,
-		method: 'PUT',
-		params: {
-		    'delete': rec.data.key
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var run_move = function(b, e, rec) {
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid,
-		type: 'lxc'
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec) {
-		    return false;
-		}
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + me.renderKey(rec.data.key, {}, rec) + "'");
-		if (rec.data.key.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: run_remove
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move Volume'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    handler: run_move
-	});
-
-	var set_button_status = function() {
-	    var rec = me.selModel.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		remove_btn.disable();
-		resize_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var isDisk = (rowdef.tdCls == 'pve-itype-icon-storage');
-
-	    var noedit = rec.data['delete'] || !rowdef.editor;
-	    if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) {
-		var mp = PVE.Parser.parseLxcMountPoint(value);
-		if (mp.type !== 'volume') {
-		    noedit = true;
-		}
-	    }
-	    edit_btn.setDisabled(noedit);
-
-	    remove_btn.setDisabled(!isDisk || rec.data.key === 'rootfs' || !diskCap);
-	    resize_btn.setDisabled(!isDisk || !diskCap);
-	    move_btn.setDisabled(!isDisk || !diskCap);
-
-	};
-	
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + baseurl,
-	    selModel: me.selModel,
-	    interval: 2000,
-	    cwidth1: 170,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Mount Point'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.lxc.MountPointEdit', {
-					url: '/api2/extjs/' + baseurl,
-					unprivileged: me.getObjectValue('unprivileged'),
-					pveSelNode: me.pveSelNode
-				    });
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		edit_btn,
-		remove_btn,
-		resize_btn,
-		move_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    editorConfig: {
-		pveSelNode: me.pveSelNode,
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	Ext.apply(me.editorConfig, { unprivileged: me.getObjectValue('unprivileged') });
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.FeaturesInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcFeaturesInputPanel',
-
-    // used to save the mounts fstypes until sending
-    mounts: [],
-
-    fstypes: ['nfs', 'cifs'],
-
-    viewModel: {
-	parent: null,
-	data: {
-	    unprivileged: false
-	},
-	formulas: {
-	    privilegedOnly: function(get) {
-		return (get('unprivileged') ? gettext('privileged only') : '');
-	    },
-	    unprivilegedOnly: function(get) {
-		return (!get('unprivileged') ? gettext('unprivileged only') : '');
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('keyctl'),
-	    name: 'keyctl',
-	    bind: {
-		disabled: '{!unprivileged}',
-		boxLabel: '{unprivilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Nesting'),
-	    name: 'nesting'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'nfs',
-	    fieldLabel: 'NFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cifs',
-	    fieldLabel: 'CIFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'fuse',
-	    fieldLabel: 'FUSE'
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-	var mounts = me.mounts;
-	me.fstypes.forEach(function(fs) {
-	    if (values[fs]) {
-		mounts.push(fs);
-	    }
-	    delete values[fs];
-	});
-
-	if (mounts.length) {
-	    values.mount = mounts.join(';');
-	}
-
-	var featuresstring = PVE.Parser.printPropertyString(values, undefined);
-	if (featuresstring == '') {
-	    return { 'delete': 'features' };
-	}
-	return { features: featuresstring };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	me.viewModel.set({ unprivileged: values.unprivileged });
-
-	if (values.features) {
-	    var res = PVE.Parser.parsePropertyString(values.features);
-	    me.mounts = [];
-	    if (res.mount) {
-		res.mount.split(/[; ]/).forEach(function(item) {
-		    if (me.fstypes.indexOf(item) === -1) {
-			me.mounts.push(item);
-		    } else {
-			res[item] = 1;
-		    }
-		});
-	    }
-	    this.callParent([res]);
-	}
-    }
-});
-
-Ext.define('PVE.lxc.FeaturesEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveLxcFeaturesEdit',
-
-    subject: gettext('Features'),
-
-    items: [{
-	xtype: 'pveLxcFeaturesInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.lxc.Options', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcOptions'],
-
-    onlineHelp: 'pct_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ? 
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'pct_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    arch: {
-		header: gettext('Architecture'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    console: {
-		header: '/dev/console',
-		defaultValue: 1,
-		renderer: Proxmox.Utils.format_enabled_toggle,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: '/dev/console',
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'console',
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			checked: true,
-			fieldLabel: '/dev/console'
-		    }
-		} : undefined
-	    },
-	    tty: {
-		header: gettext('TTY count'),
-		defaultValue: 2,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('TTY count'),
-		    items: {
-			xtype: 'proxmoxintegerfield',
-			name: 'tty',
-			minValue: 0,
-			maxValue: 6,
-			value: 2,
-			fieldLabel: gettext('TTY count'),
-			emptyText: gettext('Default'),
-			deleteEmpty: true
-		    }
-		} : undefined
-	    },
-	    cmode: {
-		header: gettext('Console mode'),
-		defaultValue: 'tty',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Console mode'),
-		    items: {
-			xtype: 'proxmoxKVComboBox',
-			name: 'cmode',
-			deleteEmpty: true,
-			value: '__default__',
-			comboItems: [
-			    ['__default__', Proxmox.Utils.defaultText + " (tty)"],
-			    ['tty', "/dev/tty[X]"],
-			    ['console', "/dev/console"],
-			    ['shell', "shell"]
-			],
-			fieldLabel: gettext('Console mode')
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    unprivileged: {
-		header: gettext('Unprivileged container'),
-		renderer: Proxmox.Utils.format_boolean,
-		defaultValue: 0
-	    },
-	    features: {
-		header: gettext('Features'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: Proxmox.UserName === 'root@pam' ?
-		    'PVE.lxc.FeaturesEdit' : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	Ext.apply(me, {
-	    url: "/api2/json/" + baseurl,
-	    selModel: sm,
-	    interval: 5000,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-    }
-});
-
-Ext.define('PVE.lxc.DNSInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcDNSInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var deletes = [];
-	if (!values.searchdomain && !me.insideWizard) {
-	    deletes.push('searchdomain');
-	}
-
-	if (values.nameserver) {
-	    var list = values.nameserver.split(/[\ \,\;]+/);
-	    values.nameserver = list.join(' ');
-	} else if(!me.insideWizard) {
-	    deletes.push('nameserver');
-	}
-
-	if (deletes.length) {
-	    values['delete'] = deletes.join(',');
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxtextfield',
-		name: 'searchdomain',
-		skipEmptyText: true,
-		fieldLabel: gettext('DNS domain'),
-		emptyText: gettext('use host settings'),
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS servers'),
-		vtype: 'IP64AddressList',
-		allowBlank: true,
-		emptyText: gettext('use host settings'),
-		name: 'nameserver',
-		itemId: 'nameserver'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.lxc.DNSInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Resources'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-
-		    if (values.nameserver) {
-			values.nameserver.replace(/[,;]/, ' ');
-			values.nameserver.replace(/^\s+/, '');
-		    }
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.DNS', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcDNS'],
-
-    onlineHelp: 'pct_container_network',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    hostname: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Hostname'),
-		editor: caps.vms['VM.Config.Network'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hostname'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    fieldLabel: gettext('Hostname'),
-			    xtype: 'textfield',
-			    name: 'hostname',
-			    vtype: 'DnsName',
-			    allowBlank: true,
-			    emptyText: 'CT' + vmid.toString()
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.hostname === undefined ||
-				values.hostname === null ||
-				values.hostname === '') {
-				params = { hostname: 'CT'+vmid.toString()};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    },
-	    nameserver: {
-		header: gettext('DNS server'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var win;
-	    if (Ext.isString(rowdef.editor)) {
-		win = Ext.create(rowdef.editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-	    //win.load();
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: run_editor
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/config",
-	    selModel: sm,
-	    cwidth1: 150,
-	    run_editor: run_editor,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status,
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.lxc.Config',
-
-    onlineHelp: 'chapter_pct',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + "/status/" + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var stopBtn = Ext.create('Ext.menu.Item',{
-	    text: gettext('Stop'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
-	    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-	    dangerous: true,
-	    handler: function() {
-		vm_command("stop");
-	    },
-	    iconCls: 'fa fa-stop'
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items:[stopBtn]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'lxc',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    guestType: 'ct',
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    disabled: !caps.vms['VM.Allocate'],
-		    itemId: 'removeBtn',
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'CT', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    consoleType: 'lxc',
-	    consoleName: vm.name,
-	    hidden: template,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'lxctab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveLxcSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push(
-		{
-		    title: gettext('Console'),
-		    itemId: 'consolejs',
-		    iconCls: 'fa fa-terminal',
-		    xtype: 'pveNoVncConsole',
-		    vmid: vmid,
-		    consoleType: 'lxc',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Resources'),
-		itemId: 'resources',
-		expandedOnInit: true,
-		iconCls: 'fa fa-cube',
-		xtype: 'pveLxcRessourceView'
-	    },
-	    {
-		title: gettext('Network'),
-		iconCls: 'fa fa-exchange',
-		itemId: 'network',
-		xtype: 'pveLxcNetworkView'
-	    },
-	    {
-		title: gettext('DNS'),
-		iconCls: 'fa fa-globe',
-		itemId: 'dns',
-		xtype: 'pveLxcDNS'
-	    },
-	    {
-		title: gettext('Options'),
-		itemId: 'options',
-		iconCls: 'fa fa-gear',
-		xtype: 'pveLxcOptions'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		iconCls: 'fa fa-list',
-		xtype: 'proxmoxNodeTasks',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveLxcSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		itemId: 'permissions',
-		iconCls: 'fa fa-unlock',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var lock;
-	    if (!success) {
-		status = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-	    }
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    stopBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'stopped');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    storage: '',
-	    unprivileged: true
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('LXC Container'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'pct_general',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid', // backend only knows vmid
-		    guestType: 'lxc',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'hostname',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Hostname'),
-		    skipEmptyText: true,
-		    allowBlank: true
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unprivileged',
-		    value: true,
-		    bind: {
-			value: '{unprivileged}'
-		    },
-		    fieldLabel: gettext('Unprivileged container')
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'password',
-		    value: '',
-		    fieldLabel: gettext('Password'),
-		    allowBlank: false,
-		    minLength: 5,
-		    change: function(f, value) {
-			if (f.rendered) {
-			    f.up().down('field[name=confirmpw]').validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'confirmpw',
-		    value: '',
-		    fieldLabel: gettext('Confirm password'),
-		    allowBlank: true,
-		    submitValue: false,
-		    validator: function(value) {
-			var pw = this.up().down('field[name=password]').getValue();
-			if (pw !== value) {
-			    return "Passwords do not match!";
-			}
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'ssh-public-keys',
-		    value: '',
-		    fieldLabel: gettext('SSH public key'),
-		    allowBlank: true,
-		    validator: function(value) {
-			var pwfield = this.up().down('field[name=password]');
-			if (value.length) {
-			    var key = PVE.Parser.parseSSHKey(value);
-			    if (!key) {
-				return "Failed to recognize ssh key";
-			    }
-			    pwfield.allowBlank = true;
-			} else {
-			    pwfield.allowBlank = false;
-			}
-			pwfield.validate();
-			return true;
-		    },
-		    afterRender: function() {
-			if (!window.FileReader) {
-			    // No FileReader support in this browser
-			    return;
-			}
-			var cancel = function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			};
-			var field = this;
-			field.inputEl.on('dragover', cancel);
-			field.inputEl.on('dragenter', cancel);
-			field.inputEl.on('drop', function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			    var files = ev.dataTransfer.files;
-			    PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
-				field.setValue(v);
-			    });
-			});
-		    }
-		},
-		{
-		    xtype: 'filebutton',
-		    name: 'file',
-		    hidden: !window.FileReader,
-		    text: gettext('Load SSH Key File'),
-		    listeners: {
-			change: function(btn, e, value) {
-			    e = e.event;
-			    var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
-			    PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
-				field.setValue(v);
-			    });
-			    btn.reset();
-			}
-		    }
-		}
-	    ]
-	},
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('Template'),
-	    onlineHelp: 'pct_container_images',
-	    column1: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'tmplstorage',
-		    fieldLabel: gettext('Storage'),
-		    storageContent: 'vztmpl',
-		    autoSelect: true,
-		    allowBlank: false,
-		    bind: {
-			value: '{storage}',
-			nodename: '{nodename}'
-		    }
-		},
-		{
-		    xtype: 'pveFileSelector',
-		    name: 'ostemplate',
-		    storageContent: 'vztmpl',
-		    fieldLabel: gettext('Template'),
-		    bind: {
-			storage: '{storage}',
-			nodename: '{nodename}'
-		    },
-		    allowBlank: false
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveLxcMountPointInputPanel',
-	    title: gettext('Root Disk'),
-	    insideWizard: true,
-	    isCreate: true,
-	    unused: false,
-	    bind: {
-		nodename: '{nodename}',
-		unprivileged: '{unprivileged}'
-	    },
-	    confid: 'rootfs'
-	},
-	{
-	    xtype: 'pveLxcCPUInputPanel',
-	    title: gettext('CPU'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcMemoryInputPanel',
-	    title: gettext('Memory'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcNetworkInputPanel',
-	    title: gettext('Network'),
-	    insideWizard: true,
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    isCreate: true
-	},
-	{
-	    xtype: 'pveLxcDNSInputPanel',
-	    title: gettext('DNS'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-				property : 'key',
-				direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var wizard = this.up('window');
-		    var kv = wizard.getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete' || key === 'tmplstorage') { // ignore
-			    return;
-			}
-			if (key === 'password') { // don't show pw
-			    return;
-			}
-			var html = Ext.htmlEncode(Ext.JSON.encode(value));
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-		delete kv.tmplstorage;
-
-		if (!kv.pool.length) {
-		    delete kv.pool;
-		}
-
-		if (!kv.password.length && kv['ssh-public-keys']) {
-		    delete kv.password;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/lxc',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response, opts){
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid
-			});
-			win.show();
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-Ext.define('PVE.lxc.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveLxcSnapshotTree'],
-
-    onlineHelp: 'pct_snapshots',
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-lxc-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-	    method: 'GET',
-	    success: function(response, options) {
-		var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-	    }
-	});
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    dangerous: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		var taskdescription = Proxmox.Utils.format_task_description('vzrollback', me.vmid);
-		var snaptime = Ext.Date.format(rec.data.snaptime,'Y-m-d H:i:s');
-		var snapname = rec.data.name;
-
-		var msg = Ext.String.format(gettext('{0} to {1} ({2})'),
-		                            taskdescription, snapname, snaptime);
-		msg += '<p>' + gettext('Note: Rollback stops CT') + '</p>';
-
-		return msg;
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', {
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-//		{
-//		    text: gettext('RAM'),
-//		    align: 'center',
-//		    resizable: false,
-//		    dataIndex: 'vmstate',
-//		    width: 50,
-//		    renderer: function(value, metaData, record) {
-//			if (record.data.name !== 'current') {
-//			    return Proxmox.Utils.format_boolean(value);
-//			}
-//		    }
-//		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    resizable: false,
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true,
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-Ext.define('PVE.window.LxcSnapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-var labelWidth = 120;
-
-Ext.define('PVE.lxc.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: Ext.create('PVE.lxc.MemoryInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-
-Ext.define('PVE.lxc.CPUEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('CPU'),
-	    items: Ext.create('PVE.lxc.CPUInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.lxc.CPUInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcCPUInputPanel',
-
-    onlineHelp: 'pct_cpu',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	PVE.Utils.delete_if_default(values, 'cores', '', me.insideWizard);
-	// cpu{limit,unit} aren't in the wizard so create is always false
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	return values;
-    },
-
-    advancedColumn1: [
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    value: 1024,
-	    minValue: 8,
-	    maxValue: 500000,
-	    labelWidth: labelWidth,
-	    allowBlank: false
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'cores',
-		minValue: 1,
-		maxValue: 128,
-		value: me.insideWizard ? 1 : '',
-		fieldLabel: gettext('Cores'),
-		allowBlank: true,
-		deleteEmpty: true,
-		emptyText: gettext('unlimited')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcMemoryInputPanel',
-
-    onlineHelp: 'pct_memory',
-
-    insideWizard: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'memory',
-		minValue: 16,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'swap',
-		minValue: 0,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Swap') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
- 
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.MPResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 120,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-/*jslint confusion: true*/
-/* hidden: boolean and string
- * bind: function and object
- * disabled: boolean and string
- */
-Ext.define('PVE.lxc.MountPointInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcMountPointInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_storage',
-
-    unused: false, // add unused disk imaged
-
-    unprivileged: false,
-
-    vmconfig: {}, // used to select unused disks
-
-    setUnprivileged: function(unprivileged) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.unprivileged = unprivileged;
-	vm.set('unpriv', unprivileged);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || "mp"+values.mpid;
-	values.file = me.down('field[name=file]').getValue();
-
-	if (me.unused) {
-	    confid = "mp"+values.mpid;
-	} else if (me.isCreate) {
-	    values.file = values.hdstorage + ':' + values.disksize;
-	}
-
-	// delete unnecessary fields
-	delete values.mpid;
-	delete values.hdstorage;
-	delete values.disksize;
-	delete values.diskformat;
-
-	var res = {};
-	res[confid] = PVE.Parser.printLxcMountPoint(values);
-	return res;
-    },
-
-
-    setMountPoint: function(mp) {
-	var me = this;
-	var vm = this.getViewModel();
-	vm.set('mptype', mp.type);
-	me.setValues(mp);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.vmconfig = vmconfig;
-	vm.set('unpriv', vmconfig.unprivileged);
-	vm.notify();
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    var name = "mp" + i.toString();
-	    if (!Ext.isDefined(vmconfig[name])) {
-		me.down('field[name=mpid]').setValue(i);
-		return false;
-	    }
-	});
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var vm = me.getViewModel();
-	vm.set('node', nodename);
-	vm.notify();
-	me.down('#diskstorage').setNodename(nodename);
-    },
-
-    controller:  {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=mpid]': {
-		change: function(field, value) {
-		    field.validate();
-		}
-	    },
-	    '#hdstorage': {
-		change: function(field, newValue) {
-		    var me = this;
-		    if (!newValue) {
-			return;
-		    }
-
-		    var rec = field.store.getById(newValue);
-		    if (!rec) {
-			return;
-		    }
-
-		    var vm = me.getViewModel();
-		    vm.set('type', rec.data.type);
-		    vm.notify();
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    vm.set('confid', view.confid);
-	    vm.set('unused', view.unused);
-	    vm.set('node', view.nodename);
-	    vm.set('unpriv', view.unprivileged);
-	    vm.set('hideStorSelector', view.unused || !view.isCreate);
-	    vm.notify();
-	}
-    },
-
-    viewModel: {
-	data: {
-	    unpriv: false,
-	    unused: false,
-	    showStorageSelector: false,
-	    mptype: '',
-	    type: '',
-	    confid: '',
-	    node: ''
-	},
-
-	formulas: {
-	    quota: function(get) {
-		return !(get('type') === 'zfs' ||
-			 get('type') === 'zfspool' ||
-			 get('unpriv') ||
-			 get('isBind'));
-	    },
-	    hasMP: function(get) {
-		return !!get('confid') && !get('unused');
-	    },
-	    isRoot: function(get) {
-		return get('confid') === 'rootfs';
-	    },
-	    isBind: function(get) {
-		return get('mptype') === 'bind';
-	    },
-	    isBindOrRoot: function(get) {
-		return get('isBind') || get('isRoot');
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'mpid',
-	    fieldLabel: gettext('Mount Point ID'),
-	    minValue: 0,
-	    maxValue: PVE.Utils.mp_counts.mps - 1,
-	    hidden: true,
-	    allowBlank: false,
-	    disabled: true,
-	    bind: {
-		hidden: '{hasMP}',
-		disabled: '{hasMP}'
-	    },
-	    validator: function(value) {
-		var me = this.up('inputpanel');
-		if (!me.rendered) {
-		    return;
-		}
-		if (Ext.isDefined(me.vmconfig["mp"+value])) {
-		    return "Mount point is already in use.";
-		}
-		/*jslint confusion: true*/
-		/* returns a string above */
-		return true;
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    itemId: 'diskstorage',
-	    storageContent: 'rootdir',
-	    hidden: true,
-	    autoSelect: true,
-	    selectformat: false,
-	    defaultSize: 8,
-	    bind: {
-		hidden: '{hideStorSelector}',
-		disabled: '{hideStorSelector}',
-		nodename: '{node}'
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    disabled: true,
-	    submitValue: false,
-	    fieldLabel: gettext('Disk image'),
-	    name: 'file',
-	    bind: {
-		hidden: '{!hideStorSelector}'
-	    }
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'textfield',
-	    name: 'mp',
-	    value: '',
-	    emptyText:  gettext('/some/path'),
-	    allowBlank: false,
-	    disabled: true,
-	    fieldLabel: gettext('Path'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'backup',
-	    fieldLabel: gettext('Backup'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isBindOrRoot}'
-	    }
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'quota',
-	    defaultValue: 0,
-	    bind: {
-		disabled: '{!quota}'
-	    },
-	    fieldLabel: gettext('Enable quota'),
-	    listeners: {
-		disable: function() {
-		    this.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'ro',
-	    defaultValue: 0,
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    },
-	    fieldLabel: gettext('Read-only')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'acl',
-	    fieldLabel: 'ACLs',
-	    deleteEmpty: false,
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText],
-		['1', Proxmox.Utils.enabledText],
-		['0', Proxmox.Utils.disabledText]
-	    ],
-	    value: '__default__',
-	    bind: {
-		disabled: '{isBind}'
-	    },
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    inputValue: '0', // reverses the logic
-	    name: 'replicate',
-	    fieldLabel: gettext('Skip replication')
-	}
-    ]
-});
-
-Ext.define('PVE.lxc.MountPointEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    unprivileged: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    unprivileged: me.unprivileged,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-	    subject = gettext('Mount Point');
-	} else {
-	    subject = gettext('Mount Point') + ' (' + me.confid + ')';
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    /*jslint confusion: true*/
-		    /*data is defined as array above*/
-		    var value = response.result.data[me.confid];
-		    /*jslint confusion: false*/
-		    var mp = PVE.Parser.parseLxcMountPoint(value);
-
-		    if (!mp) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
-			me.close();
-			return;
-		    }
-
-		    ipanel.setMountPoint(mp);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.pool.StatusView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-    disabled: true,
-
-    title: gettext('Status'),
-    cwidth1: 150,
-    interval: 30000,
-    //height: 195,
-    initComponent : function() {
-	var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var rows = {
-	    comment: {
-		header: gettext('Comment'), 
-		renderer: Ext.String.htmlEncode,
-		required: true
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/pools/" + pool,
-	    rows: rows
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var statusview = Ext.create('PVE.pool.StatusView', {
-	    pveSelNode: me.pveSelNode,
-	    style: 'padding-top:0px'
-	});
-
-	var rstore = statusview.rstore;
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    defaults: {
-		style: 'padding-top:10px',
-		width: 800
-	    },
-	    items: [ statusview ]
-	});
-
-	me.on('activate', rstore.startUpdate);
-	me.on('destroy', rstore.stopUpdate);	
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    onlineHelp: 'pveum_pools',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-	    hstateid: 'pooltab',
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    xtype: 'pvePoolSummary',
-		    itemId: 'summary'
-		},
-		{
-		    title: gettext('Members'),
-		    xtype: 'pvePoolMembers',
-		    iconCls: 'fa fa-th',
-		    pool: pool,
-		    itemId: 'members'
-		},
-		{
-		    xtype: 'pveACLView',
-		    title: gettext('Permissions'),
-		    iconCls: 'fa fa-unlock',
-		    itemId: 'permissions',
-		    path: '/pool/' + pool
-		}
-	    ]
-	});
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.panel.StorageBase', {
-    extend: 'Proxmox.panel.InputPanel',
-    controller: 'storageEdit',
-
-    type: '',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = me.type;
-	} else {
-	    delete values.storage;
-	}
-
-	values.disable = values.enable ? 0 : 1;
-	delete values.enable;
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1.unshift({
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    name: 'storage',
-	    value: me.storageId || '',
-	    fieldLabel: 'ID',
-	    vtype: 'StorageId',
-	    allowBlank: false
-	});
-
-	me.column2.unshift(
-	    {
-		xtype: 'pveNodeSelector',
-		name: 'nodes',
-		disabled: me.storageId === 'local',
-		fieldLabel: gettext('Nodes'),
-		emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
-		multiSelect: true,
-		autoSelect: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.storageId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/storage';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/storage/' + me.storageId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create(me.paneltype, {
-	    type: me.type,
-	    isCreate: me.isCreate,
-	    storageId: me.storageId
-	});
-
-	Ext.apply(me, {
-            subject: PVE.Utils.format_storage_type(me.type),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    var ctypes = values.content || '';
-
-		    values.content = ctypes.split(',');
-
-		    if (values.nodes) {
-			values.nodes = values.nodes.split(',');
-		    }
-		    values.enable = values.disable ? 0 : 1;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.Upload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveStorageUpload',
-
-    resizable: false,
-
-    modal: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var xhr;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
-
-	var pbar = Ext.create('Ext.ProgressBar', {
-            text: 'Ready',
-	    hidden: true
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    method: 'POST',
-	    waitMsgTarget: true,
-	    bodyPadding: 10,
-	    border: false,
-	    width: 300,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-            },
-	    items: [
-		{
-		    xtype: 'pveContentTypeSelector',
-		    cts: me.contents,
-		    fieldLabel: gettext('Content'),
-		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
-		    allowBlank: false
-		},
-		pbar
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doStandardSubmit = function() {
-	    form.submit({
-		url: "/api2/htmljs" + baseurl,
-		waitMsg: gettext('Uploading file...'),
-		success: function(f, action) {
-		    me.close();
-		},
-		failure: function(f, action) {
-		    var msg = PVE.Utils.extractFormActionError(action);
-                    Ext.Msg.alert(gettext('Error'), msg);
-		}
-	    });
-	};
-
-	var updateProgress = function(per, bytes) {
-	    var text = (per * 100).toFixed(2) + '%';
-	    if (bytes) {
-		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
-	    }
-	    pbar.updateProgress(per, text);
-	};
-
-	var abortBtn = Ext.create('Ext.Button', {
-	    text: gettext('Abort'),
-	    disabled: true,
-	    handler: function() {
-		me.close();
-	    }
-	});
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Upload'),
-	    disabled: true,
-	    handler: function(button) {
-		var fd;
-		try {
-		    fd = new FormData();
-		} catch (err) {
-		    doStandardSubmit();
-		    return;
-		}
-
-		button.setDisabled(true);
-		abortBtn.setDisabled(false);
-
-		var field = form.findField('content');
-		fd.append("content", field.getValue());
-		field.setDisabled(true);
-
-		field = form.findField('filename');
-		var file = field.fileInputEl.dom;
-		fd.append("filename", file.files[0]);
-		field.setDisabled(true);
-
-		pbar.setVisible(true);
-		updateProgress(0);
-
-		xhr = new XMLHttpRequest();
-
-		xhr.addEventListener("load", function(e) {
-		    if (xhr.status == 200) {
-			me.close();
-		    } else {
-			var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
-			var result = Ext.decode(xhr.responseText);
-			result.message = msg;
-			var htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.Msg.alert(gettext('Error'), htmlStatus, function(btn) {
-			    me.close();
-			});
-
-		    }
-		}, false);
-
-		xhr.addEventListener("error", function(e) {
-		    var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
-		    Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			me.close();
-		    });
-		});
-
-		xhr.upload.addEventListener("progress", function(evt) {
-		    if (evt.lengthComputable) {
-			var percentComplete = evt.loaded / evt.total;
-			updateProgress(percentComplete, evt.loaded);
-		    }
-		}, false);
-
-		xhr.open("POST", "/api2/json" + baseurl, true);
-		xhr.send(fd);
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-        Ext.apply(me, {
-            title: gettext('Upload'),
-	    items: me.formPanel,
-	    buttons: [ abortBtn, submitBtn ],
-	    listeners: {
-		close: function() {
-		    if (xhr) {
-			xhr.abort();
-		    }
-		}
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ContentView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveStorageContentView',
-
-    stateful: true,
-    stateId: 'grid-storage-content',
-    viewConfig: {
-	trackOver: false,
-	loadMask: false
-    },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-storage-content',
-	    groupField: 'content',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    },
-	    sorters: {
-		property: 'volid',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	    me.statusStore.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-
-	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
-	    text: gettext('Upload'),
-	    handler: function() {
-		var me = this;
-		var win = Ext.create('PVE.storage.Upload', {
-		    nodename: nodename,
-		    storage: storage,
-		    contents: me.contents
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var imageRemoveButton;
-	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: baseurl + '/'
-	});
-
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && rec.data.content === 'images') {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		me = this;
-
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
-		    reload();
-
-		});
-	    }
-	});
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (rec.data.volid.match(/vzdump-qemu-/)) {
-			    vmtype = 'qemu';
-			} else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
-		    }
-		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s,records,succes) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
-    }
-}, function() {
-
-    Ext.define('pve-storage-content', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'volid', 'content', 'format', 'size', 'used', 'vmid',
-	    'channel', 'id', 'lun',
-	    {
-		name: 'text',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    return PVE.Utils.render_storage_content(value, {}, record);
-		}
-	    }
-	],
-	idProperty: 'volid'
-    });
-
-});
-Ext.define('PVE.storage.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveStorageStatusView',
-
-    height: 230,
-    title: gettext('Status'),
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 30 5 30'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 30
-	},
-	{
-	    itemId: 'enabled',
-	    title: gettext('Enabled'),
-	    printBar: false,
-	    textField: 'disabled',
-	    renderer: Proxmox.Utils.format_neg_boolean
-	},
-	{
-	    itemId: 'active',
-	    title: gettext('Active'),
-	    printBar: false,
-	    textField: 'active',
-	    renderer: Proxmox.Utils.format_boolean
-	},
-	{
-	    itemId: 'content',
-	    title: gettext('Content'),
-	    printBar: false,
-	    textField: 'content',
-	    renderer: PVE.Utils.format_content_types
-	},
-	{
-	    itemId: 'type',
-	    title: gettext('Type'),
-	    printBar: false,
-	    textField: 'type',
-	    renderer: PVE.Utils.format_storage_type
-	},
-	{
-	    xtype: 'box',
-	    height: 10
-	},
-	{
-	    itemId: 'usage',
-	    title: gettext('Usage'),
-	    valueField: 'used',
-	    maxField: 'total'
-	}
-    ],
-
-    updateTitle: function() {
-	return;
-    }
-});
-Ext.define('PVE.storage.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStorageSummary',
-    scrollable: true,
-    bodyPadding: 5,
-    tbar: [
-	'->',
-	{
-	    xtype: 'proxmoxRRDTypeSelector'
-	}
-    ],
-    layout: {
-	type: 'column'
-    },
-    defaults: {
-	padding: 5,
-	columnWidth: 1
-    },
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var rstore  = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/storage/" + storage + "/status",
-	    interval: 1000
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl:  "/api2/json/nodes/" + nodename + "/storage/" + storage + "/rrddata",
-	    model: 'pve-rrd-storage'
-	});
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'pveStorageStatusView',
-		    pveSelNode: me.pveSelNode,
-		    rstore: rstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Usage'),
-		    fields: ['total','used'],
-		    fieldTitles: ['Total Size', 'Used Size'],
-		    store: rrdstore
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.Browser', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.storage.Browser',
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storeid = me.pveSelNode.data.storage;
-	if (!storeid) {
-	    throw "no storage ID specified";
-	}
-
-
-	me.items = [
-	    {
-		title: gettext('Summary'),
-		xtype: 'pveStorageSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    }
-	];
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Storage {0} on node {1}"),
-				     "'" + storeid + "'", "'" + nodename + "'"),
-	    hstateid: 'storagetab'
-	});
-
-	if (caps.storage['Datastore.Allocate'] ||
-	    caps.storage['Datastore.AllocateSpace'] ||
-	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
-	}
-
-	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.storage.DirInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_directory',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'path',
-		value: '',
-		fieldLabel: gettext('Directory'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.NFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveNFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'path',
-    displayField: 'path',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.nfsServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.nfsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.nfsServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'path', 'options' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/nfs'
-	    }
-	});
-
-	store.sort('path', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.NFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_nfs',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    // hack: for now we always create nvf v3
-	    // fixme: make this configurable
-	    values.options = 'vers=3';
-	}
-
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=export]');
-			    exportField.setServer(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'pveNFSScan' : 'displayfield',
-		name: 'export',
-		value: '',
-		fieldLabel: 'Export',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.CIFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCIFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'share',
-    displayField: 'share',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.cifsServer) {
-	    me.store.removeAll();
-	}
-
-	var params = {};
-	if (me.cifsUsername && me.cifsPassword) {
-	    params.username =  me.cifsUsername;
-	    params.password = me.cifsPassword;
-	}
-
-	if (me.cifsDomain) {
-	    params.domain = me.cifsDomain;
-	}
-
-	me.store.getProxy().setExtraParams(params);
-	me.allQuery = me.cifsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	this.cifsServer = server;
-    },
-
-    setUsername: function(username) {
-	this.cifsUsername = username;
-    },
-
-    setPassword: function(password) {
-	this.cifsPassword = password;
-    },
-
-    setDomain: function(domain) {
-	this.cifsDomain = domain;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['description', 'share'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/cifs'
-	    }
-	});
-	store.sort('share', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.CIFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_cifs',
-
-    initComponent : function() {
-	var me = this;
-
-	var passwordfield = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    inputType: 'password',
-	    name: 'password',
-	    value: me.isCreate ? '' : '********',
-	    fieldLabel: gettext('Password'),
-	    allowBlank: false,
-	    disabled: me.isCreate,
-	    minLength: 1,
-	    listeners: {
-		change: function(f, value) {
-
-		    if (me.isCreate) {
-			var exportField = me.down('field[name=share]');
-			exportField.setPassword(value);
-		    }
-		}
-	    }
-	});
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=share]');
-			    exportField.setServer(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: '',
-		fieldLabel: gettext('Username'),
-		emptyText: gettext('Guest user'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (!me.isCreate) {
-			    return;
-			}
-			var exportField = me.down('field[name=share]');
-			exportField.setUsername(value);
-
-			if (value == "") {
-			    passwordfield.disable();
-			} else {
-			    passwordfield.enable();
-			}
-			passwordfield.validate();
-		    }
-		}
-	    },
-	    passwordfield,
-	    {
-		xtype: me.isCreate ? 'pveCIFSScan' : 'displayfield',
-		name: 'share',
-		value: '',
-		fieldLabel: 'Share',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'domain',
-		value: me.isCreate ? '' : undefined,
-		fieldLabel: gettext('Domain'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-
-			    var exportField = me.down('field[name=share]');
-			    exportField.setDomain(value);
-			}
-		    }
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.GlusterFsScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveGlusterFsScan',
-
-    queryParam: 'server',
-
-    valueField: 'volname',
-    displayField: 'volname',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: 'Scanning...',
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.glusterServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.glusterServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.glusterServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'volname' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/glusterfs'
-	    }
-	});
-
-	store.sort('volname', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.GlusterFsInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_glusterfs',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var volumeField = me.down('field[name=volume]');
-			    volumeField.setServer(value);
-			    volumeField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		name: 'server2',
-		value: '',
-		fieldLabel: gettext('Second Server'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'pveGlusterFsScan' : 'displayfield',
-		name: 'volume',
-		value: '',
-		fieldLabel: 'Volume name',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'iso', 'backup', 'vztmpl', 'snippets'],
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.IScsiScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveIScsiScan',
-
-    queryParam: 'portal',
-    valueField: 'target',
-    displayField: 'target',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.portal) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.portal;
-
-	me.callParent();
-    },
-
-    setPortal: function(portal) {
-	var me = this;
-
-	me.portal = portal;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'target', 'portal' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/iscsi'
-	    }
-	});
-
-	store.sort('target', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.IScsiInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_open_iscsi',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	values.content = values.luns ? 'images' : 'none';
-	delete values.luns;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	values.luns = (values.content.indexOf('images') !== -1) ? true : false;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: 'Portal',
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=target]');
-			    exportField.setPortal(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		readOnly: !me.isCreate,
-		xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: 'Target',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'checkbox',
-		name: 'luns',
-		checked: true,
-		fieldLabel: gettext('Use LUNs directly')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.VgSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveVgSelector',
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'vg', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	store.sort('vg', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseStorageSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseStorageSelector',
-
-    existingGroupsText: gettext("Existing volume groups"),
-    queryMode: 'local',
-    editable: false,
-    value: '',
-    valueField: 'storage',
-    displayField: 'text',
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {
-		addRecords: true,
-		params: {
-		    type: 'iscsi'
-		}
-	    },
-	    fields: [ 'storage', 'type', 'content',
-		      {
-			  name: 'text',
-			  convert: function(value, record) {
-			      if (record.data.storage) {
-				  return record.data.storage + " (iSCSI)";
-			      } else {
-				  return me.existingGroupsText;
-			      }
-			  }
-		      }],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/storage/'
-	    }
-	});
-
-	store.loadData([{ storage: '' }], true);
-
-	store.sort('storage', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LVMInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvm',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.VgSelector', {
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		allowBlank: false
-	    });
-
-	    var baseField = Ext.createWidget('pveFileSelector', {
-		name: 'base',
-		hidden: true,
-		disabled: true,
-		nodename: 'localhost',
-		storageContent: 'images',
-		fieldLabel: gettext('Base volume'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseStorageSelector',
-		name: 'basesel',
-		fieldLabel: gettext('Base storage'),
-		submitValue: false,
-		listeners: {
-		    change: function(f, value) {
-			if (value) {
-			    vgnameField.setVisible(true);
-			    vgnameField.setDisabled(false);
-			    vgField.setVisible(false);
-			    vgField.setDisabled(true);
-			    baseField.setVisible(true);
-			    baseField.setDisabled(false);
-			} else {
-			    vgnameField.setVisible(false);
-			    vgnameField.setDisabled(true);
-			    vgField.setVisible(true);
-			    vgField.setDisabled(false);
-			    baseField.setVisible(false);
-			    baseField.setDisabled(true);
-			}
-			baseField.setStorage(value);
-		    }
-		}
-	    });
-
-	    me.column1.push(baseField);
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	// here value is an array, 
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.TPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveTPSelector',
-
-    queryParam: 'vg',
-    valueField: 'lv',
-    displayField: 'lv',
-    editable: false,
-
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.vg) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.vg;
-
-	me.callParent();
-    },
-
-    setVG: function(myvg) {
-	var me = this;
-
-	me.vg = myvg;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'lv' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin'
-	    }
-	});
-
-	store.sort('lv', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseVGSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseVGSelector',
-
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {},
-	    fields: [ 'vg', 'size', 'free'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LvmThinInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvmthin',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	var thinpoolField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'thinpool',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Thin Pool'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.TPoolSelector', {
-		name: 'thinpool',
-		fieldLabel: gettext('Thin Pool'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseVGSelector',
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    vgField.setVG(value);
-			    vgField.setValue('');
-			}
-		    }
-		}
-	    });
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	me.column1.push(thinpoolField);
-
-	// here value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.CephFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'storage_cephfs',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'cephfs';
-
-	me.column1 = [];
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		value: '',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: 'admin',
-		bind:  {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['backup', 'iso', 'vztmpl', 'snippets'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: 'backup',
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged cephFS')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.Ceph.Model', {
-    extend: 'Ext.app.ViewModel',
-    alias: 'viewmodel.cephstorage',
-
-    data: {
-	pveceph: true,
-	pvecephPossible: true
-    }
-});
-
-Ext.define('PVE.storage.Ceph.Controller', {
-    extend: 'PVE.controller.StorageEdit',
-    alias: 'controller.cephstorage',
-
-    control: {
-	'#': {
-	    afterrender: 'queryMonitors'
-	},
-	'textfield[name=username]': {
-	    disable: 'resetField'
-	},
-	'displayfield[name=monhost]': {
-	    enable: 'queryMonitors'
-	},
-	'textfield[name=monhost]': {
-	    disable: 'resetField',
-	    enable: 'resetField'
-	}
-    },
-    resetField: function(field) {
-	field.reset();
-    },
-    queryMonitors: function(field, newVal, oldVal) {
-	// we get called with two signatures, the above one for a field
-	// change event and the afterrender from the view, this check only
-	// can be true for the field change one and omit the API request if
-	// pveceph got unchecked - as it's not needed there.
-	if (field && !newVal && oldVal) {
-	    return;
-	}
-	var view = this.getView();
-	var vm = this.getViewModel();
-	if (!(view.isCreate || vm.get('pveceph'))) {
-	    return; // only query on create or if editing a pveceph store
-	}
-
-	var monhostField = this.lookupReference('monhost');
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/json/nodes/localhost/ceph/mon',
-	    method: 'GET',
-	    scope: this,
-	    callback: function(options, success, response) {
-		var data = response.result.data;
-		if (response.status === 200) {
-		    if (data.length > 0) {
-			var monhost = Ext.Array.pluck(data, 'name').sort().join(',');
-			monhostField.setValue(monhost);
-			monhostField.resetOriginalValue();
-			if (view.isCreate) {
-			    vm.set('pvecephPossible', true);
-			}
-		    } else {
-			vm.set('pveceph', false);
-		    }
-		} else {
-		    vm.set('pveceph', false);
-		    vm.set('pvecephPossible', false);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.storage.RBDInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'ceph_rados_block_devices',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'rbd';
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveCephPoolSelector',
-		nodename: me.nodename,
-		name: 'pool',
-		bind: {
-		    disabled: '{!pveceph}',
-		    submitValue: '{pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },{
-		xtype: 'textfield',
-		name: 'pool',
-		value: 'rbd',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		nodename: me.nodename,
-		name: 'pool',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		value: 'admin',
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'rootdir'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: ['images'],
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'krbd',
-		uncheckedValue: 0,
-		fieldLabel: 'KRBD'
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool')
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.SheepdogInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-            values.content = 'images';
-	}
-
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '127.0.0.1:7000',
-		fieldLabel: gettext('Gateway'),
-		allowBlank: false
-	    }
-	];
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.ZFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    isLIO: false,
-	    isComstar: true,
-	    hasWriteCacheOption: true
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[name=iscsiprovider]': {
-		change: 'changeISCSIProvider'
-	    }
-	},
-	changeISCSIProvider: function(f, newVal, oldVal) {
-	    var vm = this.getViewModel();
-	    vm.set('isLIO', newVal === 'LIO');
-	    vm.set('isComstar', newVal === 'comstar');
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.content = 'images';
-	}
-
-	values.nowritecache = values.writecache ? 0 : 1;
-	delete values.writecache;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function diff(values) {
-	values.writecache = values.nowritecache ? 0 : 1;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: gettext('Portal'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'blocksize',
-		value: '4k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: gettext('Target'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_tg',
-		value: '',
-		fieldLabel: gettext('Target group'),
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		allowBlank: true
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: me.isCreate ? 'pveiScsiProviderSelector' : 'displayfield',
-		name: 'iscsiprovider',
-		value: 'comstar',
-		fieldLabel: gettext('iSCSI Provider'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'writecache',
-		checked: true,
-		bind: me.isCreate ? { disabled: '{!hasWriteCacheOption}' } : { hidden: '{!hasWriteCacheOption}' },
-		uncheckedValue: 0,
-		fieldLabel: gettext('Write cache')
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_hg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		fieldLabel: gettext('Host group'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'lio_tpg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
-		allowBlank: false,
-		fieldLabel: gettext('Target portal group')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.ZFSPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveZFSPoolSelector',
-    valueField: 'pool',
-    displayField: 'pool',
-    queryMode: 'local',
-    editable: false,
-    listConfig: {
-	loadingText: gettext('Scanning...')
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'pool', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/zfs'
-	    }
-	});
-
-	store.sort('pool', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ZFSPoolInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_zfspool',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
-		name: 'pool',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	} else {
-	    me.column1.push(Ext.createWidget('displayfield', {
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	}
-
-	// value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push(
-	    {xtype: 'pveContentTypeSelector',
-	     cts: ['images', 'rootdir'],
-	     fieldLabel: gettext('Content'),
-	     name: 'content',
-	     value: ['images', 'rootdir'],
-	     multiSelect: true,
-	     allowBlank: false
-	});
-	/*jslint confusion: false*/
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'blocksize',
-		emptyText: '8k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.StatusView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAStatusView'],
-
-    onlineHelp: 'chapter_ha_manager',
-
-    sortPriority: {
-	quorum: 1,
-	master: 2,
-	lrm: 3,
-	service: 4
-    },
-    
-    initComponent : function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sortAfterUpdate: true,
-	    sorters: [{
-		sorterFn: function(rec1, rec2) {
-		    var p1 = me.sortPriority[rec1.data.type];
-		    var p2 = me.sortPriority[rec2.data.type];
-		    return (p1 !== p2) ? ((p1 > p2) ? 1 : -1) : 0;
-		}
-	    }],
-	    filters: {
-		property: 'type',
-		value: 'service',
-		operator: '!='
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 80,
-		    flex: 1,
-		    dataIndex: 'status'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-    }
-}, function() {
-
-    Ext.define('pve-ha-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'type', 'node', 'status', 'sid',
-	    'state', 'group', 'comment',
-	    'max_restart', 'max_relocate', 'type',
-	    'crm_state', 'request_state'
-	],
-	idProperty: 'id'
-    });
-
-});
-Ext.define('PVE.ha.Status', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveHAStatus',
-
-    onlineHelp: 'chapter_ha_manager',
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-	    interval: me.interval,
-	    model: 'pve-ha-status',
-	    storeid: 'pve-store-' + (++Ext.idSeed),
-	    groupField: 'type',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/ha/status/current'
-	    }
-	});
-
-	me.items = [{
-	    xtype: 'pveHAStatusView',
-	    title: gettext('Status'),
-	    rstore: me.rstore,
-	    border: 0,
-	    collapsible: true,
-	    padding: '0 0 20 0'
-	},{
-	    xtype: 'pveHAResourcesView',
-	    flex: 1,
-	    collapsible: true,
-	    title: gettext('Resources'),
-	    border: 0,
-	    rstore: me.rstore
-	}];
-
-	me.callParent();
-	me.on('activate', me.rstore.startUpdate);
-    }
-});
-Ext.define('PVE.ha.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveHAGroupSelector'],
-
-    value: [],
-    autoSelect: false,
-    valueField: 'group',
-    displayField: 'group',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		width: 100,
-		sortable: true,
-		dataIndex: 'group'
-	    },
-	    {
-		header: gettext('Nodes'),
-		width: 100,
-		sortable: false,
-		dataIndex: 'nodes'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 1,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode
-	    }
-	]
-    },
-    store: {
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getStore().load();
-    }
-
-}, function() {
-
-    Ext.define('pve-ha-groups', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'group', 'type', 'digest', 'nodes', 'comment',
-	    {
-		name : 'restricted',
-		type: 'boolean'
-	    },
-	    {
-		name : 'nofailback',
-		type: 'boolean'
-	    }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/cluster/ha/groups"
-	},
-	idProperty: 'group'
-    });
-});
-Ext.define('PVE.ha.VMResourceInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_resource_config',
-    vmid: undefined,
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.vmid) {
-	    values.sid = values.vmid;
-	}
-	delete values.vmid;
-
-	PVE.Utils.delete_if_default(values, 'group', '', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_restart', '1', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_relocate', '1', me.isCreate);
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var MIN_QUORUM_VOTES = 3;
-
-	var disabledHint = Ext.createWidget({
-	    xtype: 'displayfield', // won't get submitted by default
-	    userCls: 'pve-hint',
-	    value: 'Disabling the resource will stop the guest system. ' +
-	    'See the online help for details.',
-	    hidden: true
-	});
-
-	var fewVotesHint = Ext.createWidget({
-	    itemId: 'fewVotesHint',
-	    xtype: 'displayfield',
-	    userCls: 'pve-hint',
-	    value: 'At least three quorum votes are recommended for reliable HA.',
-	    hidden: true
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/config/nodes',
-	    method: 'GET',
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var nodes = response.result.data;
-		var votes = 0;
-		Ext.Array.forEach(nodes, function(node) {
-		    var vote = parseInt(node.quorum_votes, 10); // parse as base 10
-		    votes += vote || 0; // parseInt might return NaN, which is false
-		});
-
-		if (votes < MIN_QUORUM_VOTES) {
-		    fewVotesHint.setVisible(true);
-		}
-	    }
-	});
-
-	/*jslint confusion: true */
-	var vmidStore = (me.vmid) ? {} : {
-	    model: 'PVEResources',
-	    autoLoad: true,
-	    sorters: 'vmid',
-	    filters: [
-		{
-		    property: 'type',
-		    value: /lxc|qemu/
-		},
-		{
-		    property: 'hastate',
-		    value: /unmanaged/
-		}
-	    ]
-	};
-
-	// value is a string above, but a number below
-	me.column1 = [
-	    {
-		xtype: me.vmid ? 'displayfield' : 'vmComboSelector',
-		submitValue: me.isCreate,
-		name: 'vmid',
-		fieldLabel: (me.vmid && me.guestType === 'ct') ? 'CT' : 'VM',
-		value: me.vmid,
-		store: vmidStore,
-		validateExists: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_restart',
-		fieldLabel: gettext('Max. Restart'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_relocate',
-		fieldLabel: gettext('Max. Relocate'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.column2 = [
-	    {
-		xtype: 'pveHAGroupSelector',
-		name: 'group',
-		fieldLabel: gettext('Group')
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'state',
-		value: 'started',
-		fieldLabel: gettext('Request State'),
-		comboItems: [
-		    ['started', 'started'],
-		    ['stopped', 'stopped'],
-		    ['ignored', 'ignored'],
-		    ['disabled', 'disabled']
-		],
-		listeners: {
-		    'change': function(field, newValue) {
-			if (newValue === 'disabled') {
-			    disabledHint.setVisible(true);
-			}
-			else {
-			    if (disabledHint.isVisible()) {
-				disabledHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    disabledHint
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    fewVotesHint
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.VMResourceEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmid: undefined,
-    guestType: undefined,
-    isCreate: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	if (me.isCreate === undefined) {
-	    me.isCreate = !me.vmid;
-	}
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/resources';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/resources/' + me.vmid;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.VMResourceInputPanel', {
-	    isCreate: me.isCreate,
-	    vmid: me.vmid,
-	    guestType: me.guestType
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Resource') + ': ' + gettext('Container') +
-	    '/' + gettext('Virtual Machine'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    var regex =  /^(\S+):(\S+)$/;
-		    var res = regex.exec(values.sid);
-
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			throw "got unexpected resource type";
-		    }
-
-		    values.vmid = res[2];
-		    
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.ResourcesView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAResourcesView'],
-
-    onlineHelp: 'ha_manager_resources',
-
-    stateful: true,
-    stateId: 'grid-ha-resources',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!me.rstore) {
-	    throw "no store given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    filters: {
-		property: 'type',
-		value: 'service'
-	    }
-	});
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var render_error = function(dataIndex, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors[dataIndex];
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    var sid = rec.data.sid;
-	    
-	    var regex =  /^(\S+):(\S+)$/;
-	    var res = regex.exec(sid);
-
-	    if (res[1] !== 'vm' && res[1] !== 'ct') {
-		return;
-	    }
-	    var guestType = res[1];
-	    var vmid = res[2];
-	    
-            var win = Ext.create('PVE.ha.VMResourceEdit',{
-                guestType: guestType,
-                vmid: vmid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/resources/',
-	    getUrl: function(rec) {
-		var me = this;
-		return me.baseurl + '/' + rec.get('sid');
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.VMResourceEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'sid'
-		},
-		{
-		    header: gettext('State'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Request State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'started';
-		    },
-		    dataIndex: 'request_state'
-		},
-		{
-		    header: gettext('CRM State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    dataIndex: 'crm_state'
-		},
-		{
-		    header: gettext('Max. Restart'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || '1';
-		    },
-		    dataIndex: 'max_restart'
-		},
-		{
-		    header: gettext('Max. Relocate'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || '1';
-		    },
-		    dataIndex: 'max_relocate'
-		},
-		{
-		    header: gettext('Group'),
-		    width: 200,
-		    sortable: true,
-		    renderer: function(value, metaData, record) {
-			return render_error('group', value, metaData, record);
-		    },
-		    dataIndex: 'group'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-resources', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	  'sid', 'state', 'digest', 'errors', 'group', 'comment',
-	  'max_restart', 'max_relocate', 'type', 'status', 'node',
-	  'crm_state', 'request_state'
-	],
-	idProperty: 'sid'
-    });
-
-});
-Ext.define('PVE.ha.GroupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_groups',
-
-    groupId: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = 'group';
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var update_nodefield, update_node_selection;
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    update_nodefield(selected);
-		}
-	    }
-	});
-
-	// use already cached data to avoid an API call
-	var data = PVE.data.ResourceStore.getNodes();
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'node', 'mem', 'cpu', 'priority' ],
-	    data: data,
-	    proxy: {
-		type: 'memory',
-		reader: {type: 'json'}
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var nodegrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Node'),
-		    flex: 1,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Memory usage') + " %",
-		    renderer: PVE.Utils.render_mem_usage_percent,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'mem'
-		},
-		{
-		    header: gettext('CPU usage'),
-		    renderer: PVE.Utils.render_cpu,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'cpu'
-		},
-		{
-		    header: 'Priority',
-		    xtype: 'widgetcolumn',
-		    dataIndex: 'priority',
-		    sortable: true,
-		    stopSelection: true,
-		    widget: {
-			xtype: 'proxmoxintegerfield',
-			minValue: 0,
-			maxValue: 1000,
-			isFormField: false,
-			listeners: {
-			    change: function(numberfield, value, old_value) {
-				var record = numberfield.getWidgetRecord();
-				record.set('priority', value);
-				update_nodefield(sm.getSelection());
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	var nodefield = Ext.create('Ext.form.field.Hidden', {
-	    name: 'nodes',
-	    value: '',
-	    listeners: {
-		change: function (nodefield, value) {
-		    update_node_selection(value);
-		}
-	    },
-	    isValid: function () {
-		var value = nodefield.getValue();
-		return (value && 0 !== value.length);
-	    }
-	});
-
-	update_node_selection = function(string) {
-	    sm.deselectAll(true);
-
-	    string.split(',').forEach(function (e, idx, array) {
-		var res = e.split(':');
-
-		store.each(function(record) {
-		    var node = record.get('node');
-
-		    if (node == res[0]) {
-			sm.select(record, true);
-			record.set('priority', res[1]);
-			record.commit();
-		    }
-		});
-	    });
-	    nodegrid.reconfigure(store);
-
-	};
-
-	update_nodefield = function(selected) {
-	    var nodes = '';
-	    var first_iteration = true;
-	    Ext.Array.each(selected, function(record) {
-		if (!first_iteration) {
-		    nodes += ',';
-		}
-		first_iteration = false;
-
-		nodes += record.data.node;
-		if (record.data.priority) {
-		    nodes += ':' + record.data.priority;
-		}
-	    });
-
-	    // nodefield change listener calls us again, which results in a
-	    // endless recursion, suspend the event temporary to avoid this
-	    nodefield.suspendEvent('change');
-	    nodefield.setValue(nodes);
-	    nodefield.resumeEvent('change');
-	};
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'group',
-		value: me.groupId || '',
-		fieldLabel: 'ID',
-		vtype: 'StorageId',
-		allowBlank: false
-	    },
-	    nodefield
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'restricted',
-		uncheckedValue: 0,
-		fieldLabel: 'restricted'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'nofailback',
-		uncheckedValue: 0,
-		fieldLabel: 'nofailback'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    nodegrid
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    groupId: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	me.isCreate = !me.groupId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/groups';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
-	    isCreate: me.isCreate,
-	    groupId: me.groupId
-	});
-
-	Ext.apply(me, {
-            subject: gettext('HA Group'),
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.GroupsView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAGroupsView'],
-
-    onlineHelp: 'ha_manager_groups',
-
-    stateful: true,
-    stateId: 'grid-ha-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-	});
-	
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-            var win = Ext.create('PVE.ha.GroupEdit',{
-                groupId: rec.data.group
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/groups/',
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.GroupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Group'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'group'
-		},
-		{
-		    header: 'restricted',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'restricted'
-		},
-		{
-		    header: 'nofailback',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'nofailback'
-		},
-		{
-		    header: gettext('Nodes'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'nodes'
-		},
-		{
-		    header: gettext('Comment'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.FencingView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveFencingView'],
-
-    onlineHelp: 'ha_manager_fencing',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-fencing',
-	    data: []
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false,
-		deferEmptyText: false,
-		emptyText: 'Use watchdog based fencing.'
-	    },
-	    columns: [
-		{
-		    header: 'Node',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Command'),
-		    flex: 1,
-		    dataIndex: 'command'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-fencing', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'node', 'command', 'digest'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSummary',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: 'column',
-
-    defaults: {
-	padding: 5,
-	plugins: 'responsive',
-	responsiveConfig: {
-	    'width < 1900': {
-		columnWidth: 1
-	    },
-	    'width >= 1900': {
-		columnWidth: 0.5
-	    }
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'dcHealth',
-	    xtype: 'pveDcHealth'
-	},
-	{
-	    itemId: 'dcGuests',
-	    xtype: 'pveDcGuests'
-	},
-	{
-	    title: gettext('Resources'),
-	    xtype: 'panel',
-	    minHeight: 250,
-	    bodyPadding: 5,
-	    layout: 'hbox',
-	    defaults: {
-		xtype: 'proxmoxGauge',
-		flex: 1
-	    },
-	    items:[
-		{
-		    title: gettext('CPU'),
-		    itemId: 'cpu'
-		},
-		{
-		    title: gettext('Memory'),
-		    itemId: 'memory'
-		},
-		{
-		    title: gettext('Storage'),
-		    itemId: 'storage'
-		}
-	    ]
-	},
-	{
-	    itemId: 'nodeview',
-	    xtype: 'pveDcNodeView',
-	    height: 250
-	},
-	{
-	    title: gettext('Subscriptions'),
-	    height: 220,
-	    items: [
-		{
-		    itemId: 'subscriptions',
-		    xtype: 'pveHealthWidget',
-		    userCls: 'pointer',
-		    listeners: {
-			element: 'el',
-			click: function() {
-			    if (this.component.userCls === 'pointer') {
-				window.open('https://www.proxmox.com/en/proxmox-ve/pricing', '_blank');
-			    }
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-status',
-	    model: 'pve-dc-nodes',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/cluster/status"
-	    }
-	});
-
-	var gridstore = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    filters: {
-		property: 'type',
-		value: 'node'
-	    },
-	    sorters: {
-		property: 'id',
-		direction: 'ASC'
-	    }
-	});
-
-	me.callParent();
-
-	me.getComponent('nodeview').setStore(gridstore);
-
-	var gueststatus = me.getComponent('dcGuests');
-
-	var cpustat = me.down('#cpu');
-	var memorystat = me.down('#memory');
-	var storagestat = me.down('#storage');
-	var sp = Ext.state.Manager.getProvider();
-
-	me.mon(PVE.data.ResourceStore, 'load', function(curstore, results) {
-	    me.suspendLayout = true;
-
-	    var cpu = 0;
-	    var maxcpu = 0;
-
-	    var nodes = 0;
-
-	    var memory = 0;
-	    var maxmem = 0;
-
-	    var countedStorages = {};
-	    var used = 0;
-	    var total = 0;
-	    var usableStorages = {};
-	    var storages = sp.get('dash-storages') || '';
-	    storages.split(',').forEach(function(storage){
-		if (storage !== '') {
-		    usableStorages[storage] = true;
-		}
-	    });
-
-	    var qemu = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var lxc = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var error = 0;
-
-	    var i;
-
-	    for (i = 0; i < results.length; i++) {
-		var item = results[i];
-		switch(item.data.type) {
-		    case 'node':
-			cpu += (item.data.cpu * item.data.maxcpu);
-			maxcpu += item.data.maxcpu || 0;
-			memory += item.data.mem || 0;
-			maxmem += item.data.maxmem || 0;
-			nodes++;
-
-			// update grid also
-			var griditem = gridstore.getById(item.data.id);
-			if (griditem) {
-			    griditem.set('cpuusage', item.data.cpu);
-			    var max = item.data.maxmem || 1;
-			    var val = item.data.mem || 0;
-			    griditem.set('memoryusage', val/max);
-			    griditem.set('uptime', item.data.uptime);
-			    griditem.commit(); //else it marks the fields as dirty
-			}
-			break;
-		    case 'storage':
-			if (!Ext.Object.isEmpty(usableStorages)) {
-			    if (usableStorages[item.data.id] === true) {
-				used += item.data.disk;
-				total += item.data.maxdisk;
-			    }
-			    break;
-			}
-			if (!countedStorages[item.data.storage] ||
-			    (item.data.storage === 'local' &&
-			    !countedStorages[item.data.id])) {
-			    used += item.data.disk;
-			    total += item.data.maxdisk;
-
-			    countedStorages[item.data.storage === 'local'?item.data.id:item.data.storage] = true;
-			}
-			break;
-		    case 'qemu':
-			qemu[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    case 'lxc':
-			lxc[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    default: break;
-		}
-	    }
-
-	    var text = Ext.String.format(gettext('of {0} CPU(s)'), maxcpu);
-	    cpustat.updateValue((cpu/maxcpu), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(memory), PVE.Utils.render_size(maxmem));
-	    memorystat.updateValue((memory/maxmem), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(used), PVE.Utils.render_size(total));
-	    storagestat.updateValue((used/total), text);
-
-	    gueststatus.updateValues(qemu,lxc,error);
-
-	    me.suspendLayout = false;
-	    me.updateLayout(true);
-	});
-
-	var dcHealth = me.getComponent('dcHealth');
-	me.mon(rstore, 'load', dcHealth.updateStatus, dcHealth);
-
-	var subs = me.down('#subscriptions');
-	me.mon(rstore, 'load', function(store, records, success) {
-	    var i;
-	    var level;
-	    var curlevel;
-	    for (i = 0; i < records.length; i++) {
-		if (records[i].get('type') !== 'node') {
-		    continue;
-		}
-
-		curlevel = records[i].get('level');
-		if (level === undefined || !curlevel) {
-		    level = curlevel;
-		    continue;
-		}
-
-		if (level !== curlevel) {
-		    break;
-		}
-	    }
-
-	    if (level === '') {
-		subs.setData({
-		    title: gettext('No Subscription'),
-		    iconCls: PVE.Utils.get_health_icon('critical', true),
-		    text: gettext('You have at least one node without subscription.')
-		});
-		subs.setUserCls('pointer');
-	    } else if (level !== curlevel) {
-		subs.setData({
-		    title: gettext('Mixed Subscriptions'),
-		    iconCls: PVE.Utils.get_health_icon('warning', true),
-		    text: gettext('Warning: Your subscription levels are not the same.')
-		});
-		subs.setUserCls('pointer');
-	    } else {
-		subs.setData({
-		    title: PVE.Utils.render_support_level(level),
-		    iconCls: PVE.Utils.get_health_icon('good', true),
-		    text: gettext('Your subscription status is valid.')
-		});
-		subs.setUserCls('');
-	    }
-	});
-
-	me.on('destroy', function(){
-	    rstore.stopUpdate();
-	});
-
-	rstore.startUpdate();
-    }
-
-});
-Ext.define('PVE.window.ReplicaEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveReplicaEdit',
-
-    subject: gettext('Replication Job'),
-
-
-    url: '/cluster/replication',
-    method: 'POST',
-
-    initComponent: function() {
-	var me = this;
-
-	var vmid = me.pveSelNode.data.vmid;
-	var nodename = me.pveSelNode.data.node;
-
-	var items = [];
-
-	items.push({
-	    xtype: (me.isCreate && !vmid)?'pveGuestIDSelector':'displayfield',
-	    name: 'guest',
-	    fieldLabel: 'CT/VM ID',
-	    value: vmid || ''
-	});
-
-	items.push(
-	    {
-		xtype: me.isCreate ? 'pveNodeSelector':'displayfield',
-		name: 'target',
-		disallowedNodes: [nodename],
-		allowBlank: false,
-		onlineValidator: true,
-		fieldLabel: gettext("Target")
-	    },
-	    {
-		xtype: 'pveCalendarEvent',
-		fieldLabel: gettext('Schedule'),
-		emptyText: '*/15 - ' + Ext.String.format(gettext('Every {0} minutes'), 15),
-		name: 'schedule'
-	    },
-	    {
-		xtype: 'numberfield',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		step: 1,
-		minValue: 1,
-		emptyText: gettext('unlimited'),
-		name: 'rate'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Comment'),
-		name: 'comment'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enabled',
-		defaultValue: 'on',
-		checked: true,
-		fieldLabel: gettext('Enabled')
-	    }
-	);
-
-	me.items = [
-	    {
-		xtype: 'inputpanel',
-		itemId: 'ipanel',
-		onlineHelp: 'pvesr_schedule_time_format',
-
-		onGetValues: function(values) {
-		    var me = this.up('window');
-
-		    values.disable = values.enabled ? 0 : 1;
-		    delete values.enabled;
-
-		    PVE.Utils.delete_if_default(values, 'rate', '', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'disable', 0, me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'schedule', '*/15', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'comment', '', me.isCreate);
-
-		    if (me.isCreate) {
-			values.type = 'local';
-			var vm = vmid || values.guest;
-			var id = -1;
-			if (me.highestids[vm] !== undefined) {
-			    id = me.highestids[vm];
-			}
-			id++;
-			values.id = vm + '-' + id.toString();
-			delete values.guest;
-		    }
-		    return values;
-		},
-		items: items
-	    }
-	];
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var jobs = response.result.data;
-		    var highestids = {};
-		    Ext.Array.forEach(jobs, function(job) {
-			var match = /^([0-9]+)\-([0-9]+)$/.exec(job.id);
-			if (match) {
-			    var vmid = parseInt(match[1],10);
-			    var id = parseInt(match[2],10);
-			    if (highestids[vmid] < id ||
-				highestids[vmid] === undefined) {
-				highestids[vmid] = id;
-			    }
-			}
-		    });
-
-		    me.highestids = highestids;
-		}
-	    });
-
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    response.result.data.enabled = !response.result.data.disable;
-		    me.setValues(response.result.data);
-		    me.digest = response.result.data.digest;
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-/* callback is a function and string */
-Ext.define('PVE.grid.ReplicaView', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveReplicaView',
-
-    onlineHelp: 'chapter_pvesr',
-
-    stateful: true,
-    stateId: 'grid-pve-replication-status',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	addJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		isCreate: true,
-		method: 'POST',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	editJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var data = rec.data;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		url: '/cluster/replication/' + data.id,
-		method: 'PUT',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	scheduleJobNow: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-
-	    Proxmox.Utils.API2Request({
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/schedule_now",
-		method: 'POST',
-		waitMsgTarget: me,
-		callback: function() { controller.reload(); },
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	showLog: function(button, event, rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var logView = Ext.create('Proxmox.panel.LogView', {
-		border: false,
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/log"
-	    });
-	    var win = Ext.create('Ext.window.Window', {
-		items: [ logView ],
-		layout: 'fit',
-		width: 800,
-		height: 400,
-		modal: true,
-		title: gettext("Replication Log")
-	    });
-	    var task = {
-		run: function() {
-		    logView.requestUpdate();
-		},
-		interval: 1000
-	    };
-	    Ext.TaskManager.start(task);
-	    win.on('destroy', function() {
-		Ext.TaskManager.stop(task);
-		controller.reload();
-	    });
-	    win.show();
-	},
-
-	reload: function() {
-	    var me = this.getView();
-	    me.rstore.load();
-	},
-
-	dblClick: function(grid, record, item) {
-	    var me = this;
-	    me.editJob(undefined, undefined, record);
-	},
-
-	// check for cluster
-	// currently replication is for cluster only, so we disable the whole
-	// component
-	checkPrerequisites: function() {
-	    var me = this.getView();
-	    if (PVE.data.ResourceStore.getNodes().length < 2) {
-		me.mask(gettext("Replication needs at least two nodes"), ['pve-static-mask']);
-	    }
-	},
-
-	control: {
-	    '#': {
-		itemdblclick: 'dblClick',
-		afterlayout: 'checkPrerequisites'
-	    }
-	}
-    },
-
-    tbar: [
-	{
-	    text: gettext('Add'),
-	    itemId: 'addButton',
-	    handler: 'addJob'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    itemId: 'editButton',
-	    handler: 'editJob',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxStdRemoveButton',
-	    itemId: 'removeButton',
-	    baseurl: '/api2/extjs/cluster/replication/',
-	    dangerous: true,
-	    callback: 'reload'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Log'),
-	    itemId: 'logButton',
-	    handler: 'showLog',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Schedule now'),
-	    itemId: 'scheduleNowButton',
-	    handler: 'scheduleJobNow',
-	    disabled: true
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	var mode = '';
-	var url = '/cluster/replication';
-
-	me.nodename = me.pveSelNode.data.node;
-	me.vmid = me.pveSelNode.data.vmid;
-
-	me.columns = [
-	    {
-		text: gettext('Enabled'),
-		dataIndex: 'enabled',
-		xtype: 'checkcolumn',
-		sortable: true,
-		disabled: true
-	    },
-	    {
-		text: 'ID',
-		dataIndex: 'id',
-		width: 60,
-		hidden: true
-	    },
-	    {
-		text: gettext('Guest'),
-		dataIndex: 'guest',
-		width: 75
-	    },
-	    {
-		text: gettext('Job'),
-		dataIndex: 'jobnum',
-		width: 60
-	    },
-	    {
-		text: gettext('Target'),
-		dataIndex: 'target'
-	    }
-	];
-
-	if (!me.nodename) {
-	    mode = 'dc';
-	    me.stateId = 'grid-pve-replication-dc';
-	} else if (!me.vmid) {
-	    mode = 'node';
-	    url = '/nodes/' + me.nodename + '/replication';
-	} else {
-	    mode = 'vm';
-	    url = '/nodes/' + me.nodename + '/replication' + '?guest=' + me.vmid;
-	}
-
-	if (mode !== 'dc') {
-	    me.columns.push(
-		{
-		    text: gettext('Status'),
-		    dataIndex: 'state',
-		    minWidth: 160,
-		    flex: 1,
-		    renderer: function(value, metadata, record) {
-
-			if (record.data.pid) {
-			    metadata.tdCls = 'x-grid-row-loading';
-			    return '';
-			}
-
-			var icons = [];
-			var states = [];
-
-			if (record.data.remove_job) {
-			    icons.push('<i class="fa fa-ban warning" title="'
-					+ gettext("Removal Scheduled") + '"></i>');
-			    states.push(gettext("Removal Scheduled"));
-			}
-
-			if (record.data.error) {
-			    icons.push('<i class="fa fa-times critical" title="'
-					+ gettext("Error") + '"></i>');
-			    states.push(record.data.error);
-			}
-
-			if (icons.length == 0) {
-			    icons.push('<i class="fa fa-check good"></i>');
-			    states.push(gettext('OK'));
-			}
-
-			return icons.join(',') + ' ' + states.join(',');
-		    }
-		},
-		{
-		    text: gettext('Last Sync'),
-		    dataIndex: 'last_sync',
-		    width: 150,
-		    renderer: function(value, metadata, record) {
-			if (!value) {
-			    return '-';
-			}
-
-			if (record.data.pid) {
-			    return gettext('syncing');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		},
-		{
-		    text: gettext('Duration'),
-		    dataIndex: 'duration',
-		    width: 60,
-		    renderer: PVE.Utils.render_duration
-		},
-		{
-		    text: gettext('Next Sync'),
-		    dataIndex: 'next_sync',
-		    width: 150,
-		    renderer: function(value) {
-			if (!value) {
-			    return '-';
-			}
-
-			var now = new Date();
-			var next = new Date(value*1000);
-
-			if (next < now) {
-			    return gettext('pending');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		}
-	    );
-	}
-
-	me.columns.push(
-	    {
-		text: gettext('Schedule'),
-		width: 75,
-		dataIndex: 'schedule'
-	    },
-	    {
-		text: gettext('Rate limit'),
-		dataIndex: 'rate',
-		renderer: function(value) {
-		    if (!value) {
-			return gettext('unlimited');
-		    }
-
-		    return value.toString() + ' MB/s';
-		},
-		hidden: true
-	    },
-	    {
-		text: gettext('Comment'),
-		dataIndex: 'comment',
-		renderer: Ext.htmlEncode
-	    }
-	);
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-replica-' + me.nodename + me.vmid,
-	    model: (mode === 'dc')? 'pve-replication' : 'pve-replication-state',
-	    interval: 3000,
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + url
-	    }
-	});
-
-	me.store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sorters: [
-		{
-		    property: 'guest'
-		},
-		{
-		    property: 'jobnum'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	// we cannot access the log and scheduleNow button
-	// in the datacenter, because
-	// we do not know where/if the jobs runs
-	if (mode === 'dc') {
-	    me.down('#logButton').setHidden(true);
-	    me.down('#scheduleNowButton').setHidden(true);
-	}
-
-	// if we set the warning mask, we do not want to load
-	// or set the mask on store errors
-	if (PVE.data.ResourceStore.getNodes().length < 2) {
-	    return;
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.on('destroy', me.rstore.stopUpdate);
-	me.rstore.startUpdate();
-    }
-}, function() {
-
-    Ext.define('pve-replication', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'target', 'comment', 'rate', 'type',
-	    { name: 'guest', type: 'integer' },
-	    { name: 'jobnum', type: 'integer' },
-	    { name: 'schedule', defaultValue: '*/15' },
-	    { name: 'disable', defaultValue: '' },
-	    { name: 'enabled', calculate: function(data) { return !data.disable; } }
-	]
-    });
-
-    Ext.define('pve-replication-state', {
-	extend: 'pve-replication',
-	fields: [
-	    'last_sync', 'next_sync', 'error', 'duration', 'state',
-	    'fail_count', 'remove_job', 'pid'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Health', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcHealth',
-
-    title: gettext('Health'),
-
-    bodyPadding: 10,
-    height: 220,
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	flex: 1,
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    nodeList: [],
-    nodeIndex: 0,
-
-    updateStatus: function(store, records, success) {
-	var me = this;
-	if (!success) {
-	    return;
-	}
-
-	var cluster = {
-	    iconCls: PVE.Utils.get_health_icon('good', true),
-	    text: gettext("Standalone node - no cluster defined")
-	};
-
-	var nodes = {
-	    online: 0,
-	    offline: 0
-	};
-
-	// by default we have one node
-	var numNodes = 1;
-	var i;
-
-	for (i = 0; i < records.length; i++) {
-	    var item = records[i];
-	    if (item.data.type === 'node') {
-		nodes[item.data.online === 1 ? 'online':'offline']++;
-	    } else if(item.data.type === 'cluster') {
-		cluster.text = gettext("Cluster") + ": ";
-		cluster.text += item.data.name + ", ";
-		cluster.text += gettext("Quorate") + ": ";
-		cluster.text += Proxmox.Utils.format_boolean(item.data.quorate);
-		if (item.data.quorate != 1) {
-		    cluster.iconCls = PVE.Utils.get_health_icon('critical', true);
-		}
-
-		numNodes = item.data.nodes;
-	    }
-	}
-
-	if (numNodes !== (nodes.online + nodes.offline)) {
-	    nodes.offline = numNodes - nodes.online;
-	}
-
-	me.getComponent('clusterstatus').updateHealth(cluster);
-	me.getComponent('nodestatus').update(nodes);
-    },
-
-    updateCeph: function(store, records, success) {
-	var me = this;
-	var cephstatus = me.getComponent('ceph');
-	if (!success || records.length < 1) {
-
-	    // if ceph status is already visible
-	    // dont stop to update
-	    if (cephstatus.isVisible()) {
-		return;
-	    }
-
-	    // try all nodes until we either get a successfull api call,
-	    // or we tried all nodes
-	    if (++me.nodeIndex >= me.nodeList.length) {
-		me.cephstore.stopUpdate();
-	    } else {
-		store.getProxy().setUrl('/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status');
-	    }
-
-	    return;
-	}
-
-	var state = PVE.Utils.render_ceph_health(records[0].data.health || {});
-	cephstatus.updateHealth(state);
-	cephstatus.setVisible(true);
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    me.cephstore.stopUpdate();
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'clusterstatus',
-	    xtype: 'pveHealthWidget',
-	    title: gettext('Status')
-	},
-	{
-	    itemId: 'nodestatus',
-	    data: {
-		online: 0,
-		offline: 0
-	    },
-	    tpl: [
-		'<h3>' + gettext('Nodes') + '</h3><br />',
-		'<div style="width: 150px;margin: auto;font-size: 12pt">',
-		'<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-check">&nbsp;</i>',
-		gettext('Online'),
-		'</div>',
-		'<div class="right-aligned">{online}</div>',
-		'<br /><br />',
-		'<div class="left-aligned">',
-		'<i class="critical fa fa-fw fa-times">&nbsp;</i>',
-		gettext('Offline'),
-		'</div>',
-		'<div class="right-aligned">{offline}</div>',
-		'</div>'
-	    ]
-	},
-	{
-	    itemId: 'ceph',
-	    width: 250,
-	    columnWidth: undefined,
-	    userCls: 'pointer',
-	    title: 'Ceph',
-	    xtype: 'pveHealthWidget',
-	    hidden: true,
-	    listeners: {
-		element: 'el',
-		click: function() {
-		    var me = this.component.up('pveDcHealth');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // preselect the ceph tab
-		    sp.set('nodetab', {value:'ceph'});
-
-		    // select the node that had the successfull api call
-		    var id = me.nodeList[me.nodeIndex].id;
-		    Ext.ComponentQuery.query('pveResourceTree')[0].selectById(id);
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodeList = PVE.data.ResourceStore.getNodes();
-	me.nodeIndex = 0;
-	me.cephstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-ceph',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status'
-	    }
-	});
-	me.callParent();
-	me.mon(me.cephstore, 'load', me.updateCeph, me);
-	me.cephstore.startUpdate();
-    }
-});
-Ext.define('PVE.dc.Guests', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcGuests',
-
-
-    title: gettext('Guests'),
-    height: 220,
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-    bodyPadding: '0 20 20 20',
-
-    defaults: {
-	xtype: 'box',
-	padding: '0 50 0 50',
-	style: {
-	    'text-align':'center',
-	    'line-height':'1.2'
-	}
-    },
-    items: [{
-	itemId: 'qemu',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("Virtual Machines") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'lxc',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("LXC Container") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'error',
-	colspan: 2,
-	data: {
-	    num: 0
-	},
-	columnWidth: 1,
-	padding: '10 250 0 250',
-	tpl: [
-	    '<tpl if="num &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="critical fa fa-fw fa-times-circle">&nbsp;</i>',
-		    gettext('Error'),
-		'</div>',
-		'<div class="right-aligned">{num}</div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateValues: function(qemu, lxc, error) {
-	var me = this;
-	me.getComponent('qemu').update(qemu);
-	me.getComponent('lxc').update(lxc);
-	me.getComponent('error').update({num: error});
-    }
-});
- /*jslint confusion: true*/
-Ext.define('PVE.dc.OptionView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    onlineHelp: 'datacenter_configuration_file',
-
-    monStoreErrors: true,
-
-    add_inputpanel_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	var canEdit = (opts.caps === undefined || opts.caps);
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: canEdit ? {
-		xtype: 'proxmoxWindowEdit',
-		width: 350,
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		setValues: function(values) {
-		    // FIXME: run through parsePropertyString if not an object?
-		    var edit_value = values[name];
-		    Ext.Array.each(this.query('inputpanel'), function(panel) {
-			panel.setValues(edit_value);
-		    });
-		},
-		url: opts.url,
-		items: [{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			if (values === undefined || Object.keys(values).length === 0) {
-			    return { 'delete': name };
-			}
-			var ret_val = {};
-			ret_val[name] = PVE.Parser.printPropertyString(values);
-			return ret_val;
-		    },
-		    items: opts.items
-		}]
-	    } : undefined
-	};
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.add_combobox_row('keyboard', gettext('Keyboard Layout'), {
-	    renderer: PVE.Utils.render_kvm_language,
-	    comboItems: PVE.Utils.kvm_keymap_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('http_proxy', gettext('HTTP proxy'), {
-	    defaultValue: Proxmox.Utils.noneText,
-	    vtype: 'HttpProxy',
-	    deleteEmpty: true
-	});
-	me.add_combobox_row('console', gettext('Console Viewer'), {
-	    renderer: PVE.Utils.render_console_viewer,
-	    comboItems: PVE.Utils.console_viewer_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('email_from', gettext('Email from address'), {
-	    deleteEmpty: true,
-	    vtype: 'proxmoxMail',
-	    defaultValue: 'root@$hostname'
-	});
-	me.add_text_row('mac_prefix', gettext('MAC address prefix'), {
-	    deleteEmpty: true,
-	    vtype: 'MacPrefix',
-	    defaultValue: Proxmox.Utils.noneText
-	});
-	me.add_inputpanel_row('migration', gettext('Migration Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    defaultKey: 'type',
-	    items: [{
-		xtype: 'displayfield',
-		name: 'type',
-		fieldLabel: gettext('Type'),
-		value: 'secure',
-		submitValue: true,
-		vtype: 'IPCIDRAddress'
-	    }, {
-		xtype: 'textfield',
-		name: 'network',
-		fieldLabel: gettext('Network'),
-		vtype: 'IPCIDRAddress',
-		emptyText: Proxmox.Utils.defaultText,
-		value: ''
-	    }]
-	});
-	me.add_inputpanel_row('ha', gettext('HA Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    items: [{
-		xtype: 'proxmoxKVComboBox',
-		name: 'shutdown_policy',
-		fieldLabel: gettext('Shutdown Policy'),
-		deleteEmpty: false,
-		value: '__default__',
-		comboItems: [
-		    ['__default__', Proxmox.Utils.defaultText + ' (conditional)' ],
-		    ['freeze', 'freeze'],
-		    ['failover', 'failover'],
-		    ['conditional', 'conditional']
-		],
-		defaultValue: '__default__'
-	    }]
-	});
-
-	// TODO: bwlimits, migration net, u2f?
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    tbar: [{
-		text: gettext('Edit'),
-		xtype: 'proxmoxButton',
-		disabled: true,
-		handler: function() { me.run_editor(); },
-		selModel: me.selModel
-	    }],
-	    url: "/api2/json/cluster/options",
-	    editorConfig: {
-		url: "/api2/extjs/cluster/options"
-	    },
-	    interval: 5000,
-	    cwidth1: 200,
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	// set the new value for the default console
-	me.mon(me.rstore, 'load', function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-
-	    var rec = store.getById('console');
-	    PVE.VersionInfo.console = rec.data.value;
-	    if (rec.data.value === '__default__') {
-		delete PVE.VersionInfo.console;
-	    }
-	});
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    onlineHelp: 'chapter_storage',
-
-    stateful: true,
-    stateId: 'grid-dc-storage',
-
-    createStorageEditWindow: function(type, sid) {
-	var schema = PVE.Utils.storageSchema[type];
-	if (!schema || !schema.ipanel) {
-	    throw "no editor registered for storage type: " + type;
-	}
-
-	Ext.create('PVE.storage.BaseEdit', {
-	    paneltype: 'PVE.storage.' + schema.ipanel,
-	    type: type,
-	    storageId: sid,
-	    autoShow: true,
-	    listeners: {
-		destroy: this.reloadStore
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-storage',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/storage"
-	    },
-	    sorters: {
-		property: 'storage',
-		order: 'DESC'
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type,
-	        sid = rec.data.storage;
-
-	    me.createStorageEditWindow(type, sid);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/storage/',
-	    callback: reload
-	});
-
-	// else we cannot dynamically generate the add menu handlers
-	var addHandleGenerator = function(type) {
-	    return function() { me.createStorageEditWindow(type); };
-	};
-	var addMenuItems = [], type;
-	/*jslint forin: true */
-	for (type in PVE.Utils.storageSchema) {
-	    var storage = PVE.Utils.storageSchema[type];
-	    if (storage.hideAdd) {
-		continue;
-	    }
-	    addMenuItems.push({
-		text:  PVE.Utils.format_storage_type(type),
-		iconCls: 'fa fa-fw fa-' + storage.faIcon,
-		handler: addHandleGenerator(type)
-	    });
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    reloadStore: reload,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: addMenuItems
-		    })
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Type'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'type',
-		    renderer: PVE.Utils.format_storage_type
-		},
-		{
-		    header: gettext('Content'),
-		    flex: 3,
-		    sortable: true,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Path') + '/' + gettext('Target'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'path',
-		    renderer: function(value, metaData, record) {
-			if (record.data.target) {
-			    return record.data.target;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Shared'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'shared',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Enabled'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'disable',
-		    renderer: Proxmox.Utils.format_neg_boolean
-		},
-		{
-		    header: gettext('Bandwidth Limit'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'bwlimit'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-	    { name: 'shared', type: 'boolean'},
-	    { name: 'disable', type: 'boolean'}
-	],
-	idProperty: 'storage'
-    });
-
-});
-/*global u2f,QRCode,Uint8Array*/
-/*jslint confusion: true*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' + encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer)
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    PVE.Utils.render_u2f_error(error)
-	);
-    },
-
-    doU2FChallenge: function(response) {
-	var me = this;
-
-	var data = response.result.data;
-	me.lookup('password').setDisabled(true);
-	var msg = Ext.Msg.show({
-	    title: 'U2F: '+gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: []
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(data.appId, [data], [], function(data) {
-		msg.close();
-		if (data.errorCode) {
-		    me.showError(data.errorCode);
-		} else {
-		    me.respondToU2FChallenge(data);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data)
-	};
-	if (Proxmox.UserName !== 'root@pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    has_tfa: false,
-	    valid: false,
-	    u2f_available: true
-	},
-	formulas: {
-	    canDeleteTFA: function(get) {
-		return (get('has_tfa') && !get('tfa_required'));
-	    }
-	}
-    },
-
-    afterLoadingRealm: function(realm_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type
-		)
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    var me = this.getView();
-		    me.updateQrCode();
-		}
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		}
-	    },
-	    '#': {
-		show: function() {
-		    var me = this.getView();
-		    var viewmodel = this.getViewModel();
-
-		    me.qrdiv = document.createElement('center');
-		    me.qrcode = new QRCode(me.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M
-		    });
-		    me.down('#qrbox').getEl().appendChild(me.qrdiv);
-
-		    viewmodel.set('has_tfa', me.hasTFA);
-		    if (!me.hasTFA) {
-			this.randomizeSecret();
-		    } else {
-			me.down('#qrbox').setVisible(false);
-			me.lookup('challenge').setVisible(false);
-		    }
-
-		    if (Proxmox.UserName === 'root@pam') {
-			me.lookup('password').setVisible(false);
-			me.lookup('password').setDisabled(true);
-		    }
-		}
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    var viewmodel = this.getViewModel();
-		    viewmodel.set('in_totp_tab', newcard.itemId === 'totp-panel');
-		}
-	    }
-	},
-
-	applySettings: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	deleteTFA: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'delete'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	randomizeSecret: function() {
-	    var me = this;
-	    var rnd = new Uint8Array(16);
-	    window.crypto.getRandomValues(rnd);
-	    var data = '';
-	    rnd.forEach(function(b) {
-		// just use the first 5 bit
-		b = b & 0x1f;
-		if (b < 26) {
-		    // A..Z
-		    data += String.fromCharCode(b + 0x41);
-		} else {
-		    // 2..7
-		    data += String.fromCharCode(b-26 + 0x32);
-		}
-	    });
-	    me.lookup('tfa_secret').setValue(data);
-	},
-
-	startU2FRegistration: function() {
-	    var me = this;
-
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    border: false,
-		    layout: {
-			type: 'vbox',
-			align: 'stretch'
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5'
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    cbind: {
-					value: '{userid}'
-				    }
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					flex: 4
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1
-				    }]
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true
-				}
-			    ]
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    style: {
-				'background-color': '#23272a',
-				padding: '5px',
-				width: '266px',
-				height: '266px'
-			    }
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify')
-			}
-		    ]
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle'
-		    },
-		    bind: {
-			disabled: '{!u2f_available}'
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.')
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password')
-	}
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton'
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}'
-	    }
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}'
-	    }
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}'
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    autoLoad: true
-	});
-
-	store.on('load', function() {
-	    var user_realm = me.userid.split('@')[1];
-	    var realm = me.store.findRecord('realm', user_realm);
-	    me.afterLoadingRealm(realm && realm.data && realm.data.tfa);
-	}, me);
-
-	Ext.apply(me, { store: store });
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    }
-});
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + me.userid;
-            method = 'PUT';
-	}
-
-	var verifypw;
-	var pwfield;
-
-	var validate_pw = function() {
-	    if (verifypw.getValue() !== pwfield.getValue()) {
-		return gettext("Passwords do not match");
-	    }
-	    return true;
-	};
-
-	verifypw = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'), 
-	    name: 'verifypassword',
-	    submitValue: false,
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	pwfield = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'), 
-	    minLength: 5,
-	    name: 'password',
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	var update_passwd_field = function(realm) {
-	    if (realm === 'pve') {
-		pwfield.setVisible(true);
-		pwfield.setDisabled(false);
-		verifypw.setVisible(true);
-		verifypw.setDisabled(false);
-	    } else {
-		pwfield.setVisible(false);
-		pwfield.setDisabled(true);
-		verifypw.setVisible(false);
-		verifypw.setDisabled(true);
-	    }
-
-	};
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.isCreate ? true : false
-            },
-	    pwfield, verifypw,
-	    {
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		multiSelect: true,
-		allowBlank: true,
-		fieldLabel: gettext('Group')
-	    },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-		emptyText: 'never',
-		format: 'Y-m-d',
-		submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enabled'),
-		name: 'enable',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    }
-        ];
-
-        var column2 = [
-	    {
-		xtype: 'textfield',
-		name: 'firstname',
-		fieldLabel: gettext('First Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'lastname',
-		fieldLabel: gettext('Last Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'email',
-		fieldLabel: gettext('E-Mail'),
-		vtype: 'proxmoxMail'
-	    }
-	];
-
-        if (me.isCreate) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-		matchFieldWidth: false,
-		listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-			update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    fieldLabel: gettext('Comment')
-		}
-	    ],
-	    advancedItems: [
-		{
-		    xtype: 'textfield',
-		    name: 'keys',
-		    fieldLabel: gettext('Key IDs')
-		}
-	    ],
-	    onGetValues: function(values) {
-		// hack: ExtJS datefield does not submit 0, so we need to set that
-		if (!values.expire) {
-		    values.expire = 0;
-		}
-
-		if (realm) {
-		    values.userid = values.userid + '@' + realm;
-		}
-
-		if (!values.password) {
-		    delete values.password;
-		}
-
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 110 // for spanish translation 
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (Ext.isDefined(data.expire)) {
-			if (data.expire) {
-			    data.expire = new Date(data.expire * 1000);
-			} else {
-			    // display 'never' instead of '1970-01-01'
-			    data.expire = null;
-			}
-		    }
-		    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    onlineHelp: 'pveum_users',
-
-    stateful: true,
-    stateId: 'grid-users',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-            id: "users",
-	    model: 'pve-users',
-	    sorters: { 
-		property: 'userid', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/access/users/',
-	    enableFn: function(rec) {
-		if (!caps.access['User.Modify']) {
-		    return false;
-		}
-		return rec.data.userid !== 'root@pam';
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
- 
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec || !caps.access['User.Modify']) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    enableFn: function(rec) {
-		return !!caps.access['User.Modify'];
-	    },
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var pwchange_btn = new Proxmox.button.Button({
-	    text: gettext('Password'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('Proxmox.window.PasswordEdit', {
-                    userid: rec.data.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var win = Ext.create('PVE.window.TFAEdit',{
-                    hasTFA: d.keys != undefined && d.keys.length,
-                    userid: d.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-        var tbar = [
-            {
-		text: gettext('Add'),
-		disabled: !caps.access['User.Modify'],
-		handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-		}
-            },
-	    edit_btn, remove_btn, pwchange_btn, tfachange_btn
-        ];
-
-	var render_username = function(userid) {
-	    return userid.match(/^(.+)(@[^@]+)$/)[1];
-	};
-
-	var render_realm = function(userid) {
-	    return userid.match(/@([^@]+)$/)[1];
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('User name'),
-		    width: 200,
-		    sortable: true,
-		    renderer: render_username,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    renderer: render_realm,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'enable'
-		},
-		{
-		    header: gettext('Expire'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_expire, 
-		    dataIndex: 'expire'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    renderer: PVE.Utils.render_full_name,
-		    dataIndex: 'firstname'
-		},
-		{
-		    header: 'TFA',
-		    width: 50,
-		    sortable: true,
-		    renderer: function(v) {
-			return Proxmox.Utils.format_boolean(v !== undefined && v.length);
-		    },
-		    dataIndex: 'keys'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    onlineHelp: 'pveum_pools',
-
-    stateful: true,
-    stateId: 'grid-pools',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: { 
-		property: 'poolid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/pools/',
-	    callback: function () {
-		reload();
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.PoolEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'poolid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'poolid',
-		    value: me.poolid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    onlineHelp: 'pveum_groups',
-
-    stateful: true,
-    stateId: 'grid-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: { 
-		property: 'groupid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: '/access/groups/'
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.GroupEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'groupid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'groupid',
-		    value: me.groupid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    onlineHelp: 'pveum_roles',
-
-    stateful: true,
-    stateId: 'grid-roles',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: {
-		property: 'roleid',
-		order: 'DESC'
-	    }
-	});
-
-	var render_privs = function(value, metaData) {
-
-	    if (!value) {
-		return '-';
-	    }
-
-	    // allow word wrap
-	    metaData.style = 'white-space:normal;';
-
-	    return value.replace(/\,/g, ' ');
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-		store.load();
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (rec.data.special === "1") {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.RoleEdit',{
-		roleid: rec.data.roleid,
-		privs: rec.data.privs
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Built-In'),
-		    width: 65,
-		    sortable: true,
-		    dataIndex: 'special',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'roleid'
-		},
-		{
-		    itemid: 'privs',
-		    header: gettext('Privileges'),
-		    sortable: false,
-		    renderer: render_privs,
-		    dataIndex: 'privs',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: function() {
-		    store.load();
-		},
-		itemdblclick: run_editor
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.RoleEdit', {});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Edit'),
-		    disabled: true,
-		    selModel: sm,
-		    handler: run_editor,
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		},
-		{
-		    xtype: 'proxmoxStdRemoveButton',
-		    selModel: sm,
-		    callback: function() {
-			reload();
-		    },
-		    baseurl: '/access/roles/',
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.RoleEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveDcRoleEdit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.roleid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = '/api2/extjs/access/roles';
-	    method = 'POST';
-	} else {
-	    url = '/api2/extjs/access/roles/' + me.roleid;
-	    method = 'PUT';
-	}
-
-	Ext.applyIf(me, {
-	    subject: gettext('Role'),
-	    url: url,
-	    method: method,
-	    items: [
-		{
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    name: 'roleid',
-		    value: me.roleid,
-		    allowBlank: false,
-		    fieldLabel: gettext('Name')
-		},
-		{
-		    xtype: 'pvePrivilegesSelector',
-		    name: 'privs',
-		    value: me.privs,
-		    allowBlank: false,
-		    fieldLabel: gettext('Privileges')
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var data = response.result.data;
-		    var keys = Ext.Object.getKeys(data);
-
-		    me.setValues({
-			privs: keys,
-			roleid: me.roleid
-		    });
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveACLAdd'],
-    url: '/access/acl',
-    method: 'PUT',
-    isAdd: true,
-    initComponent : function() {
-
-        var me = this;
-
-	me.isCreate = true;
-
-	var items = [
-	    {
-		xtype: me.path ? 'hiddenfield' : 'pvePermPathSelector',
-		name: 'path',
-		value: me.path,
-		allowBlank: false,
-		fieldLabel: gettext('Path')
-	    }
-	];
-
-	if (me.aclType === 'group') {
-	    me.subject = gettext("Group Permission");
-	    items.push({
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		fieldLabel: gettext('Group')
-	    });
-	} else if (me.aclType === 'user') {
-	    me.subject = gettext("User Permission");
-	    items.push({
-		xtype: 'pveUserSelector',
-		name: 'users',
-		fieldLabel: gettext('User')
-	    });
-	} else {
-	    throw "unknown ACL type";
-	}
-
-	items.push({
-	    xtype: 'pveRoleSelector',
-	    name: 'roles',
-	    value: 'NoAccess',
-	    fieldLabel: gettext('Role')
-	});
-
-	if (!me.path) {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'propagate',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Propagate')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    items: items,
-	    onlineHelp: 'pveum_permission_management'
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    onlineHelp: 'chapter_user_management',
-
-    stateful: true,
-    stateId: 'grid-acls',
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-acl',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/access/acl"
-	    },
-	    sorters: {
-		property: 'path',
-		order: 'DESC'
-	    }
-	});
-
-	if (me.path) {
-	    store.addFilter(Ext.create('Ext.util.Filter',{
-		filterFn: function(item) {
-		    if (item.data.path === me.path) {
-			return true;
-		    }
-		}
-	    }));
-	}
-
-	var render_ugid = function(ugid, metaData, record) {
-	    if (record.data.type == 'group') {
-		return '@' + ugid;
-	    }
-
-	    return ugid;
-	};
-
-	var columns = [
-	    {
-		header: gettext('User') + '/' + gettext('Group'),
-		flex: 1,
-		sortable: true,
-		renderer: render_ugid,
-		dataIndex: 'ugid'
-	    },
-	    {
-		header: gettext('Role'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'roleid'
-	    }
-	];
-
-	if (!me.path) {
-	    columns.unshift({
-		header: gettext('Path'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'path'
-	    });
-	    columns.push({
-		header: gettext('Propagate'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'propagate'
-	    });
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: gettext('Are you sure you want to remove this entry'),
-	    handler: function(btn, event, rec) {
-		var params = {
-		    'delete': 1,
-		    path: rec.data.path,
-		    roles: rec.data.roleid
-		};
-		if (rec.data.type === 'group') {
-		    params.groups = rec.data.ugid;
-		} else if (rec.data.type === 'user') {
-		    params.users = rec.data.ugid;
-		} else {
-		    throw 'unknown data type';
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/access/acl',
-		    params: params,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: {
-			xtype: 'menu',
-			items: [
-			    {
-				text: gettext('Group Permission'),
-				iconCls: 'fa fa-fw fa-group',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'group',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('User Permission'),
-				iconCls: 'fa fa-fw fa-user',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'user',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    }
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'ugid', 'roleid',
-	    {
-		name: 'propagate',
-		type: 'boolean'
-	    }
-	]
-    });
-
-});
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    onlineHelp: 'pveum_authentication_realms',
-
-    stateful: true,
-    stateId: 'grid-authrealms',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    sorters: { 
-		property: 'realm', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-		authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    baseurl: '/access/domains/',
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
-
-        var tbar = [
-	    {
-		text: gettext('Add'),
-		menu: new Ext.menu.Menu({
-		    items: [
-			{
-			    text: gettext('Active Directory Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit', {
-				    authType: 'ad'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			},
-			{
-			    text: gettext('LDAP Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit',{
-				    authType: 'ldap'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			}
-		    ]
-		})
-	    },
-	    edit_btn, remove_btn
-        ];
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-            tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'realm'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('TFA'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'tfa'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-	];
-
-	if (me.authType === 'ad') {
-
-	    me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-	} else if (me.authType === 'ldap') {
-
-	    me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-		emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-	} else if (me.authType === 'pve') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'Proxmox VE authentication server';
-
-	} else if (me.authType === 'pam') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'linux PAM';
-
-	} else {
-	    throw 'unknown auth type ';
-	}
-
-        column1.push({
-            xtype: 'proxmoxcheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-	if (me.authType === 'ldap' || me.authType === 'ad') {
-	    column2.push(
-		{
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-		},
-		{
-                    xtype: 'proxmoxtextfield',
-                    fieldLabel: gettext('Fallback Server'),
-		    deleteEmpty: !me.isCreate,
-		    name: 'server2'
-		},
-		{
-                    xtype: 'proxmoxintegerfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-		    emptyText: gettext('Default'),
-		    submitEmptyText: false
-		},
-		{
-                    xtype: 'proxmoxcheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-		}
-            );
-	}
-
-	// Two Factor Auth settings
-
-        column2.push({
-            xtype: 'proxmoxKVComboBox',
-            name: 'tfa',
-	    deleteEmpty: !me.isCreate,
-	    value: '',
-            fieldLabel: gettext('TFA'),
-	    comboItems: [ ['__default__', Proxmox.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=oath_step]').setVisible(value === 'oath');
-		    me.down('field[name=oath_digits]').setVisible(value === 'oath');
-		    me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-		}
-	    }
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_step',
-	    value: '',
-	    minValue: 10,
-	    emptyText: Proxmox.Utils.defaultText + ' (30)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_digits',
-	    value: '',
-	    minValue: 6,
-	    maxValue: 8,
-	    emptyText: Proxmox.Utils.defaultText + ' (6)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-	    hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-	    hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-	    hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [{
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-            }],
-	    onGetValues: function(values) {
-		if (!values.port) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'port' });
-		    }
-		    delete values.port;
-		}
-
-		if (me.isCreate) {
-		    values.type = me.authType;
-		}
-
-		if (values.tfa === 'oath') {
-		    values.tfa = "type=oath";
-		    if (values.oath_step) {
-			values.tfa += ",step=" + values.oath_step;
-		    }
-		    if (values.oath_digits) {
-			values.tfa += ",digits=" + values.oath_digits;
-		    }
-		} else if (values.tfa === 'yubico') {
-		    values.tfa = "type=yubico";
-		    values.tfa += ",id=" + values.yubico_api_id;
-		    values.tfa += ",key=" + values.yubico_api_key;
-		    if (values.yubico_url) {
-			values.tfa += ",url=" + values.yubico_url;
-		    }
-		} else {
-		    delete values.tfa;
-		}
-
-		delete values.oath_step;
-		delete values.oath_digits;
-		delete values.yubico_api_id;
-		delete values.yubico_api_key;
-		delete values.yubico_url;
-		
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-                success: function(response, options) {
-		    var data = response.result.data || {};
-		    // just to be sure (should not happen)
-		    if (data.type !== me.authType) {
-			me.close();
-			throw "got wrong auth type";
-		    }
-
-		    if (data.tfa) {
-			var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-			data.tfa = tfacfg.type;
-			if (tfacfg.type === 'yubico') {
-			    data.yubico_api_key = tfacfg.key;
-			    data.yubico_api_id = tfacfg.id;
-			    data.yubico_url = tfacfg.url;
-			} else if (tfacfg.type === 'oath') {
-			    // step is a number before
-			    /*jslint confusion: true*/
-			    data.oath_step = tfacfg.step;
-			    data.oath_digits = tfacfg.digits;
-			    /*jslint confusion: false*/
-			}
-		    }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    defaultFocus: undefined,
-
-    initComponent : function() {
-         var me = this;
-
-        me.isCreate = !me.jobid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-	var vmidField = Ext.create('Ext.form.field.Hidden', {
-	    name: 'vmid'
-	});
-
-	/*jslint confusion: true*/
-	// 'value' can be assigned a string or an array
-	var selModeField =  Ext.create('Proxmox.form.KVComboBox', {
-	    xtype: 'proxmoxKVComboBox',
-	    comboItems: [
-		['include', gettext('Include selected VMs')],
-		['all', gettext('All')],
-		['exclude', gettext('Exclude selected VMs')]
-	    ],
-	    fieldLabel: gettext('Selection mode'),
-	    name: 'selMode',
-	    value: ''
-	});
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    var sel = [];
-		    Ext.Array.each(selected, function(record) {
-			sel.push(record.data.vmid);
-		    });
-
-		    // to avoid endless recursion suspend the vmidField change
-		    // event temporary as it calls us again
-		    vmidField.suspendEvent('change');
-		    vmidField.setValue(sel);
-		    vmidField.resumeEvent('change');
-		}
-	    }
-	});
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    fieldLabel: gettext('Storage'),
-	    nodename: 'localhost',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    name: 'storage'
-	});
-
-	var store = new Ext.data.Store({
-	    model: 'PVEResources',
-	    sorters: { 
-		property: 'vmid', 
-		order: 'ASC' 
-	    }
-	});
-
-	var vmgrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    disabled: true,
-	    columns: [
-		{ 
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{ 
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{ 
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{ 
-		    header: gettext('Name'), 
-		    dataIndex: 'name',
-		    flex: 1 
-		},
-		{ 
-		    header: gettext('Type'), 
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-
-	var nodesel = Ext.create('PVE.form.NodeSelector', {
-	    name: 'node',
-	    fieldLabel: gettext('Node'),
-	    allowBlank: true,
-	    editable: true,
-	    autoSelect: false,
-	    emptyText: '-- ' + gettext('All') + ' --',
-	    listeners: {
-		change: function(f, value) {
-		    storagesel.setNodename(value || 'localhost');
-		    var mode = selModeField.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!value || rec.get('node') === value);
-		    });
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    }
-		}
-	    }
-	});
-
-	var column1 = [
-	    nodesel,
-	    storagesel,
-	    {
-		xtype: 'pveDayOfWeekSelector',
-		name: 'dow',
-		fieldLabel: gettext('Day of week'),
-		multiSelect: true,
-		value: ['sat'],
-		allowBlank: false
-	    },
-	    {
-		xtype: 'timefield',
-		fieldLabel: gettext('Start Time'),
-		name: 'starttime',
-		format: 'H:i',
-		formatText: 'HH:MM',
-		value: '00:00',
-		allowBlank: false
-	    },
-	    selModeField
-	];
-
-	var column2 = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Send email to'),
-		name: 'mailto'
-	    },
-	    {
-		xtype: 'pveEmailNotificationSelector',
-		fieldLabel: gettext('Email notification'),
-		name: 'mailnotification',
-		deleteEmpty: me.isCreate ? false : true,
-		value: me.isCreate ? 'always' : ''
-	    },
-	    {
-		xtype: 'pveCompressionSelector',
-		fieldLabel: gettext('Compression'),
-		name: 'compress',
-		deleteEmpty: me.isCreate ? false : true,
-		value: 'lzo'
-	    },
-	    {
-		xtype: 'pveBackupModeSelector',
-		fieldLabel: gettext('Mode'),
-		value: 'snapshot',
-		name: 'mode'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enable'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    },
-	    vmidField
-	];
-	/*jslint confusion: false*/
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    onlineHelp: 'chapter_vzdump',
-	    column1: column1,
-	    column2:  column2,
-	    onGetValues: function(values) {
-		if (!values.node) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'node' }); 
-		    }
-		    delete values.node;
-		}
-
-		var selMode = values.selMode;
-		delete values.selMode;
-
-		if (selMode === 'all') {
-		    values.all = 1;
-		    values.exclude = '';
-		    delete values.vmid;
-		} else if (selMode === 'exclude') {
-		    values.all = 1;
-		    values.exclude = values.vmid;
-		    delete values.vmid;
-		}
-		return values;
-	    }
-	});
-
-	var update_vmid_selection = function(list, mode) {
-	    if (mode !== 'all') {
-		sm.deselectAll(true);
-		if (list) {
-		    Ext.Array.each(list.split(','), function(vmid) {
-			var rec = store.findRecord('vmid', vmid);
-			if (rec) {
-			    sm.select(rec, true);
-			}
-		    });
-		}
-	    }
-	};
-
-	vmidField.on('change', function(f, value) {
-	    var mode = selModeField.getValue();
-	    update_vmid_selection(value, mode);
-	});
-
-	selModeField.on('change', function(f, value, oldValue) {
-	    if (value === 'all') {
-		sm.selectAll(true);
-		vmgrid.setDisabled(true);
-	    } else {
-		vmgrid.setDisabled(false);
-	    }
-	    if (oldValue === 'all') {
-		sm.deselectAll(true);
-		vmidField.setValue('');
-	    }
-	    var list = vmidField.getValue();
-	    update_vmid_selection(list, value);
-	});
-		 
-	var reload = function() {
-	    store.load({
-		params: { type: 'vm' },
-		callback: function() {
-		    var node = nodesel.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!node || node.length === 0 || rec.get('node') === node);
-		    });
-		    var list = vmidField.getValue();
-		    var mode = selModeField.getValue();
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    } else {
-			update_vmid_selection(list, mode);
-		    }
-		}
-	    });
-	};
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-	    items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.isCreate) {
-	    selModeField.setValue('include');
-	} else {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-
-		    data.dow = data.dow.split(',');
-
-		    if (data.all || data.exclude) {
-			if (data.exclude) {
-			    data.vmid = data.exclude;
-			    data.selMode = 'exclude';
-			} else {
-			    data.vmid = '';
-			    data.selMode = 'all';
-			}
-		    } else {
-			data.selMode = 'include';
-		    }
-
-		    me.setValues(data);
-               }
-            });
-        }
-
-	reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-cluster-backup',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/cluster/backup"
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.BackupEdit',{
-                jobid: rec.data.id
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/backup',
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    stateful: true,
-	    stateId: 'grid-dc-backup',
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.BackupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],		
-	    columns: [
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    dataIndex: 'enabled',
-		    xtype: 'checkcolumn',
-		    sortable: true,
-		    disabled: true,
-		    disabledCls: 'x-item-enabled',
-		    stopSelection: false
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node',
-		    renderer: function(value) {
-			if (value) {
-			    return value;
-			}
-			return me.allText;
-		    }
-		},
-		{
-		    header: gettext('Day of week'),
-		    width: 200,
-		    sortable: false,
-		    dataIndex: 'dow',
-		    renderer: function(val) {
-			var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-			var selected = [];
-			var cur = -1;
-			val.split(',').forEach(function(day){
-			    cur++;
-			    var dow = (dows.indexOf(day)+6)%7;
-			    if (cur === dow) {
-				if (selected.length === 0 || selected[selected.length-1] === 0) {
-				    selected.push(1);
-				} else {
-				    selected[selected.length-1]++;
-				}
-			    } else {
-				while (cur < dow) {
-				    cur++;
-				    selected.push(0);
-				}
-				selected.push(1);
-			    }
-			});
-
-			cur = -1;
-			var days = [];
-			selected.forEach(function(item) {
-			    cur++;
-			    if (item > 2) {
-				days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
-				cur += item-1;
-			    } else if (item == 2) {
-				days.push(Ext.Date.dayNames[cur+1]);
-				days.push(Ext.Date.dayNames[(cur+2)%7]);
-				cur++;
-			    } else if (item == 1) {
-				days.push(Ext.Date.dayNames[(cur+1)%7]);
-			    }
-			});
-			return days.join(', ');
-		    }
-		},
-		{
-		    header: gettext('Start Time'),
-		    width: 60,
-		    sortable: true,
-		    dataIndex: 'starttime'
-		},
-		{
-		    header: gettext('Storage'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Selection'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'vmid',
-		    renderer: function(value, metaData, record) {
-			/*jslint confusion: true */
-			if (record.data.all) {
-			    if (record.data.exclude) {
-				return Ext.String.format(me.allExceptText, record.data.exclude);
-			    }
-			    return me.allText;
-			}
-			if (record.data.vmid) {
-			    return record.data.vmid;
-			}
-
-			return "-";
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-	
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'starttime', 'dow',
-	    'storage', 'node', 'vmid', 'exclude',
-	    'mailto',
-	    { name: 'enabled', type: 'boolean' },
-	    { name: 'all', type: 'boolean' },
-	    { name: 'snapshot', type: 'boolean' },
-	    { name: 'stop', type: 'boolean' },
-	    { name: 'suspend', type: 'boolean' },
-	    { name: 'compress', type: 'boolean' }
-	]
-    });
-});
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-    pveGuidePath: '/pve-docs/index.html',
-    onlineHelp: 'getting_help',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: function() {
-	var me = this;
-	var guideUrl = window.location.origin + me.pveGuidePath;
-	var text = Ext.String.format('<h1>Documentation</h1>'
-	+ 'The official Proxmox VE Administration Guide'
-	+ ' is included with this installation and can be browsed at '
-	+ '<a target="_blank" href="{0}">{0}</a>', guideUrl);
-	return text;
-    },
-
-    updateActive: function(data) {
-	var me = this;
-	
-	var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-
-    updateCommunity: function(data) {
-	var me = this;
-
-	var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-	 
-    updateInactive: function(data) {
-	var me = this;
-	me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/localhost/subscription',
-		method: 'GET',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.update('Unable to load subscription status' + ": " + response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-
-		    if (data.status === 'Active') {
-			if (data.level === 'c') {
-			    me.updateCommunity(data);
-			} else {
-			    me.updateActive(data);
-			}
-		    } else {
-			me.updateInactive(data);
-		    }
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('pve-security-groups', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'group', 'comment', 'digest' ],
-    idProperty: 'group'
-});
-
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = (me.group_name === undefined);
-
-	var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-	
-	var items = [	    
-	    {
-		xtype: 'textfield',
-		name: 'group',
-		value: me.group_name || '',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: me.group_comment || '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	if (me.isCreate) {
-	    subject = gettext('Security Group');
-        } else {
-	    subject = gettext('Security Group') + " '" + me.group_name + "'";
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'rename',
-		value: me.group_name
-	    });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	// InputPanel does not have a 'create' property, does it need a 'isCreate'
-	    isCreate: me.isCreate,
-	    items: items 
-	});
-
-
-	Ext.apply(me, {
-            subject: subject,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    stateful: true,
-    stateId: 'grid-securitygroups',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (me.rule_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-security-groups',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json' + me.base_url
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('group', oldrec.data.group);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.SecurityGroupEdit', {
-		digest: rec.data.digest,
-		group_name: rec.data.group,
-		group_comment: rec.data.comment
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('PVE.SecurityGroupEdit', {});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    enableFn: function(rec) {
-		return (rec && me.base_url);
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Group'), dataIndex: 'group', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = '/cluster/firewall/groups/' + rec.data.group;
-		    me.rule_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.rule_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-	var me = this;
-
-	var rule_panel = Ext.createWidget('pveFirewallRules', {
-	    region: 'center',
-	    allow_groups: false,
-	    list_refs_url: '/cluster/firewall/refs',
-	    tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-	    border: false
-	});
-
-	var sglist = Ext.createWidget('pveSecurityGroupList', {
-	    region: 'west',
-	    rule_panel: rule_panel,
-	    width: '25%',
-	    border: false,
-	    split: true
-	});
-
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-	    listeners: {
-		show: function() {
-		    sglist.fireEvent('show', sglist);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    onlineHelp: 'pve_admin_guide',
-
-    initComponent: function() {
-        var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext("Datacenter"),
-	    hstateid: 'dctab'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		title: gettext('Summary'),
-		xtype: 'pveDcSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    },
-	    {
-		title: gettext('Cluster'),
-		xtype: 'pveClusterAdministration',
-		iconCls: 'fa fa-server',
-		itemId: 'cluster'
-	    },
-	    {
-		xtype: 'pveDcOptionView',
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options'
-	    });
-	}
-
-	if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageView',
-		title: gettext('Storage'),
-		iconCls: 'fa fa-database',
-		itemId: 'storage'
-	    });
-	}
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveDcBackupView',
-		iconCls: 'fa fa-floppy-o',
-		title: gettext('Backup'),
-		itemId: 'backup'
-	    },
-	    {
-		xtype: 'pveReplicaView',
-		iconCls: 'fa fa-retweet',
-		title: gettext('Replication'),
-		itemId: 'replication'
-	    },
-	    {
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		expandedOnInit: true
-	    });
-	}
-
-	me.items.push({
-	    xtype: 'pveUserView',
-	    groups: ['permissions'],
-	    iconCls: 'fa fa-user',
-	    title: gettext('Users'),
-	    itemId: 'users'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveGroupView',
-		title: gettext('Groups'),
-		iconCls: 'fa fa-users',
-		groups: ['permissions'],
-		itemId: 'groups'
-	    },
-	    {
-		xtype: 'pvePoolView',
-		title: gettext('Pools'),
-		iconCls: 'fa fa-tags',
-		groups: ['permissions'],
-		itemId: 'pools'
-	    },
-	    {
-		xtype: 'pveRoleView',
-		title: gettext('Roles'),
-		iconCls: 'fa fa-male',
-		groups: ['permissions'],
-		itemId: 'roles'
-	    },
-	    {
-		xtype: 'pveAuthView',
-		title: gettext('Authentication'),
-		groups: ['permissions'],
-		iconCls: 'fa fa-key',
-		itemId: 'domains'
-	    },
-	    {
-		xtype: 'pveHAStatus',
-		title: 'HA',
-		iconCls: 'fa fa-heartbeat',
-		itemId: 'ha'
-	    },
-	    {
-		title: gettext('Groups'),
-		groups: ['ha'],
-		xtype: 'pveHAGroupsView',
-		iconCls: 'fa fa-object-group',
-		itemId: 'ha-groups'
-	    },
-	    {
-		title: gettext('Fencing'),
-		groups: ['ha'],
-		iconCls: 'fa fa-bolt',
-		xtype: 'pveFencingView',
-		itemId: 'ha-fencing'
-	    },
-	    {
-		xtype: 'pveFirewallRules',
-		title: gettext('Firewall'),
-		allow_iface: true,
-		base_url: '/cluster/firewall/rules',
-		list_refs_url: '/cluster/firewall/refs',
-		iconCls: 'fa fa-shield',
-		itemId: 'firewall'
-	    },
-	    {
-		xtype: 'pveFirewallOptions',
-		title: gettext('Options'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-gear',
-		base_url: '/cluster/firewall/options',
-		onlineHelp: 'pve_firewall_cluster_wide_setup',
-		fwtype: 'dc',
-		itemId: 'firewall-options'
-	    },
-	    {
-		xtype: 'pveSecurityGroups',
-		title: gettext('Security Group'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-group',
-		itemId: 'firewall-sg'
-	    },
-	    {
-		xtype: 'pveFirewallAliases',
-		title: gettext('Alias'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-external-link',
-		base_url: '/cluster/firewall/aliases',
-		itemId: 'firewall-aliases'
-	    },
-	    {
-		xtype: 'pveIPSet',
-		title: 'IPSet',
-		groups: ['firewall'],
-		iconCls: 'fa fa-list-ol',
-		base_url: '/cluster/firewall/ipset',
-		list_refs_url: '/cluster/firewall/refs',
-		itemId: 'firewall-ipset'
-	    },
-	    {
-		xtype: 'pveDcSupport',
-		title: gettext('Support'),
-		itemId: 'support',
-		iconCls: 'fa fa-comments-o'
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveDcNodeView',
-
-    title: gettext('Nodes'),
-    disableSelection: true,
-    scrollable: true,
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    dataIndex: 'name'
-	},
-	{
-	    header: 'ID',
-	    width: 40,
-	    sortable: true,
-	    dataIndex: 'nodeid'
-	},
-	{
-	    header: gettext('Online'),
-	    width: 60,
-	    sortable: true,
-	    dataIndex: 'online',
-	    renderer: function(value) {
-		var cls = (value)?'good':'critical';
-		return  '<i class="fa ' + PVE.Utils.get_health_icon(cls) + '"><i/>';
-	    }
-	},
-	{
-	    header: gettext('Support'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'level',
-	    renderer: PVE.Utils.render_support_level
-	},
-	{
-	    header: gettext('Server Address'),
-	    width: 115,
-	    sortable: true,
-	    dataIndex: 'ip'
-	},
-	{
-	    header: gettext('CPU usage'),
-	    sortable: true,
-	    width: 110,
-	    dataIndex: 'cpuusage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Memory usage'),
-	    width: 110,
-	    sortable: true,
-	    tdCls: 'x-progressbar-default-cell',
-	    dataIndex: 'memoryusage',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Uptime'),
-	    sortable: true,
-	    dataIndex: 'uptime',
-	    align: 'right',
-	    renderer: Proxmox.Utils.render_uptime
-	}
-    ],
-
-    stateful: true,
-    stateId: 'grid-cluster-nodes',
-    tools: [
-	{
-	    type: 'up',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = Math.max(me.getHeight()-50, 250);
-		me.setHeight(height);
-	    }
-	},
-	{
-	    type: 'down',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = me.getHeight()+50;
-		me.setHeight(height);
-	    }
-	}
-    ]
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-	extend: 'Ext.data.Model',
-	fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-	idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.widget.ProgressBar',{
-    extend: 'Ext.Progress',
-    alias: 'widget.pveProgressBar',
-
-    animate: true,
-    textTpl: [
-	'{percent}%'
-    ],
-
-    setValue: function(value){
-	var me = this;
-	me.callParent([value]);
-
-	me.removeCls(['warning', 'critical']);
-
-	if (value > 0.89) {
-	    me.addCls('critical');
-	} else if (value > 0.59) {
-	    me.addCls('warning');
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('pve-cluster-nodes', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
-	{ type: 'integer', name: 'quorum_votes' }
-    ],
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/nodes"
-    },
-    idProperty: 'nodeid'
-});
-
-Ext.define('pve-cluster-info', {
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/join"
-    }
-});
-
-Ext.define('PVE.ClusterAdministration', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveClusterAdministration',
-
-    title: gettext('Cluster Administration'),
-    onlineHelp: 'chapter_pvecm',
-
-    border: false,
-    defaults: { border: false },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    totem: {},
-	    nodelist: [],
-	    preferred_node: {
-		name: '',
-		fp: '',
-		addr: ''
-	    },
-	    isInCluster: false,
-	    nodecount: 0
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Cluster Information'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.store = Ext.create('Proxmox.data.UpdateStore', {
-			autoStart: true,
-			interval: 15 * 1000,
-			storeid: 'pve-cluster-info',
-			model: 'pve-cluster-info'
-		    });
-		    view.store.on('load', this.onLoad, this);
-		    view.on('destroy', view.store.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records || !records[0].data) {
-			vm.set('totem', {});
-			vm.set('isInCluster', false);
-			vm.set('nodelist', []);
-			vm.set('preferred_node', {
-			    name: '',
-			    addr: '',
-			    fp: ''
-			});
-			return;
-		    }
-		    var data = records[0].data;
-		    vm.set('totem', data.totem);
-		    vm.set('isInCluster', !!data.totem.cluster_name);
-		    vm.set('nodelist', data.nodelist);
-
-		    var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
-			return el.name === data.preferred_node;
-		    });
-
-		    vm.set('preferred_node', {
-			name: data.preferred_node,
-			addr: nodeinfo.pve_addr,
-			ring_addr: [ nodeinfo.ring0_addr, nodeinfo.ring1_addr ],
-			fp: nodeinfo.pve_fp
-		    });
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterCreateWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onClusterInfo: function() {
-		    var vm = this.getViewModel();
-		    var win = Ext.create('PVE.ClusterInfoWindow', {
-			joinInfo: {
-			    ipAddress: vm.get('preferred_node.addr'),
-			    fingerprint: vm.get('preferred_node.fp'),
-			    ring_addr: vm.get('preferred_node.ring_addr'),
-			    totem: vm.get('totem')
-			}
-		    });
-		    win.show();
-		},
-
-		onJoin: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create Cluster'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Information'),
-		    reference: 'addButton',
-		    handler: 'onClusterInfo',
-		    bind: {
-			disabled: '{!isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Cluster'),
-		    reference: 'joinButton',
-		    handler: 'onJoin',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		}
-	    ],
-	    layout: 'hbox',
-	    bodyPadding: 5,
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Cluster Name'),
-		    bind: {
-			value: '{totem.cluster_name}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Config Version'),
-		    bind: {
-			value: '{totem.config_version}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Number of Nodes'),
-		    labelWidth: 120,
-		    bind: {
-			value: '{nodecount}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    value: gettext('Standalone node - no cluster defined'),
-		    bind: {
-			hidden: '{isInCluster}'
-		    },
-		    flex: 1
-		}
-	    ]
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Cluster Nodes'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-cluster-nodes',
-			model: 'pve-cluster-nodes'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'nodeid',
-			    order: 'DESC'
-			}
-		    }));
-		    Proxmox.Utils.monStoreErrors(view, view.rstore);
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('nodecount', 0);
-			return;
-		    }
-		    vm.set('nodecount', records.length);
-		}
-	    },
-	    columns: [
-		{
-		    header: gettext('Nodename'),
-		    flex: 2,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('ID'),
-		    flex: 1,
-		    dataIndex: 'nodeid'
-		},
-		{
-		    header: gettext('Votes'),
-		    flex: 1,
-		    dataIndex: 'quorum_votes'
-		},
-		{
-		    header: gettext('Ring 0'),
-		    flex: 2,
-		    dataIndex: 'ring0_addr'
-		},
-		{
-		    header: gettext('Ring 1'),
-		    flex: 2,
-		    dataIndex: 'ring1_addr'
-		}
-	    ]
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ClusterCreateWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterCreateWindow',
-
-    title: gettext('Create Cluster'),
-    width: 600,
-
-    method: 'POST',
-    url: '/cluster/config',
-
-    isCreate: true,
-    subject: gettext('Cluster'),
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Cluster Name'),
-	    allowBlank: false,
-	    name: 'clustername'
-	},
-	{
-	    xtype: 'proxmoxtextfield',
-	    fieldLabel: gettext('Ring 0 Address'),
-	    emptyText: gettext("Optional, defaults to IP resolved by node's hostname"),
-	    name: 'ring0_addr',
-	    skipEmptyText: true
-	}
-	// TODO: for advanced options: ring1_addr
-    ]
-});
-
-Ext.define('PVE.ClusterInfoWindow', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveClusterInfoWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 800,
-    modal: true,
-    resizable: false,
-    title: gettext('Cluster Join Information'),
-
-    joinInfo: {
-	ipAddress: undefined,
-	fingerprint: undefined,
-	totem: {}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    border: false,
-	    padding: '10 10 10 10',
-	    html: gettext("Copy the Join Information here and use it on the node you want to add.")
-	},
-	{
-	    xtype: 'container',
-	    layout: 'form',
-	    border: false,
-	    padding: '0 10 10 10',
-	    items: [
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('IP Address'),
-		    cbind: { value: '{joinInfo.ipAddress}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Fingerprint'),
-		    cbind: { value: '{joinInfo.fingerprint}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textarea',
-		    inputId: 'pveSerializedClusterInfo',
-		    fieldLabel: gettext('Join Information'),
-		    grow: true,
-		    cbind: { joinInfo: '{joinInfo}' },
-		    editable: false,
-		    listeners: {
-			afterrender: function(field) {
-			    if (!field.joinInfo) {
-				return;
-			    }
-			    var jsons = Ext.JSON.encode(field.joinInfo);
-			    var base64s = Ext.util.Base64.encode(jsons);
-			    field.setValue(base64s);
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-    dockedItems: [{
-	dock: 'bottom',
-	xtype: 'toolbar',
-	items: [{
-	    xtype: 'button',
-	    handler: function(b) {
-		var el = document.getElementById('pveSerializedClusterInfo');
-		el.select();
-		document.execCommand("copy");
-	    },
-	    text: gettext('Copy Information')
-	}]
-    }]
-});
-
-Ext.define('PVE.ClusterJoinNodeWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterJoinNodeWindow',
-
-    title: gettext('Cluster Join'),
-    width: 800,
-
-    method: 'POST',
-    url: '/cluster/config/join',
-
-    defaultFocus: 'textarea[name=serializedinfo]',
-    isCreate: true,
-    submitText: gettext('Join'),
-    showTaskViewer: true,
-
-    onlineHelp: 'chapter_pvecm',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    info: {
-		fp: '',
-		ip: '',
-		ring0Needed: false,
-		ring1Possible: false,
-		ring1Needed: false
-	    }
-	},
-	formulas: {
-	    ring0EmptyText: function(get) {
-		if (get('info.ring0Needed')) {
-		    return gettext("Cannot use default address safely");
-		} else {
-		    return gettext("Default: IP resolved by node's hostname");
-		}
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#': {
-		close: function() {
-		    delete PVE.Utils.silenceAuthFailures;
-		}
-	    },
-	    'proxmoxcheckbox[name=assistedEntry]': {
-		change: 'onInputTypeChange'
-	    },
-	    'textarea[name=serializedinfo]': {
-		change: 'recomputeSerializedInfo',
-		enable: 'resetField'
-	    },
-	    'proxmoxtextfield[name=ring1_addr]': {
-		enable: 'ring1Needed'
-	    },
-	    'textfield': {
-		disable: 'resetField'
-	    }
-	},
-	resetField: function(field) {
-	    field.reset();
-	},
-	ring1Needed: function(f) {
-	    var vm = this.getViewModel();
-	    f.allowBlank = !vm.get('info.ring1Needed');
-	},
-	onInputTypeChange: function(field, assistedInput) {
-	    var vm = this.getViewModel();
-	    if (!assistedInput) {
-		vm.set('info.ring1Possible', true);
-	    }
-	},
-	recomputeSerializedInfo: function(field, value) {
-	    var vm = this.getViewModel();
-	    var jsons = Ext.util.Base64.decode(value);
-	    var joinInfo = Ext.JSON.decode(jsons, true);
-
-	    var info = {
-		fp: '',
-		ring1Needed: false,
-		ring1Possible: false,
-		ip: ''
-	    };
-
-	    var totem = {};
-	    if (!(joinInfo && joinInfo.totem)) {
-		field.valid = false;
-	    } else {
-		var ring0Needed = false;
-		if (joinInfo.ring_addr !== undefined) {
-		    ring0Needed = joinInfo.ring_addr[0] !== joinInfo.ipAddress;
-		}
-
-		info = {
-		    ip: joinInfo.ipAddress,
-		    fp: joinInfo.fingerprint,
-		    ring0Needed: ring0Needed,
-		    ring1Possible: !!joinInfo.totem['interface']['1'],
-		    ring1Needed: !!joinInfo.totem['interface']['1']
-		};
-		totem = joinInfo.totem;
-		field.valid = true;
-	    }
-
-	    vm.set('info', info);
-	}
-    },
-
-    submit: function() {
-	// joining may produce temporarily auth failures, ignore as long the task runs
-	PVE.Utils.silenceAuthFailures = true;
-	this.callParent();
-    },
-
-    taskDone: function(success) {
-	delete PVE.Utils.silenceAuthFailures;
-	if (success) {
-	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
-	    // ensure user cannot do harm
-	    Ext.getBody().mask(txt, ['pve-static-mask']);
-	    // TaskView may hide above mask, so tell him directly
-	    Ext.Msg.show({
-		title: gettext('Join Task Finished'),
-		icon: Ext.Msg.INFO,
-		msg: txt
-	    });
-	    // reload always (if user wasn't faster), but wait a bit for pveproxy
-	    Ext.defer(function() {
-		window.location.reload(true);
-	    }, 5000);
-	}
-    },
-
-    items: [{
-	xtype: 'proxmoxcheckbox',
-	reference: 'assistedEntry',
-	name: 'assistedEntry',
-	submitValue: false,
-	value: true,
-	autoEl: {
-	    tag: 'div',
-	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
-	},
-	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
-    },
-    {
-	xtype: 'textarea',
-	name: 'serializedinfo',
-	submitValue: false,
-	allowBlank: false,
-	fieldLabel: gettext('Information'),
-	emptyText: gettext('Paste encoded Cluster Information here'),
-	validator: function(val) {
-	    return val === '' || this.valid ||
-	       gettext('Does not seem like a valid encoded Cluster Information!');
-	},
-	bind: {
-	    disabled: '{!assistedEntry.checked}',
-	    hidden: '{!assistedEntry.checked}'
-	},
-	value: ''
-    },
-    {
-	xtype: 'inputpanel',
-	column1: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Peer Address'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.ip}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'hostname'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		emptyText: gettext("Peer's root password"),
-		fieldLabel: gettext('Password'),
-		allowBlank: false,
-		name: 'password'
-	    }
-	],
-	column2: [
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('Corosync Ring 0'),
-		bind: {
-		    emptyText: '{ring0EmptyText}',
-		    allowBlank: '{!info.ring0Needed}'
-		},
-		skipEmptyText: true,
-		name: 'ring0_addr'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('Corosync Ring 1'),
-		skipEmptyText: true,
-		bind: {
-		    disabled: '{!info.ring1Possible}'
-		},
-		name: 'ring1_addr'
-	    }
-	],
-	columnB: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Fingerprint'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.fp}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'fingerprint'
-	    }
-	]
-    }]
-});
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-	var me = this;
-	me.loginData = loginData;
-	Proxmox.Utils.setAuthData(loginData);
-
-	var rt = me.down('pveResourceTree');
-	rt.setDatacenterText(loginData.clustername);
-
-	if (loginData.cap) {
-	    Ext.state.Manager.set('GuiCap', loginData.cap);
-	}
-
-	me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-	var me = this;
-
-	Proxmox.Utils.authClear();
-	Proxmox.UserName = null;
-	me.loginData = null;
-
-	if (!me.login) {
-	    me.login = Ext.create('PVE.window.LoginWindow', {
-		handler: function(data) {
-		    me.login = null;
-		    me.updateLoginData(data);
-		    Proxmox.Utils.checked_command(function() {}); // display subscription status
-		}
-	    });
-	}
-	me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.tip.QuickTipManager.init();
-
-	// fixme: what about other errors
-	Ext.Ajax.on('requestexception', function(conn, response, options) {
-	    if (response.status == 401 && !PVE.Utils.silenceAuthFailures) { // auth failure
-		me.showLogin();
-	    }
-	});
-
-	me.callParent();
-
-        if (!Proxmox.Utils.authOK()) {
-	    me.showLogin();
-	} else { 
-	    if (me.loginData) {
-		me.onLogin(me.loginData);
-	    }
-	}
-
-	Ext.TaskManager.start({
-	    run: function() {
-		var ticket = Proxmox.Utils.authOK();
-		if (!ticket || !Proxmox.UserName) {
-		    return;
-		}
-
-		Ext.Ajax.request({
-		    params: { 
-			username: Proxmox.UserName,
-			password: ticket
-		    },
-		    url: '/api2/json/access/ticket',
-		    method: 'POST',
-		    success: function(response, opts) {
-			var obj = Ext.decode(response.responseText);
-			me.updateLoginData(obj.data);
-		    }
-		});
-	    },
-	    interval: 15*60*1000
-	});
-
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-	var me = this;
-	
-	var cont = me.child('#content');
-
-	var lay = cont.getLayout();
-
-	var cur = lay.getActiveItem();
-
-	if (comp) {
-	    Proxmox.Utils.setErrorMask(cont, false);
-	    comp.border = false;
-	    cont.add(comp);
-	    if (cur !== null && lay.getNext()) {
-		lay.next();
-		var task = Ext.create('Ext.util.DelayedTask', function(){
-		    cont.remove(cur);
-		});
-		task.delay(10);
-	    }
-	}
-	else {
-	    // helper for cleaning the content when logging out
-	    cont.removeAll();
-	}
-    },
-
-    selectById: function(nodeid) {
-	var me = this;
-	var tree = me.down('pveResourceTree');
-	tree.selectById(nodeid);
-    },
-
-    onLogin: function(loginData) {
-	var me = this;
-
-	me.updateUserInfo();
-
-	if (loginData) {
-	    PVE.data.ResourceStore.startUpdate();
-
-	    Proxmox.Utils.API2Request({
-		url: '/version',
-		method: 'GET',
-		success: function(response) {
-		    PVE.VersionInfo = response.result.data;
-		    me.updateVersionInfo();
-		}
-	    });
-	}
-    },
-
-    updateUserInfo: function() {
-	var me = this;
-
-	var ui = me.query('#userinfo')[0];
-
-	if (Proxmox.UserName) {
-	    var msg =  Ext.String.format(gettext("You are logged in as {0}"), "'" + Proxmox.UserName + "'");
-	    ui.update('<div class="x-unselectable" style="white-space:nowrap;">' + msg + '</div>');
-	} else {
-	    ui.update('');
-	}
-	ui.updateLayout();
-    },
-
-    updateVersionInfo: function() {
-	var me = this;
-
-	var ui = me.query('#versioninfo')[0];
-
-	if (PVE.VersionInfo) {
-	    var version = PVE.VersionInfo.version + '-' + PVE.VersionInfo.release;
-	    ui.update('Virtual Environment ' + version);
-	} else {
-	    ui.update('Virtual Environment');
-	}
-	ui.updateLayout();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.History.init();
-
-	var sprovider = Ext.create('PVE.StateProvider');
-	Ext.state.Manager.setProvider(sprovider);
-
-	var selview = Ext.create('PVE.form.ViewSelector');
-
-	var rtree = Ext.createWidget('pveResourceTree', {
-	    viewFilter: selview.getViewFilter(),
-	    flex: 1,
-	    selModel: {
-		selType: 'treemodel',
-		listeners: {
-		    selectionchange: function(sm, selected) {
-			if (selected.length > 0) {
-			    var n = selected[0];
-			    var tlckup = {
-				root: 'PVE.dc.Config',
-				node: 'PVE.node.Config',
-				qemu: 'PVE.qemu.Config',
-				lxc: 'PVE.lxc.Config',
-				storage: 'PVE.storage.Browser',
-				pool: 'pvePoolConfig'
-			    };
-			    var comp = {
-				xtype: tlckup[n.data.type || 'root'] || 
-				    'pvePanelConfig',
-				showSearch: (n.data.id === 'root') ||
-				    Ext.isDefined(n.data.groupbyid),
-				pveSelNode: n,
-				workspace: me,
-				viewFilter: selview.getViewFilter()
-			    };
-			    PVE.curSelectedNode = n;
-			    me.setContent(comp);
-			}
-		    }
-		}
-	    }
-	});
-
-	selview.on('select', function(combo, records) { 
-	    if (records) {
-		var view = combo.getViewFilter();
-		rtree.setViewFilter(view);
-	    }
-	});
-
-	var caps = sprovider.get('GuiCap');
-
-	var createVM = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-desktop',
-	    text: gettext("Create VM"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	var createCT = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-cube',
-	    text: gettext("Create CT"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	sprovider.on('statechange', function(sp, key, value) {
-	    if (key === 'GuiCap' && value) {
-		caps = value;
-		createVM.setDisabled(!caps.vms['VM.Allocate']);
-		createCT.setDisabled(!caps.vms['VM.Allocate']);
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		{
-		    region: 'north',
-		    layout: { 
-			type: 'hbox',
-			align: 'middle'
-		    },
-		    baseCls: 'x-plain',		
-		    defaults: {
-			baseCls: 'x-plain'			
-		    },
-		    border: false,
-		    margin: '2 0 2 5',
-		    items: [
-			{
-			    html: '<a class="x-unselectable" target=_blank href="http://www.proxmox.com">' +
-				'<img style="padding-top:4px;padding-right:5px" src="/pve2/images/proxmox_logo.png"/></a>'
-			},
-			{
-			    minWidth: 150,
-			    id: 'versioninfo',
-			    html: 'Virtual Environment'
-			},
-			{
-			    xtype: 'pveGlobalSearchField',
-			    tree: rtree
-			},
-			{
-			    flex: 1
-			},
-			{
-			    pack: 'end',
-			    id: 'userinfo',
-			    stateful: false
-			},
-			{
-			    xtype: 'button',
-			    margin: '0 10 0 3',
-			    iconCls: 'fa black fa-gear',
-			    userCls: 'pointer',
-			    handler: function() {
-				var win = Ext.create('PVE.window.Settings');
-				win.show();
-			    }
-			},
-			{
-			    xtype: 'proxmoxHelpButton',
-			    hidden: false,
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
-			    listenToGlobalEvent: false,
-			    onlineHelp: 'pve_documentation_index',
-			    text: gettext('Documentation'),
-			    margin: '0 5 0 0'
-			},
-			createVM, 
-			createCT,
-			{
-			    pack: 'end',
-			    margin: '0 5 0 0',
-			    xtype: 'button',
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-sign-out',
-			    text: gettext("Logout"),
-			    handler: function() { 
-				PVE.data.ResourceStore.loadData([], false);
-				me.showLogin(); 
-				me.setContent(null);
-				var rt = me.down('pveResourceTree');
-				rt.setDatacenterText(undefined);
-				rt.clearTree();
-
-				// empty the stores of the StatusPanel child items
-				var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
-				Ext.Array.forEach(statusPanels, function(comp) {
-				    if (comp.getStore()) {
-					comp.getStore().loadData([], false);
-				    }
-				});
-			    }
-			}
-		    ]
-		},
-		{
-		    region: 'center',
-		    stateful: true,
-		    stateId: 'pvecenter',
-		    minWidth: 100,
-		    minHeight: 100,
-		    id: 'content',
-		    xtype: 'container',
-		    layout: { type: 'card' },
-		    border: false,
-		    margin: '0 5 0 0',
-		    items: []
-		},
-		{
-		    region: 'west',
-		    stateful: true,
-		    stateId: 'pvewest',
-		    itemId: 'west',
-		    xtype: 'container',
-		    border: false,
-		    layout: { type: 'vbox', align: 'stretch' },
-		    margin: '0 0 0 5',
-		    split: true,
-		    width: 200,
-		    items: [ selview, rtree ],
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewWidth = me.getSize().width;
-			    if (width > viewWidth - 100) {
-				panel.setWidth(viewWidth - 100);
-			    }
-			}
-		    }
-		},
-		{
-		    xtype: 'pveStatusPanel',
-		    stateful: true,
-		    stateId: 'pvesouth',
-		    itemId: 'south',
-		    region: 'south',
-		    margin:'0 5 5 5',
-		    title: gettext('Logs'),
-		    collapsible: true,
-		    header: false,
-		    height: 200,
-		    split:true,
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewHeight = me.getSize().height;
-			    if (height > (viewHeight - 150)) {
-				panel.setHeight(viewHeight - 150);
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.updateUserInfo();
-
-	// on resize, center all modal windows
-	Ext.on('resize', function(){
-	    var wins = Ext.ComponentQuery.query('window[modal]');
-	    if (wins.length > 0) {
-		wins.forEach(function(win){
-		    win.alignTo(me, 'c-c');
-		});
-	    }
-	});
-    }
-});
-
diff --git a/serverside/jsmod/5.4-3/pvemanagerlib.js.original b/serverside/jsmod/5.4-3/pvemanagerlib.js.original
deleted file mode 100644
index 6e17ec54387d139e8d2d2e8194f0d57b8d074f55..0000000000000000000000000000000000000000
--- a/serverside/jsmod/5.4-3/pvemanagerlib.js.original
+++ /dev/null
@@ -1,38347 +0,0 @@
-var pveOnlineHelpInfo = {
-   "ceph_rados_block_devices" : {
-      "link" : "/pve-docs/chapter-pvesm.html#ceph_rados_block_devices",
-      "title" : "Ceph RADOS Block Devices (RBD)"
-   },
-   "chapter_ha_manager" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#chapter_ha_manager",
-      "title" : "High Availability"
-   },
-   "chapter_lvm" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_lvm",
-      "title" : "Logical Volume Manager (LVM)"
-   },
-   "chapter_pct" : {
-      "link" : "/pve-docs/chapter-pct.html#chapter_pct",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "chapter_pve_firewall" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#chapter_pve_firewall",
-      "title" : "Proxmox VE Firewall"
-   },
-   "chapter_pveceph" : {
-      "link" : "/pve-docs/chapter-pveceph.html#chapter_pveceph",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "chapter_pvecm" : {
-      "link" : "/pve-docs/chapter-pvecm.html#chapter_pvecm",
-      "title" : "Cluster Manager"
-   },
-   "chapter_pvesr" : {
-      "link" : "/pve-docs/chapter-pvesr.html#chapter_pvesr",
-      "title" : "Storage Replication"
-   },
-   "chapter_storage" : {
-      "link" : "/pve-docs/chapter-pvesm.html#chapter_storage",
-      "title" : "Proxmox VE Storage"
-   },
-   "chapter_system_administration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_system_administration",
-      "title" : "Host System Administration"
-   },
-   "chapter_user_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#chapter_user_management",
-      "title" : "User Management"
-   },
-   "chapter_virtual_machines" : {
-      "link" : "/pve-docs/chapter-qm.html#chapter_virtual_machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "chapter_vzdump" : {
-      "link" : "/pve-docs/chapter-vzdump.html#chapter_vzdump",
-      "title" : "Backup and Restore"
-   },
-   "chapter_zfs" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_zfs",
-      "title" : "ZFS on Linux"
-   },
-   "datacenter_configuration_file" : {
-      "link" : "/pve-docs/pve-admin-guide.html#datacenter_configuration_file",
-      "title" : "Datacenter Configuration"
-   },
-   "getting_help" : {
-      "link" : "/pve-docs/pve-admin-guide.html#getting_help",
-      "title" : "Getting Help"
-   },
-   "gui_my_settings" : {
-      "link" : "/pve-docs/chapter-pve-gui.html#gui_my_settings",
-      "subtitle" : "My Settings",
-      "title" : "Graphical User Interface"
-   },
-   "ha_manager_fencing" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_fencing",
-      "subtitle" : "Fencing",
-      "title" : "High Availability"
-   },
-   "ha_manager_groups" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_groups",
-      "subtitle" : "Groups",
-      "title" : "High Availability"
-   },
-   "ha_manager_resource_config" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resource_config",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_resources" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resources",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "pct_configuration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_configuration",
-      "subtitle" : "Configuration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_images" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_images",
-      "subtitle" : "Container Images",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_network" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_network",
-      "subtitle" : "Network",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_storage" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_storage",
-      "subtitle" : "Container Storage",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_cpu" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_cpu",
-      "subtitle" : "CPU",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_general" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_general",
-      "subtitle" : "General Settings",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_memory" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_memory",
-      "subtitle" : "Memory",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_migration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_migration",
-      "subtitle" : "Migration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_options" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_options",
-      "subtitle" : "Options",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_snapshots" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_snapshots",
-      "subtitle" : "Snapshots",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Containers",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pve_admin_guide" : {
-      "link" : "/pve-docs/pve-admin-guide.html",
-      "title" : "Proxmox VE Administration Guide"
-   },
-   "pve_ceph_install" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_install",
-      "subtitle" : "Installation of Ceph Packages",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_monitors" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_monitors",
-      "subtitle" : "Creating Ceph Monitors",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_osds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_osds",
-      "subtitle" : "Creating Ceph OSDs",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_pools" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_pools",
-      "subtitle" : "Creating Ceph Pools",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_documentation_index" : {
-      "link" : "/pve-docs/index.html",
-      "title" : "Proxmox VE Documentation Index"
-   },
-   "pve_firewall_cluster_wide_setup" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_cluster_wide_setup",
-      "subtitle" : "Cluster Wide Setup",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_host_specific_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_host_specific_configuration",
-      "subtitle" : "Host Specific Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_aliases" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_aliases",
-      "subtitle" : "IP Aliases",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_sets" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_sets",
-      "subtitle" : "IP Sets",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_vm_container_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_vm_container_configuration",
-      "subtitle" : "VM/Container Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_service_daemons" : {
-      "link" : "/pve-docs/index.html#_service_daemons",
-      "title" : "Service Daemons"
-   },
-   "pveceph_fs" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs",
-      "subtitle" : "CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_create" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_create",
-      "subtitle" : "Create a CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_mds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_mds",
-      "subtitle" : "Metadata Server (MDS)",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pvesr_schedule_time_format" : {
-      "link" : "/pve-docs/chapter-pvesr.html#pvesr_schedule_time_format",
-      "subtitle" : "Schedule Format",
-      "title" : "Storage Replication"
-   },
-   "pveum_authentication_realms" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_authentication_realms",
-      "subtitle" : "Authentication Realms",
-      "title" : "User Management"
-   },
-   "pveum_groups" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_groups",
-      "subtitle" : "Groups",
-      "title" : "User Management"
-   },
-   "pveum_permission_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_permission_management",
-      "subtitle" : "Permission Management",
-      "title" : "User Management"
-   },
-   "pveum_pools" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_pools",
-      "subtitle" : "Pools",
-      "title" : "User Management"
-   },
-   "pveum_roles" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_roles",
-      "subtitle" : "Roles",
-      "title" : "User Management"
-   },
-   "pveum_tfa_auth" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_tfa_auth",
-      "subtitle" : "Two factor authentication",
-      "title" : "User Management"
-   },
-   "pveum_users" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_users",
-      "subtitle" : "Users",
-      "title" : "User Management"
-   },
-   "qm_bios_and_uefi" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_bios_and_uefi",
-      "subtitle" : "BIOS and UEFI",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cloud_init" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cloud_init",
-      "title" : "Cloud-Init Support"
-   },
-   "qm_copy_and_clone" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_copy_and_clone",
-      "subtitle" : "Copies and Clones",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cpu" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cpu",
-      "subtitle" : "CPU",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_general_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_general_settings",
-      "subtitle" : "General Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_hard_disk" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_hard_disk",
-      "subtitle" : "Hard Disk",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_memory" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_memory",
-      "subtitle" : "Memory",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_migration" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_migration",
-      "subtitle" : "Migration",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_network_device" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_network_device",
-      "subtitle" : "Network Device",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_options" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_options",
-      "subtitle" : "Options",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_os_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_os_settings",
-      "subtitle" : "OS Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_pci_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_pci_passthrough",
-      "title" : "PCI(e) Passthrough"
-   },
-   "qm_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Virtual Machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_system_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_system_settings",
-      "subtitle" : "System Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_usb_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_usb_passthrough",
-      "subtitle" : "USB Passthrough",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_virtual_machines_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_virtual_machines_settings",
-      "subtitle" : "Virtual Machines Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "storage_cephfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cephfs",
-      "title" : "Ceph Filesystem (CephFS)"
-   },
-   "storage_cifs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cifs",
-      "title" : "CIFS Backend"
-   },
-   "storage_directory" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_directory",
-      "title" : "Directory Backend"
-   },
-   "storage_glusterfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_glusterfs",
-      "title" : "GlusterFS Backend"
-   },
-   "storage_lvm" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvm",
-      "title" : "LVM Backend"
-   },
-   "storage_lvmthin" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvmthin",
-      "title" : "LVM thin Backend"
-   },
-   "storage_nfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_nfs",
-      "title" : "NFS Backend"
-   },
-   "storage_open_iscsi" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_open_iscsi",
-      "title" : "Open-iSCSI initiator"
-   },
-   "storage_zfspool" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_zfspool",
-      "title" : "Local ZFS Pool Backend"
-   },
-   "sysadmin_certificate_management" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_certificate_management",
-      "title" : "Certificate Management"
-   },
-   "sysadmin_network_configuration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_network_configuration",
-      "title" : "Network Configuration"
-   }
-};
-Ext.ns('PVE');
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	log: function() {}
-    };
-}
-console.log("Starting PVE Manager");
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-/*jslint confusion: true */
-Ext.define('PVE.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js
-
-    bus_match: /^(ide|sata|virtio|scsi)\d+$/,
-
-    log_severity_hash: {
-	0: "panic",
-	1: "alert",
-	2: "critical",
-	3: "error",
-	4: "warning",
-	5: "notice",
-	6: "info",
-	7: "debug"
-    },
-
-    support_level_hash: {
-	'c': gettext('Community'),
-	'b': gettext('Basic'),
-	's': gettext('Standard'),
-	'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="http://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-	'Linux': [
-	    { desc: '4.X/3.X/2.6 Kernel', val: 'l26' },
-	    { desc: '2.4 Kernel', val: 'l24' }
-	],
-	'Microsoft Windows': [
-	    { desc: '10/2016', val: 'win10' },
-	    { desc: '8.x/2012/2012r2', val: 'win8' },
-	    { desc: '7/2008r2', val: 'win7' },
-	    { desc: 'Vista/2008', val: 'w2k8' },
-	    { desc: 'XP/2003', val: 'wxp' },
-	    { desc: '2000', val: 'w2k' }
-	],
-	'Solaris Kernel': [
-	    { desc: '-', val: 'solaris'}
-	],
-	'Other': [
-	    { desc: '-', val: 'other'}
-	]
-    },
-
-    get_health_icon: function(state, circle) {
-	if (circle === undefined) {
-	    circle = false;
-	}
-
-	if (state === undefined) {
-	    state = 'uknown';
-	}
-
-	var icon = 'faded fa-question';
-	switch(state) {
-	    case 'good':
-		icon = 'good fa-check';
-		break;
-	    case 'warning':
-		icon = 'warning fa-exclamation';
-		break;
-	    case 'critical':
-		icon = 'critical fa-times';
-		break;
-	    default: break;
-	}
-
-	if (circle) {
-	    icon += '-circle';
-	}
-
-	return icon;
-    },
-
-    map_ceph_health: {
-	'HEALTH_OK':'good',
-	'HEALTH_WARN':'warning',
-	'HEALTH_ERR':'critical'
-    },
-
-    render_ceph_health: function(healthObj) {
-	var state = {
-	    iconCls: PVE.Utils.get_health_icon(),
-	    text: ''
-	};
-
-	if (!healthObj || !healthObj.status) {
-	    return state;
-	}
-
-	var health = PVE.Utils.map_ceph_health[healthObj.status];
-
-	state.iconCls = PVE.Utils.get_health_icon(health, true);
-	state.text = healthObj.status;
-
-	return state;
-    },
-
-    render_zfs_health: function(value) {
-	if (typeof value == 'undefined'){
-	    return "";
-	}
-	var iconCls = 'question-circle';
-	switch (value) {
-	    case 'AVAIL':
-	    case 'ONLINE':
-		iconCls = 'check-circle good';
-		break;
-	    case 'REMOVED':
-	    case 'DEGRADED':
-		iconCls = 'exclamation-circle warning';
-		break;
-	    case 'UNAVAIL':
-	    case 'FAULTED':
-	    case 'OFFLINE':
-		iconCls = 'times-circle critical';
-		break;
-	    default: //unknown
-	}
-
-	return '<i class="fa fa-' + iconCls + '"></i> ' + value;
-
-    },
-
-    get_kvm_osinfo: function(value) {
-	var info = { base: 'Other' }; // default
-	if (value) {
-	    Ext.each(Object.keys(PVE.Utils.kvm_ostypes), function(k) {
-		Ext.each(PVE.Utils.kvm_ostypes[k], function(e) {
-		    if (e.val === value) {
-			info = { desc: e.desc, base: k };
-		    }
-		});
-	    });
-	}
-	return info;
-    },
-
-    render_kvm_ostype: function (value) {
-	var osinfo = PVE.Utils.get_kvm_osinfo(value);
-	if (osinfo.desc && osinfo.desc !== '-') {
-	    return osinfo.base + ' ' + osinfo.desc;
-	} else {
-	    return osinfo.base;
-	}
-    },
-
-    render_hotplug_features: function (value) {
-	var fa = [];
-
-	if (!value || (value === '0')) {
-	    return gettext('Disabled');
-	}
-
-	if (value === '1') {
-	    value = 'disk,network,usb';
-	}
-
-	Ext.each(value.split(','), function(el) {
-	    if (el === 'disk') {
-		fa.push(gettext('Disk'));
-	    } else if (el === 'network') {
-		fa.push(gettext('Network'));
-	    } else if (el === 'usb') {
-		fa.push('USB');
-	    } else if (el === 'memory') {
-		fa.push(gettext('Memory'));
-	    } else if (el === 'cpu') {
-		fa.push(gettext('CPU'));
-	    } else {
-		fa.push(el);
-	    }
-	});
-
-	return fa.join(', ');
-    },
-
-    render_qga_features: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText  + ')';
-	}
-	var props = PVE.Parser.parsePropertyString(value, 'enabled');
-	if (!PVE.Parser.parseBoolean(props.enabled)) {
-	    return Proxmox.Utils.disabledText;
-	}
-
-	delete props.enabled;
-	var agentstring = Proxmox.Utils.enabledText;
-
-	Ext.Object.each(props, function(key, value) {
-	    var keystring = '' ;
-	    agentstring += ', ' + key + ': ';
-
-	    if (PVE.Parser.parseBoolean(value)) {
-		agentstring += Proxmox.Utils.enabledText;
-	    } else {
-		agentstring += Proxmox.Utils.disabledText;
-	    }
-	});
-
-	return agentstring;
-    },
-
-    render_qemu_machine: function(value) {
-	return value || (Proxmox.Utils.defaultText + ' (i440fx)');
-    },
-
-    render_qemu_bios: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (SeaBIOS)';
-	} else if (value === 'seabios') {
-	    return "SeaBIOS";
-	} else if (value === 'ovmf') {
-	    return "OVMF (UEFI)";
-	} else {
-	    return value;
-	}
-    },
-
-    render_dc_ha_opts: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	} else {
-	    return PVE.Parser.printPropertyString(value);
-	}
-    },
-    render_as_property_string: function(value) {
-	return (!value) ? Proxmox.Utils.defaultText
-	    : PVE.Parser.printPropertyString(value);
-    },
-
-    render_scsihw: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (LSI 53C895A)';
-	} else if (value === 'lsi') {
-	    return 'LSI 53C895A';
-	} else if (value === 'lsi53c810') {
-	    return 'LSI 53C810';
-	} else if (value === 'megasas') {
-	    return 'MegaRAID SAS 8708EM2';
-	} else if (value === 'virtio-scsi-pci') {
-	    return 'VirtIO SCSI';
-	} else if (value === 'virtio-scsi-single') {
-	    return 'VirtIO SCSI single';
-	} else if (value === 'pvscsi') {
-	    return 'VMware PVSCSI';
-	} else {
-	    return value;
-	}
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-	//ar: 'Arabic',
-	da: 'Danish',
-	de: 'German',
-	'de-ch': 'German (Swiss)',
-	'en-gb': 'English (UK)',
-	'en-us': 'English (USA)',
-	es: 'Spanish',
-	//et: 'Estonia',
-	fi: 'Finnish',
-	//fo: 'Faroe Islands',
-	fr: 'French',
-	'fr-be': 'French (Belgium)',
-	'fr-ca': 'French (Canada)',
-	'fr-ch': 'French (Swiss)',
-	//hr: 'Croatia',
-	hu: 'Hungarian',
-	is: 'Icelandic',
-	it: 'Italian',
-	ja: 'Japanese',
-	lt: 'Lithuanian',
-	//lv: 'Latvian',
-	mk: 'Macedonian',
-	nl: 'Dutch',
-	//'nl-be': 'Dutch (Belgium)',
-	no: 'Norwegian',
-	pl: 'Polish',
-	pt: 'Portuguese',
-	'pt-br': 'Portuguese (Brazil)',
-	//ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	//th: 'Thai',
-	tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-	std: gettext('Standard VGA'),
-	vmware: gettext('VMware compatible'),
-	qxl: 'SPICE',
-	qxl2: 'SPICE dual monitor',
-	qxl3: 'SPICE three monitors',
-	qxl4: 'SPICE four monitors',
-	serial0: gettext('Serial terminal') + ' 0',
-	serial1: gettext('Serial terminal') + ' 1',
-	serial2: gettext('Serial terminal') + ' 2',
-	serial3: gettext('Serial terminal') + ' 3',
-	virtio: 'VirtIO-GPU',
-	none: Proxmox.Utils.noneText
-    },
-
-    render_kvm_language: function (value) {
-	if (!value || value === '__default__') {
-	    return Proxmox.Utils.defaultText;
-	}
-	var text = PVE.Utils.kvm_keymaps[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_keymap_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_language('')]];
-	Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_language(value)]);
-	});
-
-	return data;
-    },
-
-    console_map: {
-	'__default__': Proxmox.Utils.defaultText + ' (HTML5)',
-	'vv': 'SPICE (remote-viewer)',
-	'html5': 'HTML5 (noVNC)',
-	'xtermjs': 'xterm.js'
-    },
-
-    render_console_viewer: function(value) {
-	value = value || '__default__';
-	if (PVE.Utils.console_map[value]) {
-	    return PVE.Utils.console_map[value];
-	}
-	return value;
-    },
-
-    console_viewer_array: function() {
-	return Ext.Array.map(Object.keys(PVE.Utils.console_map), function(v) {
-	    return [v, PVE.Utils.render_console_viewer(v)];
-	});
-    },
-
-    render_kvm_vga_driver: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	}
-	var vga = PVE.Parser.parsePropertyString(value, 'type');
-	var text = PVE.Utils.kvm_vga_drivers[vga.type];
-	if (!vga.type) {
-	    text = Proxmox.Utils.defaultText;
-	}
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_vga_driver_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_vga_driver('')]];
-	Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-	});
-
-	return data;
-    },
-
-    render_kvm_startup: function(value) {
-	var startup = PVE.Parser.parseStartup(value);
-
-	var res = 'order=';
-	if (startup.order === undefined) {
-	    res += 'any';
-	} else {
-	    res += startup.order;
-	}
-	if (startup.up !== undefined) {
-	    res += ',up=' + startup.up;
-	}
-	if (startup.down !== undefined) {
-	    res += ',down=' + startup.down;
-	}
-
-	return res;
-    },
-
-    extractFormActionError: function(action) {
-	var msg;
-	switch (action.failureType) {
-	case Ext.form.action.Action.CLIENT_INVALID:
-	    msg = gettext('Form fields may not be submitted with invalid values');
-	    break;
-	case Ext.form.action.Action.CONNECT_FAILURE:
-	    msg = gettext('Connection error');
-	    var resp = action.response;
-	    if (resp.status && resp.statusText) {
-		msg += " " + resp.status + ": " + resp.statusText;
-	    }
-	    break;
-	case Ext.form.action.Action.LOAD_FAILURE:
-	case Ext.form.action.Action.SERVER_INVALID:
-	    msg = Proxmox.Utils.extractRequestError(action.result, true);
-	    break;
-	}
-	return msg;
-    },
-
-    format_duration_short: function(ut) {
-
-	if (ut < 60) {
-	    return ut.toFixed(1) + 's';
-	}
-
-	if (ut < 3600) {
-	    var mins = ut / 60;
-	    return mins.toFixed(1) + 'm';
-	}
-
-	if (ut < 86400) {
-	    var hours = ut / 3600;
-	    return hours.toFixed(1) + 'h';
-	}
-
-	var days = ut / 86400;
-	return days.toFixed(1) + 'd';
-    },
-
-    contentTypes: {
-	'images': gettext('Disk image'),
-	'backup': gettext('VZDump backup file'),
-	'vztmpl': gettext('Container template'),
-	'iso': gettext('ISO image'),
-	'rootdir': gettext('Container'),
-	'snippets': gettext('Snippets')
-    },
-
-    storageSchema: {
-	dir: {
-	    name: Proxmox.Utils.directoryText,
-	    ipanel: 'DirInputPanel',
-	    faIcon: 'folder'
-	},
-	lvm: {
-	    name: 'LVM',
-	    ipanel: 'LVMInputPanel',
-	    faIcon: 'folder'
-	},
-	lvmthin: {
-	    name: 'LVM-Thin',
-	    ipanel: 'LvmThinInputPanel',
-	    faIcon: 'folder'
-	},
-	nfs: {
-	    name: 'NFS',
-	    ipanel: 'NFSInputPanel',
-	    faIcon: 'building'
-	},
-	cifs: {
-	    name: 'CIFS',
-	    ipanel: 'CIFSInputPanel',
-	    faIcon: 'building'
-	},
-	glusterfs: {
-	    name: 'GlusterFS',
-	    ipanel: 'GlusterFsInputPanel',
-	    faIcon: 'building'
-	},
-	iscsi: {
-	    name: 'iSCSI',
-	    ipanel: 'IScsiInputPanel',
-	    faIcon: 'building'
-	},
-	sheepdog: {
-	    name: 'Sheepdog',
-	    ipanel: 'SheepdogInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	cephfs: {
-	    name: 'CephFS',
-	    ipanel: 'CephFSInputPanel',
-	    faIcon: 'building'
-	},
-	pvecephfs: {
-	    name: 'CephFS (PVE)',
-	    ipanel: 'CephFSInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	rbd: {
-	    name: 'RBD',
-	    ipanel: 'RBDInputPanel',
-	    faIcon: 'building'
-	},
-	pveceph: {
-	    name: 'RBD (PVE)',
-	    ipanel: 'RBDInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	zfs: {
-	    name: 'ZFS over iSCSI',
-	    ipanel: 'ZFSInputPanel',
-	    faIcon: 'building'
-	},
-	zfspool: {
-	    name: 'ZFS',
-	    ipanel: 'ZFSPoolInputPanel',
-	    faIcon: 'folder'
-	},
-	drbd: {
-	    name: 'DRBD',
-	    hideAdd: true
-	}
-    },
-
-    format_storage_type: function(value, md, record) {
-	if (value === 'rbd') {
-	    value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
-	} else if (value === 'cephfs') {
-	    value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
-	}
-
-	var schema = PVE.Utils.storageSchema[value];
-	if (schema) {
-	    return schema.name;
-	}
-	return Proxmox.Utils.unknownText;
-    },
-
-    format_ha: function(value) {
-	var text = Proxmox.Utils.noneText;
-
-	if (value.managed) {
-	    text = value.state || Proxmox.Utils.noneText;
-
-	    text += ', ' +  Proxmox.Utils.groupText + ': ';
-	    text += value.group || Proxmox.Utils.noneText;
-	}
-
-	return text;
-    },
-
-    format_content_types: function(value) {
-	return value.split(',').sort().map(function(ct) {
-	    return PVE.Utils.contentTypes[ct] || ct;
-	}).join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-	var data = record.data;
-	if (Ext.isNumber(data.channel) &&
-	    Ext.isNumber(data.id) &&
-	    Ext.isNumber(data.lun)) {
-	    return "CH " +
-		Ext.String.leftPad(data.channel,2, '0') +
-		" ID " + data.id + " LUN " + data.lun;
-	}
-	return data.volid.replace(/^.*:(.*\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-	return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	if (!(record.data.uptime && Ext.isNumeric(value))) {
-	    return '';
-	}
-
-	var maxcpu = record.data.maxcpu || 1;
-
-	if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-	    return '';
-	}
-
-	var per = value * 100;
-
-	return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-	/*jslint confusion: true */
-
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value);
-    },
-
-    render_bandwidth: function(value) {
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value) + '/s';
-    },
-
-    render_timestamp_human_readable: function(value) {
-	return Ext.Date.format(new Date(value * 1000), 'l d F Y H:i:s');
-    },
-
-    render_duration: function(value) {
-	if (value === undefined) {
-	    return '-';
-	}
-	return PVE.Utils.format_duration_short(value);
-    },
-
-    calculate_mem_usage: function(data) {
-	if (!Ext.isNumeric(data.mem) ||
-	    data.maxmem === 0 ||
-	    data.uptime < 1) {
-	    return -1;
-	}
-
-	return (data.mem / data.maxmem);
-    },
-
-    render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-	if (value > 1 ) {
-	    // we got no percentage but bytes
-	    var mem = value;
-	    var maxmem = record.data.maxmem;
-	    if (!record.data.uptime ||
-		maxmem === 0 ||
-		!Ext.isNumeric(mem)) {
-		return '';
-	    }
-
-	    return ((mem*100)/maxmem).toFixed(1) + " %";
-	}
-	return (value*100).toFixed(1) + " %";
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var mem = value;
-	var maxmem = record.data.maxmem;
-
-	if (!record.data.uptime) {
-	    return '';
-	}
-
-	if (!(Ext.isNumeric(mem) && maxmem)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    calculate_disk_usage: function(data) {
-
-	if (!Ext.isNumeric(data.disk) ||
-	    data.type === 'qemu' ||
-	    (data.type === 'lxc' && data.uptime === 0) ||
-	    data.maxdisk === 0) {
-	    return -1;
-	}
-
-	return (data.disk / data.maxdisk);
-    },
-
-    render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-
-	return (value * 100).toFixed(1) + " %";
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var disk = value;
-	var maxdisk = record.data.maxdisk;
-	var type = record.data.type;
-
-	if (!Ext.isNumeric(disk) ||
-	    type === 'qemu' ||
-	    maxdisk === 0 ||
-	    (type === 'lxc' && record.data.uptime === 0)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    get_object_icon_class: function(type, record) {
-	var status = '';
-	var objType = type;
-
-	if (type === 'type') {
-	    // for folder view
-	    objType = record.groupbyid;
-	} else if (record.template) {
-	    // templates
-	    objType = 'template';
-	    status = type;
-	} else {
-	    // everything else
-	    status = record.status + ' ha-' + record.hastate;
-	}
-
-	var defaults = PVE.tree.ResourceTree.typeDefaults[objType];
-	if (defaults && defaults.iconCls) {
-	    var retVal = defaults.iconCls + ' ' + status;
-	    return retVal;
-	}
-
-	return '';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
-	var fa = '<i class="fa-fw x-grid-icon-custom ' + cls  + '"></i> ';
-	return fa + value;
-    },
-
-    render_support_level: function(value, metaData, record) {
-	return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    /* render functions for new status panel */
-
-    render_usage: function(val) {
-	return (val*100).toFixed(2) + '%';
-    },
-
-    render_cpu_usage: function(val, max) {
-	return Ext.String.format(gettext('{0}% of {1}') +
-	    ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
-    },
-
-    render_size_usage: function(val, max) {
-	if (max === 0) {
-	    return gettext('N/A');
-	}
-	return (val*100/max).toFixed(2) + '% '+ '(' +
-	    Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
-    },
-
-    /* this is different for nodes */
-    render_node_cpu_usage: function(value, record) {
-	return PVE.Utils.render_cpu_usage(value, record.cpus);
-    },
-
-    /* this is different for nodes */
-    render_node_size_usage: function(record) {
-	return PVE.Utils.render_size_usage(record.used, record.total);
-    },
-
-    render_optional_url: function(value) {
-	var match;
-	if (value && (match = value.match(/^https?:\/\//)) !== null) {
-	    return '<a target="_blank" href="' + value + '">' + value + '</a>';
-	}
-	return value;
-    },
-
-    render_san: function(value) {
-	var names = [];
-	if (Ext.isArray(value)) {
-	    value.forEach(function(val) {
-		if (!Ext.isNumber(val)) {
-		    names.push(val);
-		}
-	    });
-	    return names.join('<br>');
-	}
-	return value;
-    },
-
-    render_full_name: function(firstname, metaData, record) {
-	var first = firstname || '';
-	var last = record.data.lastname || '';
-	return Ext.htmlEncode(first + " " + last);
-    },
-
-    render_u2f_error: function(error) {
-	var ErrorNames = {
-	    '1': gettext('Other Error'),
-	    '2': gettext('Bad Request'),
-	    '3': gettext('Configuration Unsupported'),
-	    '4': gettext('Device Ineligible'),
-	    '5': gettext('Timeout')
-	};
-	return "U2F Error: "  + ErrorNames[error] || Proxmox.Utils.unknownText;
-    },
-
-    windowHostname: function() {
-	return window.location.hostname.replace(Proxmox.Utils.IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-
-    openDefaultConsoleWindow: function(consoles, vmtype, vmid, nodename, vmname, cmd) {
-	var dv = PVE.Utils.defaultViewer(consoles);
-	PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname, cmd);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname, cmd) {
-	// kvm, lxc, shell, upgrade
-
-	if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-	    throw "missing vmid";
-	}
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (viewer === 'html5') {
-	    PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'xtermjs') {
-	    Proxmox.Utils.openXtermJsViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'vv') {
-	    var url;
-	    var params = { proxy: PVE.Utils.windowHostname() };
-	    if (vmtype === 'kvm') {
-		url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'lxc') {
-		url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'shell') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'upgrade') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.upgrade = 1;
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'cmd') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.cmd = cmd;
-		PVE.Utils.openSpiceViewer(url, params);
-	    }
-	} else {
-	    throw "unknown viewer type";
-	}
-    },
-
-    defaultViewer: function(consoles) {
-
-	var allowSpice, allowXtermjs;
-
-	if (consoles === true) {
-	    allowSpice = true;
-	    allowXtermjs = true;
-	} else if (typeof consoles === 'object') {
-	    allowSpice = consoles.spice;
-	    allowXtermjs = !!consoles.xtermjs;
-	}
-	var vncdefault = 'html5';
-	var dv = PVE.VersionInfo.console || vncdefault;
-	if ((dv === 'vv' && !allowSpice) || (dv === 'xtermjs' && !allowXtermjs)) {
-	    dv = vncdefault;
-	}
-
-	return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    novnc: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    resize: 'off',
-	    cmd: cmd
-	});
-	var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-	if (nw) {
-	    nw.focus();
-	}
-    },
-
-    openSpiceViewer: function(url, params){
-
-	var downloadWithName = function(uri, name) {
-	    var link = Ext.DomHelper.append(document.body, {
-		tag: 'a',
-		href: uri,
-		css : 'display:none;visibility:hidden;height:0px;'
-	    });
-
-	    // Note: we need to tell android the correct file name extension
-	    // but we do not set 'download' tag for other environments, because
-	    // It can have strange side effects (additional user prompt on firefox)
-	    var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-	    if (andriod) {
-		link.download = name;
-	    }
-
-	    if (link.fireEvent) {
-		link.fireEvent('onclick');
-	    } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-		link.dispatchEvent(evt);
-	    }
-	};
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    params: params,
-	    method: 'POST',
-	    failure: function(response, opts){
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, opts){
-		var raw = "[virt-viewer]\n";
-		Ext.Object.each(response.result.data, function(k, v) {
-		    raw += k + "=" + v + "\n";
-		});
-		var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-		    encodeURIComponent(raw);
-
-		downloadWithName(url, "pve-spice.vv");
-	    }
-	});
-    },
-
-    openTreeConsole: function(tree, record, item, index, e) {
-	e.stopEvent();
-	var nodename = record.data.node;
-	var vmid = record.data.vmid;
-	var vmname = record.data.name;
-	if (record.data.type === 'qemu' && !record.data.template) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var allowSpice = !!response.result.data.spice;
-		    PVE.Utils.openDefaultConsoleWindow(allowSpice, 'kvm', vmid, nodename, vmname);
-		}
-	    });
-	} else if (record.data.type === 'lxc' && !record.data.template) {
-	    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-	}
-    },
-
-    // test automation helper
-    call_menu_handler: function(menu, text) {
-
-	var list = menu.query('menuitem');
-
-	Ext.Array.each(list, function(item) {
-	    if (item.text === text) {
-		if (item.handler) {
-		    item.handler();
-		    return 1;
-		} else {
-		    return undefined;
-		}
-	    }
-	});
-    },
-
-    createCmdMenu: function(v, record, item, index, event) {
-	event.stopEvent();
-	if (!(v instanceof Ext.tree.View)) {
-	    v.select(record);
-	}
-	var menu;
-	var template = !!record.data.template;
-	var type = record.data.type;
-
-	if (template) {
-	    if (type === 'qemu' || type == 'lxc') {
-		menu = Ext.create('PVE.menu.TemplateMenu', {
-		    pveSelNode: record
-		});
-	    }
-	} else if (type === 'qemu' ||
-		   type === 'lxc' ||
-		   type === 'node') {
-	    menu = Ext.create('PVE.' + type + '.CmdMenu', {
-		pveSelNode: record,
-		nodename: record.data.node
-	    });
-	} else {
-	    return;
-	}
-
-	menu.showAt(event.getXY());
-	return menu;
-    },
-
-    // helper for deleting field which are set to there default values
-    delete_if_default: function(values, fieldname, default_val, create) {
-	if (values[fieldname] === '' || values[fieldname] === default_val) {
-	    if (!create) {
-		if (values['delete']) {
-		    values['delete'] += ',' + fieldname;
-		} else {
-		    values['delete'] = fieldname;
-		}
-	    }
-
-	    delete values[fieldname];
-	}
-    },
-
-    loadSSHKeyFromFile: function(file, callback) {
-	// ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-	// a user@host comment, 1420 for 8192 bits; current max is 16kbit
-	// assume: 740*8 for max. 32kbit (5920 byte file)
-	// round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
-	if (file.size > 8192) {
-	    Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
-	    return;
-	}
-	/*global
-	  FileReader
-	*/
-	var reader = new FileReader();
-	reader.onload = function(evt) {
-	    callback(evt.target.result);
-	};
-	reader.readAsText(file);
-    },
-
-    bus_counts: { ide: 4, sata: 6, scsi: 16, virtio: 16 },
-
-    // types is either undefined (all busses), an array of busses, or a single bus
-    forEachBus: function(types, func) {
-	var busses = Object.keys(PVE.Utils.bus_counts);
-	var i, j, count, cont;
-
-	if (Ext.isArray(types)) {
-	    busses = types;
-	} else if (Ext.isDefined(types)) {
-	    busses = [ types ];
-	}
-
-	// check if we only have valid busses
-	for (i = 0; i < busses.length; i++) {
-	    if (!PVE.Utils.bus_counts[busses[i]]) {
-		throw "invalid bus: '" + busses[i] + "'";
-	    }
-	}
-
-	for (i = 0; i < busses.length; i++) {
-	    count = PVE.Utils.bus_counts[busses[i]];
-	    for (j = 0; j < count; j++) {
-		cont = func(busses[i], j);
-		if (!cont && cont !== undefined) {
-		    return;
-		}
-	    }
-	}
-    },
-
-    mp_counts: { mps: 256, unused: 256 },
-
-    forEachMP: function(func, includeUnused) {
-	var i, cont;
-	for (i = 0; i < PVE.Utils.mp_counts.mps; i++) {
-	    cont = func('mp', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-
-	if (!includeUnused) {
-	    return;
-	}
-
-	for (i = 0; i < PVE.Utils.mp_counts.unused; i++) {
-	    cont = func('unused', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-    },
-
-    cleanEmptyObjectKeys: function (obj) {
-	var propName;
-	for (propName in obj) {
-	    if (obj.hasOwnProperty(propName)) {
-		if (obj[propName] === null || obj[propName] === undefined) {
-		    delete obj[propName];
-		}
-	    }
-	}
-    },
-
-    handleStoreErrorOrMask: function(me, store, regex, callback) {
-
-	me.mon(store, 'load', function (proxy, response, success, operation) {
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-	    var msg;
-
-	    if (operation.error.statusText) {
-		if (operation.error.statusText.match(regex)) {
-		    callback(me, operation.error);
-		    return;
-		} else {
-		    msg = operation.error.statusText + ' (' + operation.error.status + ')';
-		}
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    showCephInstallOrMask: function(container, msg, nodename, callback){
-	var regex = new RegExp("not (installed|initialized)", "i");
-	if (msg.match(regex)) {
-	    if (Proxmox.UserName === 'root@pam') {
-		container.el.mask();
-		if (!container.down('pveCephInstallWindow')){
-		    var isInstalled = msg.match(/not initialized/i) ? true : false;
-		    var win = Ext.create('PVE.ceph.Install', {
-			nodename: nodename
-		    });
-		    win.getViewModel().set('isInstalled', isInstalled);
-		    container.add(win);
-		    win.show();
-		    callback(win);
-		}
-	    } else {
-		container.mask(Ext.String.format(gettext('{0} not installed.') +
-		    ' ' + gettext('Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
-	    }
-	    return true;
-	} else {
-	    return false;
-	}
-    }
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-    }
-
-});
-
-// ExtJS related things
-
-Proxmox.Utils.toolkit = 'extjs';
-
-// custom PVE specific VTypes
-Ext.apply(Ext.form.field.VTypes, {
-
-    QemuStartDate: function(v) {
-	return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-    IP64AddressList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == '') {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.IP64_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    IP64AddressListText: gettext('Example') + ': 192.168.1.1,192.168.1.2',
-    IP64AddressListMask: /[A-Fa-f0-9\,\:\.\;\ ]/
-});
-
-Ext.define('PVE.form.field.Display', {
-    override: 'Ext.form.field.Display',
-
-    setSubmitValue: function(value) {
-	// do nothing, this is only to allow generalized  bindings for the:
-	// `me.isCreate ? 'textfield' : 'displayfield'` cases we have.
-    }
-});
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseACME: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-	var errors = false;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; //continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
-		res.domains = match_res[1].split(/[;, ]/);
-	    } else {
-		errors = true;
-		return false;
-	    }
-	});
-
-	if (errors || !res) {
-	    return;
-	}
-
-	return res;
-    },
-
-    parseBoolean: function(value, default_value) {
-	if (!Ext.isDefined(value)) {
-	    return default_value;
-	}
-	value = value.toLowerCase();
-	return value === '1' ||
-	       value === 'on' ||
-	       value === 'yes' ||
-	       value === 'true';
-    },
-
-    parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
-		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	});
-
-	if (error !== undefined) {
-	    console.error(error);
-	    return;
-	}
-
-	return res;
-    },
-
-    printPropertyString: function(data, defaultKey) {
-	var stringparts = [];
-
-	Ext.Object.each(data, function(key, value) {
-	    if (defaultKey !== undefined && key === defaultKey) {
-		stringparts.unshift(value);
-	    } else {
-		stringparts.push(key + '=' + value);
-	    }
-	});
-
-	return stringparts.join(',');
-    },
-
-    parseQemuNetwork: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-		res.model = match_res[1].toLowerCase();
-		if (match_res[3]) {
-		    res.macaddr = match_res[3];
-		}
-	    } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-		res.bridge = match_res[1];
-	    } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-		res.rate = match_res[1];
-	    } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-		res.tag = match_res[1];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		res.firewall = match_res[1];
-	    } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-		res.disconnect = match_res[1];
-	    } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-		res.queues = match_res[1];
-	    } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
-		res.trunks = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors || !res.model) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-	var netstr = net.model;
-	if (net.macaddr) {
-	    netstr += "=" + net.macaddr;
-	}
-	if (net.bridge) {
-	    netstr += ",bridge=" + net.bridge;
-	    if (net.tag) {
-		netstr += ",tag=" + net.tag;
-	    }
-	    if (net.firewall) {
-		netstr += ",firewall=" + net.firewall;
-	    }
-	}
-	if (net.rate) {
-	    netstr += ",rate=" + net.rate;
-	}
-	if (net.queues) {
-	    netstr += ",queues=" + net.queues;
-	}
-	if (net.disconnect) {
-	    netstr += ",link_down=" + net.disconnect;
-	}
-	if (net.trunks) {
-	    netstr += ",trunks=" + net.trunks;
-	}
-	return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var match_res = key.match(/^([a-z]+)(\d+)$/);
-	if (!match_res) {
-	    return;
-	}
-	res['interface'] = match_res[1];
-	res.index = match_res[2];
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    if (k === 'cache' && v === 'off') {
-		v = 'none';
-	    }
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-	var drivestr = drive.file;
-
-	Ext.Object.each(drive, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'index' || key === 'interface') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseIPConfig: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
-		res.ip = match_res[1];
-	    } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
-		res.gw = match_res[1];
-	    } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
-		res.ip6 = match_res[1];
-	    } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
-		res.gw6 = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printIPConfig: function(cfg) {
-	var c = "";
-	var str = "";
-	if (cfg.ip) {
-	    str += "ip=" + cfg.ip;
-	    c = ",";
-	}
-	if (cfg.gw) {
-	    str += c + "gw=" + cfg.gw;
-	    c = ",";
-	}
-	if (cfg.ip6) {
-	    str += c + "ip6=" + cfg.ip6;
-	    c = ",";
-	}
-	if (cfg.gw6) {
-	    str += c + "gw6=" + cfg.gw6;
-	    c = ",";
-	}
-	return str;
-    },
-
-    parseOpenVZNetIf: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(';'), function(item) {
-	    if (!item || item.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var data = {};
-	    Ext.Array.each(item.split(','), function(p) {
-		if (!p || p.match(/^\s*$/)) {
-		    return; // continue
-		}
-		var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-		if (!match_res) {
-		    errors = true;
-		    return false; // break
-		}
-		if (match_res[1] === 'bridge'){
-		    var bridgevlanf = match_res[2];
-		    var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-		    if (!bridge_res) {
-			errors = true;
-			return false; // break
-		    }
-		    data.bridge = bridge_res[1];
-		    data.tag = bridge_res[4];
-		    /*jslint confusion: true*/
-		    data.firewall = bridge_res[5] ? 1 : 0;
-		    /*jslint confusion: false*/
-		} else {
-		    data[match_res[1]] = match_res[2];
-		}
-	    });
-
-	    if (errors || !data.ifname) {
-		errors = true;
-		return false; // break
-	    }
-
-	    data.raw = item;
-
-	    res[data.ifname] = data;
-	});
-
-	return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-	var netarray = [];
-
-	Ext.Object.each(netif, function(iface, data) {
-	    var tmparray = [];
-	    Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-		var value = data[key];
-		if (key === 'bridge'){
-		    if(data.tag){
-			value = value + 'v' + data.tag;
-		    }
-		    if (data.firewall){
-			value = value + 'f';
-		    }
-		}
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-
-	    });
-	    netarray.push(tmparray.join(','));
-	});
-
-	return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var data = {};
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
-	    if (match_res) {
-		data[match_res[1]] = match_res[2];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		data.firewall = PVE.Parser.parseBoolean(match_res[1]);
-	    } else {
-		// todo: simply ignore errors ?
-		return; // continue
-	    }
-	});
-
-	return data;
-    },
-
-    printLxcNetwork: function(data) {
-	var tmparray = [];
-	Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-			'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-		var value = data[key];
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-	});
-
-	/*jslint confusion: true*/
-	if (data.rate > 0) {
-	    tmparray.push('rate=' + data.rate);
-	}
-	/*jslint confusion: false*/
-	return tmparray.join(',');
-    },
-
-    parseLxcMountPoint: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(.+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
-	if (m) {
-	    res.storage = m[1];
-	    res.type = 'volume';
-	} else if (res.file.match(/^\/dev\//)) {
-	    res.type = 'device';
-	} else {
-	    res.type = 'bind';
-	}
-
-	return res;
-    },
-
-    printLxcMountPoint: function(mp) {
-	var drivestr = mp.file;
-
-	Ext.Object.each(mp, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'type' || key === 'storage') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseStartup: function(value) {
-	if (value === undefined) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-		res.order = match_res[2];
-	    } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-		res.up = match_res[1];
-	    } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printStartup: function(startup) {
-	var arr = [];
-	if (startup.order !== undefined && startup.order !== '') {
-	    arr.push('order=' + startup.order);
-	}
-	if (startup.up !== undefined && startup.up !== '') {
-	    arr.push('up=' + startup.up);
-	}
-	if (startup.down !== undefined && startup.down !== '') {
-	    arr.push('down=' + startup.down);
-	}
-
-	return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-	var datastr = '';
-
-	Ext.Object.each(data, function(key, value) {
-	    if (value === '') { return; }
-	    datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-	});
-
-	return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    parseQemuCpu: function(value) {
-	if (!value) {
-	    return {};
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    if (!p.match(/\=/)) {
-		if (Ext.isDefined(res.cpu)) {
-		    errors = true;
-		    return false; // break
-		}
-		res.cputype = p;
-		return; // continue
-	    }
-
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var k = match_res[1];
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    res[k] = match_res[2];
-	});
-
-	if (errors || !res.cputype) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuCpu: function(cpu) {
-	var cpustr = cpu.cputype;
-	var optstr = '';
-
-	Ext.Object.each(cpu, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'cputype') {
-		return; // continue
-	    }
-	    optstr += ',' + key + '=' + value;
-	});
-
-	if (!cpustr) {
-	    if (optstr) {
-		return 'kvm64' + optstr;
-	    }
-	    return;
-	}
-
-	return cpustr + optstr;
-    },
-
-    parseSSHKey: function(key) {
-	//                |--- options can have quotes--|     type    key        comment
-	var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
-	var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
-
-	var m = key.match(keyre);
-	if (!m) {
-	    return null;
-	}
-	if (m.length < 3 || !m[2]) { // [2] is always either type or key
-	    return null;
-	}
-	if (m[1] && m[1].match(typere)) {
-	    return {
-		type: m[1],
-		key: m[2],
-		comment: m[3]
-	    };
-	}
-	if (m[2].match(typere)) {
-	    return {
-		options: m[1],
-		type: m[2],
-		key: m[3],
-		comment: m[4]
-	    };
-	}
-	return null;
-    }
-}});
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-	var me = this;
-
-	var changes = false;
-	var oldtext = Ext.encode(me.UIState[name]);
-	var newtext = Ext.encode(newvalue);
-	if (newtext != oldtext) {
-	    changes = true;
-	    me.UIState[name] = newvalue;
-	    //console.log("changed old " + name + " " + oldtext);
-	    //console.log("changed new " + name + " " + newtext);
-	    if (fireEvents) {
-		me.fireEvent("statechange", me, name, { value: newvalue });
-	    }
-	}
-	return changes;
-    },
-
-    // private
-    hslist: [
-	// order is important for notifications
-	// [ name, default ]
-	['view', 'server'],
-	['rid', 'root'],
-	['ltab', 'tasks'],
-	['nodetab', ''],
-	['storagetab', ''],
-	['pooltab', ''],
-	['kvmtab', ''],
-	['lxctab', ''],
-	['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-	cloudinit: 52,
-	replication: 51,
-	system: 50,
-	monitor: 49,
-	'ha-fencing': 48,
-	'ha-groups': 47,
-	'ha-resources': 46,
-	'ceph-log': 45,
-	'ceph-crushmap':44,
-	'ceph-pools': 43,
-	'ceph-osdtree': 42,
-	'ceph-disklist': 41,
-	'ceph-monlist': 40,
-	'ceph-config': 39,
-	ceph: 38,
-	'firewall-fwlog': 37,
-	'firewall-options': 36,
-	'firewall-ipset': 35,
-	'firewall-aliases': 34,
-	'firewall-sg': 33,
-	firewall: 32,
-	apt: 31,
-	members: 30,
-	snapshot: 29,
-	ha: 28,
-	support: 27,
-	pools: 26,
-	syslog: 25,
-	ubc: 24,
-	initlog: 23,
-	openvz: 22,
-	backup: 21,
-	resources: 20,
-	content: 19,
-	root: 18,
-	domains: 17,
-	roles: 16,
-	groups: 15,
-	users: 14,
-	time: 13,
-	dns: 12,
-	network: 11,
-	services: 10,
-	options: 9,
-	console: 8,
-	hardware: 7,
-	permissions: 6,
-	summary: 5,
-	tasks: 4,
-	clog: 3,
-	storage: 2,
-	folder: 1,
-	server: 0
-    },
-
-    decodeHToken: function(token) {
-	var me = this;
-
-	var state = {};
-	if (!token) {
-	    Ext.Array.each(me.hslist, function(rec) {
-		state[rec[0]] = rec[1];
-	    });
-	    return state;
-	}
-
-	// return Ext.urlDecode(token);
-
-	var items = token.split(':');
-	var prefix = items.shift();
-
-	if (prefix != me.hprefix) {
-	    return me.decodeHToken();
-	}
-
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = items.shift();
-	    if (value) {
-		if (value[0] === '=') {
-		    value = decodeURIComponent(value.slice(1));
-		} else {
-		    Ext.Object.each(me.compDict, function(key, cv) {
-			if (value == cv) {
-			    value = key;
-			    return false;
-			}
-		    });
-		}
-	    }
-	    state[rec[0]] = value;
-	});
-
-	return state;
-    },
-
-    encodeHToken: function(state) {
-	var me = this;
-
-	// return Ext.urlEncode(state);
-
-	var ctoken = me.hprefix;
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = state[rec[0]];
-	    if (!Ext.isDefined(value)) {
-		value = rec[1];
-	    }
-	    value = encodeURIComponent(value);
-	    if (!value) {
-		ctoken += ':';
-	    } else {
-		var comp = me.compDict[value];
-		if (Ext.isDefined(comp)) {
-		    ctoken += ":" + comp;
-		} else {
-		    ctoken += ":=" + value;
-		}
-	    }
-	});
-
-	return ctoken;
-    },
-
-    constructor: function(config){
-	var me = this;
-
-	me.callParent([config]);
-
-	me.UIState = me.decodeHToken(); // set default
-
-	var history_change_cb = function(token) {
-	    //console.log("HC " + token);
-	    if (!token) {
-		var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-		if (res){
-		    // process text value and close...
-		    Ext.History.back();
-		} else {
-		    Ext.History.forward();
-		}
-		return;
-	    }
-
-	    var newstate = me.decodeHToken(token);
-	    Ext.Array.each(me.hslist, function(rec) {
-		if (typeof newstate[rec[0]] == "undefined") {
-		    return;
-		}
-		me.setHV(rec[0], newstate[rec[0]], true);
-	    });
-	};
-
-	var start_token = Ext.History.getToken();
-	if (start_token) {
-	    history_change_cb(start_token);
-	} else {
-	    var htext = me.encodeHToken(me.UIState);
-	    Ext.History.add(htext);
-	}
-
-	Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-	/*jslint confusion: true */
-	var me = this;
-	var data;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    data = { value: me.UIState[name] };
-	} else {
-	    data = me.callParent(arguments);
-	    if (!data && name === 'GuiCap') {
-		data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-	    }
-	}
-
-	//console.log("GET " + name + " " + Ext.encode(data));
-	return data;
-    },
-
-    clear: function(name){
-	var me = this;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    me.UIState[name] = null;
-	}
-
-	me.callParent(arguments);
-    },
-
-    set: function(name, value){
-        var me = this;
-
-	//console.log("SET " + name + " " + Ext.encode(value));
-	if (typeof me.UIState[name] != "undefined") {
-	    var newvalue = value ? value.value : null;
-	    if (me.setHV(name, newvalue, false)) {
-		var htext = me.encodeHToken(me.UIState);
-		Ext.History.add(htext);
-	    }
-	} else {
-	    me.callParent(arguments);
-	}
-    }
-});
-Ext.define('PVE.menu.Item', {
-    extend: 'Ext.menu.Item',
-    alias: 'widget.pveMenuItem',
-
-    // set to wrap the handler callback in a confirm dialog  showing this text
-    confirmMsg: false,
-
-    // set to focus 'No' instead of 'Yes' button and show a warning symbol
-    dangerous: false,
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.handler) {
-	    me.setHandler(me.handler, me.scope);
-	}
-
-	me.callParent();
-    },
-
-    setHandler: function(fn, scope) {
-	var me = this;
-	me.scope = scope;
-	me.handler = function(button, e) {
-	    var rec, msg;
-	    if (me.confirmMsg) {
-		msg = me.confirmMsg;
-		Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: msg,
-		    buttons: Ext.Msg.YESNO,
-		    defaultFocus: me.dangerous ? 'no' : 'yes',
-		    callback: function(btn) {
-			if (btn === 'yes') {
-			    Ext.callback(fn, me.scope, [me, e], 0, me);
-			}
-		    }
-		});
-	    } else {
-		Ext.callback(fn, me.scope, [me, e], 0, me);
-	    }
-	};
-    }
-});
-Ext.define('PVE.menu.TemplateMenu', {
-    extend: 'Ext.menu.Menu',
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var guestType = me.pveSelNode.data.type;
-	if (guestType !== 'qemu' && guestType != 'lxc') {
-	    throw "invalid guest type";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var template = me.pveSelNode.data.template;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	me.title = (guestType === 'qemu' ? 'VM ' : 'CT ') + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: guestType,
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: template
-		    });
-		    win.show();
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade', 'cmd'
-
-    cmd: undefined,
-
-    consoleName: undefined,
-
-    iconCls: 'fa fa-terminal',
-
-    enableSpice: true,
-    enableXtermjs: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    text: gettext('Console'),
-
-    setEnableSpice: function(enable){
-	var me = this;
-
-	me.enableSpice = enable;
-	me.down('#spicemenu').setDisabled(!enable);
-    },
-
-    setEnableXtermJS: function(enable){
-	var me = this;
-
-	me.enableXtermjs = enable;
-	me.down('#xtermjs').setDisabled(!enable);
-    },
-
-    handler: function() {
-	var me = this;
-	var consoles = {
-	    spice: me.enableSpice,
-	    xtermjs: me.enableXtermjs
-	};
-	PVE.Utils.openDefaultConsoleWindow(consoles, me.consoleType, me.vmid,
-					   me.nodename, me.consoleName, me.cmd);
-    },
-
-    menu: [
-	{
-	    xtype:'menuitem',
-	    text: 'noVNC',
-	    iconCls: 'pve-itype-icon-novnc',
-	    type: 'html5',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    xterm: 'menuitem',
-	    itemId: 'spicemenu',
-	    text: 'SPICE',
-	    type: 'vv',
-	    iconCls: 'pve-itype-icon-virt-viewer',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    text: 'xterm.js',
-	    itemId: 'xtermjs',
-	    iconCls: 'pve-itype-icon-xtermjs',
-	    type: 'xtermjs',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- *
- *   does this for the button and every menu item
- */
-Ext.define('PVE.button.Split', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveSplitButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    handlerWrapper: function(button, event) {
-	var me = this;
-	var rec, msg;
-	if (me.selModel) {
-	    rec = me.selModel.getSelection()[0];
-	    if (!rec || (me.enableFn(rec) === false)) {
-		return;
-	    }
-	}
-
-	if (me.confirmMsg) {
-	    msg = me.confirmMsg;
-	    // confirMsg can be boolean or function
-	    /*jslint confusion: true*/
-	    if (Ext.isFunction(me.confirmMsg)) {
-		msg = me.confirmMsg(rec);
-	    }
-	    /*jslint confusion: false*/
-	    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-	    Ext.Msg.show({
-		title: gettext('Confirm'),
-		icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		msg: msg,
-		buttons: Ext.Msg.YESNO,
-		callback: function(btn) {
-		    if (btn !== 'yes') {
-			return;
-		    }
-		    me.realHandler(button, event, rec);
-		}
-	    });
-	} else {
-	    me.realHandler(button, event, rec);
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-	    me.realHandler = me.handler;
-	    me.handler = me.handlerWrapper;
-	}
-
-	if (me.menu && me.menu.items) {
-	    me.menu.items.forEach(function(item) {
-		if (item.handler) {
-		    item.realHandler = item.handler;
-		    item.handler = me.handlerWrapper;
-		}
-
-		if (item.selModel) {
-		    me.mon(item.selModel, "selectionchange", function() {
-			var rec = item.selModel.getSelection()[0];
-			if (!rec || (item.enableFn(rec) === false )) {
-			    item.setDisabled(true);
-			} else {
-			    item.setDisabled(false);
-			}
-		    });
-		}
-	    });
-	}
-
-	me.callParent();
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.controller.StorageEdit', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.storageEdit',
-    control: {
-	'field[name=content]': {
-	    change: function(field, value) {
-		var hasBackups = Ext.Array.contains(value, 'backup');
-		var maxfiles = this.lookupReference('maxfiles');
-		if (!maxfiles) {
-		    return;
-		}
-
-		if (!hasBackups) {
-		// clear values which will never be submitted
-		    maxfiles.reset();
-		}
-		maxfiles.setDisabled(!hasBackups);
-	    }
-	}
-    }
-});
-Ext.define('PVE.qemu.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'suspended':
-		stopped = false;
-		suspended = true;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = "VM " + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: running || suspended,
-		disabled: running || suspended,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-	    {
-		text: gettext('Pause'),
-		iconCls: 'fa fa-fw fa-pause',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmpause', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Hibernate'),
-		iconCls: 'fa fa-fw fa-download',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		tooltip: gettext('Suspend to disk'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmsuspend', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend', { todisk: 1 });
-		    });
-		}
-	    },
-	    {
-		text: gettext('Resume'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: !suspended,
-		handler: function() {
-		    vm_command('resume');
-		}
-	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'qemu',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'qemu');
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		hidden: !caps.vms['VM.Allocate'],
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmtemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			     url: '/nodes/' + nodename + '/qemu/' + vmid + '/template',
-			     method: 'POST',
-			     failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			     }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    Proxmox.Utils.API2Request({
-			url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-			failure: function(response, opts) {
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, opts) {
-			    var allowSpice = response.result.data.spice;
-			    var allowXtermjs = response.result.data.serial;
-			    var consoles = {
-				spice: allowSpice,
-				xtermjs: allowXtermjs
-			    };
-			    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-			}
-		    });
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no CT ID specified";
-	}
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/lxc/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = 'CT ' + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		disabled: running,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-//	    {
-//		text: gettext('Suspend'),
-//		iconCls: 'fa fa-fw fa-pause',
-//		hidde: suspended,
-//		disabled: stopped || suspended,
-//		handler: function() {
-//		    var msg = Proxmox.Utils.format_task_description('vzsuspend', vmid);
-//		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-//			if (btn !== 'yes') {
-//			    return;
-//			}
-//
-//			vm_command('suspend');
-//		    });
-//		}
-//	    },
-//	    {
-//		text: gettext('Resume'),
-//		iconCls: 'fa fa-fw fa-play',
-//		hidden: !suspended,
-//		handler: function() {
-//		    vm_command('resume');
-//		}
-//	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: standalone || !caps.vms['VM.Migrate']
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'lxc');
-		}
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'lxc',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vztemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/lxc/' + vmid + '/template',
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-    xtype: 'nodeCmdMenu',
-
-    showSeparator: false,
-
-    items: [
-	{
-	    text: gettext('Create VM'),
-	    itemId: 'createvm',
-	    iconCls: 'fa fa-desktop',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{
-	    text: gettext('Create CT'),
-	    itemId: 'createct',
-	    iconCls: 'fa fa-cube',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Bulk Start'),
-	    itemId: 'bulkstart',
-	    iconCls: 'fa fa-fw fa-play',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Start'),
-		    btnText: gettext('Start'),
-		    action: 'startall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Stop'),
-	    itemId: 'bulkstop',
-	    iconCls: 'fa fa-fw fa-stop',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Stop'),
-		    btnText: gettext('Stop'),
-		    action: 'stopall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Migrate'),
-	    itemId: 'bulkmigrate',
-	    iconCls: 'fa fa-fw fa-send-o',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Migrate'),
-		    btnText: gettext('Migrate'),
-		    action: 'migrateall'
-		});
-		win.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Shell'),
-	    itemId: 'shell',
-	    iconCls: 'fa fa-fw fa-terminal',
-	    handler: function() {
-		var me = this.up('menu');
-		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, me.nodename, undefined);
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Wake-on-LAN'),
-	    itemId: 'wakeonlan',
-	    iconCls: 'fa fa-fw fa-power-off',
-	    handler: function() {
-		var me = this.up('menu');
-		Proxmox.Utils.API2Request({
-		    param: {},
-		    url: '/nodes/' + me.nodename + '/wakeonlan',
-		    method: 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, opts) {
-			Ext.Msg.show({
-			    title: 'Success',
-			    icon: Ext.Msg.INFO,
-			    msg: Ext.String.format(gettext("Wake on LAN packet send for '{0}': '{1}'"), me.nodename, response.result.data)
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no nodename specified';
-	}
-
-	me.title = gettext('Node') + " '" + me.nodename + "'";
-	me.callParent();
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	// disable not allowed options
-	if (!caps.vms['VM.Allocate']) {
-	    me.getComponent('createct').setDisabled(true);
-	    me.getComponent('createvm').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.PowerMgmt']) {
-	    me.getComponent('bulkstart').setDisabled(true);
-	    me.getComponent('bulkstop').setDisabled(true);
-	    me.getComponent('bulkmigrate').setDisabled(true);
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.Console']) {
-	    me.getComponent('shell').setDisabled(true);
-	}
-
-	if (me.pveSelNode.data.running) {
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-    }
-});
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-
-    vmid: undefined,
-
-    cmd: undefined,
-
-    consoleType: undefined, // lxc, kvm, shell, cmd
-
-    layout: 'fit',
-
-    xtermjs: false,
-
-    border: false,
-
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.consoleType) {
-	    throw "no console type specified";
-	}
-
-	if (!me.vmid && me.consoleType !== 'shell' && me.consoleType !== 'cmd') {
-	    throw "no VM ID specified";
-	}
-
-	// always use same iframe, to avoid running several noVnc clients
-	// at same time (to avoid performance problems)
-	var box = Ext.create('Ext.ux.IFrame', { itemid : "vncconsole" });
-
-	var type = me.xtermjs ? 'xtermjs' : 'novnc';
-	Ext.apply(me, {
-	    items: box,
-	    listeners: {
-		activate: function() {
-		    var queryDict = {
-			console: me.consoleType, // kvm, lxc, upgrade or shell
-			vmid: me.vmid,
-			node: me.nodename,
-			cmd: me.cmd,
-			resize: 'scale'
-		    };
-		    queryDict[type] = 1;
-		    PVE.Utils.cleanEmptyObjectKeys(queryDict);
-		    var url = '/?' + Ext.Object.toQueryString(queryDict);
-		    box.load(url);
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.on('afterrender', function() {
-	    me.focus();
-	});
-    }
-});
-
-Ext.define('PVE.data.PermPathStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.pvePermPath',
-    fields: [ 'value' ],
-    autoLoad: false,
-    data: [
-	{'value':  '/'},
-	{'value':  '/access'},
-	{'value': '/nodes'},
-	{'value': '/pool'},
-	{'value': '/storage'},
-	{'value': '/vms'}
-    ],
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	me.callParent([config]);
-
-	me.suspendEvents();
-	PVE.data.ResourceStore.each(function(record) {
-	    switch (record.get('type')) {
-		case 'node':
-		    me.add({value: '/nodes/' + record.get('text')});
-		    break;
-
-		case 'qemu':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'lxc':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'storage':
-		    me.add({value: '/storage/' + record.get('storage')});
-		    break;
-		case 'pool':
-		    me.add({value: '/pool/' + record.get('pool')});
-		    break;
-	    }
-	});
-	me.resumeEvents();
-
-	me.fireEvent('refresh', me);
-	me.fireEvent('datachanged', me);
-
-	me.sort({
-	    property: 'value',
-	    direction: 'ASC'
-	});
-    }
-});
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-	var me = this, i;
-
-	return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-
-    // returns the cached data from all nodes
-    getNodes: function() {
-	var me = this;
-
-	var nodes = [];
-	me.each(function(record) {
-	    if (record.get('type') == "node") {
-		nodes.push( record.getData() );
-	    }
-	});
-
-	return nodes;
-    },
-
-    storageIsShared: function(storage_path) {
-	var me = this;
-
-	var index = me.findExact('id', storage_path);
-
-	return me.getAt(index).data.shared;
-    },
-
-    guestNode: function(vmid) {
-	var me = this;
-
-	var index = me.findExact('vmid', parseInt(vmid, 10));
-
-	return me.getAt(index).data.node;
-    },
-
-    constructor: function(config) {
-	// fixme: how to avoid those warnings
-	/*jslint confusion: true */
-
-	var me = this;
-
-	config = config || {};
-
-	var field_defaults = {
-	    type: {
-		header: gettext('Type'),
-		type: 'string',
-		renderer: PVE.Utils.render_resource_type,
-		sortable: true,
-		hideable: false,
-		width: 100
-	    },
-	    id: {
-		header: 'ID',
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    running: {
-		header: gettext('Online'),
-		type: 'boolean',
-		renderer: Proxmox.Utils.format_boolean,
-		hidden: true,
-		convert: function(value, record) {
-		    var info = record.data;
-		    return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-		}
-	    },
-	    text: {
-		header: gettext('Description'),
-		type: 'string',
-		sortable: true,
-		width: 200,
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-
-		    if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
-			text = String(info.vmid);
-			if (info.name) {
-			    text += " (" + info.name + ')';
-			}
-		    } else { // node, pool, storage
-			text = info[info.type] || info.id;
-			if (info.node && info.type !== 'node') {
-			    text += " (" + info.node + ")";
-			}
-		    }
-
-		    return text;
-		}
-	    },
-	    vmid: {
-		header: 'VMID',
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    name: {
-		header: gettext('Name'),
-		hidden: true,
-		sortable: true,
-		type: 'string'
-	    },
-	    disk: {
-		header: gettext('Disk usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_disk_usage,
-		sortable: true,
-		width: 100,
-		hidden: true
-	    },
-	    diskuse: {
-		header: gettext('Disk usage') + " %",
-		type: 'number',
-		sortable: true,
-		renderer: PVE.Utils.render_disk_usage_percent,
-		width: 100,
-		calculate: PVE.Utils.calculate_disk_usage,
-		sortType: 'asFloat'
-	    },
-	    maxdisk: {
-		header: gettext('Disk size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    mem: {
-		header: gettext('Memory usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_mem_usage,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    memuse: {
-		header: gettext('Memory usage') + " %",
-		type: 'number',
-		renderer: PVE.Utils.render_mem_usage_percent,
-		calculate: PVE.Utils.calculate_mem_usage,
-		sortType: 'asFloat',
-		sortable: true,
-		width: 100
-	    },
-	    maxmem: {
-		header: gettext('Memory size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		hidden: true,
-		sortable: true,
-		width: 100
-	    },
-	    cpu: {
-		header: gettext('CPU usage'),
-		type: 'float',
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100
-	    },
-	    maxcpu: {
-		header: gettext('maxcpu'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    diskread: {
-		header: gettext('Total Disk Read'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    diskwrite: {
-		header: gettext('Total Disk Write'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netin: {
-		header: gettext('Total NetIn'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netout: {
-		header: gettext('Total NetOut'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    template: {
-		header: gettext('Template'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    uptime: {
-		header: gettext('Uptime'),
-		type: 'integer',
-		renderer: Proxmox.Utils.render_uptime,
-		sortable: true,
-		width: 110
-	    },
-	    node: {
-		header: gettext('Node'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    storage: {
-		header: gettext('Storage'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    pool: {
-		header: gettext('Pool'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    hastate: {
-		header: gettext('HA State'),
-		type: 'string',
-		defaultValue: 'unmanaged',
-		hidden: true,
-		sortable: true
-	    },
-	    status: {
-		header: gettext('Status'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    }
-	};
-
-	var fields = [];
-	var fieldNames = [];
-	Ext.Object.each(field_defaults, function(key, value) {
-	    var field = {name: key, type: value.type};
-	    if (Ext.isDefined(value.convert)) {
-		field.convert = value.convert;
-	    }
-
-	    if (Ext.isDefined(value.calculate)) {
-		field.calculate = value.calculate;
-	    }
-
-	    if (Ext.isDefined(value.defaultValue)) {
-		field.defaultValue = value.defaultValue;
-	    }
-
-	    fields.push(field);
-	    fieldNames.push(key);
-	});
-
-	Ext.define('PVEResources', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/resources'
-	    }
-	});
-
-	Ext.define('PVETree', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: { type: 'memory' }
-	});
-
-	Ext.apply(config, {
-	    storeid: 'PVEResources',
-	    model: 'PVEResources',
-	    defaultColumns: function() {
-		var res = [];
-		Ext.Object.each(field_defaults, function(field, info) {
-		    var fi = Ext.apply({ dataIndex: field }, info);
-		    res.push(fi);
-		});
-		return res;
-	    },
-	    fieldNames: fieldNames
-	});
-
-	me.callParent([config]);
-    }
-});
-Ext.define('pve-domains', {
-    extend: "Ext.data.Model",
-    fields: [
-	'realm', 'type', 'comment', 'default', 'tfa',
-	{
-	    name: 'descr',
-	    // Note: We use this in the RealmComboBox.js (see Bug #125)
-	    convert: function(value, record) {
-		if (value) {
-		    return value;
-		}
-
-		var info = record.data;
-		// return realm if there is no comment
-		var text = info.comment || info.realm;
-
-		if (info.tfa) {
-		    text += " (+ " + info.tfa + ")";
-		}
-
-		return Ext.String.htmlEncode(text);
-	    }
-	}
-    ],
-    idProperty: 'realm',
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/domains"
-    }
-});
-Ext.define('pve-rrd-node', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	{
-	    name:'iowait',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'loadavg',
-	'maxcpu',
-	'memtotal',
-	'memused',
-	'netin',
-	'netout',
-	'roottotal',
-	'rootused',
-	'swaptotal',
-	'swapused',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-guest', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'maxcpu',
-	'netin',
-	'netout',
-	'mem',
-	'maxmem',
-	'disk',
-	'maxdisk',
-	'diskread',
-	'diskwrite',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-storage', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'used',
-	'total',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    minValue: 1,
-	    maxValue: 4094
-	});
-
-	me.callParent();
-    }
-});
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-    comboItems: [
-	['__default__', gettext('Default')],
-	[1, gettext('Yes')],
-	[0, gettext('No')]
-    ]
-});
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['0', Proxmox.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-    valueField: 'poolid',
-    displayField: 'poolid',
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: 'poolid'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    autoSelect: false,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Pool'),
-			sortable: true,
-			dataIndex: 'poolid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-	extend: 'Ext.data.Model',
-	fields: [ 'poolid', 'comment' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/pools"
-	},
-	idProperty: 'poolid'
-    });
-
-});
-Ext.define('PVE.form.PrivilegesSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'pvePrivilegesSelector',
-
-    multiSelect: true,
-
-    initComponent: function() {
-	var me = this;
-
-	// So me.store is available.
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/roles/Administrator',
-	    method: 'GET',
-	    success: function(response, options) {
-		var data = [], key;
-		/*jslint forin: true */
-		for (key in response.result.data) {
-		    data.push([key, key]);
-		}
-		/*jslint forin: false */
-
-		me.store.setData(data);
-
-		me.store.sort({
-		    property: 'key',
-		    direction: 'ASC'
-		});
-	    },
-
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-Ext.define('pve-groups', {
-    extend: 'Ext.data.Model',
-    fields: [ 'groupid', 'comment' ],
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/groups"
-    },
-    idProperty: 'groupid'
-});
-
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveGroupSelector',
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'groupid',
-    displayField: 'groupid',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		sortable: true,
-		dataIndex: 'groupid',
-		flex: 1
-	    },
-	    {
-		header: gettext('Comment'),
-		sortable: false,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: [{
-		property: 'groupid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-Ext.define('PVE.form.UserSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'userid',
-    displayField: 'userid',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-users',
-	    sorters: [{
-		property: 'userid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('User'),
-			sortable: true,
-			dataIndex: 'userid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Name'),
-			sortable: true,
-			renderer: PVE.Utils.render_full_name,
-			dataIndex: 'firstname',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'userid', 'firstname', 'lastname' , 'email', 'comment',
-	    { type: 'boolean', name: 'enable' },
-	    { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/users"
-	},
-	idProperty: 'userid'
-    });
-
-});
-
-
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'roleid',
-    displayField: 'roleid',
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: [{
-		property: 'roleid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Role'),
-			sortable: true,
-			dataIndex: 'roleid',
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-	extend: 'Ext.data.Model',
-	fields: [ 'roleid', 'privs' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/roles"
-	},
-	idProperty: 'roleid'
-    });
-
-});
-Ext.define('PVE.form.GuestIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveGuestIDSelector',
-
-    allowBlank: false,
-
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeID: false,
-
-    guestType: undefined,
-
-    validator: function(value) {
-	var me = this;
-
-	if (!Ext.isNumeric(value) ||
-	    value < me.minValue ||
-	    value > me.maxValue) {
-	    // check is done by ExtJS
-	    return true;
-	}
-
-	if (me.validateExists === true && !me.exists) {
-	    return me.unknownID;
-	}
-
-	if (me.validateExists === false && me.exists) {
-	    return me.inUseID;
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var label = '{0} ID';
-	var unknownID = gettext('This {0} ID does not exists');
-	var inUseID = gettext('This {0} ID is already in use');
-	var type = 'CT/VM';
-
-	if (me.guestType === 'lxc') {
-	    type = 'CT';
-	} else if (me.guestType === 'qemu') {
-	    type = 'VM';
-	}
-
-	me.label = Ext.String.format(label, type);
-	me.unknownID = Ext.String.format(unknownID, type);
-	me.inUseID = Ext.String.format(inUseID, type);
-
-	Ext.apply(me, {
-	    fieldLabel: me.label,
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    if (!Ext.isDefined(me.validateExists)) {
-			return;
-		    }
-		    Proxmox.Utils.API2Request({
-			params: { vmid: newValue },
-			url: '/cluster/nextid',
-			method: 'GET',
-			success: function(response, opts) {
-			    me.exists = false;
-			    me.validate();
-			},
-			failure: function(response, opts) {
-			    me.exists = true;
-			    me.validate();
-			}
-		    });
-		}
-	    }
-	});
-
-        me.callParent();
-
-	if (me.loadNextFreeID) {
-	    Proxmox.Utils.API2Request({
-		url: '/cluster/nextid',
-		method: 'GET',
-		success: function(response, opts) {
-		    me.setRawValue(response.result.data);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    allowDecimals: false,
-
-    allowExponential: false,
-
-    computeUpDown: function(value) {
-	var me = this;
-
-	if (!me.hotplug) {
-	    return { up: value + me.step, down: value - me.step };
-	}
-	
-	var dimm_size = 512;
-	var prev_dimm_size = 0;
-	var min_size = 1024;
-	var current_size = min_size;
-	var value_up = min_size;
-	var value_down = min_size;
-	var value_start = min_size;
-
-	var i, j;
-	for (j = 0; j < 9; j++) {
-	    for (i = 0; i < 32; i++) {
-		if ((value >= current_size) && (value < (current_size + dimm_size))) {
-		    value_start = current_size;
-		    value_up = current_size + dimm_size;
-		    value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-		}
-		current_size += dimm_size;				
-	    }
-	    prev_dimm_size = dimm_size;
-	    dimm_size = dimm_size*2;
-	}
-
-	return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-	}
-    },
-
-    onSpinDown: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.hotplug) {
-	    me.minValue = 1024;
-
-	    me.on('blur', function(field) {
-		var value = me.getValue();
-		var res = me.computeUpDown(value);
-		if (value === res.start || value === res.up || value === res.down) {
-		    return;
-		}
-		field.setValue(res.up);
-	    });
-	}
-
-        me.callParent();
-    }
-});
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveNetworkCardSelector',
-    comboItems: [
-	['e1000', 'Intel E1000'],
-	['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-	['rtl8139', 'Realtek RTL8139'],
-	['vmxnet3', 'VMware vmxnet3']
-    ]
-});
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveDiskFormatSelector',
-    comboItems:  [
-	['raw', gettext('Raw disk image') + ' (raw)'],
-	['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-	['vmdk', gettext('VMware image format') + ' (vmdk)']
-    ]
-});
-Ext.define('PVE.form.DiskSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveDiskSelector',
-
-    // can be
-    // undefined: all
-    // unused: only unused
-    // journal_disk: all disks with gpt
-    diskType: undefined,
-
-    valueField: 'devpath',
-    displayField: 'devpath',
-    emptyText: gettext('No Disks unused'),
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Device'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'devpath'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 60,
-		sortable: false,
-		renderer: Proxmox.Utils.format_size,
-		dataIndex: 'size'
-	    },
-	    {
-		header: gettext('Serial'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'serial'
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    filterOnLoad: true,
-	    model: 'pve-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list",
-		extraParams: { type: me.diskType }
-	    },
-	    sorters: [
-		{
-		    property : 'devpath',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-}, function() {
-
-    Ext.define('pve-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial'],
-	idProperty: 'devpath'
-    });
-});
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveBusSelector',
-  
-    noVirtIO: false,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [['ide', 'IDE'], ['sata', 'SATA']];
-
-	if (!me.noVirtIO) {
-	    me.comboItems.push(['virtio', 'VirtIO Block']);
-	}
-
-	me.comboItems.push(['scsi', 'SCSI']);
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveControllerSelector',
-   
-    statics: {
-	maxIds: {
-	    ide: 3,
-	    sata: 5,
-	    virtio: 15,
-	    scsi: 13
-	}
-    },
-
-    noVirtIO: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    sortByPreviousUsage: function(vmconfig, controllerList) {
-
-	var usedControllers = Ext.clone(PVE.form.ControllerSelector.maxIds);
-
-	var type;
-	for (type in usedControllers) {
-	    if(usedControllers.hasOwnProperty(type)) {
-		usedControllers[type] = 0;
-	    }
-	}
-
-	var property;
-	for (property in vmconfig) {
-	    if (vmconfig.hasOwnProperty(property)) {
-		if (property.match(PVE.Utils.bus_match) && !vmconfig[property].match(/media=cdrom/)) {
-		    var foundController = property.match(PVE.Utils.bus_match)[1];
-		    usedControllers[foundController]++;
-		}
-	    }
-	}
-
-	var vmDefaults = PVE.qemu.OSDefaults[vmconfig.ostype];
-
-	var sortPriority = vmDefaults && vmDefaults.busPriority
-	    ? vmDefaults.busPriority : PVE.qemu.OSDefaults.generic;
-
-	var sortedList = Ext.clone(controllerList);
-	sortedList.sort(function(a,b) {
-	    if (usedControllers[b] == usedControllers[a]) {
-		return sortPriority[b] - sortPriority[a];
-	    }
-	    return usedControllers[b] - usedControllers[a];
-	});
-	
-	return sortedList;
-    },
-
-    setVMConfig: function(vmconfig, autoSelect) {
-	var me = this;
-
-	me.vmconfig = Ext.apply({}, vmconfig);
-
-	var clist = ['ide', 'virtio', 'scsi', 'sata'];
-	var bussel = me.down('field[name=controller]');
-	var deviceid = me.down('field[name=deviceid]');
-
-	if (autoSelect === 'cdrom') {
-	    clist = ['ide', 'scsi', 'sata'];
-	    if (!Ext.isDefined(me.vmconfig.ide2)) {
-		bussel.setValue('ide');
-		deviceid.setValue(2);
-		return;
-	    }
-	} else  {
-	    // in most cases we want to add a disk to the same controller
-	    // we previously used
-	    clist = me.sortByPreviousUsage(me.vmconfig, clist);
-	}
-
-	Ext.Array.each(clist, function(controller) {
-	    var confid, i;
-	    bussel.setValue(controller);
-	    for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
-		confid = controller + i.toString();
-		if (!Ext.isDefined(me.vmconfig[confid])) {
-		    deviceid.setValue(i);
-		    return false; // break
-		}
-	    }
-	});
-	deviceid.validate();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    fieldLabel: gettext('Bus/Device'),
-	    layout: 'hbox',
-	    defaults: {
-                hideLabel: true
-	    },
-	    items: [
-		{
-		    xtype: 'pveBusSelector',
-		    name: 'controller',
-		    value: PVE.qemu.OSDefaults.generic.busType,
-		    noVirtIO: me.noVirtIO,
-		    allowBlank: false,
-		    flex: 2,
-		    listeners: {
-			change: function(t, value) {
-			    if (!value) {
-				return;
-			    }
-			    var field = me.down('field[name=deviceid]');
-			    field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
-			    field.validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'deviceid',
-		    minValue: 0,
-		    maxValue: PVE.form.ControllerSelector.maxIds.ide,
-		    value: '0',
-		    flex: 1,
-		    allowBlank: false,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.rendered) {
-			    return;
-			}
-			var field = me.down('field[name=controller]');
-			var controller = field.getValue();
-			var confid = controller + value;
-			if (Ext.isDefined(me.vmconfig[confid])) {
-			    return "This device is already in use.";
-			}
-			return true;
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
-/*global Proxmox*/
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    view.store.on('load', this.onLoad, view);
-	},
-
-	onLoad: function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-	    var me = this;
-	    var val = me.getValue();
-	    if (!val || !me.store.findRecord('realm', val)) {
-		var def = 'pam';
-		Ext.each(records, function(rec) {
-		    if (rec.data && rec.data['default']) {
-			def = rec.data.realm;
-		    }
-		});
-		me.setValue(def);
-	    }
-	}
-    },
-
-    fieldLabel: gettext('Realm'),
-    name: 'realm',
-    queryMode: 'local',
-    allowBlank: false,
-    editable: false,
-    forceSelection: true,
-    autoSelect: false,
-    triggerAction: 'all',
-    valueField: 'realm',
-    displayField: 'descr',
-    getState: function() {
-	return { value: this.getValue() };
-    },
-    applyState : function(state) {
-	if (state && state.value) {
-	    this.setValue(state.value);
-	}
-    },
-    stateEvents: [ 'select' ],
-    stateful: true, // last chosen auth realm is saved between page reloads
-    id: 'pveloginrealm', // We need stable ids when using stateful, not autogenerated
-    stateID: 'pveloginrealm',
-
-    needOTP: function(realm) {
-	var me = this;
-	// use exact match
-	var rec = me.store.findRecord('realm', realm, 0, false, false, true);
-	return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    store: {
-	model: 'pve-domains',
-	autoLoad: true
-    }
-});
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    editable: false,
-    allowBlank: false,
-    forceSelection: true,
-    autoSelect: false,
-    valueField: 'key',
-    displayField: 'value',
-    hideLabel: true,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	var default_views = {
-	    server: {
-		text: gettext('Server View'),
-		groups: ['node']
-	    },
-	    folder: {
-		text: gettext('Folder View'),
-		groups: ['type']
-	    },
-	    storage: {
-		text: gettext('Storage View'),
-		groups: ['node'],
-		filterfn: function(node) {
-		    return node.data.type === 'storage' || node.data.type === 'node';
-		}
-	    },
-	    pool: { 
-		text: gettext('Pool View'), 
-		groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-			node.data.type === 'pool';
-                }
-	    }
-	};
-
-	var groupdef = [];
-	Ext.Object.each(default_views, function(viewname, value) {
-	    groupdef.push([viewname, value.text]);
-	});
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-            proxy: {
-		type: 'memory',
-		reader: 'array'
-            },
-	    data: groupdef,
-	    autoload: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    value: groupdef[0][0],
-	    getViewFilter: function() {
-		var view = me.getValue();
-		return Ext.apply({ id: view }, default_views[view] || default_views.server);
-	    },
-
-	    getState: function() {
-		return { value: me.getValue() };
-	    },
-
-	    applyState : function(state, doSelect) {
-		var view = me.getValue();
-		if (state && state.value && (view != state.value)) {
-		    var record = store.findRecord('key', state.value);
-		    if (record) {
-			me.setValue(state.value, true);
-			if (doSelect) {
-			    me.fireEvent('select', me, [record]);
-			}
-		    }
-		}
-	    },
-	    stateEvents: [ 'select' ],
-	    stateful: true,
-	    stateId: 'pveview',
-	    id: 'view'
-	});
-
-	me.callParent();
-
-	var statechange = function(sp, key, value) {
-	    if (key === me.id) {
-		me.applyState(value, true);
-	    }
-	};
-
-	var sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', statechange, me);
-    }
-});
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveNodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // do not allow those nodes (array)
-    disallowedNodes: undefined,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'node',
-    displayField: 'node',
-    store: {
-	    fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes'
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		},
-		{
-		    property : 'mem',
-		    direction: 'DESC'
-		}
-	    ]
-	},
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node',
-		sortable: true,
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Memory usage') + " %",
-		renderer: PVE.Utils.render_mem_usage_percent,
-		sortable: true,
-		width: 100,
-		dataIndex: 'mem'
-	    },
-	    {
-		header: gettext('CPU usage'),
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100,
-		dataIndex: 'cpu'
-	    }
-	]
-    },
-
-    validator: function(value) {
-	/*jslint confusion: true */
-	var me = this;
-	if (!me.onlineValidator || (me.allowBlank && !value)) {
-	    return true;
-	}
-
-	var offline = [];
-	var notAllowed = [];
-
-	Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-	    var rec = me.store.findRecord(me.valueField, node);
-	    if (!(rec && rec.data) || !Ext.isNumeric(rec.data.mem)) {
-		offline.push(node);
-	    } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-		notAllowed.push(node);
-	    }
-	});
-
-	if (value && notAllowed.length !== 0) {
-	    return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-	}
-
-	if (value && offline.length !== 0) {
-	    return "Node " + offline.join(', ') + " seems to be offline!";
-	}
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-        me.getStore().load();
-
-	// filter out disallowed nodes
-	me.getStore().addFilter(new Ext.util.Filter({
-	    filterFn: function(item) {
-		if (Ext.isArray(me.disallowedNodes)) {
-		    return !Ext.Array.contains(me.disallowedNodes, item.data.node);
-		} else {
-		    return true;
-		}
-	    }
-	}));
-
-	me.mon(me.getStore(), 'load', function(){
-	    me.isValid();
-	});
-    }
-});
-Ext.define('PVE.form.FileSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFileSelector',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    listeners: {
-	afterrender: function() {
-	    var me = this;
-	    if (!me.disabled) {
-		me.setStorage(me.storage, me.nodename);
-	    }
-	}
-    },
-
-    setStorage: function(storage, nodename) {
-	var me = this;
-
-	var change = false;
-	if (storage && (me.storage !== storage)) {
-	    me.storage = storage;
-	    change = true;
-	}
-
-	if (nodename && (me.nodename !== nodename)) {
-	    me.nodename = nodename;
-	    change = true;
-	}
-
-	if (!(me.storage && me.nodename && change)) {
-	    return;
-	}
-
-	var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-	if (me.storageContent) {
-	    url += '?content=' + me.storageContent;
-	}
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url
-	});
-
-	me.store.removeAll();
-	me.store.load();
-    },
-
-    setNodename: function(nodename) {
-	this.setStorage(undefined, nodename);
-    },
-
-    store: {
-	model: 'pve-storage-content'
-    },
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'volid',
-    displayField: 'text',
-
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'text',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Format'),
-		width: 60,
-		dataIndex: 'format'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 100,
-		dataIndex: 'size',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveStorageSelector',
-
-    allowBlank: false,
-    valueField: 'storage',
-    displayField: 'storage',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'storage',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Type'),
-		width: 60,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Avail'),
-		width: 80,
-		dataIndex: 'avail',
-		renderer: Proxmox.Utils.format_size
-	    },
-	    {
-		header: gettext('Capacity'),
-		width: 80,
-		dataIndex: 'total',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    },
-
-    reloadStorageList: function() {
-	var me = this;
-	if (!me.nodename) {
-	    return;
-	}
-
-	var params = {
-	    format: 1
-	};
-	var url = '/api2/json/nodes/' + me.nodename + '/storage';
-	if (me.storageContent) {
-	    params.content = me.storageContent;
-	}
-	if (me.targetNode) {
-	    params.target = me.targetNode;
-	    params.enabled = 1; // skip disabled storages
-	}
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url,
-	    extraParams: params
-	});
-
-	me.store.load();
- 
-    },
-
-    setTargetNode: function(targetNode) {
-	var me = this;
-
-	if (!targetNode || (me.targetNode === targetNode)) {
-	    return;
-	}
-
-	me.targetNode = targetNode;
-
-	me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.reloadStorageList();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-status',
-	    sorters: {
-		property: 'storage', 
-		order: 'DESC' 
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	if (nodename) {
-	    me.setNodename(nodename);
-	}
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-	idProperty: 'storage'
-    });
-
-});
-Ext.define('PVE.form.DiskStorageSelector', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveDiskStorageSelector',
-
-    layout: 'fit',
-    defaults: {
-	margin: '0 0 5 0'
-    },
-
-    // the fieldLabel for the storageselector
-    storageLabel: gettext('Storage'),
-
-    // the content to show (e.g., images or rootdir)
-    storageContent: undefined,
-
-    // if true, selects the first available storage
-    autoSelect: false,
-
-    allowBlank: false,
-    emptyText: '',
-
-    // hides the selection field
-    // this is always hidden on creation,
-    // and only shown when the storage needs a selection and
-    // hideSelection is not true
-    hideSelection: undefined,
-
-    // hides the size field (e.g, for the efi disk dialog)
-    hideSize: false,
-
-    // sets the intial size value
-    // string because else we get a type confusion
-    defaultSize: '32',
-
-    changeStorage: function(f, value) {
-	var me = this;
-	var formatsel = me.getComponent('diskformat');
-	var hdfilesel = me.getComponent('hdimage');
-	var hdsizesel = me.getComponent('disksize');
-
-	// initial store load, and reset/deletion of the storage
-	if (!value) {
-	    hdfilesel.setDisabled(true);
-	    hdfilesel.setVisible(false);
-
-	    formatsel.setDisabled(true);
-	    return;
-	}
-
-	var rec = f.store.getById(value);
-	// if the storage is not defined, or valid,
-	// we cannot know what to enable/disable
-	if (!rec) {
-	    return;
-	}
-
-	var selectformat = false;
-	if (rec.data.format) {
-	    var format = rec.data.format[0]; // 0 is the formats, 1 the default in the backend
-	    delete format.subvol; // we never need subvol in the gui
-	    selectformat = (Ext.Object.getSize(format) > 1);
-	}
-
-	var select = !!rec.data.select_existing && !me.hideSelection;
-
-	formatsel.setDisabled(!selectformat);
-	formatsel.setValue(selectformat ? 'qcow2' : 'raw');
-
-	hdfilesel.setDisabled(!select);
-	hdfilesel.setVisible(select);
-	if (select) {
-	    hdfilesel.setStorage(value);
-	}
-
-	hdsizesel.setDisabled(select || me.hideSize);
-	hdsizesel.setVisible(!select && !me.hideSize);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-	var hdfilesel = me.getComponent('hdimage');
-
-	hdstorage.setNodename(nodename);
-	hdfilesel.setNodename(nodename);
-    },
-
-    setDisabled: function(value) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-
-	// reset on disable
-	if (value) {
-	    hdstorage.setValue();
-	}
-	hdstorage.setDisabled(value);
-
-	// disabling does not always fire this event and we do not need
-	// the value of the validity
-	hdstorage.fireEvent('validitychange');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'pveStorageSelector',
-		itemId: 'hdstorage',
-		name: 'hdstorage',
-		reference: 'hdstorage',
-		fieldLabel: me.storageLabel,
-		nodename: me.nodename,
-		storageContent: me.storageContent,
-		disabled: me.disabled,
-		autoSelect: me.autoSelect,
-		allowBlank: me.allowBlank,
-		emptyText: me.emptyText,
-		listeners: {
-		    change: {
-			fn: me.changeStorage,
-			scope: me
-		    }
-		}
-	    },
-	    {
-		xtype: 'pveFileSelector',
-		name: 'hdimage',
-		reference: 'hdimage',
-		itemId: 'hdimage',
-		fieldLabel: gettext('Disk image'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: true
-	    },
-	    {
-		xtype: 'numberfield',
-		itemId: 'disksize',
-		reference: 'disksize',
-		name: 'disksize',
-		fieldLabel: gettext('Disk size') + ' (GiB)',
-		hidden: me.hideSize,
-		disabled: me.hideSize,
-		minValue: 0.001,
-		maxValue: 128*1024,
-		decimalPrecision: 3,
-		value: me.defaultSize,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveDiskFormatSelector',
-		itemId: 'diskformat',
-		reference: 'diskformat',
-		name: 'diskformat',
-		fieldLabel: gettext('Format'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: me.storageContent === 'rootdir',
-		value: 'qcow2',
-		allowBlank: false
-	    }
-	];
-
-	// use it to disable the children but not ourself
-	me.disabled = false;
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    store: {
-	fields: [ 'iface', 'active', 'type' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	]
-    },
-    valueField: 'iface',
-    displayField: 'iface',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Bridge'),
-		dataIndex: 'iface',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Active'),
-		width: 60,
-		dataIndex: 'active',
-		renderer: Proxmox.Utils.format_boolean
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comments',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-		me.bridgeType
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-        me.callParent();
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.PCISelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pvePCISelector',
-
-    store: {
-	fields: [ 'id','vendor_name', 'device_name', 'vendor', 'device', 'iommugroup', 'mdev' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'id',
-		direction: 'ASC'
-	    }
-	]
-    },
-
-    autoSelect: false,
-    valueField: 'id',
-    displayField: 'id',
-
-    // can contain a load callback for the store
-    // useful to determine the state of the IOMMU
-    onLoadCallBack: undefined,
-
-    listConfig: {
-	width: 800,
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'id',
-		width: 80
-	    },
-	    {
-		header: gettext('IOMMU Group'),
-		dataIndex: 'iommugroup',
-		width: 50
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor_name',
-		flex: 2
-	    },
-	    {
-		header: gettext('Device'),
-		dataIndex: 'device_name',
-		flex: 6
-	    },
-	    {
-		header: gettext('Mediated Devices'),
-		dataIndex: 'mdev',
-		flex: 1,
-		renderer: function(val) {
-		    return Proxmox.Utils.format_boolean(!!val);
-		}
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined;
-
-        me.callParent();
-
-	if (me.onLoadCallBack !== undefined) {
-	    me.mon(me.getStore(), 'load', me.onLoadCallBack);
-	}
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.MDevSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveMDevSelector',
-
-    store: {
-	fields: [ 'type','available', 'description' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'type',
-		direction: 'ASC'
-	    }
-	]
-    },
-    autoSelect: false,
-    valueField: 'type',
-    displayField: 'type',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		flex: 1
-	    },
-	    {
-		header: gettext('Available'),
-		dataIndex: 'available',
-		width: 80
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'description',
-		flex: 1,
-		renderer: function(value) {
-		    if (!value) {
-			return '';
-		    }
-
-		    return value.split('\n').join('<br>');
-		}
-	    }
-	]
-    },
-
-    setPciID: function(pciid, force) {
-	var me = this;
-
-	if (!force && (!pciid || (me.pciid === pciid))) {
-	    return;
-	}
-
-	me.pciid = pciid;
-	me.updateProxy();
-    },
-
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-	me.updateProxy();
-    },
-
-    updateProxy: function() {
-	var me = this;
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci/' + me.pciid + '/mdev'
-	});
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no node name specified';
-	}
-
-        me.callParent();
-
-	if (me.pciid) {
-	    me.setPciID(me.pciid, true);
-	}
-    }
-});
-
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    valueField: 'group',
-    displayField: 'group',
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'group', 'comment' ],
-	    idProperty: 'group',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/groups"
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Security Group'),
-			dataIndex: 'group',
-			hideable: false,
-			width: 100
-		    },
-		    {
-			header: gettext('Comment'),  
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    valueField: 'ref',
-    displayField: 'ref',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-
-	var url = "/api2/json" + me.base_url;
-	if (me.ref_type) {
-	    url += "?type=" + me.ref_type;
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'type', 'name', 'ref', 'comment' ],
-	    idProperty: 'ref',
-	    proxy: {
-		type: 'proxmox',
-		url: url
-	    },
-	    sorters: {
-		property: 'ref',
-		order: 'DESC'
-	    }
-	});
-
-	var disable_query_for_ips = function(f, value) {
-	    if (value === null || 
-		value.match(/^\d/)) { // IP address starts with \d
-		f.queryDelay = 9999999999; // hack: disbale with long delay
-	    } else {
-		f.queryDelay = 10;
-	    }
-	};
-
-	var columns = [];
-
-	if (!me.ref_type) {
-	    columns.push({
-		header: gettext('Type'),
-		dataIndex: 'type',
-		hideable: false,
-		width: 60
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Name'),
-		dataIndex: 'ref',
-		hideable: false,
-		width: 140
-	    },
-	    {
-		header: gettext('Comment'),  
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: { columns: columns }
-	});
-
-	me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-    valueField: 'p',
-    displayField: 'p',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'p',
-		hideable: false,
-		sortable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Number'),
-		dataIndex: 'n',
-		hideable: false,
-		sortable: false,
-		width: 50
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'd',
-		hideable: false,
-		sortable: false,
-		flex: 1
-	    }
-	]
-    },
-    store: {
-	    fields: [ 'p', 'd', 'n'],
-	    data: [
-		{ p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-		{ p: 'udp', n: 17, d: 'User Datagram Protocol' },
-		{ p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-		{ p: 'igmp', n: 2,  d: 'Internet Group Management' },
-		{ p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-		{ p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-		{ p: 'st', n: 5, d: 'ST datagram mode' },
-		{ p: 'egp', n: 8, d: 'exterior gateway protocol' },
-		{ p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-		{ p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-		{ p: 'hmp', n: 20, d: 'host monitoring protocol' },
-		{ p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-		{ p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-		{ p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-		{ p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-		{ p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-		{ p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-		{ p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-		{ p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-		{ p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-		{ p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-		{ p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-		{ p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-		{ p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-		{ p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-		{ p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-		{ p: 'skip', n: 57, d: 'SKIP' },
-		{ p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-		{ p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-		{ p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-		{ p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-		{ p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-		{ p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-		{ p: 'ax.25', n: 93, d: 'AX.25 frames' },
-		{ p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-		{ p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-		{ p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-		{ p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-		{ p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-		{ p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-		{ p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-		{ p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-		{ p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-		{ p: 'fc', n: 133, d: 'Fibre Channel' },
-		{ p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-		{ p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-		{ p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-		{ p: 'hip', n: 139, d: 'Host Identity Protocol' },
-		{ p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-		{ p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-		{ p: 'rohc', n: 142, d: 'Robust Header Compression' }
-	    ]
-	}
-});
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CPUModelSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + ' (kvm64)'],
-	['486', '486'],
-	['athlon', 'athlon'],
-	['core2duo', 'core2duo'],
-	['coreduo', 'coreduo'],
-	['kvm32', 'kvm32'],
-	['kvm64', 'kvm64'],
-	['pentium', 'pentium'],
-	['pentium2', 'pentium2'],
-	['pentium3', 'pentium3'],
-	['phenom', 'phenom'],
-	['qemu32', 'qemu32'],
-	['qemu64', 'qemu64'],
-	['Conroe', 'Conroe'],
-	['Penryn', 'Penryn'],
-	['Nehalem', 'Nehalem'],
-	['Westmere', 'Westmere'],
-	['SandyBridge', 'SandyBridge'],
-	['IvyBridge', 'IvyBridge'],
-	['Haswell', 'Haswell'],
-	['Haswell-noTSX','Haswell-noTSX'],
-	['Broadwell', 'Broadwell'],
-	['Broadwell-noTSX','Broadwell-noTSX'],
-	['Skylake-Client','Skylake-Client'],
-	['Opteron_G1', 'Opteron_G1'],
-	['Opteron_G2', 'Opteron_G2'],
-	['Opteron_G3', 'Opteron_G3'],
-	['Opteron_G4', 'Opteron_G4'],
-	['Opteron_G5', 'Opteron_G5'],
-	['EPYC', 'EPYC'],
-	['host', 'host']
-
-    ]
-});
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + " (" + gettext('No cache') + ")"],
-	['directsync', 'Direct sync'],
-	['writethrough', 'Write through'],
-	['writeback', 'Write back'],
-	['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-	['none', gettext('No cache')]
-    ]
-});
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    valueField: 'name',
-    displayField: 'name',
-
-    loadStore: function(nodename, vmid) {
-	var me = this;
-
-	if (!nodename) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-        if (!vmid) {
-	    return;
-        }
-
-	me.vmid = vmid;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid +'/snapshot'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-	if (!me.guestType) {
-	    throw "no guest type specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'name'],
-	    filterOnLoad: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Snapshot'),
-			dataIndex: 'name',
-			hideable: false,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	me.loadStore(me.nodename, me.vmid);
-    }
-});
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-
-    cts: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [];
-
-	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'snippets'];
-	}
-
-	Ext.Array.each(me.cts, function(ct) {
-	    me.comboItems.push([ct, PVE.Utils.format_content_types(ct)]);
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'Ext.form.CheckboxGroup',
-    alias: 'widget.pveHotplugFeatureSelector',
-
-    columns: 1,
-    vertical: true,
-
-    defaults: {
-	name: 'hotplug',
-	submitValue: false
-    },
-    items: [
-	{
-	    boxLabel: gettext('Disk'),
-	    inputValue: 'disk',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Network'),
-	    inputValue: 'network',
-	    checked: true
-	},
-	{
-	    boxLabel: 'USB',
-	    inputValue: 'usb',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Memory'),
-	    inputValue: 'memory'
-	},
-	{
-	    boxLabel: gettext('CPU'),
-	    inputValue: 'cpu'
-	}
-    ],
-
-    setValue: function(value) {
-	var me = this;
-	var newVal = [];
-	if (value === '1') {
-	    newVal = ['disk', 'network', 'usb'];
-	} else if (value !== '0') {
-	    newVal = value.split(',');
-	}
-	me.callParent([{ hotplug: newVal }]);
-    },
-
-    // overide framework function to
-    // assemble the hotplug value
-    getSubmitData: function() {
-	var me = this,
-	boxes = me.getBoxes(),
-	data = [];
-	Ext.Array.forEach(boxes, function(box){
-	    if (box.getValue()) {
-		data.push(box.inputValue);
-	    }
-	});
-
-	/* because above is hotplug an array */
-	/*jslint confusion: true*/
-	if (data.length === 0) {
-	    return { 'hotplug':'0' };
-	} else {
-	    return { 'hotplug': data.join(',') };
-	}
-    }
-
-});
-Ext.define('PVE.form.AgentFeatureSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: ['widget.pveAgentFeatureSelector'],
-
-    initComponent: function() {
-	var me = this;
-	me.items= [
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Qemu Agent'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		listeners: {
-		    change: function(f, value, old) {
-			var gtcb = me.down('proxmoxcheckbox[name=fstrim_cloned_disks]');
-			if (value) {
-			    gtcb.setDisabled(false);
-			} else {
-			    gtcb.setDisabled(true);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Run guest-trim after clone disk'),
-		name: 'fstrim_cloned_disks',
-		disabled: true
-	    }
-	];
-	me.callParent();
-    },
-
-    onGetValues: function(values) {
-	var agentstr = PVE.Parser.printPropertyString(values, 'enabled');
-	return { agent: agentstr };
-    },
-
-    setValues: function(values) {
-	var agent = values.agent || '';
-	var res = PVE.Parser.parsePropertyString(agent, 'enabled');
-	this.callParent([res]);
-    }
-});
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-    comboItems: [
-	['comstar', 'Comstar'],
-	[ 'istgt', 'istgt'],
-	[ 'iet', 'IET'],
-	[ 'LIO', 'LIO']
-    ]
-});
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems:[],
-    initComponent: function(){
-	var me = this;
-	me.comboItems = [
-	    ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-	    ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-	    ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-	    ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-	    ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-	    ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])],
-	    ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])]
-	];
-	this.callParent();
-    }
-});
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-    comboItems: [
-	['__default__', PVE.Utils.render_scsihw('')],
-	['lsi', PVE.Utils.render_scsihw('lsi')],
-	['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-	['megasas', PVE.Utils.render_scsihw('megasas')],
-	['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-	['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-	['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-    ]
-});
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-    comboItems: [
-	    ['ACCEPT', 'ACCEPT'],
-	    ['REJECT', 'REJECT'],
-	    [ 'DROP', 'DROP']
-	]
-});
-/*
- *  This is a global search field
- *  it loads the /cluster/resources on focus
- *  and displays the result in a floating grid
- *
- *  it filters and sorts the objects by the algorithm in
- *  the customFilter function
- *
- *  also it does accept key up/down and enter for input
- *  and it opens to ctrl+shift+f and ctrl+space
- */
-Ext.define('PVE.form.GlobalSearchField', {
-    extend: 'Ext.form.field.Text',
-    alias: 'widget.pveGlobalSearchField',
-
-    emptyText: gettext('Search'),
-    enableKeyEvents: true,
-    selectOnFocus: true,
-    padding: '0 5 0 5',
-
-    grid: {
-	xtype: 'gridpanel',
-	focusOnToFront: false,
-	floating: true,
-	emptyText: Proxmox.Utils.noneText,
-	width: 600,
-	height: 400,
-	scrollable: {
-	    xtype: 'scroller',
-	    y: true,
-	    x:false
-	},
-	store: {
-	    model: 'PVEResources',
-	    proxy:{
-		type: 'proxmox',
-		url: '/api2/extjs/cluster/resources'
-	    }
-	},
-	plugins: {
-	    ptype: 'bufferedrenderer',
-	    trailingBufferZone: 20,
-	    leadingBufferZone: 20
-	},
-
-	hideMe: function() {
-	    var me = this;
-	    if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
-		return;
-	    }
-	    me.hasFocus = false;
-	    if (!me.textfield.hasFocus) {
-		me.hide();
-	    }
-	},
-
-	setFocus: function() {
-	    var me = this;
-	    me.hasFocus = true;
-	},
-
-	listeners: {
-	    rowclick: function(grid, record) {
-		var me = this;
-		me.textfield.selectAndHide(record.id);
-	    },
-	    itemcontextmenu: function(v, record, item, index, event) {
-		var me = this;
-		me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
-	    },
-	    /* because of lint */
-	    focusleave: {
-		fn: 'hideMe'
-	    },
-	    focusenter: 'setFocus'
-	},
-
-	columns: [
-	    {
-		text: gettext('Type'),
-		dataIndex: 'type',
-		width: 100,
-		renderer: PVE.Utils.render_resource_type
-	    },
-	    {
-		text: gettext('Description'),
-		flex: 1,
-		dataIndex: 'text'
-	    },
-	    {
-		text: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		text: gettext('Pool'),
-		dataIndex: 'pool'
-	    }
-	]
-    },
-
-    customFilter: function(item) {
-	var me = this;
-	var match = 0;
-	var fieldArr = [];
-	var i,j, fields;
-
-	// different types of objects have different fields to search
-	// for example, a node will never have a pool and vice versa
-	switch (item.data.type) {
-	    case 'pool': fieldArr = ['type', 'pool', 'text']; break;
-	    case 'node': fieldArr = ['type', 'node', 'text']; break;
-	    case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
-	    default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
-	}
-	if (me.filterVal === '') {
-	    item.data.relevance = 0;
-	    return true;
-	}
-
-	// all text is case insensitive and each word is
-	// searched alone
-	// for every partial match, the row gets
-	// 1 match point, for every exact match
-	// it gets 2 points
-	//
-	// results gets sorted by points (descending)
-	fields = me.filterVal.split(/\s+/);
-	for(i = 0; i < fieldArr.length; i++) {
-	    var v = item.data[fieldArr[i]];
-	    if (v !== undefined) {
-		v = v.toString().toLowerCase();
-		for(j = 0; j < fields.length; j++) {
-		    if (v.indexOf(fields[j]) !== -1) {
-			match++;
-			if(v === fields[j]) {
-			    match++;
-			}
-		    }
-		}
-	    }
-	}
-	// give the row the 'relevance' value
-	item.data.relevance = match;
-	return (match > 0);
-    },
-
-    updateFilter: function(field, newValue, oldValue) {
-	var me = this;
-	// parse input and filter store,
-	// show grid
-	me.grid.store.filterVal = newValue.toLowerCase().trim();
-	me.grid.store.clearFilter(true);
-	me.grid.store.filterBy(me.customFilter);
-	me.grid.getSelectionModel().select(0);
-    },
-
-    selectAndHide: function(id) {
-	var me = this;
-	me.tree.selectById(id);
-	me.grid.hide();
-	me.setValue('');
-	me.blur();
-    },
-
-    onKey: function(field, e) {
-	var me = this;
-	var key = e.getKey();
-
-	switch(key) {
-	    case Ext.event.Event.ENTER:
-		// go to first entry if there is one
-		if (me.grid.store.getCount() > 0) {
-		    me.selectAndHide(me.grid.getSelection()[0].data.id);
-		}
-		break;
-	    case Ext.event.Event.UP:
-		me.grid.getSelectionModel().selectPrevious();
-		break;
-	    case Ext.event.Event.DOWN:
-		me.grid.getSelectionModel().selectNext();
-		break;
-	    case Ext.event.Event.ESC:
-		me.grid.hide();
-		me.blur();
-		break;
-	}
-    },
-
-    loadValues: function(field) {
-	var me = this;
-	var records = [];
-
-	me.hasFocus = true;
-	me.grid.textfield = me;
-	me.grid.store.load();
-	me.grid.showBy(me, 'tl-bl');
-    },
-
-    hideGrid: function() {
-	var me = this;
-
-	me.hasFocus = false;
-	if (!me.grid.hasFocus) {
-	    me.grid.hide();
-	}
-    },
-
-    listeners: {
-	change: {
-	    fn: 'updateFilter',
-	    buffer: 250
-	},
-	specialkey: 'onKey',
-	focusenter: 'loadValues',
-	focusleave: {
-	    fn: 'hideGrid',
-	    delay: 100
-	}
-    },
-
-    toggleFocus: function() {
-	var me = this;
-	if (!me.hasFocus) {
-	    me.focus();
-	} else {
-	    me.blur();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.tree) {
-	    throw "no tree given";
-	}
-
-	me.grid = Ext.create(me.grid);
-
-	me.callParent();
-
-	/*jslint confusion: true*/
-	/*because shift is also a function*/
-	// bind ctrl+shift+f and ctrl+space
-	// to open/close the search
-	me.keymap = new Ext.KeyMap({
-	    target: Ext.get(document),
-	    binding: [{
-		key:'F',
-		ctrl: true,
-		shift: true,
-		fn: me.toggleFocus,
-		scope: me
-	    },{
-		key:' ',
-		ctrl: true,
-		fn: me.toggleFocus,
-		scope: me
-	    }]
-	});
-
-	// always select first item and
-	// sort by relevance after load
-	me.mon(me.grid.store, 'load', function() {
-	    me.grid.getSelectionModel().select(0);
-	    me.grid.store.sort({
-		property: 'relevance',
-		direction: 'DESC'
-	    });
-	});
-    }
-
-});
-Ext.define('PVE.form.QemuBiosSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveQemuBiosSelector'],
-
-    initComponent: function() {
-	var me = this;
-
-        me.comboItems = [
-	    ['__default__', PVE.Utils.render_qemu_bios('')],
-	    ['seabios', PVE.Utils.render_qemu_bios('seabios')],
-	    ['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-/* filter is a javascript builtin, but extjs calls it also filter */
-Ext.define('PVE.form.VMSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    allowBlank: true,
-    selectAll: false,
-    isFormField: true,
-
-    plugins: 'gridfilters',
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-    columns: [
-	{
-	    header: 'ID',
-	    dataIndex: 'vmid',
-	    width: 80,
-	    filter: {
-		type: 'number'
-	    }
-	},
-	{
-	    header: gettext('Node'),
-	    dataIndex: 'node'
-	},
-	{
-	    header: gettext('Status'),
-	    dataIndex: 'status',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1,
-	    filter: {
-		type: 'string'
-	    }
-	},
-	{
-	    header: gettext('Pool'),
-	    dataIndex: 'pool',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Type'),
-	    dataIndex: 'type',
-	    width: 120,
-	    renderer: function(value) {
-		if (value === 'qemu') {
-		    return gettext('Virtual Machine');
-		} else if (value === 'lxc') {
-		    return gettext('LXC Container');
-		}
-
-		return '';
-	    },
-	    filter: {
-		type: 'list',
-		store: {
-		    data: [
-			{id: 'qemu', text: gettext('Virtual Machine')},
-			{id: 'lxc', text: gettext('LXC Container')}
-		    ],
-		    // due to EXTJS-18711
-		    // we have to do a static list via a store
-		    // but to avoid creating an object,
-		    // we have to have a pseudo un function
-		    un: function(){}
-		}
-	    }
-	},
-	{
-	    header: 'HA ' + gettext('Status'),
-	    dataIndex: 'hastate',
-	    flex: 1,
-	    filter: {
-		type: 'list'
-	    }
-	}
-    ],
-
-    selModel: {
-	selType: 'checkboxmodel',
-	mode: 'SIMPLE'
-    },
-
-    checkChangeEvents: [
-	'selectionchange',
-	'change'
-    ],
-
-    listeners: {
-	selectionchange: function() {
-	    // to trigger validity and error checks
-	    this.checkChange();
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	var selection = sm.getSelection();
-	var values = [];
-	var store = me.getStore();
-	selection.forEach(function(item) {
-	    // only add if not filtered
-	    if (store.findExact('vmid', item.data.vmid) !== -1) {
-		values.push(item.data.vmid);
-	    }
-	});
-	return values;
-    },
-
-    setValue: function(value) {
-	console.log(value);
-	var me = this;
-	var sm = me.getSelectionModel();
-	if (!Ext.isArray(value)) {
-	    value = value.split(',');
-	}
-	var selection = [];
-	var store = me.getStore();
-
-	value.forEach(function(item) {
-	    var rec = store.findRecord('vmid',item, 0, false, true, true);
-	    console.log(store);
-
-	    if (rec) {
-		console.log(rec);
-		selection.push(rec);
-	    }
-	});
-
-	sm.select(selection);
-
-	return me.mixins.field.setValue.call(me, value);
-    },
-
-    getErrors: function(value) {
-	var me = this;
-	if (me.allowBlank ===  false &&
-	    me.getSelectionModel().getCount() === 0) {
-	    me.addBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	    return [gettext('No VM selected')];
-	}
-
-	me.removeBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	return [];
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.nodename) {
-	    me.store.filters.add({
-		property: 'node',
-		exactMatch: true,
-		value: me.nodename
-	    });
-	}
-
-	// only show the relevant guests by default
-	if (me.action) {
-	    var statusfilter = '';
-	    switch (me.action) {
-		case 'startall':
-		    statusfilter = 'stopped';
-		    break;
-		case 'stopall':
-		    statusfilter = 'running';
-		    break;
-	    }
-	    if (statusfilter !== '') {
-		me.store.filters.add({
-		    property: 'template',
-		    value: 0
-		},{
-		    id: 'x-gridfilter-status',
-		    operator: 'in',
-		    property: 'status',
-		    value: [statusfilter]
-		});
-	    }
-	}
-
-	var store = me.getStore();
-	var sm = me.getSelectionModel();
-
-	if (me.selectAll) {
-	    me.mon(store,'load', function(){
-		me.getSelectionModel().selectAll(false);
-	    });
-	}
-    }
-});
-
-
-Ext.define('PVE.form.VMComboSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.vmComboSelector',
-
-    valueField: 'vmid',
-    displayField: 'vmid',
-
-    autoSelect: false,
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-
-    listConfig: {
-	width: 600,
-	plugins: 'gridfilters',
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'vmid',
-		width: 80,
-		filter: {
-		    type: 'number'
-		}
-	    },
-	    {
-		header: gettext('Name'),
-		dataIndex: 'name',
-		flex: 1,
-		filter: {
-		    type: 'string'
-		}
-	    },
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		header: gettext('Status'),
-		dataIndex: 'status',
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Pool'),
-		dataIndex: 'pool',
-		hidden: true,
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		width: 120,
-		renderer: function(value) {
-		    if (value === 'qemu') {
-			return gettext('Virtual Machine');
-		    } else if (value === 'lxc') {
-			return gettext('LXC Container');
-		    }
-
-		    return '';
-		},
-		filter: {
-		    type: 'list',
-		    store: {
-			data: [
-			    {id: 'qemu', text: gettext('Virtual Machine')},
-			    {id: 'lxc', text: gettext('LXC Container')}
-			],
-			un: function(){} // due to EXTJS-18711
-		    }
-		}
-	    },
-	    {
-		header: 'HA ' + gettext('Status'),
-		dataIndex: 'hastate',
-		hidden: true,
-		flex: 1,
-		filter: {
-		    type: 'list'
-		}
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.USBSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUSBSelector'],
-    allowBlank: false,
-    autoSelect: false,
-    displayField: 'usbid',
-    valueField: 'usbid',
-    editable: true,
-
-    getUSBValue: function() {
-	var me = this;
-	var rec = me.store.findRecord('usbid', me.value);
-	var val = 'host='+ me.value;
-	if (rec && rec.data.speed === "5000") {
-	    val = 'host=' + me.value + ",usb3=1";
-	}
-	return val;
-    },
-
-    validator: function(value) {
-	var me = this;
-	if (me.type === 'device') {
-	    return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
-	} else if (me.type === 'port') {
-	    return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
-	}
-	return false;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (me.type !== 'device' && me.type !== 'port') {
-	    throw "no valid type specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-usb-' + me.type,
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/scan/usb"
-	    },
-	    filters: [
-		function (item) {
-		    return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: (me.type === 'device')?gettext('Device'):gettext('Port'),
-			sortable: true,
-			dataIndex: 'usbid',
-			width: 80
-		    },
-		    {
-			header: gettext('Manufacturer'),
-			sortable: true,
-			dataIndex: 'manufacturer',
-			width: 100
-		    },
-		    {
-			header: gettext('Product'),
-			sortable: true,
-			dataIndex: 'product',
-			flex: 1
-		    },
-		    {
-			header: gettext('Speed'),
-			width: 70,
-			sortable: true,
-			dataIndex: 'speed',
-			renderer: function(value) {
-			    if (value === "5000") {
-				return "USB 3.0";
-			    } else if (value === "480") {
-				return "USB 2.0";
-			    } else {
-				return "USB 1.x";
-			    }
-			}
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-usb-device', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val, data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('vendid') + ':' + data.get('prodid');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-
-    Ext.define('pve-usb-port', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val,data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('busnum') + '-' + data.get('usbpath');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-});
-Ext.define('PVE.form.CalendarEvent', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pveCalendarEvent',
-
-    editable: true,
-
-    valueField: 'value',
-    displayField: 'text',
-    queryMode: 'local',
-
-    store: {
-	field: [ 'value', 'text'],
-	data: [
-	    { value: '*/30', text: Ext.String.format(gettext("Every {0} minutes"), 30) },
-	    { value: '*/2:00', text: gettext("Every two hours")},
-	    { value: '2,22:30', text: gettext("Every day") + " 02:30, 22:30"},
-	    { value: 'mon..fri', text: gettext("Monday to Friday") + " 00:00"},
-	    { value: 'mon..fri */1:00', text: gettext("Monday to Friday") + ': ' +  gettext("hourly")},
-	    { value: 'sun 01:00', text: gettext("Sunday") + " 01:00"}
-	]
-    },
-
-    tpl: [
-	'<ul class="x-list-plain"><tpl for=".">',
-	    '<li role="option" class="x-boundlist-item">{text}</li>',
-	'</tpl></ul>'
-    ],
-
-    displayTpl: [
-	'<tpl for=".">',
-	'{value}',
-	'</tpl>'
-    ]
-
-});
-Ext.define('PVE.form.CephPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephPoolSelector',
-
-    allowBlank: false,
-    valueField: 'pool_name',
-    displayField: 'pool_name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/pools'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.form.PermPathSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pvePermPathSelector',
-
-    valueField: 'value',
-    displayField: 'value',
-    typeAhead: true,
-    queryMode: 'local',
-    store: {
-	type: 'pvePermPath'
-    }
-});
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-	var me = this;
-
-	var taskstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-tasks',
-	    model: 'proxmox-tasks',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/tasks'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: taskstore,
-	    sortAfterUpdate: true,
-	    appendAtStart: true,
-	    sorters: [
-		{
-		    property : 'pid',
-		    direction: 'DESC'
-		},
-		{
-		    property : 'starttime',
-		    direction: 'DESC'
-		}
-	    ]
-
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 150,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type == "vncproxy" ||
-				record.data.type == "vncshell" ||
-				record.data.type == "spiceproxy") {
-				metaData.tdCls =  "x-grid-row-console";
-			    } else {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type != "vncproxy") {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return Proxmox.Utils.errorText + ': ' + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		show: taskstore.startUpdate,
-		destroy: taskstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-	var me = this;
-
-	var logstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-log',
-	    model: 'proxmox-cluster-log',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/log'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: logstore,
-	    appendAtStart: true 
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true,
- 
-		getRowClass: function(record, index) {
-		    var pri = record.get('pri');
-
-		    if (pri && pri <= 3) {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{ 
-		    header: gettext("Time"), 
-		    dataIndex: 'time',
-		    width: 150,
-		    renderer: function(value) { 
-			return Ext.Date.format(value, "M d H:i:s"); 
-		    }
-		},
-		{ 
-		    header: gettext("Node"), 
-		    dataIndex: 'node',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Service"), 
-		    dataIndex: 'tag',
-		    width: 100
-		},
-		{ 
-		    header: "PID", 
-		    dataIndex: 'pid',
-		    width: 100 
-		},
-		{ 
-		    header: gettext("User name"), 
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Severity"), 
-		    dataIndex: 'pri',
-		    renderer: PVE.Utils.render_serverity,
-		    width: 100 
-		},
-		{ 
-		    header: gettext("Message"), 
-		    dataIndex: 'msg',
-		    flex: 1	  
-		}
-	    ],
-	    listeners: {
-		activate: logstore.startUpdate,
-		deactivate: logstore.stopUpdate,
-		destroy: logstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = 'ltab';
-	var sp = Ext.state.Manager.getProvider();
-
-	var state = sp.get(stateid);
-	if (state && state.value) {
-	    me.activeTab = state.value;
-	}
-
-	Ext.apply(me, {
-	    listeners: {
-		tabchange: function() {
-		    var atab = me.getActiveTab().itemId;
-		    var state = { value: atab };
-		    sp.set(stateid, state);
-		}
-	    },
-	    items: [
-		{
-		    itemId: 'tasks',
-		    title: gettext('Tasks'),
-		    xtype: 'pveClusterTasks'
-		},
-		{
-		    itemId: 'clog',
-		    title: gettext('Cluster log'),
-		    xtype: 'pveClusterLog'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.items.get(0).fireEvent('show', me.items.get(0));
-
-	var statechange = function(sp, key, state) {
-	    if (key === stateid) {
-		var atab = me.getActiveTab().itemId;
-		var ntab = state.value;
-		if (state && ntab && (atab != ntab)) {
-		    me.setActiveTab(ntab);
-		}
-	    }
-	};
-
-	sp.on('statechange', statechange);
-	me.on('destroy', function() {
-	    sp.un('statechange', statechange);		    
-	});
-
-    }
-});
-Ext.define('PVE.panel.StatusView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStatusView',
-
-    layout: {
-	type: 'column'
-    },
-
-    title: gettext('Status'),
-
-    getRecordValue: function(key, store) {
-	if (!key) {
-	    throw "no key given";
-	}
-	var me = this;
-
-	if (store === undefined) {
-	    store = me.getStore();
-	}
-
-	var rec = store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-
-	return '';
-    },
-
-    fieldRenderer: function(val,max) {
-	if (max === undefined) {
-	    return val;
-	}
-
-	if (!Ext.isNumeric(max) || max === 1) {
-	    return PVE.Utils.render_usage(val);
-	}
-	return PVE.Utils.render_size_usage(val,max);
-    },
-
-    fieldCalculator: function(used, max) {
-	if (!Ext.isNumeric(max) && Ext.isNumeric(used)) {
-	    return used;
-	} else if(!Ext.isNumeric(used)) {
-	    /* we come here if the field is from a node
-	     * where the records are not mem and maxmem
-	     * but mem.used and mem.total
-	     */
-	    if (used.used !== undefined &&
-		used.total !== undefined) {
-		return used.used/used.total;
-	    }
-	}
-
-	return used/max;
-    },
-
-    updateField: function(field) {
-	var me = this;
-	var text = '';
-	var renderer = me.fieldRenderer;
-	if (Ext.isFunction(field.renderer)) {
-	    renderer = field.renderer;
-	}
-	if (field.multiField === true) {
-	    field.updateValue(renderer.call(field, me.getStore().getRecord()));
-	} else if (field.textField !== undefined) {
-	    field.updateValue(renderer.call(field, me.getRecordValue(field.textField)));
-	} else if(field.valueField !== undefined) {
-	    var used = me.getRecordValue(field.valueField);
-	    /*jslint confusion: true*/
-	    /* string and int */
-	    var max = field.maxField !== undefined ? me.getRecordValue(field.maxField) : 1;
-
-	    var calculate = me.fieldCalculator;
-
-	    if (Ext.isFunction(field.calculate)) {
-		calculate = field.calculate;
-	    }
-	    field.updateValue(renderer.call(field, used,max), calculate(used,max));
-	}
-    },
-
-    getStore: function() {
-	var me = this;
-	if (!me.rstore) {
-	    throw "there is no rstore";
-	}
-
-	return me.rstore;
-    },
-
-    updateTitle: function() {
-	var me = this;
-	me.setTitle(me.getRecordValue('name'));
-    },
-
-    updateValues: function(store, records, success) {
-	if (!success) {
-	    return; // do not update if store load was not successful
-	}
-	var me = this;
-	var itemsToUpdate = me.query('pveInfoWidget');
-
-	itemsToUpdate.forEach(me.updateField, me);
-
-	me.updateTitle(store);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	if (!me.title) {
-	    throw "no title given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', 'updateValues');
-    }
-
-});
-Ext.define('PVE.panel.GuestStatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveGuestStatusView',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    height: 300,
-
-    cbindData: function (initialConfig) {
-	var me = this;
-	return {
-	    isQemu: me.pveSelNode.data.type === 'qemu',
-	    isLxc: me.pveSelNode.data.type === 'lxc'
-	};
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'status',
-	    title: gettext('Status'),
-	    iconCls: 'fa fa-info fa-fw',
-	    printBar: false,
-	    multiField: true,
-	    renderer: function(record) {
-		var me = this;
-		var text = record.data.status;
-		var qmpstatus = record.data.qmpstatus;
-		if (qmpstatus && qmpstatus !== record.data.status) {
-		    text += ' (' + qmpstatus + ')';
-		}
-		return text;
-	    }
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    xtype: 'pveInfoWidget',
-	    itemId: 'node',
-	    iconCls: 'fa fa-building fa-fw',
-	    title: gettext('Node'),
-	    cbind: {
-		text: '{pveSelNode.data.node}'
-	    },
-	    printBar: false
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpus',
-	    renderer: PVE.Utils.render_cpu_usage,
-	    // in this specific api call
-	    // we already have the correct value for the usage
-	    calculate: Ext.identityFn
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory usage'),
-	    valueField: 'mem',
-	    maxField: 'maxmem'
-	},
-	{
-	    itemId: 'swap',
-	    xtype: 'pveInfoWidget',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'maxswap',
-	    cbind: {
-		hidden: '{isQemu}',
-		disabled: '{isQemu}'
-	    }
-	},
-	{
-	    itemId: 'rootfs',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    valueField: 'disk',
-	    maxField: 'maxdisk',
-	    printBar: false,
-	    renderer: function(used, max) {
-		var me = this;
-		me.setPrintBar(used > 0);
-		if (used === 0) {
-		    return PVE.Utils.render_size(max);
-		} else {
-		    return PVE.Utils.render_size_usage(used,max);
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'ips',
-	    xtype: 'pveAgentIPView',
-	    cbind: {
-		rstore: '{rstore}',
-		pveSelNode: '{pveSelNode}',
-		hidden: '{isLxc}',
-		disabled: '{isLxc}'
-	    }
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = me.getRecordValue('uptime');
-
-	var text = "";
-	if (Number(uptime) > 0) {
-	    text = " (" + gettext('Uptime') + ': ' + Proxmox.Utils.format_duration_long(uptime)
-		+ ')';
-	}
-
-	me.setTitle(me.getRecordValue('name') + text);
-    }
-});
-/*
- * This is a running chart widget
- * you add time datapoints to it,
- * and we only show the last x of it
- * used for ceph performance charts
- */
-Ext.define('PVE.widget.RunningChart', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveRunningChart',
-
-    layout: {
-	type: 'hbox',
-	align: 'center'
-    },
-    items: [
-	{
-	    width: 80,
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}:</h3>'
-	},
-	{
-	    flex: 1,
-	    xtype: 'cartesian',
-	    height: '100%',
-	    itemId: 'chart',
-	    border: false,
-	    axes: [
-		{
-		    type: 'numeric',
-		    position: 'left',
-		    hidden: true,
-		    minimum: 0
-		},
-		{
-		    type: 'numeric',
-		    position: 'bottom',
-		    hidden: true
-		}
-	    ],
-
-	    store: {
-		data: {}
-	    },
-
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '0 B/s',
-		textAlign: 'end',
-		textBaseline: 'middle',
-		fontSize: 14
-	    }],
-
-	    series: [{
-		type: 'line',
-		xField: 'time',
-		yField: 'val',
-		fill: 'true',
-		colors: ['#cfcfcf'],
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function( tooltip, record, ctx) {
-			var me = this.getChart();
-			var date = new Date(record.data.time);
-			var value = me.up().renderer(record.data.val);
-			tooltip.setHtml(
-			    me.up().title + ': ' + value + '<br />' +
-			    Ext.Date.format(date, 'H:i:s')
-			);
-		    }
-		},
-		style: {
-		    lineWidth: 1.5,
-		    opacity: 0.60
-		},
-		marker: {
-		    opacity: 0,
-		    scaling: 0.01,
-		    fx: {
-			duration: 200,
-			easing: 'easeOut'
-		    }
-		},
-		highlightCfg: {
-		    opacity: 1,
-		    scaling: 1.5
-		}
-	    }]
-	}
-    ],
-
-    // the renderer for the tooltip and last value,
-    // default just the value
-    renderer: Ext.identityFn,
-
-    // show the last x seconds
-    // default is 5 minutes
-    timeFrame: 5*60,
-
-    addDataPoint: function(value, time) {
-	var me = this.chart;
-	var panel = me.up();
-	var now = new Date();
-	var begin = new Date(now.getTime() - (1000*panel.timeFrame));
-
-	me.store.add({
-	    time: time || now.getTime(),
-	    val: value || 0
-	});
-
-	// delete all old records when we have 20 times more datapoints
-	// than seconds in our timeframe (so even a subsecond graph does
-	// not trigger this often)
-	//
-	// records in the store do not take much space, but like this,
-	// we prevent a memory leak when someone has the site open for a long time
-	// with minimal graphical glitches
-	if (me.store.count() > panel.timeFrame * 20) {
-	    var oldData = me.store.getData().createFiltered(function(item) {
-		return item.data.time < begin.getTime();
-	    });
-
-	    me.store.remove(oldData.getRange());
-	}
-
-	me.timeaxis.setMinimum(begin.getTime());
-	me.timeaxis.setMaximum(now.getTime());
-	me.valuesprite.setText(panel.renderer(value || 0).toString());
-	me.valuesprite.setAttributes({
-	    x: me.getWidth() - 15,
-	    y: me.getHeight()/2
-	}, true);
-	me.redraw();
-    },
-
-    setTitle: function(title) {
-	this.title = title;
-	var me = this.getComponent('title');
-	me.update({title: title});
-    },
-
-    initComponent: function(){
-	var me = this;
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.chart = me.getComponent('chart');
-	me.chart.timeaxis = me.chart.getAxes()[1];
-	me.chart.valuesprite = me.chart.getSurface('chart').get('valueSprite');
-	if (me.color) {
-	    me.chart.series[0].setStyle({
-		fill: me.color,
-		stroke: me.color
-	    });
-	}
-    }
-});
-Ext.define('PVE.widget.Info',{
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveInfoWidget',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    value: 0,
-    maximum: 1,
-    printBar: true,
-    items: [
-	{
-	    xtype: 'component',
-	    itemId: 'label',
-	    data: {
-		title: '',
-		usage: '',
-		iconCls: undefined
-	    },
-	    tpl: [
-		'<div class="left-aligned">',
-		'<tpl if="iconCls">',
-		'<i class="{iconCls}"></i> ',
-		'</tpl>',
-		'{title}</div>&nbsp;<div class="right-aligned">{usage}</div>'
-	    ]
-	},
-	{
-	    height: 2,
-	    border: 0
-	},
-	{
-	    xtype: 'progressbar',
-	    itemId: 'progress',
-	    height: 5,
-	    value: 0,
-	    animate: true
-	}
-    ],
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-
-    setPrintBar: function(enable) {
-	var me = this;
-	me.printBar = enable;
-	me.getComponent('progress').setVisible(enable);
-    },
-
-    setIconCls: function(iconCls) {
-	var me = this;
-	me.getComponent('label').data.iconCls = iconCls;
-    },
-
-    updateValue: function(text, usage) {
-	var me = this;
-	var label = me.getComponent('label');
-	label.update(Ext.apply(label.data, {title: me.title, usage:text}));
-
-	if (usage !== undefined &&
-	    me.printBar &&
-	    Ext.isNumeric(usage) &&
-	    usage >= 0) {
-	    var progressBar = me.getComponent('progress');
-	    progressBar.updateProgress(usage, '');
-	    if (usage > me.criticalThreshold) {
-		progressBar.removeCls('warning');
-		progressBar.addCls('critical');
-	    } else if (usage > me.warningThreshold) {
-		progressBar.removeCls('critical');
-		progressBar.addCls('warning');
-	    } else {
-		progressBar.removeCls('warning');
-		progressBar.removeCls('critical');
-	    }
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.title) {
-	    throw "no title defined";
-	}
-
-	me.callParent();
-
-	me.getComponent('progress').setVisible(me.printBar);
-
-	me.updateValue(me.text, me.value);
-	me.setIconCls(me.iconCls);
-    }
-
-});
-Ext.define('PVE.panel.TemplateStatusView',{
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveTemplateStatusView',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	printBar: false,
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    itemId: 'node',
-	    iconCls: 'fa fa-fw fa-building',
-	    title: gettext('Node')
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'cpus',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('Processors'),
-	    textField: 'cpus'
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory'),
-	    textField: 'maxmem',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'swap',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('Swap'),
-	    textField: 'maxswap',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'disk',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    textField: 'maxdisk',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var name = me.pveSelNode.data.name;
-	if (!name) {
-	    throw "no name specified";
-	}
-
-	me.title = name;
-
-	me.callParent();
-	if (me.pveSelNode.data.type !== 'lxc') {
-	    me.remove(me.getComponent('swap'));
-	}
-	me.getComponent('node').updateValue(me.pveSelNode.data.node);
-    }
-});
-Ext.define('PVE.widget.HealthWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveHealthWidget',
-
-    data: {
-	iconCls: PVE.Utils.get_health_icon(undefined, true),
-	text: '',
-	title: ''
-    },
-
-    style: {
-	'text-align':'center'
-    },
-
-    tpl: [
-	'<h3>{title}</h3>',
-	'<i class="fa fa-5x {iconCls}"></i>',
-	'<br /><br/>',
-	'{text}'
-    ],
-
-    updateHealth: function(data) {
-	var me = this;
-	me.update(Ext.apply(me.data, data));
-    },
-
-    initComponent: function(){
-	var me = this;
-
-	if (me.title) {
-	    me.config.data.title = me.title;
-	}
-
-	me.callParent();
-    }
-
-});
-/*global u2f*/
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onLogon: function() {
-	    var me = this;
-
-	    var form = this.lookupReference('loginForm');
-	    var unField = this.lookupReference('usernameField');
-	    var saveunField = this.lookupReference('saveunField');
-	    var view = this.getView();
-
-	    if (!form.isValid()) {
-		return;
-	    }
-
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
-	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
-
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
-
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
-
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
-			} else {
-			    me.perform_otp();
-			}
-		    } else {
-			me.success(data);
-		    }
-		}
-	    });
-
-	},
-	failure: function(resp) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.unmask();
-	    var handler = function() {
-		var uf = me.lookupReference('usernameField');
-		uf.focus(true, true);
-	    };
-
-	    Ext.MessageBox.alert(gettext('Error'),
-				 gettext("Login failed. Please try again"),
-				 handler);
-	},
-	success: function(data) {
-	    var me = this;
-	    var view = me.getView();
-	    var handler = view.handler || Ext.emptyFn;
-	    handler.call(me, data);
-	    view.close();
-	},
-
-	perform_otp: function() {
-	    var me = this;
-	    var win = Ext.create('PVE.window.TFALoginWindow', {
-		onLogin: function(value) {
-		    me.finish_tfa(value);
-		},
-		onCancel: function() {
-		    Proxmox.LoggedOut = false;
-		    Proxmox.Utils.authClear();
-		    me.getView().show();
-		}
-	    });
-	    win.show();
-	},
-
-	perform_u2f: function(data) {
-	    var me = this;
-	    // Show the message:
-	    var msg = Ext.Msg.show({
-		title: 'U2F: '+gettext('Verification'),
-		message: gettext('Please press the button on your U2F Device'),
-		buttons: []
-	    });
-	    var chlg = data.U2FChallenge;
-	    var key = {
-		version: chlg.version,
-		keyHandle: chlg.keyHandle
-	    };
-	    u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
-		msg.close();
-		if (res.errorCode) {
-		    Proxmox.Utils.authClear();
-		    Ext.Msg.alert(gettext('Error'), PVE.Utils.render_u2f_error(res.errorCode));
-		    return;
-		}
-		delete res.errorCode;
-		me.finish_tfa(JSON.stringify(res));
-	    });
-	},
-	finish_tfa: function(res) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-	    var params = { response: res };
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'POST',
-		timeout: 5000, // it'll delay both success & failure
-		success: function(resp, opts) {
-		    view.el.unmask();
-		    // Fill in what we copy over from the 1st factor:
-		    var data = resp.result.data;
-		    data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-		    data.username = Proxmox.UserName;
-		    // Finish logging in:
-		    me.success(data);
-		},
-		failure: function(resp, opts) {
-		    Proxmox.Utils.authClear();
-		    me.failure(resp);
-		}
-	    });
-	},
-
-	control: {
-	    'field[name=username]': {
-		specialkey: function(f, e) {
-		    if (e.getKey() === e.ENTER) {
-			var pf = this.lookupReference('passwordField');
-			if (!pf.getValue()) {
-			    pf.focus(false);
-			}
-		    }
-		}
-	    },
-	    'field[name=lang]': {
-		change: function(f, value) {
-		    var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-		    Ext.util.Cookies.set('PVELangCookie', value, dt);
-		    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
-		    window.location.reload();
-		}
-	    },
-            'button[reference=loginButton]': {
-		click: 'onLogon'
-            },
-	    '#': {
-		show: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var checkboxField = this.lookupReference('saveunField');
-		    var unField = this.lookupReference('usernameField');
-
-		    var checked = sp.get(checkboxField.getStateId());
-		    checkboxField.setValue(checked);
-
-		    if(checked === true) {
-			var username = sp.get(unField.getStateId());
-			unField.setValue(username);
-			var pwField = this.lookupReference('passwordField');
-			pwField.focus();
-		    }
-		}
-	    }
-	}
-    },
-
-    width: 400,
-
-    modal: true,
-
-    border: false,
-
-    draggable: true,
-
-    closable: false,
-
-    resizable: false,
-
-    layout: 'auto',
-
-    title: gettext('Proxmox VE Login'),
-
-    defaultFocus: 'usernameField',
-
-    defaultButton: 'loginButton',
-
-    items: [{
-	xtype: 'form',
-	layout: 'form',
-	url: '/api2/extjs/access/ticket',
-	reference: 'loginForm',
-
-	fieldDefaults: {
-	    labelAlign: 'right',
-	    allowBlank: false
-	},
-
-	items: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('User name'),
-		name: 'username',
-		itemId: 'usernameField',
-		reference: 'usernameField',
-		stateId: 'login-username'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		fieldLabel: gettext('Password'),
-		name: 'password',
-		reference: 'passwordField'
-	    },
-	    {
-		xtype: 'pveRealmComboBox',
-		name: 'realm'
-	    },
-	    {
-		xtype: 'proxmoxLanguageSelector',
-		fieldLabel: gettext('Language'),
-		value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
-		name: 'lang',
-		reference: 'langField',
-		submitValue: false
-	    }
-	],
-	buttons: [
-	    {
-		xtype: 'checkbox',
-		fieldLabel: gettext('Save User name'),
-		name: 'saveusername',
-		reference: 'saveunField',
-		stateId: 'login-saveusername',
-		labelWidth: 'auto',
-		labelAlign: 'right',
-		submitValue: false
-	    },
-	    {
-		text: gettext('Login'),
-		reference: 'loginButton'
-	    }
-	]
-    }]
- });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	login: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onLogin(me.lookup('otpField').value);
-	    view.close();
-	},
-	cancel: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onCancel();
-	    view.close();
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Please enter your OTP verification code:'),
-	    name: 'otp',
-	    itemId: 'otpField',
-	    reference: 'otpField',
-	    allowBlank: false
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Login'),
-	    reference: 'loginButton',
-	    handler: 'login'
-	},
-	{
-	    text: gettext('Cancel'),
-	    handler: 'cancel'
-	}
-    ]
-});
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-
-    activeTitle: '', // used for automated testing
-
-    width: 700,
-    height: 510,
-
-    modal: true,
-    border: false,
-
-    draggable: true,
-    closable: true,
-    resizable: false,
-
-    layout: 'border',
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var tabs = me.items || [];
-	delete me.items;
-	
-	/* 
-	 * Items may have the following functions:
-	 * validator(): per tab custom validation
-	 * onSubmit(): submit handler
-	 * onGetValues(): overwrite getValues results
-	 */
-
-	Ext.Array.each(tabs, function(tab) {
-	    tab.disabled = true;
-	});
-	tabs[0].disabled = false;
-
-	var maxidx = 0;
-	var curidx = 0;
-
-	var check_card = function(card) {
-	    var valid = true;
-	    var fields = card.query('field, fieldcontainer');
-	    if (card.isXType('fieldcontainer')) {
-		fields.unshift(card);
-	    }
-	    Ext.Array.each(fields, function(field) {
-		// Note: not all fielcontainer have isValid()
-		if (Ext.isFunction(field.isValid) && !field.isValid()) {
-		    valid = false;
-		}
-	    });
-
-	    if (Ext.isFunction(card.validator)) {
-		return card.validator();
-	    }
-
-	    return valid;
-	};
-
-	var disable_at = function(card) {
-	    var tp = me.down('#wizcontent');
-	    var idx = tp.items.indexOf(card);
-	    for(;idx < tp.items.getCount();idx++) {
-		var nc = tp.items.getAt(idx);
-		if (nc) {
-		    nc.disable();
-		}
-	    }
-	};
-
-	var tabchange = function(tp, newcard, oldcard) {
-	    if (newcard.onSubmit) {
-		me.down('#next').setVisible(false);
-		me.down('#submit').setVisible(true); 
-	    } else {
-		me.down('#next').setVisible(true);
-		me.down('#submit').setVisible(false); 
-	    }
-	    var valid = check_card(newcard);
-	    me.down('#next').setDisabled(!valid);    
-	    me.down('#submit').setDisabled(!valid);    
-	    me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-	    var idx = tp.items.indexOf(newcard);
-	    if (idx > maxidx) {
-		maxidx = idx;
-	    }
-	    curidx = idx;
-
-	    var next = idx + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (valid && ntab && !newcard.onSubmit) {
-		ntab.enable();
-	    }
-	};
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, true, false);
-	}
-
-	var sp = Ext.state.Manager.getProvider();
-	var advchecked = sp.get('proxmox-advanced-cb');
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'form',
-		    region: 'center',
-		    layout: 'fit',
-		    border: false,
-		    margins: '5 5 0 5',
-		    fieldDefaults: {
-			labelWidth: 100,
-			anchor: '100%'
-		    },
-		    items: [{
-			itemId: 'wizcontent',
-			xtype: 'tabpanel',
-			activeItem: 0,
-			bodyPadding: 10,
-			listeners: {
-			    afterrender: function(tp) {
-				var atab = this.getActiveTab();
-				tabchange(tp, atab);
-			    },
-			    tabchange: function(tp, newcard, oldcard) {
-				tabchange(tp, newcard, oldcard);
-			    }
-			},
-			items: tabs
-		    }]
-		}
-	    ],
-	    fbar: [
-		{
-		    xtype: 'proxmoxHelpButton',
-		    itemId: 'help'
-		},
-		'->',
-		{
-		    xtype: 'proxmoxcheckbox',
-		    boxLabelAlign: 'before',
-		    boxLabel: gettext('Advanced'),
-		    value: advchecked,
-		    listeners: {
-			change: function(cb, val) {
-			    var tp = me.down('#wizcontent');
-			    tp.query('inputpanel').forEach(function(ip) {
-				ip.setAdvancedVisible(val);
-			    });
-
-			    sp.set('proxmox-advanced-cb', val);
-			}
-		    }
-		},
-		{
-		    text: gettext('Back'),
-		    disabled: true,
-		    itemId: 'back',
-		    minWidth: 60,
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			var prev = tp.items.indexOf(atab) - 1;
-			if (prev < 0) {
-			    return;
-			}
-			var ntab = tp.items.getAt(prev);
-			if (ntab) {
-			    tp.setActiveTab(ntab);
-			}
-		    }
-		},
-		{
-		    text: gettext('Next'),
-		    disabled: true,
-		    itemId: 'next',
-		    minWidth: 60,
-		    handler: function() {
-
-			var form = me.down('form').getForm();
-
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			if (!check_card(atab)) {
-			    return;
-			}
-
-			var next = tp.items.indexOf(atab) + 1;
-			var ntab = tp.items.getAt(next);
-			if (ntab) {
-			    ntab.enable();
-			    tp.setActiveTab(ntab);
-			}
-
-		    }
-		},
-		{
-		    text: gettext('Finish'),
-		    minWidth: 60,
-		    hidden: true,
-		    itemId: 'submit',
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			atab.onSubmit();
-		    }
-		}
-	    ]
-	});
-	me.callParent();
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setAdvancedVisible(advchecked);
-	});
-
-	Ext.Array.each(me.query('field'), function(field) {
-	    var validcheck = function() {
-		var tp = me.down('#wizcontent');
-
-		// check tabs from current to the last enabled for validity
-		// since we might have changed a validity on a later one
-		var i;
-		for (i = curidx; i <= maxidx && i < tp.items.getCount(); i++) {
-		    var tab = tp.items.getAt(i);
-		    var valid = check_card(tab);
-
-		    // only set the buttons on the current panel
-		    if (i === curidx) {
-			me.down('#next').setDisabled(!valid);
-			me.down('#submit').setDisabled(!valid);
-		    }
-
-		    // if a panel is invalid, then disable it and all following,
-		    // else enable it and go to the next
-		    var ntab = tp.items.getAt(i + 1);
-		    if (!valid) {
-			disable_at(ntab);
-			return;
-		    } else if (ntab && !tab.onSubmit) {
-			ntab.enable();
-		    }
-		}
-	    };
-	    field.on('change', validcheck);
-	    field.on('validitychange', validcheck);
-	});
-    }
-});
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    title: gettext('Notes'),
-	    width: 600,
-	    height: '400px',
-	    resizable: true,
-	    layout: 'fit',
-	    defaultButton: undefined,
-	    items: {
-		xtype: 'textarea',
-		name: 'description',
-		height: '100%',
-		value: '',
-		hideLabel: true
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: me.storage,
-	    fieldLabel: gettext('Storage'),
-	    storageContent: 'backup',
-	    allowBlank: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		storagesel,
-		{
-		    xtype: 'pveBackupModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    value: 'snapshot',
-		    name: 'mode'
-		},
-		{
-		    xtype: 'pveCompressionSelector',
-		    name: 'compress',
-		    value: 'lzo',
-		    fieldLabel: gettext('Compression')
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Send email to'),
-		    name: 'mailto',
-		    emptyText: Proxmox.Utils.noneText
-		}
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Backup'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid,
-		    mode: values.mode,
-		    remove: 0
-		};
-
-		if ( values.mailto ) {
-		    params.mailto = values.mailto;
-		}
-
-		if (values.compress) {
-		    params.compress = values.compress;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/vzdump',
-		    params: params,
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			// close later so we reload the grid
-			// after the task has completed
-			me.hide();
-
-			var upid = response.result.data;
-			
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				close: function() {
-				    me.close();
-				}
-			    }
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var helpBtn = Ext.create('Proxmox.button.Help', {
-	    onlineHelp: 'chapter_vzdump',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	});
-
-	var title = gettext('Backup') + " " + 
-	    ((me.vmtype === 'lxc') ? "CT" : "VM") +
-	    " " + me.vmid;
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 350,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ helpBtn, '->', submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: Proxmox.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.volid) {
-	    throw "no volume ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no vmtype specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: '',
-	    fieldLabel: gettext('Storage'),
-	    storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-	    allowBlank: true
-	});
-
-	var IDfield;
-	if (me.vmid) {
-	    IDfield = Ext.create('Ext.form.field.Display', {
-		name: 'vmid',
-		value: me.vmid,
-		fieldLabel: (me.vmtype === 'lxc') ? 'CT' : 'VM'
-	    });
-	} else {
-	    IDfield = Ext.create('PVE.form.GuestIDSelector', {
-		name: 'vmid',
-		guestType: me.vmtype,
-		loadNextFreeID: true,
-		validateExists: false
-	    });
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		value: me.volidText || me.volid,
-		fieldLabel: gettext('Source')
-	    },
-	    storagesel,
-	    IDfield,
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'bwlimit',
-		fieldLabel: gettext('Read Limit (MiB/s)'),
-		minValue: 0,
-		emptyText: gettext('Defaults to target storage restore limit'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext("Use '0' to disable all bandwidth limits.")
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'unique',
-		fieldLabel: gettext('Unique'),
-		hidden: !!me.vmid,
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext('Autogenerate unique properties, e.g., MAC addresses')
-		},
-		checked: false
-	    }
-	];
-
-	/*jslint confusion: true*/
-	if (me.vmtype === 'lxc') {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'unprivileged',
-		value: true,
-		fieldLabel: gettext('Unprivileged container')
-	    });
-	}
-	/*jslint confusion: false*/
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doRestore = function(url, params) {
-	    Proxmox.Utils.API2Request({
-		url: url,
-		params: params,
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.close();
-		}
-	    });
-	};
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Restore'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid || values.vmid,
-		    force: me.vmid ? 1 : 0
-		};
-		if (values.unique) { params.unique = 1; }
-
-		if (values.bwlimit !== undefined) {
-		    params.bwlimit = values.bwlimit * 1024;
-		}
-
-		var url;
-		var msg;
-		if (me.vmtype === 'lxc') {
-		    url = '/nodes/' + me.nodename + '/lxc';
-		    params.ostemplate = me.volid;
-		    params.restore = 1;
-		    if (values.unprivileged) { params.unprivileged = 1; }
-		    msg = Proxmox.Utils.format_task_description('vzrestore', params.vmid);
-		} else if (me.vmtype === 'qemu') {
-		    url = '/nodes/' + me.nodename + '/qemu';
-		    params.archive = me.volid;
-		    msg = Proxmox.Utils.format_task_description('qmrestore', params.vmid);
-		} else {
-		    throw 'unknown VM type';
-		}
-
-		if (me.vmid) {
-		    msg += '. ' + gettext('This will permanently erase current VM data.');
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRestore(url, params);
-		    });
-		} else {
-		    doRestore(url, params);
-		}
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-	var title =  gettext('Restore') + ": " + (
-	    (me.vmtype === 'lxc') ? 'CT' : 'VM');
-
-	if (me.vmid) {
-	    title += " " + me.vmid;
-	}
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 500,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-/* Popup a message window
- * where the user has to manually enter the ressource ID
- * to enable the destroy button
- */
-Ext.define('PVE.window.SafeDestroy', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSafeDestroy',
-
-    title: gettext('Confirm'),
-    modal: true,
-    buttonAlign: 'center',
-    bodyPadding: 10,
-    width: 450,
-    layout: { type:'hbox' },
-    defaultFocus: 'confirmField',
-    showProgress: false,
-
-    config: {
-	item: {
-	    id: undefined,
-	    type: undefined
-	},
-	url: undefined,
-	params: {}
-    },
-
-    getParams: function() {
-	var me = this;
-	if (Ext.Object.isEmpty(me.params)) {
-	    return '';
-	}
-	return '?' + Ext.Object.toQueryString(me.params);
-    },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=confirm]': {
-		change: function(f, value) {
-		    var view = this.getView();
-		    var removeButton = this.lookupReference('removeButton');
-		    if (value === view.getItem().id.toString()) {
-			removeButton.enable();
-		    } else {
-			removeButton.disable();
-		    }
-		},
-		specialkey: function (field, event) {
-		    var removeButton = this.lookupReference('removeButton');
-		    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
-			removeButton.fireEvent('click', removeButton, event);
-		    }
-		}
-	    },
-           'button[reference=removeButton]': {
-		click: function() {
-		    var view = this.getView();
-		    Proxmox.Utils.API2Request({
-			url: view.getUrl() + view.getParams(),
-			method: 'DELETE',
-			waitMsgTarget: view,
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var hasProgressBar = view.showProgress &&
-				response.result.data ? true : false;
-
-			    if (hasProgressBar) {
-				// stay around so we can trigger our close events
-				// when background action is completed
-				view.hide();
-
-				var upid = response.result.data;
-				var win = Ext.create('Proxmox.window.TaskProgress', {
-				    upid: upid,
-				    listeners: {
-					destroy: function () {
-					    view.close();
-					}
-				    }
-				});
-				win.show();
-			    } else {
-				view.close();
-			    }
-			}
-		    });
-		}
-            }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    cls: [ Ext.baseCSSPrefix + 'message-box-icon',
-		   Ext.baseCSSPrefix + 'message-box-warning',
-		   Ext.baseCSSPrefix + 'dlg-icon']
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    xtype: 'component',
-		    reference: 'messageCmp'
-		},
-		{
-		    itemId: 'confirmField',
-		    reference: 'confirmField',
-		    xtype: 'textfield',
-		    name: 'confirm',
-		    labelWidth: 300,
-		    hideTrigger: true,
-		    allowBlank: false
-		}
-	    ]
-	}
-    ],
-    buttons: [
-	{
-	    reference: 'removeButton',
-	    text: gettext('Remove'),
-	    disabled: true
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	var item = me.getItem();
-
-	if (!Ext.isDefined(item.id)) {
-	    throw "no ID specified";
-	}
-
-	if (!Ext.isDefined(item.type)) {
-	    throw "no VM type specified";
-	}
-
-	var messageCmp = me.lookupReference('messageCmp');
-	var msg;
-
-	if (item.type === 'VM') {
-	    msg = Proxmox.Utils.format_task_description('qmdestroy', item.id);
-	} else if (item.type === 'CT') {
-	    msg = Proxmox.Utils.format_task_description('vzdestroy', item.id);
-	} else if (item.type === 'CephPool') {
-	    msg = Proxmox.Utils.format_task_description('cephdestroypool', item.id);
-	} else if (item.type === 'Image') {
-	    msg = Proxmox.Utils.format_task_description('unknownimgdel', item.id);
-	} else {
-	    throw "unknown item type specified";
-	}
-
-	messageCmp.setHtml(msg);
-
-	var confirmField = me.lookupReference('confirmField');
-	msg = gettext('Please enter the ID to confirm') +
-	    ' (' + item.id + ')';
-	confirmField.setFieldLabel(msg);
-    }
-});
-Ext.define('PVE.window.BackupConfig', {
-    extend: 'Ext.window.Window',
-    title: gettext('Configuration'),
-    width: 600,
-    height: 400,
-    layout: 'fit',
-    modal: true,
-    items: {
-	xtype: 'component',
-	itemId: 'configtext',
-	autoScroll: true,
-	style: {
-	    'background-color': 'white',
-	    'white-space': 'pre',
-	    'font-family': 'monospace',
-	    padding: '5px'
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.volume) {
-	    throw "no volume specified";
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + nodename + "/vzdump/extractconfig",
-	    method: 'GET',
-	    params: {
-		volume: me.volume
-	    },
-	    failure: function(response, opts) {
-		me.close();
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response,options) {
-		me.show();
-		me.down('#configtext').update(Ext.htmlEncode(response.result.data));
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.Settings', {
-    extend: 'Ext.window.Window',
-
-    width: '800px',
-    title: gettext('My Settings'),
-    iconCls: 'fa fa-gear',
-    modal: true,
-    bodyPadding: 10,
-    resizable: false,
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    onlineHelp: 'gui_my_settings',
-	    hidden: false
-	},
-	'->',
-	{
-	    text: gettext('Close'),
-	    handler: function() {
-		this.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    var me = this;
-	    var sp = Ext.state.Manager.getProvider();
-
-	    var username = sp.get('login-username') || Proxmox.Utils.noneText;
-	    me.lookupReference('savedUserName').setValue(username);
-
-	    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-	    settings.forEach(function(setting) {
-		var val = localStorage.getItem('pve-xterm-' + setting);
-		if (val !== undefined && val !== null) {
-		    var field = me.lookup(setting);
-		    field.setValue(val);
-		    field.resetOriginalValue();
-		}
-	    });
-	},
-
-	set_button_status: function() {
-	    var me = this;
-
-	    var form = me.lookup('xtermform');
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-
-	    var hasvalues = false;
-	    var values = form.getValues();
-	    Ext.Object.eachValue(values, function(value) {
-		if (value) {
-		    hasvalues = true;
-		    return false;
-		}
-	    });
-
-	    me.lookup('xtermsave').setDisabled(!dirty || !valid);
-	    me.lookup('xtermreset').setDisabled(!hasvalues);
-	},
-
-	control: {
-	    '#xtermjs form': {
-		dirtychange: 'set_button_status',
-		validitychange: 'set_button_status'
-	    },
-	    '#xtermjs button': {
-		click: function(button) {
-		    var me = this;
-		    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-		    settings.forEach(function(setting) {
-			var field = me.lookup(setting);
-			if (button.reference === 'xtermsave') {
-			    var value = field.getValue();
-			    if (value) {
-				localStorage.setItem('pve-xterm-' + setting, value);
-			    } else {
-				localStorage.removeItem('pve-xterm-' + setting);
-			    }
-			} else if (button.reference === 'xtermreset') {
-			    field.setValue(undefined);
-			    localStorage.removeItem('pve-xterm-' + setting);
-			}
-			field.resetOriginalValue();
-		    });
-		    me.set_button_status();
-		}
-	    },
-	    'button[name=reset]': {
-		click: function () {
-		    var blacklist = ['GuiCap', 'login-username', 'dash-storages'];
-		    var sp = Ext.state.Manager.getProvider();
-		    var state;
-		    for (state in sp.state) {
-			if (sp.state.hasOwnProperty(state)) {
-			    if (blacklist.indexOf(state) !== -1) {
-				continue;
-			    }
-
-			    sp.clear(state);
-			}
-		    }
-
-		    window.location.reload();
-		}
-	    },
-	    'button[name=clear-username]': {
-		click: function () {
-		    var me = this;
-		    var usernamefield = me.lookupReference('savedUserName');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    usernamefield.setValue(Proxmox.Utils.noneText);
-		    sp.clear('login-username');
-		}
-	    },
-	    'grid[reference=dashboard-storages]': {
-		selectionchange: function(grid, selected) {
-		    var me = this;
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // saves the selected storageids as
-		    // "id1,id2,id3,..."
-		    // or clears the variable
-		    if (selected.length > 0) {
-			sp.set('dash-storages',
-			    Ext.Array.pluck(selected, 'id').join(','));
-		    } else {
-			sp.clear('dash-storages');
-		    }
-		},
-		afterrender: function(grid) {
-		    var me = grid;
-		    var sp = Ext.state.Manager.getProvider();
-		    var store = me.getStore();
-		    var items = [];
-		    me.suspendEvent('selectionchange');
-		    var storages = sp.get('dash-storages') || '';
-		    storages.split(',').forEach(function(storage){
-			// we have to get the records
-			// to be able to select them
-			if (storage !== '') {
-			    var item = store.getById(storage);
-			    if (item) {
-				items.push(item);
-			    }
-			}
-		    });
-		    me.getSelectionModel().select(items);
-		    me.resumeEvent('selectionchange');
-		}
-	    }
-	}
-    },
-
-    items: [{
-	    xtype: 'fieldset',
-	    width: '50%',
-	    title: gettext('Webinterface Settings'),
-	    margin: '5',
-	    layout: {
-		type: 'vbox',
-		align: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Dashboard Storages'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'grid',
-		    maxHeight: 150,
-		    reference: 'dashboard-storages',
-		    selModel: {
-			selType: 'checkboxmodel'
-		    },
-		    columns: [{
-			header: gettext('Name'),
-			dataIndex: 'storage',
-			flex: 1
-		    },{
-			header: gettext('Node'),
-			dataIndex: 'node',
-			flex: 1
-		    }],
-		    store: {
-			type: 'diff',
-			field: ['type', 'storage', 'id', 'node'],
-			rstore: PVE.data.ResourceStore,
-			filters: [{
-			    property: 'type',
-			    value: 'storage'
-			}],
-			sorters: [ 'node','storage']
-		    }
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Saved User name'),
-		    labelAlign: 'left',
-		    labelWidth: '50%',
-		    stateId: 'login-username',
-		    reference: 'savedUserName',
-		    value: ''
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Clear User name'),
-		    width: 'auto',
-		    name: 'clear-username'
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Layout'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Reset Layout'),
-		    width: 'auto',
-		    name: 'reset'
-		}
-	    ]
-    },{
-	xtype: 'fieldset',
-	itemId: 'xtermjs',
-	width: '50%',
-	margin: '5',
-	title: gettext('xterm.js Settings'),
-	items: [{
-	    xtype: 'form',
-	    reference: 'xtermform',
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		algin: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'textfield',
-		    name: 'fontFamily',
-		    reference: 'fontFamily',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Font-Family')
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    emptyText: Proxmox.Utils.defaultText,
-		    name: 'fontSize',
-		    reference: 'fontSize',
-		    minValue: 1,
-		    fieldLabel: gettext('Font-Size')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'letterSpacing',
-		    reference: 'letterSpacing',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Letter Spacing')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'lineHeight',
-		    minValue: 0.1,
-		    reference: 'lineHeight',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Line Height')
-		},
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'hbox',
-			pack: 'end'
-		    },
-		    items: [
-			{
-			    xtype: 'button',
-			    reference: 'xtermreset',
-			    disabled: true,
-			    text: gettext('Reset')
-			},
-			{
-			    xtype: 'button',
-			    reference: 'xtermsave',
-			    disabled: true,
-			    text: gettext('Save')
-			}
-		    ]
-		}
-	    ]
-	}]
-    }],
-
-    onShow: function() {
-	var me = this;
-	me.callParent();
-    }
-});
-Ext.define('PVE.panel.StartupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'qm_startup_and_shutdown',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = PVE.Parser.printStartup(values);
-
-	if (res === undefined || res === '') {
-	    return { 'delete': 'startup' };
-	}
-
-	return { startup: res };
-    },
-
-    setStartup: function(value) {
-	var me = this;
-
-	var startup = PVE.Parser.parseStartup(value);
-	if (startup) {
-	    me.setValues(startup);
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		name: 'order',
-		defaultValue: '',
-		emptyText: 'any',
-		fieldLabel: gettext('Start/Shutdown order')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'up',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Startup delay')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'down',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Shutdown timeout')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.window.StartupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveWindowStartupEdit',
-    onlineHelp: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-	var ipanelConfig = me.onlineHelp ? {onlineHelp: me.onlineHelp} : {};
-	var ipanel = Ext.create('PVE.panel.StartupInputPanel', ipanelConfig);
-
-	Ext.applyIf(me, {
-	    subject: gettext('Start/Shutdown order'),
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		ipanel.setStartup(me.vmconfig.startup);		    
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.Install', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveCephInstallWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 220,
-    header: false,
-    resizable: false,
-    draggable: false,
-    modal: true,
-    nodename: undefined,
-    shadow: false,
-    border: false,
-    bodyBorder: false,
-    closable: false,
-    cls: 'install-mask',
-    bodyCls: 'install-mask',
-    layout: {
-        align: 'stretch',
-        pack: 'center',
-	type: 'vbox'
-    },
-    viewModel: {
-	data: {
-	      cephVersion: 'luminous',
-	      isInstalled: false
-	},
-	formulas: {
-	    buttonText: function (get){
-		if (get('isInstalled')) {
-		    return gettext('Configure Ceph');
-		} else {
-		    return gettext('Install Ceph-') + get('cephVersion');
-		}
-	    },
-	    windowText: function (get) {
-		if (get('isInstalled')) {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not initialized.'), 'Ceph') + ' '+
-		    gettext('You need to create a initial config once.') + '</p>';
-		} else {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '<br>' +
-		    gettext('Would you like to install it now?') + '</p>';
-		}
-	    }
-	}
-    },
-    items: [
-	{
-	    bind: {
-		html: '{windowText}'
-	    },
-	    border: false,
-	    padding: 5,
-	    bodyCls: 'install-mask'
-
-	},
-	{
-	    xtype: 'button',
-	    bind: {
-		text: '{buttonText}'
-	    },
-	    viewModel: {},
-	    cbind: {
-		nodename: '{nodename}'
-	    },
-	    handler: function() {
-		var me = this.up('pveCephInstallWindow');
-		var win = Ext.create('PVE.ceph.CephInstallWizard',{
-		    nodename: me.nodename
-		});
-		win.getViewModel().set('isInstalled', this.getViewModel().get('isInstalled'));
-		win.show();
-		me.mon(win,'beforeClose', function(){
-		    me.fireEvent("cephInstallWindowClosed");
-		    me.close();
-		});
-
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallEnableEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveFirewallEnableEdit'],
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    subject: gettext('Firewall'),
-    cbindData: {
-	defaultValue: 0
-    },
-    width: 350,
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    uncheckedValue: 0,
-	    cbind: {
-		defaultValue: '{defaultValue}',
-		checked: '{defaultValue}'
-	    },
-	    deleteDefaultValue: false,
-	    fieldLabel: gettext('Firewall')
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'warning',
-	    userCls: 'pve-hint',
-	    value: gettext('Warning: Firewall still disabled at datacenter level!'),
-	    hidden: true
-	}
-    ],
-
-    beforeShow: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/cluster/firewall/options',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		if (!response.result.data.enable) {
-		    me.down('displayfield[name=warning]').setVisible(true);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallLograteInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveFirewallLograteInputPanel',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    reference: 'enable',
-	    fieldLabel: gettext('Enable'),
-	    value: false
-	},
-	{
-	    layout: 'hbox',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'numberfield',
-		    name: 'rate',
-		    fieldLabel: gettext('Log rate limit'),
-		    minValue: 1,
-		    maxValue: 99,
-		    allowBlank: false,
-		    flex: 2,
-		    value: 1
-		},
-		{
-		    html: '<div style="margin: auto; padding: 2.5px;"><b>/</b></div>'
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    name: 'unit',
-		    comboItems: [['second', 'second'], ['minute', 'minute'],
-			['hour', 'hour'], ['day', 'day']],
-		    allowBlank: false,
-		    flex: 1,
-		    value: 'second'
-		}
-	    ]
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'burst',
-	    fieldLabel: gettext('Log burst limit'),
-	    minValue: 1,
-	    maxValue: 99,
-	    value: 5
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var vals = {};
-	vals.enable = values.enable !== undefined ? 1 : 0;
-	vals.rate = values.rate + '/' + values.unit;
-	vals.burst = values.burst;
-	var properties = PVE.Parser.printPropertyString(vals, undefined);
-	if (properties == '') {
-	    return { 'delete': 'log_ratelimit' };
-	}
-	return { log_ratelimit: properties };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var properties = {};
-	if (values.log_ratelimit !== undefined) {
-	    properties = PVE.Parser.parsePropertyString(values.log_ratelimit);
-	    var matches = properties.rate.match(/^(\d+)\/(second|minute|hour|day)$/);
-	    if (matches) {
-		properties.rate = matches[1];
-		properties.unit = matches[2];
-	    }
-	}
-	me.callParent([properties]);
-    }
-});
-
-Ext.define('PVE.FirewallLograteEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveFirewallLograteEdit',
-
-    subject: gettext('Log rate limit'),
-
-    items: [{
-	xtype: 'pveFirewallLograteInputPanel'
-    }],
-    autoLoad: true
-});
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNotesView',
-
-    title: gettext("Notes"),
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 10,
-    scrollable: true,
-
-    tbar: {
-	itemId: 'tbar',
-	hidden: true,
-	items: [
-	    {
-		text: gettext('Edit'),
-		handler: function() {
-		    var me = this.up('panel');
-		    me.run_editor();
-		}
-	    }
-	]
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create('PVE.window.NotesEdit', {
-	    pveSelNode: me.pveSelNode,
-	    url: me.url
-	});
-	win.show();
-	win.on('destroy', me.load, me);
-    },
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data.description || '';
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    listeners: {
-	render: function(c) {
-	    var me = this;
-	    me.getEl().on('dblclick', me.run_editor, me);
-	}
-    },
-
-    tools: [{
-	type: 'gear',
-	handler: function() {
-	    var me = this.up('panel');
-	    me.run_editor();
-	}
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	if (!Ext.Array.contains(['node', 'qemu', 'lxc'], type)) {
-	    throw 'invalid type specified';
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid && type !== 'node') {
-	    throw "no VM ID specified";
-	}
-
-	me.url = '/api2/extjs/nodes/' + nodename + '/';
-
-	// add the type specific path if qemu/lxc
-	if (type === 'qemu' || type === 'lxc') {
-	    me.url += type + '/' + vmid + '/';
-	}
-
-	me.url += 'config';
-
-	me.callParent();
-	if (type === 'node') {
-	    me.down('#tbar').setVisible(true);
-	}
-	me.load();
-    }
-});
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    border: false,
-    defaultSorter: {
-	property: 'type',
-	direction: 'ASC'
-    },
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	var coldef = rstore.defaultColumns();
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: me.defaultSorter,
-	    proxy: { type: 'memory' }
-	});
-
-	var textfilter = '';
-
-	var textfilter_match = function(item) {
-	    var match = false;
-	    Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-		var v = item.data[field];
-		if (v !== undefined) {
-		    v = v.toLowerCase();
-		    if (v.indexOf(textfilter) >= 0) {
-			match = true;
-			return false;
-		    }
-		}
-	    });
-	    return match;
-	};
-
-	var updateGrid = function() {
-
-	    var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-	    
-	    //console.log("START GRID UPDATE " +  me.viewFilter);
-
-	    store.suspendEvents();
-
-	    var nodeidx = {};
-	    var gather_child_nodes = function(cn) {
-		if (!cn) {
-		    return;
-		}
-                var cs = cn.childNodes;
-		if (!cs) {
-		    return;
-		}
-		var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-		    var child = cs[i];
-		    var orgnode = rstore.data.get(child.data.id);
-		    if (orgnode) {
-			if ((!filterfn || filterfn(child)) &&
-			    (!textfilter || textfilter_match(child))) {
-			    nodeidx[child.data.id] = orgnode;
-			}
-		    }
-		    gather_child_nodes(child);
-		}
-	    };
-	    gather_child_nodes(me.pveSelNode);
-
-	    // remove vanished items
-	    var rmlist = [];
-	    store.each(function(olditem) {
-		var item = nodeidx[olditem.data.id];
-		if (!item) {
-		    //console.log("GRID REM UID: " + olditem.data.id);
-		    rmlist.push(olditem);
-		}
-	    });
-
-	    if (rmlist.length) {
-		store.remove(rmlist);
-	    }
-
-	    // add new items
-	    var addlist = [];
-	    var key;
-	    for (key in nodeidx) {
-		if (nodeidx.hasOwnProperty(key)) {
-		    var item = nodeidx[key];
-		
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var olditem = store.getById(item.data.id);
-		    var olditem = store.data.get(item.data.id);
-
-		    if (!olditem) {
-			//console.log("GRID ADD UID: " + item.data.id);
-			var info = Ext.apply({}, item.data);
-			var child = Ext.create(store.model, info);
-			addlist.push(item);
-			continue;
-		    }
-		    // try to detect changes
-		    var changes = false;
-		    var fieldkeys = PVE.data.ResourceStore.fieldNames;
-		    var fieldcount = fieldkeys.length;
-		    var fieldind;
-		    for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-			var field = fieldkeys[fieldind];
-			if (field != 'id' && item.data[field] != olditem.data[field]) {
-			    changes = true;
-			    //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-			    olditem.beginEdit();
-			    olditem.set(field, item.data[field]);
-			}
-		    }
-		    if (changes) {
-			olditem.endEdit(true);
-			olditem.commit(true); 
-		    }
-		}
-	    }
-
-	    if (addlist.length) {
-		store.add(addlist);
-	    }
-
-	    store.sort();
-
-	    store.resumeEvents();
-
-	    store.fireEvent('refresh', store);
-
-	    //console.log("END GRID UPDATE");
-	};
-
-	var filter_task = new Ext.util.DelayedTask(function(){
-	    updateGrid();
-	});
-
-	var load_cb = function() { 
-	    updateGrid(); 
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-resource',
-	    tbar: [
-		'->', 
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: textfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    var v = field.getValue();
-			    textfilter = v.toLowerCase();
-			    filter_task.delay(500);
-			}
-		    }
-		}
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		destroy: function() {
-		    rstore.un("load", load_cb);
-		}
-	    },
-            columns: coldef
-	});
-	me.callParent();
-	updateGrid();
-	rstore.on("load", load_cb);
-    }
-});
-Ext.define('PVE.pool.AddVM', {
-    extend: 'Proxmox.window.Edit',
-    width: 600,
-    height: 400,
-    isAdd: true,
-    isCreate: true,
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	var vmsField = Ext.create('Ext.form.field.Text', {
-	    name: 'vms',
-	    hidden: true,
-	    allowBlank: false
-	});
-
-	var vmStore = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property: 'vmid',
-		    order: 'ASC'
-		}
-	    ],
-	    filters: [
-		function(item) {
-		    return ((item.data.type === 'lxc' || item.data.type === 'qemu') && item.data.pool === '');
-		}
-	    ]
-	});
-
-	var vmGrid = Ext.create('widget.grid',{
-	    store: vmStore,
-	    border: true,
-	    height: 300,
-	    scrollable: true,
-	    selModel: {
-		selType: 'checkboxmodel',
-		mode: 'SIMPLE',
-		listeners: {
-		    selectionchange: function(model, selected, opts) {
-			var selectedVms = [];
-			selected.forEach(function(vm) {
-			    selectedVms.push(vm.data.vmid);
-			});
-			vmsField.setValue(selectedVms);
-		    }
-		}
-	    },
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-	Ext.apply(me, {
-	    subject: gettext('Virtual Machine'),
-	    items: [ vmsField, vmGrid ]
-	});
-
-	me.callParent();
-	vmStore.load();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.isCreate = true;
-	me.isAdd = true;
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	Ext.apply(me, {
-	    subject: gettext('Storage'),
-	    width: 350,
-	    items: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'storage',
-		    nodename: 'localhost',
-		    autoSelect: false,
-		    value:  '',
-		    fieldLabel: gettext("Storage")
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    stateful: true,
-    stateId: 'grid-pool-members',
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property : 'type',
-		    direction: 'ASC'
-		}
-	    ],
-	    proxy: {
-		type: 'proxmox',
-		root: 'data.members',
-		url: "/api2/json/pools/" + me.pool
-	    }
-	});
-
-	var coldef = PVE.data.ResourceStore.defaultColumns();
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		var params = { 'delete': 1 };
-		if (rec.data.type === 'storage') {
-		    params.storage = rec.data.storage;
-		} else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-		    params.vms = rec.data.vmid;
-		} else {
-		    throw "unknown resource type";
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/pools/' + me.pool,
-		    method: 'PUT',
-		    params: params,
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Virtual Machine'),
-				iconCls: 'pve-itype-icon-qemu',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Storage'),
-				iconCls: 'pve-itype-icon-storage',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-            columns: coldef,
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-    allowBlank: true,
-    autoSelect: false,
-    valueField: 'macro',
-    displayField: 'macro',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Description'),
-		renderer: Ext.String.htmlEncode,
-		flex: 1,
-		dataIndex: 'descr'
-	    }
-	]
-    },
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'macro', 'descr' ],
-	    idProperty: 'macro',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/macros"
-	    },
-	    sorters: {
-		property: 'macro',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	// hack: editable ComboGrid returns nothing when empty, so we need to set ''
-	// Also, disabled text fields return nothing, so we need to set ''
-
-	Ext.Array.each(['source', 'dest', 'macro', 'proto', 'sport', 'dport', 'log'], function(key) {
-	    if (values[key] === undefined) {
-		values[key] = '';
-	    }
-	});
-
-	delete values.modified_marker;
- 
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.column1 = [
-	    {
-		// hack: we use this field to mark the form 'dirty' when the
-		// record has errors- so that the user can safe the unmodified 
-		// form again.
-		xtype: 'hiddenfield',
-		name: 'modified_marker',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'type',
-		value: 'in',
-		comboItems: [['in', 'in'], ['out', 'out']],
-		fieldLabel: gettext('Direction'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'action',
-		value: 'ACCEPT',
-		comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-		fieldLabel: gettext('Action'),
-		allowBlank: false
-	    }
-        ];
-
-	if (me.allow_iface) {
-	    me.column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		fieldLabel: '',
-		value: ''
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'source',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Source')
-
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'dest',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Destination')
-	    }
-	);
-
-	
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    },
-	    {
-		xtype: 'pveFWMacroSelector',
-		name: 'macro',
-		fieldLabel: gettext('Macro'),
-		editable: true,
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-                        if (value === null) {
-			    me.down('field[name=proto]').setDisabled(false);
-			    me.down('field[name=sport]').setDisabled(false);
-			    me.down('field[name=dport]').setDisabled(false);
-                        } else {
-			    me.down('field[name=proto]').setDisabled(true);
-			    me.down('field[name=proto]').setValue('');
-			    me.down('field[name=sport]').setDisabled(true);
-			    me.down('field[name=sport]').setValue('');
-			    me.down('field[name=dport]').setDisabled(true);
-			    me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-	    },
-	    {
-		xtype: 'pveIPProtocolSelector',
-		name: 'proto',
-		autoSelect: false,
-		editable: true,
-		value: '',
-		fieldLabel: gettext('Protocol')
-	    },
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'sport',
-		value: '',
-		fieldLabel: gettext('Source port')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'dport',
-		value: '',
-		fieldLabel: gettext('Dest. port')
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'pveFirewallLogLevels'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.FirewallRulePanel', {
-	    isCreate: me.isCreate,
-	    list_refs_url: me.list_refs_url,
-	    allow_iface: me.allow_iface,
-	    rule_pos: me.rule_pos
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		    if (values.errors) {
-			var field = me.query('[isFormField][name=modified_marker]')[0];
-			field.setValue(1);
-			Ext.Function.defer(function() {
-			    var form = ipanel.up('form').getForm();
-			    form.markInvalid(values.errors);
-			}, 100);
-		    }
-		}
-	    });
-	} else if (me.rec) {
-	    ipanel.setValues(me.rec.data);
-	}
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: 'group'
-	    },
-	    {
-		xtype: 'pveSecurityGroupsSelector',
-		name: 'action',
-		value: '',
-		fieldLabel: gettext('Security Group'),
-		allowBlank: false
-	    }
-	];
-
-	if (me.allow_iface) {
-	    column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'enable',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: gettext('Enable')
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    onlineHelp: 'chapter_pve_firewall',
-
-    stateful: true,
-    stateId: 'grid-firewall-rules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(true);
-	    }
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(false);
-	    }
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + "/" + from,
-	    method: 'PUT',
-	    params: { moveto: to },
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	rule.enable = rule.enable ? 1 : 0;
-
-	var pos = rule.pos;
-	delete rule.pos;
-	delete rule.errors;
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + '/' + pos.toString(),
-	    method: 'PUT',
-	    params: rule,
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-fw-rule'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-	    var editor;
-	    if (type === 'in' || type === 'out') {
-		editor = 'PVE.FirewallRuleEdit';
-	    } else if (type === 'group') {
-		editor = 'PVE.FirewallGroupRuleEdit';
-	    } else {
-		return;
-	    }
-
-	    var win = Ext.create(editor, {
-		digest: rec.data.digest,
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rule_pos: rec.data.pos
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallRuleEdit', {
-		    allow_iface: me.allow_iface,
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var run_copy_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-
-	    if (!(type === 'in' || type === 'out')) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallRuleEdit', {
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rec: rec
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.copyBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Copy'),
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return (rec.data.type === 'in' || rec.data.type === 'out');
-	    },
-	    disabled: true,
-	    handler: run_copy_editor
-	});
-
-	if (me.allow_groups) {
-	    me.groupBtn =  Ext.create('Ext.Button', {
-		text: gettext('Insert') + ': ' + 
-		    gettext('Security Group'),
-		disabled: true,
-		handler: function() {
-		    var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-			allow_iface: me.allow_iface,
-			base_url: me.base_url
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    confirmMsg: false,
-	    getRecordName: function(rec) {
-		var rule = rec.data;
-		return rule.pos.toString() +
-		    '?digest=' + encodeURIComponent(rule.digest);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-
-	var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-	tbar.push(me.addBtn, me.copyBtn);
-	if (me.groupBtn) {
-	    tbar.push(me.groupBtn);
-	}
-	tbar.push(me.removeBtn, me.editBtn);
-
-	var render_errors = function(name, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors && errors[name]) {
-		metaData.tdCls = 'proxmox-invalid-row';
-		var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-		metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-		    html.replace(/\"/g,'&quot;') + '"';
-	    }
-	    return value;
-	};
-
-	var columns = [
-	    {
-		// similar to xtype: 'rownumberer',
-		dataIndex: 'pos',
-		resizable: false,
-		width: 23,
-		sortable: false,
-		align: 'right',
-		hideable: false,
-		menuDisabled: true,
-		renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-		    metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-		    if (value >= 0) {
-			return value;
-		    }
-		    return '';
-		}
-	    },
-	    {
-		xtype: 'checkcolumn',
-		header: gettext('Enable'),
-		dataIndex: 'enable',
-		listeners: {
-		    checkchange: function(column, recordIndex, checked) {
-			var record = me.getStore().getData().items[recordIndex];
-			record.commit();
-			var data = {};
-			Ext.Array.forEach(record.getFields(), function(field) {
-			    data[field.name] = record.get(field.name);
-			});
-			if (!me.allow_iface || !data.iface) {
-			    delete data.iface;
-			}
-			me.updateRule(data);
-		    }
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		renderer: function(value, metaData, record) {
-		    return render_errors('type', value, metaData, record);
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Action'),
-		dataIndex: 'action',
-		renderer: function(value, metaData, record) {
-		    return render_errors('action', value, metaData, record);
-		},
-		width: 80
-	    },
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		renderer: function(value, metaData, record) {
-		    return render_errors('macro', value, metaData, record);
-		},
-		width: 80
-	    }
-	];
-
-	if (me.allow_iface) {
-	    columns.push({
-		header: gettext('Interface'),
-		dataIndex: 'iface',
-		renderer: function(value, metaData, record) {
-		    return render_errors('iface', value, metaData, record);
-		},
-		width: 80
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Source'),
-		dataIndex: 'source',
-		renderer: function(value, metaData, record) {
-		    return render_errors('source', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Destination'),
-		dataIndex: 'dest',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dest', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'proto',
-		renderer: function(value, metaData, record) {
-		    return render_errors('proto', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Dest. port'),
-		dataIndex: 'dport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Source port'),
-		dataIndex: 'sport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('sport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Log level'),
-		dataIndex: 'log',
-		renderer: function(value, metaData, record) {
-		    return render_errors('log', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comment',
-		flex: 1,
-		renderer: function(value, metaData, record) {
-		    return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-		}
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-            viewConfig: {
-		plugins: [
-		    {
-			ptype: 'gridviewdragdrop',
-			dragGroup: 'FWRuleDDGroup',
-			dropGroup: 'FWRuleDDGroup'
-		    }
-		],
-		listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-			if (!dropRec) {
-			    return false; // empty view
-			}
-			var moveto = dropRec.get('pos');
-			if (dropPosition === 'after') {
-			    moveto++;
-			}
-			var pos = data.records[0].get('pos');
-			me.moveRule(pos, moveto);
-			return 0;
-                    },
-		    itemdblclick: run_editor
-		}
-	    },
-	    sortableColumns: false,
-	    columns: columns
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'enable', type: 'boolean' },
-		  'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-		  'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-	idProperty: 'pos'
-    });
-
-});
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    
-    alias_name: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.alias_name === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-            me.method = 'PUT';
-        }
-
-	var items =  [
-	    {
-		xtype: 'textfield',
-		name: me.isCreate ? 'name' : 'rename',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'cidr',
-		fieldLabel: gettext('IP/CIDR'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    items: items
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Alias'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    values.rename = values.name;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('pve-fw-aliases', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'name', 'cidr', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    onlineHelp: 'pve_firewall_ip_aliases',
-
-    stateful: true,
-    stateId: 'grid-firewall-aliases',
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-aliases',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallAliasEdit', {
-		base_url: me.base_url,
-		alias_name: rec.data.name
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallAliasEdit', {
-		    base_url: me.base_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Name'), dataIndex: 'name', width: 100 },
-		{ header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-	me.on('activate', reload);
-    }
-});
-Ext.define('PVE.FirewallOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-	    if (me.fwtype === 'node') {
-		me.cwidth1 = 250;
-	    }
-	} else {
-	    throw "unknown firewall option type";
-	}
-
-	me.rows = {};
-
-	var add_boolean_row = function(name, text, defaultValue) {
-	    me.add_boolean_row(name, text, { defaultValue: defaultValue });
-	};
-	var add_integer_row = function(name, text, minValue, labelWidth) {
-	    me.add_integer_row(name, text, {
-		minValue: minValue,
-		deleteEmpty: true,
-		labelWidth: labelWidth,
-		renderer: function(value) {
-		    if (value === undefined) {
-			return Proxmox.Utils.defaultText;
-		    }
-
-		    return value;
-		}
-	    });
-	};
-
-	var add_log_row = function(name, labelWidth) {
-	    me.rows[name] = {
-		header: name,
-		required: true,
-		defaultValue: 'nolog',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: name,
-		    fieldDefaults: { labelWidth: labelWidth || 100 },
-		    items: {
-			xtype: 'pveFirewallLogLevels',
-			name: name,
-			fieldLabel: name
-		    }
-		}
-	    };
-	};
-
-	if (me.fwtype === 'node') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 1,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 1
-		}
-	    };
-	    add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-	    add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 32768, 120);
-	    add_integer_row('nf_conntrack_tcp_timeout_established',
-			    'nf_conntrack_tcp_timeout_established', 7875, 250);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	    add_log_row('tcp_flags_log_level', 120);
-	    add_log_row('smurf_log_level');
-	} else if (me.fwtype === 'vm') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 0,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 0
-		}
-	    };
-	    add_boolean_row('dhcp', 'DHCP', 1);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_boolean_row('radv', gettext('Router Advertisement'), 0);
-	    add_boolean_row('macfilter', gettext('MAC filter'), 1);
-	    add_boolean_row('ipfilter', gettext('IP filter'), 0);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	} else if (me.fwtype === 'dc') {
-	    add_boolean_row('enable', gettext('Firewall'), 0);
-	    add_boolean_row('ebtables', 'ebtables', 1);
-	    me.rows.log_ratelimit = {
-		header: gettext('Log rate limit'),
-		required: true,
-		defaultValue: 'enable=0',
-		editor: {
-		    xtype: 'pveFirewallLograteEdit'
-		}
-	    };
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-	    me.rows.policy_in = {
-		header: gettext('Input Policy'),
-		required: true,
-		defaultValue: 'DROP',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Input Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_in',
-			value: 'DROP',
-			fieldLabel: gettext('Input Policy')
-		    }
-		}
-	    };
-
-	    me.rows.policy_out = {
-		header: gettext('Output Policy'),
-		required: true,
-		defaultValue: 'ACCEPT',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Output Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_out',
-			value: 'ACCEPT',
-			fieldLabel: gettext('Output Policy')
-		    }
-		}
-	    };
-	}
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = me.rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json" + me.base_url,
-	    tbar: [ edit_btn ],
-	    editorConfig: {
-		url: '/api2/extjs/' + me.base_url
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-
-
-Ext.define('PVE.FirewallLogLevels', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallLogLevels'],
-
-    name: 'log',
-    fieldLabel: gettext('Log level'),
-    value: 'nolog',
-    comboItems: [['nolog', 'nolog'], ['emerg', 'emerg'], ['alert', 'alert'],
-	['crit', 'crit'], ['err', 'err'], ['warning', 'warning'],
-	['notice', 'notice'], ['info', 'info'], ['debug', 'debug']]
-});
-/*
- * Left Treepanel, containing all the ressources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-	typeDefaults: {
-	    node: { 
-		iconCls: 'fa fa-building',
-		text: gettext('Nodes')
-	    },
-	    pool: { 
-		iconCls: 'fa fa-tags',
-		text: gettext('Resource Pool')
-	    },
-	    storage: {
-		iconCls: 'fa fa-database',
-		text: gettext('Storage')
-	    },
-	    qemu: {
-		iconCls: 'fa fa-desktop',
-		text: gettext('Virtual Machine')
-	    },
-	    lxc: {
-		//iconCls: 'x-tree-node-lxc',
-		iconCls: 'fa fa-cube',
-		text: gettext('LXC Container')
-	    },
-	    template: {
-		iconCls: 'fa fa-file-o'
-	    }
-	}
-    },
-
-    useArrows: true,
-
-    // private
-    nodeSortFn: function(node1, node2) {
-	var n1 = node1.data;
-	var n2 = node2.data;
-
-	if ((n1.groupbyid && n2.groupbyid) ||
-	    !(n1.groupbyid || n2.groupbyid)) {
-
-	    var tcmp;
-
-	    var v1 = n1.type;
-	    var v2 = n2.type;
-
-	    if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		return tcmp;
-	    }
-
-	    // numeric compare for VM IDs
-	    // sort templates after regular VMs
-	    if (v1 === 'qemu' || v1 === 'lxc') {
-		if (n1.template && !n2.template) {
-		    return 1;
-		} else if (n2.template && !n1.template) {
-		    return -1;
-		}
-		v1 = n1.vmid;
-		v2 = n2.vmid;
-		if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		    return tcmp;
-		}
-	    }
-
-	    return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
-	} else if (n1.groupbyid) {
-	    return -1;
-	} else if (n2.groupbyid) {
-	    return 1;
-	}
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-	var me = this;
-
-	var diff = end - start;
-
-	var mid = start + (diff>>1);
-
-	if (diff <= 0) {
-	    return start;
-	}
-
-	var res = me.nodeSortFn(child, node.childNodes[mid]);
-	if (res <= 0) {
-	    return me.findInsertIndex(node, child, start, mid);
-	} else {
-	    return me.findInsertIndex(node, child, mid + 1, end);
-	}
-    },
-
-    setIconCls: function(info) {
-	var me = this;
-
-	var cls = PVE.Utils.get_object_icon_class(info.type, info);
-
-	if (cls !== '') {
-	    info.iconCls = cls;
-	}
-    },
-
-    // add additional elements to text
-    // at the moment only the usage indicator for storages
-    setText: function(info) {
-	var me = this;
-
-	var status = '';
-	if (info.type === 'storage') {
-	    var maxdisk = info.maxdisk;
-	    var disk = info.disk;
-	    var usage = disk/maxdisk;
-	    var cls = '';
-	    if (usage <= 1.0 && usage >= 0.0) {
-		var height = (usage*100).toFixed(0);
-		var neg_height = (100-usage*100).toFixed(0);
-		status = '<div class="usage-wrapper">';
-		status += '<div class="usage-negative" style="height: ';
-		status += neg_height + '%"></div>';
-		status += '<div class="usage" style="height: '+ height +'%"></div>';
-		status += '</div> ';
-	    }
-	}
-
-	info.text = status + info.text;
-    },
-
-    setToolTip: function(info) {
-	if (info.type === 'pool' || info.groupbyid !== undefined) {
-	    return;
-	}
-
-	var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
-	if (info.hastate != 'unmanaged') {
-	    qtips.push(gettext('HA State') + ": " + info.hastate);
-	}
-
-	info.qtip = qtips.join(', ');
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-	var me = this;
-
-	me.setIconCls(info);
-	me.setText(info);
-	me.setToolTip(info);
-
-	var defaults;
-	if (info.groupbyid) {
-	    info.text = info.groupbyid;
-	    if (info.type === 'type') {
-		defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-		if (defaults && defaults.text) {
-		    info.text = defaults.text;
-		}
-	    }
-	}
-	var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-	var pos;
-	if (cs) {
-	    pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-	}
-
-	node.insertBefore(child, pos);
-
-	return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-	var me = this;
-
-	var groupby = groups[level];
-	var v = info[groupby];
-
-	if (v) {
-            var group = node.findChild('groupbyid', v);
-	    if (!group) {
-		var groupinfo;
-		if (info.type === groupby) {
-		    groupinfo = info;
-		} else {
-		    groupinfo = {
-			type: groupby,
-			id : groupby + "/" + v
-		    };
-		    if (groupby !== 'type') {
-			groupinfo[groupby] = v;
-		    }
-		}
-		groupinfo.leaf = false;
-		groupinfo.groupbyid = v; 
-		group = me.addChildSorted(node, groupinfo);
-	    }
-	    if (info.type === groupby) {
-		return group;
-	    }
-	    if (group) {
-		return me.groupChild(group, info, groups, level + 1);
-	    }
-	}
-
-	return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	if (!me.viewFilter) {
-	    me.viewFilter = {};
-	}
-
-	var pdata = {
-	    dataIndex: {},
-	    updateCount: 0
-	};
-
-	var store = Ext.create('Ext.data.TreeStore', {
-	    model: 'PVETree',
-	    root: {
-		expanded: true,
-		id: 'root',
-		text: gettext('Datacenter'),
-		iconCls: 'fa fa-server'
-	    }
-	});
-
-	var stateid = 'rid';
-
-	var updateTree = function() {
-	    var tmp;
-
-	    store.suspendEvents();
-
-	    var rootnode = me.store.getRootNode();
-	    // remember selected node (and all parents)
-	    var sm = me.getSelectionModel();
-
-	    var lastsel = sm.getSelection()[0];
-	    var reselect = false;
-	    var parents = [];
-	    var p = lastsel;
-	    while (p && !!(p = p.parentNode)) {
-		parents.push(p);
-	    }
-
-	    var index = pdata.dataIndex;
-
-	    var groups = me.viewFilter.groups || [];
-	    var filterfn = me.viewFilter.filterfn;
-
-	    // remove vanished or moved items
-	    // update in place changed items
-	    var key;
-	    for (key in index) {
-		if (index.hasOwnProperty(key)) {
-		    var olditem = index[key];
-
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var item = rstore.getById(olditem.data.id);
-		    var item = rstore.data.get(olditem.data.id);
-
-		    var changed = false;
-		    var moved = false;
-		    if (item) {
-			// test if any grouping attributes changed
-			// this will also catch migrated nodes
-			// in server view
-			var i, len;
-			for (i = 0, len = groups.length; i < len; i++) {
-			    var attr = groups[i];
-			    if (item.data[attr] != olditem.data[attr]) {
-				//console.log("changed " + attr);
-				moved = true;
-				break;
-			    }
-			}
-
-			// explicitely check for node, since
-			// in some views, node is not a grouping
-			// attribute
-			if (!moved && item.data.node !== olditem.data.node) {
-			    moved = true;
-			}
-
-			// tree item has been updated
-			if ((item.data.text !== olditem.data.text) ||
-			    (item.data.running !== olditem.data.running) ||
-			    (item.data.template !== olditem.data.template) ||
-			    (item.data.status !== olditem.data.status) ||
-			    (item.data.hastate!== olditem.data.hastate)) {
-			    //console.log("changed node/text/running " + olditem.data.id);
-			    changed = true;
-			}
-
-			// fixme: also test filterfn()?
-		    }
-
-		    if (changed) {
-			olditem.beginEdit();
-			//console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-			var info = olditem.data;
-			Ext.apply(info, item.data);
-			me.setIconCls(info);
-			me.setText(info);
-			me.setToolTip(info);
-			olditem.commit();
-		    }
-		    if ((!item || moved) && olditem.isLeaf()) {
-			//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-			delete index[key];
-			var parentNode = olditem.parentNode;
-			// when the selected item disappears,
-			// we have to deselect it here, and reselect it
-			// later
-			if (lastsel && olditem.data.id === lastsel.data.id) {
-			    reselect = true;
-			    sm.deselect(olditem);
-			}
-			// since the store events are suspended, we
-			// manually remove the item from the store also
-			store.remove(olditem);
-			parentNode.removeChild(olditem, true);
-		    }
-		}
-	    }
-
-	    // add new items
-            rstore.each(function(item) {
-		var olditem = index[item.data.id];
-		if (olditem) {
-		    return;
-		}
-
-		if (filterfn && !filterfn(item)) {
-		    return;
-		}
-
-		//console.log("ADD UID: " + item.data.id);
-
-		var info = Ext.apply({ leaf: true }, item.data);
-
-		var child = me.groupChild(rootnode, info, groups, 0);
-		if (child) {
-		    index[item.data.id] = child;
-		}
-	    });
-
-	    store.resumeEvents();
-	    store.fireEvent('refresh', store);
-
-	    // select parent node is selection vanished
-	    if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-		lastsel = rootnode;
-		while (!!(p = parents.shift())) {
-		    if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-			lastsel = tmp;
-			break;
-		    }
-		}
-		me.selectById(lastsel.data.id);
-	    } else if (lastsel && reselect) {
-		me.selectById(lastsel.data.id);
-	    }
-
-	    // on first tree load set the selection from the stateful provider
-	    if (!pdata.updateCount) {
-		rootnode.expand();
-		me.applyState(sp.get(stateid));
-	    }
-
-	    pdata.updateCount++;
-	};
-
-	var statechange = function(sp, key, value) {
-	    if (key === stateid) {
-		me.applyState(value);
-	    }
-	};
-
-	sp.on('statechange', statechange);
-
-	Ext.apply(me, {
-	    allowSelection: true,
-	    store: store,
-	    viewConfig: {
-		// note: animate cause problems with applyState
-		animate: false
-	    },
-	    //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		destroy: function() {
-		    rstore.un("load", updateTree);
-		},
-		beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
-		    var sm = me.getSelectionModel();
-		    // disable selection when right clicking
-		    // except the record is already selected
-		    me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
-		},
-		beforeselect: function (tree, record, index, eopts) {
-		    var allow = me.allowSelection;
-		    me.allowSelection = true;
-		    return allow;
-		},
-		itemdblclick: PVE.Utils.openTreeConsole
-	    },
-	    setViewFilter: function(view) {
-		me.viewFilter = view;
-		me.clearTree();
-		updateTree();
-	    },
-	    setDatacenterText: function(clustername) {
-		var rootnode = me.store.getRootNode();
-
-		var rnodeText = gettext('Datacenter');
-		if (clustername !== undefined) {
-		    rnodeText += ' (' + clustername + ')';
-		}
-
-		rootnode.beginEdit();
-		rootnode.data.text = rnodeText;
-		rootnode.commit();
-	    },
-	    clearTree: function() {
-		pdata.updateCount = 0;
-		var rootnode = me.store.getRootNode();
-		rootnode.collapse();
-		rootnode.removeAll();
-		pdata.dataIndex = {};
-		me.getSelectionModel().deselectAll();
-	    },
-	    selectExpand: function(node) {
-		var sm = me.getSelectionModel();
-		if (!sm.isSelected(node)) {
-		    sm.select(node);
-		    var cn = node;
-		    while (!!(cn = cn.parentNode)) {
-			if (!cn.isExpanded()) {
-			    cn.expand();
-			}
-		    }
-		    me.getView().focusRow(node);
-		}
-	    },
-	    selectById: function(nodeid) {
-		var rootnode = me.store.getRootNode();
-		var sm = me.getSelectionModel();
-		var node;
-		if (nodeid === 'root') {
-		    node = rootnode;
-		} else {
-		    node = rootnode.findChild('id', nodeid, true);
-		}
-		if (node) {
-		    me.selectExpand(node);
-		}
-		return node;
-	    },
-	    applyState : function(state) {
-		var sm = me.getSelectionModel();
-		if (state && state.value) {
-		    me.selectById(state.value);
-		} else {
-		    sm.deselectAll();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	var sm = me.getSelectionModel();
-	sm.on('select', function(sm, n) {		    
-	    sp.set(stateid, { value: n.data.id});
-	});
-
-	rstore.on("load", updateTree);
-	rstore.startUpdate();
-	//rstore.stopUpdate();
-    }
-
-});
-Ext.define('pve-fw-ipsets', {
-    extend: 'Ext.data.Model',
-    fields: [ 'name', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsetlist',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-
-        var me = this;
-
-	if (me.ipset_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-ipsets',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('Proxmox.window.Edit', {
-		subject: "IPSet '" + rec.data.name + "'",
-		url: me.base_url,
-		method: 'POST',
-		digest: rec.data.digest,
-		items: [
-		    {
-			xtype: 'hiddenfield',
-			name: 'rename',
-			value: rec.data.name
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'name',
-			value: rec.data.name,
-			fieldLabel: gettext('Name'),
-			allowBlank: false
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'comment',
-			value: rec.data.comment,
-			fieldLabel: gettext('Comment')
-		    }
-		]
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('Proxmox.window.Edit', {
-		    subject: 'IPSet',
-		    url: me.base_url,
-		    method: 'POST',
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'name',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'textfield',
-			    name: 'comment',
-			    value: '',
-			    fieldLabel: gettext('Comment')
-			}
-		    ]
-		});
-		win.show();
-		win.on('destroy', reload);
-
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: 'IPSet', dataIndex: 'name', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = me.base_url + '/' + rec.data.name;
-		    me.ipset_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.ipset_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.cidr === undefined);
-
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-	var column1 = [];
-
-	if (me.isCreate) {
-	    if (!me.list_refs_url) {
-		throw "no alias_base_url specified";
-	    }
-
-	    column1.push({
-		xtype: 'pveIPRefSelector',
-		name: 'cidr',
-		ref_type: 'alias',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	} else {
-	    column1.push({
-		xtype: 'displayfield',
-		name: 'cidr',
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'nomatch',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: 'nomatch'
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('IP/CIDR'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsets',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no1 list_refs_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ipset'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.IPSetCidrEdit', {
-		base_url: me.base_url,
-		cidr: rec.data.cidr
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		if (!me.base_url) {
-		    return;
-		}
-		var win = Ext.create('PVE.IPSetCidrEdit', {
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	var render_errors = function(value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors.cidr || errors.nomatch;
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	Ext.apply(me, {
-	    tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    store: store,
-	    selModel: sm,
-	    listeners: {
-		itemdblclick: run_editor
-	    },
-	    columns: [
-		{
-		    xtype: 'rownumberer'
-		},
-		{
-		    header: gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			value = render_errors(value, metaData, record);
-			if (record.data.nomatch) {
-			    return '<b>! </b>' + value;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    flex: 1,
-		    renderer: function(value) {
-			return Ext.util.Format.htmlEncode(value);
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'nomatch', type: 'boolean' },
-		  'cidr', 'comment', 'errors' ],
-	idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    onlineHelp: 'pve_firewall_ip_sets',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-	    region: 'center',
-	    list_refs_url: me.list_refs_url,
-	    border: false
-	});
-
-	var ipset_list = Ext.createWidget('pveIPSetList', {
-	    region: 'west',
-	    ipset_panel: ipset_panel,
-	    base_url: me.base_url,
-	    width: '50%',
-	    border: false,
-	    split: true
-	});
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-	    listeners: {
-		show: function() {
-		    ipset_list.fireEvent('show', ipset_list);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Base class for all the multitab config panels
- *
- * How to use this:
- *
- * You create a subclass of this, and then define your wanted tabs
- * as items like this:
- *
- * items: [{
- *  title: "myTitle",
- *  xytpe: "somextype",
- *  iconCls: 'fa fa-icon',
- *  groups: ['somegroup'],
- *  expandedOnInit: true,
- *  itemId: 'someId'
- * }]
- *
- * this has to be in the declarative syntax, else we
- * cannot save them for later
- * (so no Ext.create or Ext.apply of an item in the subclass)
- *
- * the groups array expects the itemids of the items
- * which are the parents, which have to come before they
- * are used
- *
- * if you want following the tree:
- *
- * Option1
- * Option2
- *   -> SubOption1
- *	-> SubSubOption1
- *
- * the suboption1 group array has to look like this:
- * groups: ['itemid-of-option2']
- *
- * and of subsuboption1:
- * groups: ['itemid-of-option2', 'itemid-of-suboption1']
- *
- * setting the expandedOnInit determines if the item/group is expanded
- * initially (false by default)
- */
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    showSearch: true, // add a ressource grid with a search button as first tab
-    viewFilter: undefined, // a filter to pass to that ressource grid
-
-    tbarSpacing: true, // if true, adds a spacer after the title in tbar
-
-    dockedItems: [{
-	// this is needed for the overflow handler
-	xtype: 'toolbar',
-	overflowHandler: 'scroller',
-	dock: 'left',
-	style: {
-	    backgroundColor: '#f5f5f5',
-	    padding: 0,
-	    margin: 0
-	},
-	items: {
-	    xtype: 'treelist',
-	    itemId: 'menu',
-	    ui: 'nav',
-	    expanderOnly: true,
-	    expanderFirst: false,
-	    animation: false,
-	    singleExpand: false,
-	    listeners: {
-		selectionchange: function(treeList, selection) {
-		    var me = this.up('panel');
-		    me.suspendLayout = true;
-		    me.activateCard(selection.data.id);
-		    me.suspendLayout = false;
-		    me.updateLayout();
-		},
-		itemclick: function(treelist, info) {
-		    var olditem = treelist.getSelection();
-		    var newitem = info.node;
-
-		    // when clicking on the expand arrow,
-		    // we dont select items, but still want
-		    // the original behaviour
-		    if (info.select === false) {
-			return;
-		    }
-
-		    // if you click on a different item which is open,
-		    // leave it open
-		    // else toggle the clicked item
-		    if (olditem.data.id !== newitem.data.id &&
-			newitem.data.expanded === true) {
-			info.toggle = false;
-		    } else {
-			info.toggle = true;
-		    }
-		}
-	    }
-	}
-    },
-    {
-	xtype: 'toolbar',
-	itemId: 'toolbar',
-	dock: 'top',
-	height: 36,
-	overflowHandler: 'scroller'
-    }],
-
-    firstItem: '',
-    layout: 'card',
-    border: 0,
-
-    // used for automated test
-    selectById: function(cardid) {
-	var me = this;
-
-	var root = me.store.getRoot();
-	var selection = root.findChild('id', cardid, true);
-
-	if (selection) {
-	    selection.expand();
-	    var menu = me.down('#menu');
-	    menu.setSelection(selection);
-	    return cardid;
-	}
-    },
-
-    activateCard: function(cardid) {
-	var me = this;
-	if (me.savedItems[cardid]) {
-	    var curcard = me.getLayout().getActiveItem();
-	    var newcard = me.add(me.savedItems[cardid]);
-	    me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp);
-	    if (curcard) {
-		me.setActiveItem(cardid);
-		me.remove(curcard, true);
-
-		// trigger state change
-
-		var ncard = cardid;
-		// Note: '' is alias for first tab.
-		// First tab can be 'search' or something else
-		if (cardid === me.firstItem) {
-		    ncard = '';
-		}
-		if (me.hstateid) {
-		   me.sp.set(me.hstateid, { value: ncard });
-		}
-	    }
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = me.hstateid;
-
-	me.sp = Ext.state.Manager.getProvider();
-
-	var activeTab; // leaving this undefined means items[0] will be the default tab
-
-	if (stateid) {
-	    var state = me.sp.get(stateid);
-	    if (state && state.value) {
-		// if this tab does not exists, it chooses the first
-		activeTab = state.value;
-	    }
-	}
-
-	// get title
-	var title = me.title || me.pveSelNode.data.text;
-	me.title = undefined;
-
-	// create toolbar
-	var tbar = me.tbar || [];
-	me.tbar = undefined;
-
-	if (!me.onlineHelp) {
-	    switch(me.pveSelNode.data.id) {
-		case 'type/storage':me.onlineHelp = 'chapter-pvesm.html'; break;
-		case 'type/qemu':me.onlineHelp = 'chapter-qm.html'; break;
-		case 'type/lxc':me.onlineHelp = 'chapter-pct.html'; break;
-		case 'type/pool':me.onlineHelp = 'chapter-pveum.html#_pools'; break;
-		case 'type/node':me.onlineHelp = 'chapter-sysadmin.html'; break;
-	    }
-	}
-
-	if (me.tbarSpacing) {
-	    tbar.unshift('->');
-	}
-	tbar.unshift({
-	    xtype: 'tbtext',
-	    text: title,
-	    baseCls: 'x-panel-header-text'
-	});
-
-	me.helpButton = Ext.create('Proxmox.button.Help', {
-	    hidden: false,
-	    listenToGlobalEvent: false,
-	    onlineHelp: me.onlineHelp || undefined
-	});
-
-	tbar.push(me.helpButton);
-
-	me.dockedItems[1].items = tbar;
-
-	// include search tab
-	me.items = me.items || [];
-	if (me.showSearch) {
-	    me.items.unshift({
-		itemId: 'search',
-		title: gettext('Search'),
-		iconCls: 'fa fa-search',
-		xtype: 'pveResourceGrid',
-		pveSelNode: me.pveSelNode
-	    });
-	}
-
-	me.savedItems = {};
-	/*jslint confusion:true*/
-	if (me.items[0]) {
-	    me.firstItem = me.items[0].itemId;
-	}
-	/*jslint confusion:false*/
-
-	me.store = Ext.create('Ext.data.TreeStore', {
-	    root: {
-		expanded: true
-	    }
-	});
-	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
-
-	delete me.items;
-	me.defaults = me.defaults || {};
-	Ext.apply(me.defaults, {
-	    pveSelNode: me.pveSelNode,
-	    viewFilter: me.viewFilter,
-	    workspace: me.workspace,
-	    border: 0
-	});
-
-	me.callParent();
-
-	var menu = me.down('#menu');
-	var selection = root.findChild('id', activeTab, true) || root.firstChild;
-	var node = selection;
-	while (node !== root) {
-	    node.expand();
-	    node = node.parentNode;
-	}
-	menu.setStore(me.store);
-	menu.setSelection(selection);
-
-	// on a state change,
-	// select the new item
-	var statechange = function(sp, key, state) {
-	    // it the state change is for this panel
-	    if (stateid && (key === stateid) && state) {
-		// get active item
-		var acard = me.getLayout().getActiveItem().itemId;
-		// get the itemid of the new value
-		var ncard = state.value || me.firstItem;
-		if (ncard && (acard != ncard)) {
-		    // select the chosen item
-		    menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
-		}
-	    }
-	};
-
-	if (stateid) {
-	    me.mon(me.sp, 'statechange', statechange);
-	}
-    }
-});
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    stateful: true,
-    stateId: 'grid-guest-backup',
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmtype = me.pveSelNode.data.type;
-	if (!vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var vmtypeFilter;
-	if (vmtype === 'openvz') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-openvz-');
-	    };
-	} else if (vmtype === 'lxc') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-lxc-');
-	    };
-	} else if (vmtype === 'qemu') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-qemu-');
-	    };
-	} else {
-	    throw "unsupported VM type '" + vmtype + "'";
-	}
-
-	var searchFilter = {
-	    property: 'volid',
-	// on initial store display only our vmid backups
-	// surround with minus sign to prevent the 2016 VMID bug
-	    value: vmtype + '-' + vmid + '-',
-	    anyMatch: true,
-	    caseSensitive: false
-	};
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-content',
-	    sorters: { 
-		property: 'volid', 
-		order: 'DESC' 
-	    },
-	    filters: [
-	        vmtypeFilter,
-		searchFilter
-		]
-	});
-
-	var reload = Ext.Function.createBuffered(function() {
-	    if (me.store) {
-		me.store.load();
-	    }
-	}, 100);
-
-	var setStorage = function(storage) {
-	    var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-	    url += '?content=backup';
-
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: url
-	    });
-
-	    reload();
-	};
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    setStorage(value);
-		}
-	    }
-	});
-
-	var storagefilter = Ext.create('Ext.form.field.Text', {
-	    fieldLabel: gettext('Search'),
-	    labelWidth: 50,
-	    labelAlign: 'right',
-	    enableKeyEvents: true,
-	    value: searchFilter.value,
-	    listeners: {
-		buffer: 500,
-		keyup: function(field) {
-		    me.store.clearFilter(true);
-		    searchFilter.value = field.getValue();
-		    me.store.filter([
-			vmtypeFilter,
-			searchFilter
-		    ]);
-		}
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var backup_btn = Ext.create('Ext.button.Button', {
-	    text: gettext('Backup now'),
-	    handler: function() {
-		var win = Ext.create('PVE.window.Backup', { 
-		    nodename: nodename,
-		    vmid: vmid,
-		    vmtype: vmtype,
-		    storage: storagesel.getValue(),
-		    listeners : {
-			close: function() {
-			    reload();
-			}
-		    }
-		});
-		win.show();
-	    }
-	});
-
-	var restore_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Restore'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var volid = rec.data.volid;
-
-		var win = Ext.create('PVE.window.Restore', {
-		    nodename: nodename,
-		    vmid: vmid,
-		    volid: rec.data.volid,
-		    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-		    vmtype: vmtype
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var delete_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.volid + "'");
-		msg += " " + gettext('This will permanently erase all data.');
-
-		return msg;
-	    },
-	    getUrl: function(rec) {
-		var storage = storagesel.getValue();
-		return '/nodes/' + nodename + '/storage/' + storage + '/content/' + rec.data.volid;
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	var config_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show Configuration'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var storage = storagesel.getValue();
-		if (!storage) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.window.BackupConfig', {
-		    volume: rec.data.volid,
-		    pveSelNode: me.pveSelNode
-		});
-
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    tbar: [ backup_btn, restore_btn, delete_btn,config_btn, '->', storagesel, storagefilter ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'volid'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.CephCreateFS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateFS',
-
-    showTaskViewer: true,
-    onlineHelp: 'pveceph_fs_create',
-
-    subject: 'Ceph FS',
-    isCreate: true,
-    method: 'POST',
-
-    setFSName: function(fsName) {
-	var me = this;
-
-	if (fsName === '' || fsName === undefined) {
-	    fsName = 'cephfs';
-	}
-
-	me.url = "/nodes/" + me.nodename + "/ceph/fs/" + fsName;
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    value: 'cephfs',
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateFS').setFSName(value);
-		}
-	    },
-	    submitValue: false, // already encoded in apicall URL
-	    emptyText: 'cephfs'
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'Placement Groups',
-	    name: 'pg_num',
-	    value: 128,
-	    emptyText: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add Storage'),
-	    value: true,
-	    name: 'add-storage'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setFSName();
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.CephCreateMDS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateMDS',
-
-    showProgress: true,
-    onlineHelp: 'pveceph_fs_mds',
-
-    subject: 'Ceph MDS',
-    isCreate: true,
-    method: 'POST',
-
-    setNode: function(nodename) {
-	var me = this;
-
-	me.nodename = nodename;
-	me.url = "/nodes/" + nodename + "/ceph/mds/" + nodename;
-    },
-
-    items: [
-	{
-	    xtype: 'pveNodeSelector',
-	    fieldLabel: gettext('Node'),
-	    selectCurNode: true,
-	    submitValue: false,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateMDS').setNode(value);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setNode(me.nodename);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.NodeCephFSPanel', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNodeCephFSPanel',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    title: gettext('CephFS'),
-    onlineHelp: 'pveceph_fs',
-
-    border: false,
-    defaults: {
-	border: false,
-	cbind: {
-	    nodename: '{nodename}'
-	}
-    },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    cephfsConfigured: false,
-	    mdsCount: 0
-	},
-	formulas: {
-	    canCreateFS: function(get) {
-		return (!get('cephfsConfigured') && get('mdsCount') > 0);
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'CephFS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-fs',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/' + view.nodename + '/ceph/fs'
-			},
-			model: 'pve-ceph-fs'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'name',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateFS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!(success && records && records.length > 0)) {
-			vm.set('cephfsConfigured', false);
-			return;
-		    }
-		    vm.set('cephfsConfigured', true);
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create CephFS'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			// only one CephFS per Ceph cluster makes sense for now
-			disabled: '{!canCreateFS}'
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: 'Data Pool',
-		    flex: 1,
-		    dataIndex: 'data_pool'
-		},
-		{
-		    header: 'Metadata Pool',
-		    flex: 1,
-		    dataIndex: 'metadata_pool'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Metadata Servers'),
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'MDS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 3 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-mds',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/'+ view.nodename +'/ceph/mds'
-			},
-			model: 'pve-ceph-mds'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'id',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('mdsCount', 0);
-			return;
-		    }
-		    vm.set('mdsCount', records.length);
-		},
-		onCreateMDS: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateMDS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create MDS'),
-		    reference: 'createButton',
-		    handler: 'onCreateMDS'
-		},
-		{
-		    text: gettext('Destroy MDS'),
-		    xtype: 'proxmoxStdRemoveButton',
-		    getUrl: function(rec) {
-			if (!rec.data.host) {
-			    Ext.Msg.alert(gettext('Error'), "entry has no host");
-			    return;
-			}
-			return "/nodes/" + rec.data.host + "/ceph/mds/" + rec.data.name;
-		    },
-		    callback: function(options, success, response) {
-			if (!success) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    return;
-			}
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Host'),
-		    flex: 1,
-		    dataIndex: 'host'
-		},
-		{
-		    header: gettext('Address'),
-		    flex: 1,
-		    dataIndex: 'addr'
-		},
-		{
-		    header: gettext('State'),
-		    flex: 1,
-		    dataIndex: 'state'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-}, function() {
-    Ext.define('pve-ceph-mds', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'host', 'addr', 'state' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/mds"
-	},
-	idProperty: 'name'
-    });
-    Ext.define('pve-ceph-fs', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'data_pool', 'metadata_pool' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/fs"
-	},
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.CephCreatePool', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreatePool',
-
-    showProgress: true,
-    onlineHelp: 'pve_ceph_pools',
-
-    subject: 'Ceph Pool',
-    isCreate: true,
-    method: 'POST',
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Size'),
-	    name: 'size',
-	    value: 3,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Min. Size'),
-	    name: 'min_size',
-	    value: 2,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'pveCephRuleSelector',
-	    fieldLabel: 'Crush Rule', // do not localize
-	    name: 'crush_rule',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'pg_num',
-	    name: 'pg_num',
-	    value: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add Storage'),
-	    name: 'add_storages'
-	}
-    ],
-    initComponent : function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.apply(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/pools",
-	    defaults: {
-		nodename: me.nodename
-	    }
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephPoolList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeCephPoolList',
-
-    onlineHelp: 'chapter_pveceph',
-    stateful: true,
-    stateId: 'grid-ceph-pools',
-    bufferedRenderer: false,
-    features: [ { ftype: 'summary'} ],
-    columns: [
-	{
-	    header: gettext('Name'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'pool_name'
-	},
-	{
-	    header: gettext('Size') + '/min',
-	    width: 80,
-	    sortable: false,
-	    renderer: function(v, meta, rec) {
-		return v + '/' + rec.data.min_size;
-	    },
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'pg_num',
-	    width: 100,
-	    sortable: false,
-	    dataIndex: 'pg_num'
-	},
-	{
-	    header: 'rule',
-	    width: 50,
-	    sortable: false,
-	    dataIndex: 'crush_rule'
-	},
-	{
-	    header: 'rule_name',
-	    width: 50,
-	    sortable: false,
-	    dataIndex: 'crush_rule_name'
-	},
-	{
-	    header: gettext('Used'),
-	    columns: [
-		{
-		    header: '%',
-		    width: 80,
-		    sortable: true,
-		    align: 'right',
-		    renderer: Ext.util.Format.numberRenderer('0.00'),
-		    dataIndex: 'percent_used',
-		    summaryType: 'sum',
-		    summaryRenderer: Ext.util.Format.numberRenderer('0.00')
-		},
-		{
-		    header: gettext('Total'),
-		    width: 100,
-		    sortable: true,
-		    renderer: PVE.Utils.render_size,
-		    align: 'right',
-		    dataIndex: 'bytes_used',
-		    summaryType: 'sum',
-		    summaryRenderer: PVE.Utils.render_size
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-pool-list' + nodename,
-	    model: 'ceph-pool-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/pools"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		var win = Ext.create('PVE.CephCreatePool', {
-                    nodename: nodename
-		});
-		win.show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	var destroy_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Destroy'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.pool_name) {
-		    return;
-		}
-		var base_url = '/nodes/' + nodename + '/ceph/pools/' +
-		    rec.data.pool_name;
-
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    showProgress: true,
-		    url: base_url,
-		    params: {
-			remove_storages: 1
-		    },
-		    item: { type: 'CephPool', id: rec.data.pool_name }
-		}).show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ create_btn, destroy_btn ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-pool-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'pool_name',
-		  { name: 'pool', type: 'integer'},
-		  { name: 'size', type: 'integer'},
-		  { name: 'min_size', type: 'integer'},
-		  { name: 'pg_num', type: 'integer'},
-		  { name: 'bytes_used', type: 'integer'},
-		  { name: 'percent_used', type: 'number'},
-		  { name: 'crush_rule', type: 'integer'},
-		  { name: 'crush_rule_name', type: 'string'}
-		],
-	idProperty: 'pool_name'
-    });
-});
-
-Ext.define('PVE.form.CephRuleSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephRuleSelector',
-
-    allowBlank: false,
-    valueField: 'name',
-    displayField: 'name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/rules'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.CephCreateOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephCreateOsd'],
-
-    subject: 'Ceph OSD',
-
-    showProgress: true,
-
-    onlineHelp: 'pve_ceph_osds',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'dev',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'journal_dev',
-		    nodename: me.nodename,
-		    diskType: 'journal_disks',
-		    fieldLabel: gettext('Journal/DB Disk'),
-		    value: '',
-		    autoSelect: false,
-		    allowBlank: true,
-		    emptyText: 'use OSD disk'
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'bluestore',
-		    fieldLabel: 'Bluestore',
-		    uncheckedValue: '0',
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.CephRemoveOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephRemoveOsd'],
-
-    isRemove: true,
-
-    showProgress: true,
-    method: 'DELETE',
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cleanup',
-	    checked: true,
-	    labelWidth: 130,
-	    fieldLabel: gettext('Remove Partitions')
-	}
-    ],
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (me.osdid === undefined || me.osdid < 0) {
-	    throw "no osdid specified";
-	}
-
-	me.isCreate = true;
-
-	me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephOsdTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveNodeCephOsdTree'],
-    onlineHelp: 'chapter_pveceph',
-    stateful: true,
-    stateId: 'grid-ceph-osd',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: 'Name',
-	    dataIndex: 'name',
-	    width: 150
-	},
-	{
-	    text: 'Type',
-	    dataIndex: 'type',
-	    align: 'right',
-	    width: 60
-	},
-	{
-	    text: gettext("Class"),
-	    dataIndex: 'device_class',
-	    align: 'right',
-	    width: 40
-	},
-	{
-	    text: "OSD Type",
-	    dataIndex: 'osdtype',
-	    align: 'right',
-	    width: 40
-	},
-	{
-	    text: "Bluestore Device",
-	    dataIndex: 'blfsdev',
-	    align: 'right',
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: "DB Device",
-	    dataIndex: 'dbdev',
-	    align: 'right',
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: "WAL Device",
-	    dataIndex: 'waldev',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (!value &&
-		    rec.data.osdtype === 'bluestore' &&
-		    rec.data.type === 'osd') {
-		    return 'N/A';
-		}
-		return value;
-	    },
-	    width: 40,
-	    hidden: true
-	},
-	{
-	    text: 'Status',
-	    dataIndex: 'status',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (!value) {
-		    return value;
-		}
-		var inout = rec.data['in'] ? 'in' : 'out';
-		var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
-						  'critical fa-arrow-circle-down';
-
-		var inouticon = rec.data['in'] ? 'good fa-circle' :
-						 'warning fa-circle-o';
-
-		var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
-			   inout + ' <i class="fa ' + inouticon + '"></i>';
-
-		return text;
-	    },
-	    width: 80
-	},
-	{
-	    text: 'weight',
-	    dataIndex: 'crush_weight',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return value;
-	    },
-	    width: 80
-	},
-	{
-	    text: 'reweight',
-	    dataIndex: 'reweight',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return value;
-	    },
-	    width: 90
-	},
-	{
-	    header: gettext('Used'),
-	    columns: [
-		{
-		    text: '%',
-		    dataIndex: 'percent_used',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return Ext.util.Format.number(value, '0.00');
-		    },
-		    width: 80
-		},
-		{
-		    text: gettext('Total'),
-		    dataIndex: 'total_space',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return PVE.Utils.render_size(value);
-		    },
-		    width: 100
-		}
-	    ]
-	},
-	{
-	    header: gettext('Latency (ms)'),
-	    columns: [
-		{
-		    text: 'Apply',
-		    dataIndex: 'apply_latency_ms',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return value;
-		    },
-		    width: 60
-		},
-		{
-		    text: 'Commit',
-		    dataIndex: 'commit_latency_ms',
-		    align: 'right',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.type !== 'osd') {
-			    return '';
-			}
-			return value;
-		    },
-		    width: 60
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	// we expect noout to be not set by default
-	var noout = false;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	var set_button_status; // defined later
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + nodename + "/ceph/osd",
-		waitMsgTarget: me,
-		method: 'GET',
-		failure: function(response, opts) {
-		    var msg = response.htmlStatus;
-		    PVE.Utils.showCephInstallOrMask(me, msg, me.pveSelNode.data.node,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', function(){
-				reload();
-			    });
-			}
-		    );
-		},
-		success: function(response, opts) {
-		    sm.deselectAll();
-		    me.setRootNode(response.result.data.root);
-		    me.expandAll();
-		    // extract noout flag
-		    if (response.result.data.flags &&
-			response.result.data.flags.search(/noout/) !== -1) {
-			noout = true;
-		    } else {
-			noout = false;
-		    }
-		    set_button_status();
-		}
-	    });
-	};
-
-	var osd_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + rec.data.host + "/ceph/osd/" +
-		    rec.data.id + '/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		success: reload,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var service_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!(rec && rec.data.name && rec.data.host)) {
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		params: { service: rec.data.name },
-		waitMsgTarget: me,
-		method: 'POST',
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		    win.show();
-		    me.mon(win, 'close', reload, me);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var create_btn = new Proxmox.button.Button({
-	    text: gettext('Create') + ': OSD',
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.CephCreateOsd', {
-                    nodename: nodename
-		});
-		win.show();
-		me.mon(win, 'close', reload, me);
-	    }
-	});
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){ service_cmd('start'); }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){ service_cmd('stop'); }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){ service_cmd('restart'); }
-	});
-
-	var osd_out_btn = new Ext.Button({
-	    text: 'Out',
-	    disabled: true,
-	    handler: function(){ osd_cmd('out'); }
-	});
-
-	var osd_in_btn = new Ext.Button({
-	    text: 'In',
-	    disabled: true,
-	    handler: function(){ osd_cmd('in'); }
-	});
-
-	var remove_btn = new Ext.Button({
-	    text: gettext('Destroy'),
-	    disabled: true,
-	    handler: function(){
-		var rec = sm.getSelection()[0];
-		if (!(rec && (rec.data.id >= 0) && rec.data.host)) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.CephRemoveOsd', {
-                    nodename: rec.data.host,
-		    osdid: rec.data.id
-		});
-		win.show();
-		me.mon(win, 'close', reload, me);
-	    }
-	});
-
-	var noout_btn = new Ext.Button({
-	    text: gettext('Set noout'),
-	    handler: function() {
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + nodename + "/ceph/flags/noout",
-		    waitMsgTarget: me,
-		    method: noout ? 'DELETE' : 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: reload
-		});
-	    }
-	});
-
-	var osd_label = new Ext.toolbar.TextItem({
-	    data: {
-		osd: undefined
-	    },
-	    tpl: [
-		'<tpl if="osd">',
-		'{osd}:',
-		'<tpl else>',
-		gettext('No OSD selected'),
-		'</tpl>'
-	    ]
-	});
-
-	set_button_status = function() {
-	    var rec = sm.getSelection()[0];
-	    noout_btn.setText(noout?gettext('Unset noout'):gettext('Set noout'));
-
-	    if (!rec) {
-		start_btn.setDisabled(true);
-		stop_btn.setDisabled(true);
-		restart_btn.setDisabled(true);
-		remove_btn.setDisabled(true);
-		osd_out_btn.setDisabled(true);
-		osd_in_btn.setDisabled(true);
-		return;
-	    }
-
-	    var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
-
-	    start_btn.setDisabled(!(isOsd && (rec.data.status !== 'up')));
-	    stop_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
-	    restart_btn.setDisabled(!(isOsd && (rec.data.status !== 'down')));
-	    remove_btn.setDisabled(!(isOsd && (rec.data.status === 'down')));
-
-	    osd_out_btn.setDisabled(!(isOsd && rec.data['in']));
-	    osd_in_btn.setDisabled(!(isOsd && !rec.data['in']));
-
-	    osd_label.update(isOsd?{osd:rec.data.name}:undefined);
-	};
-
-	sm.on('selectionchange', set_button_status);
-
-	var reload_btn = new Ext.Button({
-	    text: gettext('Reload'),
-	    handler: reload
-	});
-
-	Ext.apply(me, {
-	    tbar: [ create_btn, reload_btn, noout_btn, '->', osd_label, start_btn, stop_btn, restart_btn, osd_out_btn, osd_in_btn, remove_btn ],
-	    rootVisible: false,
-	    useArrows: true,
-	    fields: ['name', 'type', 'status', 'host', 'in', 'id' ,
-		     { type: 'number', name: 'reweight' },
-		     { type: 'number', name: 'percent_used' },
-		     { type: 'integer', name: 'bytes_used' },
-		     { type: 'integer', name: 'total_space' },
-		     { type: 'integer', name: 'apply_latency_ms' },
-		     { type: 'integer', name: 'commit_latency_ms' },
-		     { type: 'string', name: 'device_class' },
-		     { type: 'string', name: 'osdtype' },
-		     { type: 'string', name: 'blfsdev' },
-		     { type: 'string', name: 'dbdev' },
-		     { type: 'string', name: 'waldev' },
-		     { type: 'string', name: 'iconCls', calculate: function(data) {
-			 var iconCls = 'fa x-fa-tree fa-';
-			 switch (data.type) {
-			    case 'host':
-				 iconCls += 'building';
-				 break;
-			    case 'osd':
-				 iconCls += 'hdd-o';
-				 break;
-			    case 'root':
-				 iconCls += 'server';
-				 break;
-			    default:
-				 return undefined;
-			 }
-			 return iconCls;
-		     } },
-		     { type: 'number', name: 'crush_weight' }],
-	    selModel: sm,
-
-	    listeners: {
-		activate: function() {
-		    reload();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	reload();
-    }
-});
-Ext.define('PVE.CephCreateMon', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephCreateMon'],
-
-    subject: 'Ceph Monitor/Manager',
-    onlineHelp: 'pve_ceph_monitors',
-
-    showProgress: true,
-
-    setNode: function(nodename) {
-        var me = this;
-
-	me.nodename = nodename;
-        me.url = "/nodes/" + nodename + "/ceph/mon";
-    },
-
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.setNode(me.nodename);
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-            method: 'POST',
-            items: [
-               {
-		   xtype: 'pveNodeSelector',
-		   submitValue: false,
-		   fieldLabel: gettext('Host'),
-		   selectCurNode: true,
-		   allowBlank: false,
-		   listeners: {
-		       change: function(f, value) {
-			   me.setNode(value);
-		       }
-		   }
-	       }
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephMonList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveNodeCephMonList'],
-
-    onlineHelp: 'chapter_pveceph',
-
-    stateful: true,
-    stateId: 'grid-ceph-monitor',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-mon-list' + nodename,
-	    model: 'ceph-mon-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/mon"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sorters: [{ property: 'name'}]
-	});
-
-
-	var service_cmd = function(cmd) {
-	    var rec = sm.getSelection()[0];
-	    if (!rec.data.host) {
-		Ext.Msg.alert(gettext('Error'), "entry has no host");
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		method: 'POST',
-		params: { service: "mon." + rec.data.name },
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var start_btn = new Proxmox.button.Button({
-	    text: gettext('Start'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Proxmox.button.Button({
-	    text: gettext('Stop'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Proxmox.button.Button({
-	    text: gettext('Restart'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function(){
-		var win = Ext.create('PVE.CephCreateMon', {
-                    nodename: nodename
-		});
-		win.show();
-	    }
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.host) {
-		    Ext.Msg.alert(gettext('Error'), "entry has no host");
-		    return;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + rec.data.host + "/ceph/mon/" +
-			rec.data.name,
-		    method: 'DELETE',
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ start_btn, stop_btn, restart_btn, '-', create_btn, remove_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) { return "mon." + v; },
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Host'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'unknown';
-		    },
-		    dataIndex: 'host'
-		},
-		{
-		    header: gettext('Quorum'),
-		    width: 70,
-		    sortable: false,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'quorum'
-		},
-		{
-		    header: gettext('Address'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'addr'
-		}
-	    ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-mon-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'addr', 'name', 'rank', 'host', 'quorum' ],
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.node.CephCrushMap', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveNodeCephCrushMap'],
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    stateful: true,
-    stateId: 'layout-ceph-crush',
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/crush',
-
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.node.CephStatus', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephStatus',
-
-    onlineHelp: 'chapter_pveceph',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: {
-	type: 'column'
-    },
-
-    defaults: {
-	padding: 5
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Health'),
-	    bodyPadding: 10,
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5
-		}
-	    },
-	    minHeight: 210,
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    itemId: 'overallhealth',
-		    xtype: 'pveHealthWidget',
-		    title: gettext('Status')
-		},
-		{
-		    flex: 2,
-		    itemId: 'warnings',
-		    stateful: true,
-		    stateId: 'ceph-status-warnings',
-		    xtype: 'grid',
-		    // since we load the store manually,
-		    // to show the emptytext, we have to
-		    // specify an empty store
-		    store: { data:[] },
-		    emptyText: gettext('No Warnings/Errors'),
-		    columns: [
-			{
-			    dataIndex: 'severity',
-			    header: gettext('Severity'),
-			    align: 'center',
-			    width: 70,
-			    renderer: function(value) {
-				var health = PVE.Utils.map_ceph_health[value];
-				var classes = PVE.Utils.get_health_icon(health);
-
-				return '<i class="fa fa-fw ' + classes + '"></i>';
-			    },
-			    sorter: {
-				sorterFn: function(a,b) {
-				    var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-				    return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-				}
-			    }
-			},
-			{
-			    dataIndex: 'summary',
-			    header: gettext('Summary'),
-			    flex: 1
-			},
-			{
-			    xtype: 'actioncolumn',
-			    width: 40,
-			    align: 'center',
-			    tooltip: gettext('Detail'),
-			    items: [
-				{
-				    iconCls: 'x-fa fa-info-circle',
-				    handler: function(grid, rowindex, colindex, item, e, record) {
-					var win = Ext.create('Ext.window.Window', {
-					    title: gettext('Detail'),
-					    resizable: true,
-					    modal: true,
-					    width: 650,
-					    height: 400,
-					    layout: {
-						type: 'fit'
-					    },
-					    items: [{
-						scrollable: true,
-						padding: 10,
-						xtype: 'box',
-						html: [
-						    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-						    '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-						]
-					    }]
-					});
-					win.show();
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveCephStatusDetail',
-	    itemId: 'statusdetail',
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5
-		}
-	    },
-	    title: gettext('Status')
-	},
-	{
-	    xtype: 'panel',
-	    title: gettext('Performance'),
-	    columnWidth: 1,
-	    bodyPadding: 5,
-	    layout: {
-		type: 'hbox',
-		align: 'center'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    xtype: 'proxmoxGauge',
-		    itemId: 'space',
-		    title: gettext('Usage')
-		},
-		{
-		    flex: 2,
-		    xtype: 'container',
-		    defaults: {
-			padding: 0,
-			height: 100
-		    },
-		    items: [
-			{
-			    itemId: 'reads',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Reads'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'writes',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Writes'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'iops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS', // do not localize
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'readiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Reads'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'writeiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Writes'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			}
-		    ]
-		}
-	    ]
-	}
-    ],
-
-    generateCheckData: function(health) {
-	var result = [];
-	var checks = health.checks || {};
-	var keys = Ext.Object.getKeys(checks).sort();
-
-	Ext.Array.forEach(keys, function(key) {
-	    var details = checks[key].detail || [];
-	    result.push({
-		id: key,
-		summary: checks[key].summary.message,
-		detail: Ext.Array.reduce(
-			    checks[key].detail,
-			    function(first, second) {
-				return first + '\n' + second.message;
-			    },
-			    ''
-			),
-		severity: checks[key].severity
-	    });
-	});
-
-	return result;
-    },
-
-    updateAll: function(store, records, success) {
-	if (!success || records.length === 0) {
-	    return;
-	}
-
-	var me = this;
-	var rec = records[0];
-
-	// add health panel
-	me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
-	// add errors to gridstore
-	me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
-
-	// update detailstatus panel
-	me.getComponent('statusdetail').updateAll(
-	    rec.data.health || {},
-	    rec.data.monmap || {},
-	    rec.data.pgmap || {},
-	    rec.data.osdmap || {},
-	    rec.data.quorum_names || []);
-
-	// add performance data
-	var used = rec.data.pgmap.bytes_used;
-	var total = rec.data.pgmap.bytes_total;
-
-	var text = Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(used),
-	    PVE.Utils.render_size(total)
-	);
-
-	// update the usage widget
-	me.down('#space').updateValue(used/total, text);
-
-	// TODO: logic for jewel (iops splitted in read/write)
-
-	var iops = rec.data.pgmap.op_per_sec;
-	var readiops = rec.data.pgmap.read_op_per_sec;
-	var writeiops = rec.data.pgmap.write_op_per_sec;
-	var reads = rec.data.pgmap.read_bytes_sec || 0;
-	var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-	if (iops !== undefined && me.version !== 'hammer') {
-	    me.change_version('hammer');
-	} else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-	    me.change_version('jewel');
-	}
-	// update the graphs
-	me.reads.addDataPoint(reads);
-	me.writes.addDataPoint(writes);
-	me.iops.addDataPoint(iops);
-	me.readiops.addDataPoint(readiops);
-	me.writeiops.addDataPoint(writeiops);
-    },
-
-    change_version: function(version) {
-	var me = this;
-	me.version = version;
-	me.sp.set('ceph-version', version);
-	me.iops.setVisible(version === 'hammer');
-	me.readiops.setVisible(version === 'jewel');
-	me.writeiops.setVisible(version === 'jewel');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-	me.store = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-status-' + nodename,
-	    interval: 5000,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/ceph/status'
-	    }
-	});
-
-	// save references for the updatefunction
-	me.iops = me.down('#iops');
-	me.readiops = me.down('#readiops');
-	me.writeiops = me.down('#writeiops');
-	me.reads = me.down('#reads');
-	me.writes = me.down('#writes');
-
-	// get ceph version
-	me.sp = Ext.state.Manager.getProvider();
-	me.version = me.sp.get('ceph-version');
-	me.change_version(me.version);
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-	    me.store.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.mon(me.store, 'load', me.updateAll, me);
-	me.on('destroy', me.store.stopUpdate);
-	me.store.startUpdate();
-    }
-
-});
-Ext.define('PVE.ceph.StatusDetail', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephStatusDetail',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5 20',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [{
-	flex: 1,
-	itemId: 'monitors',
-	xtype: 'container',
-	items: [
-	    {
-		xtype: 'box',
-		width: '100%',
-		html: '<h3>' + gettext('Monitors') + '</h3>'
-	    }
-	]
-    },{
-	flex: 1,
-	itemId: 'osds',
-	data: {
-	    total: 0,
-	    upin: 0,
-	    upout: 0,
-	    downin: 0,
-	    downout: 0
-	},
-	tpl: [
-	    '<h3>' + 'OSDs' + '</h3>',
-	    '<table class="osds">',
-	    '<tr><td></td>',
-	    '<td><i class="fa fa-fw good fa-circle"></i>',
-	    gettext('In'),
-	    '</td>',
-	    '<td><i class="fa fa-fw warning fa-circle-o"></i>',
-	    gettext('Out'),
-	    '</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
-	    gettext('Up'),
-	    '</td>',
-	    '<td>{upin}</td>',
-	    '<td>{upout}</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
-	    gettext('Down'),
-	    '</td>',
-	    '<td>{downin}</td>',
-	    '<td>{downout}</td>',
-	    '</tr>',
-	    '</table>',
-	    '<br /><div>',
-	    gettext('Total'),
-	    ': {total}',
-	    '</div>'
-	]
-    },
-    {
-	flex: 1.6,
-	itemId: 'pgs',
-	padding: '0 10',
-	data: {
-	    states: []
-	},
-	tpl: [
-	    '<h3>' + 'PGs' + '</h3>',
-	    '<tpl for="states">',
-	    '<div class="left-aligned">{state_name}:</div>',
-	    '<div class="right-aligned">{count}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateAll: function(health, monmap, pgmap, osdmap, quorum_names) {
-	var me = this;
-	me.suspendLayout = true;
-
-	// update pgs sorted
-	var pgs_by_state = pgmap.pgs_by_state || [];
-	pgs_by_state.sort(function(a,b){
-	    return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
-	});
-	me.getComponent('pgs').update({states: pgs_by_state});
-
-	var downinregex = /(\d+) osds down/;
-	var monnameregex = /^mon.(\S+) /;
-	var downin_osds = 0;
-	var monmsgs = {};
-
-	// we collect monitor/osd information from the checks
-	Ext.Object.each(health.checks, function(key, value, obj) {
-	    var found = null;
-	    if (key === 'OSD_DOWN') {
-		found = value.summary.message.match(downinregex);
-		if (found !== null) {
-		    downin_osds = parseInt(found[1],10);
-		}
-	    }
-	    else if (Ext.String.startsWith(key, 'MON_')) {
-		if (!value.detail) {
-		    return;
-		}
-		found = value.detail[0].message.match(monnameregex);
-		if (found !== null) {
-		    if (!monmsgs[found[1]]) {
-			monmsgs[found[1]] = [];
-		    }
-		    monmsgs[found[1]].push({
-			text: Ext.Array.reduce(value.detail, function(first, second) {
-			    return first + '\n' + second.message;
-			}, ''),
-			severity: value.severity
-		    });
-		}
-	    }
-	});
-
-	// update osds counts
-
-	var total_osds = osdmap.osdmap.num_osds || 0;
-	var in_osds = osdmap.osdmap.num_in_osds || 0;
-	var up_osds = osdmap.osdmap.num_up_osds || 0;
-	var out_osds = total_osds - in_osds;
-	var down_osds = total_osds - up_osds;
-
-	var downout_osds = down_osds - downin_osds;
-	var upin_osds = in_osds - downin_osds;
-	var upout_osds = up_osds - upin_osds;
-	var osds = {
-	    total: total_osds,
-	    upin: upin_osds,
-	    upout: upout_osds,
-	    downin: downin_osds,
-	    downout: downout_osds
-	};
-	me.getComponent('osds').update(osds);
-
-	// update the monitors
-	var mons = monmap.mons.sort(function(a,b) {
-	    return (a.name < b.name)?-1:(a.name > b.name)?1:0;
-	});
-
-	var monContainer = me.getComponent('monitors');
-
-	var i;
-	for (i = 0; i < mons.length; i++) {
-	    var monitor = monContainer.getComponent('mon.' + mons[i].name);
-	    if (!monitor) {
-		// since mons are already sorted, and
-		// we always have a sorted list
-		// we can add it at the mons+1 position (because of the title)
-		monitor = monContainer.insert(i+1, {
-		    xtype: 'pveCephMonitorWidget',
-		    itemId: 'mon.' + mons[i].name
-		});
-	    }
-	    monitor.updateMonitor(mons[i], monmsgs, quorum_names);
-	}
-	me.suspendLayout = false;
-	me.updateLayout();
-    }
-});
-
-Ext.define('PVE.ceph.MonitorWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveCephMonitorWidget',
-
-    userCls: 'monitor inline-block',
-    data: {
-	name: '0',
-	health: 'HEALTH_ERR',
-	text: '',
-	iconCls: PVE.Utils.get_health_icon(),
-	addr: ''
-    },
-
-    tpl: [
-	'{name}: ',
-	'<i class="fa fa-fw {iconCls}"></i>'
-    ],
-
-    // expects 3 variables which are
-    // timestate: the status from timechecks.mons
-    // data: the monmap.mons data
-    // quorum_names: the quorum_names array
-    updateMonitor: function(data, monmsgs, quorum_names) {
-	var me = this;
-	var state = 'HEALTH_ERR';
-	var text = '';
-	var healthstates = {
-	    'HEALTH_OK': 3,
-	    'HEALTH_WARN': 2,
-	    'HEALTH_ERR': 1
-	};
-
-	if (quorum_names &&
-	    quorum_names.indexOf(data.name) !== -1) {
-	    state = 'HEALTH_OK';
-	}
-
-	if (monmsgs[data.name]) {
-	    Ext.Array.forEach(monmsgs[data.name], function(msg) {
-		if (healthstates[msg.severity] < healthstates[state]) {
-		    state = msg.severity;
-		}
-
-		text += msg.text + "\n";
-	    });
-	}
-
-	me.update(Ext.apply(me.data, {
-	    health: state,
-	    text: text,
-	    addr: data.addr,
-	    name: data.name,
-	    iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[state])
-	}));
-    },
-
-    listeners: {
-	mouseenter: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (!me) {
-		    return;
-		}
-		if (!me.tooltip) {
-		    me.tooltip = Ext.create('Ext.tip.ToolTip', {
-			target: me.el,
-			trackMouse: true,
-			renderTo: Ext.getBody(),
-			html: gettext('Monitor') + ': ' + me.data.name + '<br />' +
-			      gettext('Address') + ': ' + me.data.addr + '<br />' +
-			      gettext('Health')  + ': ' + me.data.health + '<br />' + 
-			      me.data.text
-		    });
-		}
-		me.tooltip.show();
-	    }
-	},
-	mouseleave: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (me.tooltip) {
-		    me.tooltip.destroy();
-		    delete me.tooltip;
-		}
-	    }
-	}
-    }
-});
-Ext.define('PVE.node.CephConfig', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfig',
-
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/config',
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.CephConfigCrush', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfigCrush',
-
-    onlineHelp: 'chapter_pveceph',
-
-    layout: 'border',
-    items: [{
-	    title: gettext('Configuration'),
-	    xtype: 'pveNodeCephConfig',
-	    region: 'center'
-	},
-	{
-	    title: 'Crush Map', // do not localize
-	    xtype: 'pveNodeCephCrushMap',
-	    region: 'east',
-	    split: true,
-	    width: '50%'
-    }],
-
-    initComponent: function() {
-	var me = this;
-	me.defaults = {
-	    pveSelNode: me.pveSelNode
-	};
-	me.callParent();
-    }
-});
-Ext.define('PVE.ceph.Log', {
-    extend: 'Proxmox.panel.LogView',
-    xtype: 'cephLogView',
-    nodename: undefined,
-    failCallback: function(response) {
-	var me = this;
-	var msg = response.htmlStatus;
-	var windowShow = PVE.Utils.showCephInstallOrMask(me, msg, me.nodename,
-	    function(win){
-		me.mon(win, 'cephInstallWindowClosed', function(){
-		    me.loadTask.delay(200);
-		});
-	    }
-	);
-	if (!windowShow) {
-	    Proxmox.Utils.setErrorMask(me, msg);
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.CephInstallWizard', {
-	extend: 'PVE.window.Wizard',
-	alias: 'widget.pveCephInstallWizard',
-	mixins: ['Proxmox.Mixin.CBind'],
-	resizable: false,
-	nodename: undefined,
-	viewModel: {
-	    data: {
-		nodename: '',
-		configuration: true,
-		isInstalled: false
-	    }
-	},
-	cbindData: {
-	    nodename: undefined
-	},
-	title: gettext('Setup'),
-	navigateNext: function() {
-	    var tp = this.down('#wizcontent');
-	    var atab = tp.getActiveTab();
-
-	    var next = tp.items.indexOf(atab) + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (ntab) {
-		ntab.enable();
-		tp.setActiveTab(ntab);
-	    }
-	},
-	setInitialTab: function (index) {
-	    var tp = this.down('#wizcontent');
-	    var initialTab = tp.items.getAt(index);
-	    initialTab.enable();
-	    tp.setActiveTab(initialTab);
-	},
-	onShow: function() {
-		this.callParent(arguments);
-		var isInstalled = this.getViewModel().get('isInstalled');
-		if (isInstalled) {
-		    this.getViewModel().set('configuration', false);
-		    this.setInitialTab(2);
-		}
-	},
-	items: [
-	    {
-		title: gettext('Info'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'chapter_pveceph',
-		html: '<h3>Ceph?</h3>'+
-		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
-		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
-		' This wizard will guide you through the necessary steps, after the initial installation you will be offered to create a initial configuration.'+
-		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
-		'<p>Please take a look at our documentation, by clicking the help button below, before starting the installation, '+
-		'if you want to gain deeper knowledge about Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#back').hide(true);
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Start installation'));
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
-		    }
-		}
-	    },
-	    {
-		title: gettext('Installation'),
-		xtype: 'panel',
-		layout: 'fit',
-		cbind:{
-		    nodename: '{nodename}'
-		},
-		viewModel: {}, // needed to inherit parent viewModel data
-		listeners: {
-		    afterrender: function() {
-			var me = this;
-			if (this.getViewModel().get('isInstalled')) {
-			    this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
-			} else {
-			    me.down('pveNoVncConsole').fireEvent('activate');
-			}
-		    },
-		    activate: function() {
-			var me = this;
-			var nodename = me.nodename;
-			me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
-				storeid: 'ceph-status-' + nodename,
-				interval: 1000,
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + nodename + '/ceph/status'
-				},
-				listeners: {
-				    load: function(rec, response, success, operation) {
-
-					if (success) {
-					    me.updateStore.stopUpdate();
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("not initialized", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("rados_connect failed", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
-					    me.down('textfield').setValue('success');
-					} else if (!operation.error.statusText.match("not installed", "i")) {
-					    Proxmox.Utils.setErrorMask(me, operation.error.statusText);
-					}
-				    }
-				}
-			});
-			me.updateStore.startUpdate();
-		    },
-		    destroy: function() {
-			var me = this;
-			if (me.updateStore) {
-			    me.updateStore.stopUpdate();
-			}
-		    }
-		},
-		items: [
-		    {
-			itemId: 'jsconsole',
-			consoleType: 'cmd',
-			xtermjs: true,
-			xtype: 'pveNoVncConsole',
-			cbind:{
-			    nodename: '{nodename}'
-			},
-			cmd: 'ceph_install'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'installSuccess',
-			value: '',
-			allowBlank: false,
-			submitValue: false,
-			hidden: true
-		    }
-		]
-	    },
-	    {
-		xtype: 'inputpanel',
-		title: gettext('Configuration'),
-		onlineHelp: 'chapter_pveceph',
-		cbind: {
-		    nodename: '{nodename}'
-		},
-		viewModel: {
-		    data: {
-			replicas: undefined,
-			minreplicas: undefined
-		    }
-		},
-		listeners: {
-		    activate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
-		    },
-		    beforeshow: function() {
-			if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			    this.mask("Coniguration already initialized",['pve-static-mask']);
-			} else {
-			    this.unmask();
-			}
-		    },
-		    deactivate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
-		    }
-		},
-		column1: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('Ceph cluster configuration') + ':'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'network',
-			vtype: 'IPCIDRAddress',
-			value: '',
-			fieldLabel: 'Public Network IP/CIDR',
-			bind: {
-			    allowBlank: '{configuration}'
-			},
-			setAllowBlank: function(allowBlank) {
-			    this.allowBlank = allowBlank;
-			    this.validate();
-			}
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'cluster-network',
-			vtype: 'IPCIDRAddress',
-			fieldLabel: 'Cluster Network IP/CIDR',
-			allowBlank: true,
-			emptyText: gettext('Same as Public Network')
-		    }
-		    // FIXME: add hint about cluster network and/or reference user to docs??
-		],
-		column2: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('First Ceph monitor') + ':'
-		    },
-		    {
-			xtype: 'pveNodeSelector',
-			fieldLabel: gettext('Monitor node'),
-			name: 'mon-node',
-			selectCurNode: true,
-			allowBlank: false
-		    },
-		    {
-			xtype: 'displayfield',
-			value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
-			userCls: 'pve-hint'
-		    }
-		],
-		advancedColumn1: [
-		    {
-			xtype: 'numberfield',
-			name: 'size',
-			fieldLabel: 'Number of replicas',
-			bind: {
-			    value: '{replicas}'
-			},
-			maxValue: 7,
-			minValue: 2,
-			emptyText: '3'
-		    },
-		    {
-			xtype: 'numberfield',
-			name: 'min_size',
-			fieldLabel: 'Minimum replicas',
-			bind: {
-			    maxValue: '{replicas}',
-			    value: '{minreplicas}'
-			},
-			minValue: 2,
-			maxValue: 3,
-			setMaxValue: function(value) {
-			    this.maxValue = Ext.Number.from(value, 2);
-			    // allow enough to avoid split brains with max 'size', but more makes simply no sense
-			    if (this.maxValue > 4) {
-				this.maxValue = 4;
-			    }
-			    this.toggleSpinners();
-			    this.validate();
-			},
-			emptyText: '2'
-		    }
-		],
-		onGetValues: function(values) {
-		    ['cluster-network', 'size', 'min_size'].forEach(function(field) {
-			if (!values[field]) {
-			    delete values[field];
-			}
-		    });
-		    return values;
-		},
-		onSubmit: function() {
-		    var me = this;
-		    if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			var wizard = me.up('window');
-			var kv = wizard.getValues();
-			delete kv['delete'];
-			var monNode = kv['mon-node'];
-			delete kv['mon-node'];
-			var nodename = me.nodename;
-			delete kv.nodename;
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/ceph/init',
-			    waitMsgTarget: wizard,
-			    method: 'POST',
-			    params: kv,
-			    success: function() {
-				Proxmox.Utils.API2Request({
-				    url: '/nodes/' + monNode + '/ceph/mon',
-				    waitMsgTarget: wizard,
-				    method: 'POST',
-				    success: function() {
-					me.up('pveCephInstallWizard').navigateNext();
-				    },
-				    failure: function(response, opts) {
-					Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				    }
-				});
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-
-		    } else {
-			me.up('pveCephInstallWizard').navigateNext();
-		    }
-		}
-	    },
-	    {
-		title: gettext('Success'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'pve_ceph_install',
-		html: '<h3>Installation successful!</h3>'+
-		'<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
-		    '<ol><li>Install Ceph on other nodes</li>'+
-		    '<li>Create additional Ceph Monitors</li>'+
-		    '<li>Create Ceph OSDs</li>'+
-		    '<li>Create Ceph Pools</li></ol>'+
-		'<p>To learn more click on the help button below.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-
-			var tp = this.up('#wizcontent');
-			var idx = tp.items.indexOf(this)-1;
-			for(;idx >= 0;idx--) {
-			    var nc = tp.items.getAt(idx);
-			    if (nc) {
-				nc.disable();
-			    }
-			}
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-		    }
-		},
-		onSubmit: function() {
-		    var wizard = this.up('pveCephInstallWizard');
-		    wizard.close();
-		}
-	    }
-	]
-    });
-Ext.define('PVE.node.DiskList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeDiskList',
-    emptyText: gettext('No Disks found'),
-    stateful: true,
-    stateId: 'grid-node-disks',
-    columns: [
-	{
-	    header: gettext('Device'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'devpath'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 80,
-	    sortable: true,
-	    dataIndex: 'type',
-	    renderer: function(v) {
-		if (v === 'ssd') {
-		    return 'SSD';
-		} else if (v === 'hdd') {
-		    return 'Hard Disk';
-		} else if (v === 'usb'){
-		    return 'USB';
-		} else {
-		    return gettext('Unknown');
-		}
-	    }
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 80,
-	    sortable: false,
-	    renderer: function(v, metaData, rec) {
-		if (rec) {
-		    if (rec.data.osdid >= 0) {
-			var bluestore = '';
-			if (rec.data.bluestore === 1) {
-			    bluestore = ' (Bluestore)';
-			}
-			return "Ceph osd." + rec.data.osdid.toString() + bluestore;
-		    }
-
-		    var types = [];
-		    if (rec.data.journals > 0) {
-			types.push('Journal');
-		    }
-
-		    if (rec.data.db > 0) {
-			types.push('DB');
-		    }
-
-		    if (rec.data.wal > 0) {
-			types.push('WAL');
-		    }
-
-		    if (types.length > 0) {
-			return 'Ceph (' + types.join(', ') + ')';
-		    }
-		}
-
-		return v || Proxmox.Utils.noText;
-	    },
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'GPT',
-	    width: 60,
-	    align: 'right',
-	    renderer: function(value) {
-		if (value) {
-		    return Proxmox.Utils.yesText;
-		} else {
-		    return Proxmox.Utils.noText;
-		}
-	    },
-	    dataIndex: 'gpt'
-	},
-	{
-	    header: gettext('Vendor'),
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'vendor'
-	},
-	{
-	    header: gettext('Model'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'model'
-	},
-	{
-	    header: gettext('Serial'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'serial'
-	},
-	{
-	    header: 'S.M.A.R.T.',
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'health'
-	},
-	{
-	    header: 'Wearout',
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'wearout',
-	    renderer: function(value) {
-		if (Ext.isNumeric(value)) {
-		    return (100 - value).toString() + '%';
-		}
-		return 'N/A';
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var store = Ext.create('Ext.data.Store', {
-	    storeid: 'node-disk-list' + nodename,
-	    model: 'node-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list"
-	    },
-	    sorters: [
-		{
-		    property : 'dev',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reloadButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reload'),
-	    handler: function() {
-		me.store.load();
-	    }
-	});
-
-	var smartButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show S.M.A.R.T. values'),
-	    selModel: sm,
-	    enableFn: function() {
-		return !!sm.getSelection().length;
-	    },
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.DiskSmartWindow', {
-                    nodename: nodename,
-		    dev: rec.data.devpath
-		});
-		win.show();
-	    }
-	});
-
-	var initButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Initialize Disk with GPT'),
-	    selModel: sm,
-	    enableFn: function() {
-		var selection = sm.getSelection();
-
-		if (!selection.length || selection[0].data.used) {
-		    return false;
-		} else {
-		    return true;
-		}
-	    },
-	    disabled: true,
-
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
-		    waitMsgTarget: me,
-		    method: 'POST',
-		    params: { disk: rec.data.devpath},
-		    failure: function(response, options) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    upid: upid
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	me.loadCount = 1; // avoid duplicate loadmask
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ reloadButton, smartButton, initButton ],
-	    listeners: {
-		itemdblclick: function() {
-		    var rec = sm.getSelection()[0];
-
-		    var win = Ext.create('PVE.DiskSmartWindow', {
-			nodename: nodename,
-			dev: rec.data.devpath
-		    });
-		    win.show();
-		}
-	    }
-	});
-
-
-	me.callParent();
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('node-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
-	idProperty: 'devpath'
-    });
-});
-
-Ext.define('PVE.DiskSmartWindow', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSmartWindow',
-
-    modal: true,
-
-    items: [
-	{
-	    xtype: 'gridpanel',
-	    layout: {
-		type: 'fit'
-	    },
-	    emptyText: gettext('No S.M.A.R.T. Values'),
-	    scrollable: true,
-	    flex: 1,
-	    itemId: 'smarts',
-	    reserveScrollbar: true,
-	    columns: [
-	    { text: 'ID', dataIndex: 'id', width: 50 },
-	    { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Normalized'), dataIndex: 'value', width: 60},
-	    { text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
-	    { text: gettext('Worst'), dataIndex: 'worst', width: 60},
-	    { text: gettext('Flags'), dataIndex: 'flags'},
-	    { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
-	    ]
-	},
-	{
-	    xtype: 'component',
-	    itemId: 'text',
-	    layout: {
-		type: 'fit'
-	    },
-	    hidden: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Reload'),
-	    name: 'reload',
-	    handler: function() {
-		var me = this;
-		me.up('window').store.reload();
-	    }
-	},
-	{
-	    text: gettext('Close'),
-	    name: 'close',
-	    handler: function() {
-		var me = this;
-		me.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    width: 800,
-    height: 500,
-    minWidth: 600,
-    minHeight: 400,
-    bodyPadding: 5,
-    title: gettext('S.M.A.R.T. Values'),
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var dev = me.dev;
-	if (!dev) {
-	    throw "no device specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'disk-smart',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
-	    }
-	});
-
-	me.callParent();
-	var grid = me.down('#smarts');
-	var text = me.down('#text');
-
-	Proxmox.Utils.monStoreErrors(grid, me.store);
-	me.mon(me.store, 'load', function(s, records, success) {
-	    if (success && records.length > 0) {
-		var rec = records[0];
-		switch (rec.data.type) {
-		    case 'text':
-			grid.setVisible(false);
-			text.setVisible(true);
-			text.setHtml(Ext.String.htmlEncode(rec.data.text));
-			break;
-		    default:
-			// includes 'ata'
-			// cannot use empty case because
-			// of jslint
-			grid.setVisible(true);
-			text.setVisible(false);
-			grid.setStore(rec.attributes());
-			break;
-		}
-	    }
-	});
-
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('disk-smart', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'health'},
-	    { name:'type'},
-	    { name:'text'}
-	],
-	hasMany: {model: 'smart-attribute', name: 'attributes'}
-    });
-    Ext.define('smart-attribute', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
-	]
-    });
-});
-Ext.define('PVE.node.CreateLVM', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVM',
-
-    subject: 'LVM Volume Group',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMList', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveLVMList',
-    emptyText: gettext('No Volume Groups found'),
-    stateful: true,
-    stateId: 'grid-node-lvm',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Number of LVs'),
-	    dataIndex: 'lvcount',
-	    width: 150,
-	    align: 'right'
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Volume Group',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVM', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'size', 'free',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			txt += (data.leaf) ? 'hdd-o' : 'object-group';
-			return txt;
-		    }
-		},
-		{
-		    type: 'number',
-		    name: 'usage',
-		    calculate: function(data) {
-			return ((data.size-data.free)/data.size);
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateLVMThin', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVMThin',
-
-    subject: 'LVM Thinpool',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvmthin",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMThinList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveLVMThinList',
-
-    emptyText: gettext('No thinpools found'),
-    stateful: true,
-    stateId: 'grid-node-lvmthin',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'lv',
-	    flex: 1
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'lv_size'
-	},
-	{
-	    header: gettext('Used'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Metadata Usage'),
-	    width: 120,
-	    dataIndex: 'metadata_usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Metadata Size'),
-	    width: 120,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_size'
-	},
-	{
-	    header: gettext('Metadata Used'),
-	    width: 125,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_used'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Thinpool',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVMThin', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['lv', 'lv_size', 'used', 'metadata_size', 'metadata_used',
-		    {
-			type: 'number',
-			name: 'usage',
-			calculate: function(data) {
-			    return data.used/data.lv_size;
-			}
-		    },
-		    {
-			type: 'number',
-			name: 'metadata_usage',
-			calculate: function(data) {
-			    return data.metadata_used/data.metadata_size;
-			}
-		    }
-		],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/lvmthin'
-		},
-		sorters: 'lv'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateDirectory', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateDirectory',
-
-    subject: Proxmox.Utils.directoryText,
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/directory",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    comboItems: [
-			['ext4', 'ext4'],
-			['xfs', 'xfs']
-		    ],
-		    fieldLabel: gettext('Filesystem'),
-		    name: 'filesystem',
-		    value: '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.Directorylist', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveDirectoryList',
-
-    stateful: true,
-    stateId: 'grid-node-directory',
-    columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 100,
-	    dataIndex: 'type'
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options'
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateDirectory', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['path', 'device', 'type', 'options', 'unitfile' ],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/directory'
-		},
-		sorters: 'path'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.node.CreateZFS', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateZFS',
-
-    subject: 'ZFS',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_zfs',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-	var update_disklist = function() {
-	    var grid = me.down('#disklist');
-	    var disks = grid.getSelection();
-
-	    var val = [];
-	    disks.sort(function(a,b) {
-		var aorder = a.get('order') || 0;
-		var border = b.get('order') || 0;
-		return (aorder - border);
-	    });
-
-	    disks.forEach(function(disk) {
-		val.push(disk.get('devpath'));
-	    });
-
-	    me.down('field[name=devices]').setValue(val.join(','));
-	};
-
-	Ext.apply(me, {
-	    url: '/nodes/' + me.nodename + '/disks/zfs',
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'textfield',
-			    hidden: true,
-			    name: 'devices',
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxtextfield',
-			    name: 'name',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'add_storage',
-			    fieldLabel: gettext('Add Storage'),
-			    value: '1'
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('RAID Level'),
-			    name: 'raidlevel',
-			    value: 'single',
-			    comboItems: [
-				['single', gettext('Single Disk')],
-				['mirror', 'Mirror'],
-				['raid10', 'RAID10'],
-				['raidz', 'RAIDZ'],
-				['raidz2', 'RAIDZ2'],
-				['raidz3', 'RAIDZ3']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('Compression'),
-			    name: 'compression',
-			    value: 'on',
-			    comboItems: [
-				['on', 'on'],
-				['off', 'off'],
-				['gzip', 'gzip'],
-				['lz4', 'lz4'],
-				['lzjb', 'lzjb'],
-				['zle', 'zle']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    fieldLabel: gettext('ashift'),
-			    minValue: 9,
-			    maxValue: 16,
-			    value: '12',
-			    name: 'ashift'
-			}
-		    ],
-		    columnB: [
-			{
-			    xtype: 'grid',
-			    height: 200,
-			    emptyText: gettext('No Disks unused'),
-			    itemId: 'disklist',
-			    selModel: 'checkboxmodel',
-			    listeners: {
-				selectionchange: update_disklist
-			    },
-			    store: {
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + me.nodename + '/disks/list?type=unused'
-				}
-			    },
-			    columns: [
-				{
-				    text: gettext('Device'),
-				    dataIndex: 'devpath',
-				    flex: 1
-				},
-				{
-				    text: gettext('Serial'),
-				    dataIndex: 'serial'
-				},
-				{
-				    text: gettext('Size'),
-				    dataIndex: 'size',
-				    renderer: PVE.Utils.render_size
-				},
-				{
-				    header: gettext('Order'),
-				    xtype: 'widgetcolumn',
-				    dataIndex: 'order',
-				    sortable: true,
-				    widget: {
-					xtype: 'proxmoxintegerfield',
-					minValue: 1,
-					isFormField: false,
-					listeners: {
-					    change: function(numberfield, value, old_value) {
-						var record = numberfield.getWidgetRecord();
-						record.set('order', value);
-						update_disklist(record);
-					    }
-					}
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	});
-
-        me.callParent();
-	me.down('#disklist').getStore().load();
-    }
-});
-
-Ext.define('PVE.node.ZFSDevices', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveZFSDevices',
-    stateful: true,
-    stateId: 'grid-node-zfsstatus',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'state'
-	},
-	{
-	    text: 'READ',
-	    dataIndex: 'read'
-	},
-	{
-	    text: 'WRITE',
-	    dataIndex: 'write'
-	},
-	{
-	    text: 'CKSUM',
-	    dataIndex: 'cksum'
-	},
-	{
-	    text: gettext('Message'),
-	    dataIndex: 'msg'
-	}
-    ],
-
-    rootVisible: true,
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/zfs/" + me.zpool,
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'status',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			if (data.leaf) {
-			    return txt + 'hdd-o';
-			}
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSStatus', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveZFSStatus',
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/disks/zfs/" + me.zpool;
-
-	me.rows = {
-	    scan: {
-		header: gettext('Scan')
-	    },
-	    status: {
-		header: gettext('Status')
-	    },
-	    action: {
-		header: gettext('Action')
-	    },
-	    errors: {
-		header: gettext('Errors')
-	    }
-	};
-
-	me.callParent();
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveZFSList',
-
-    stateful: true,
-    stateId: 'grid-node-zfs',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    header: gettext('Size'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	},
-	{
-	    header: gettext('Allocated'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'alloc'
-	},
-	{
-	    header: gettext('Fragmentation'),
-	    renderer: function(value) {
-		return value.toString() + '%';
-	    },
-	    dataIndex: 'frag'
-	},
-	{
-	    header: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'health'
-	},
-	{
-	    header: gettext('Deduplication'),
-	    hidden: true,
-	    renderer: function(value) {
-		return value.toFixed(2).toString() + 'x';
-	    },
-	    dataIndex: 'dedup'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': ZFS',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateZFS', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	},
-	{
-	    text: gettext('Detail'),
-	    itemId: 'detailbtn',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('panel');
-		var selection = me.getSelection();
-		if (selection.length < 1) {
-		    return;
-		}
-		me.show_detail(selection[0].get('name'));
-	    }
-	}
-    ],
-
-    show_detail: function(zpool) {
-	var me = this;
-
-	var detailsgrid = Ext.create('PVE.node.ZFSStatus', {
-	    layout: 'fit',
-	    nodename: me.nodename,
-	    flex: 0,
-	    zpool: zpool
-	});
-
-	var devicetree = Ext.create('PVE.node.ZFSDevices', {
-	    title: gettext('Devices'),
-	    nodename: me.nodename,
-	    flex: 1,
-	    zpool: zpool
-	});
-
-
-	var win = Ext.create('Ext.window.Window', {
-	    modal: true,
-	    width: 800,
-	    height: 400,
-	    resizable: true,
-	    layout: 'fit',
-	    title: gettext('Status') + ': ' + zpool,
-	    items:[{
-		xtype: 'panel',
-		region: 'center',
-		layout: {
-		    type: 'vbox',
-		    align: 'stretch'
-		},
-		items: [detailsgrid, devicetree],
-		tbar: [{
-		    text: gettext('Reload'),
-		    iconCls: 'fa fa-refresh',
-		    handler: function() {
-
-			devicetree.reload();
-			detailsgrid.reload();
-		    }
-		}]
-	    }]
-	}).show();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var selection = me.getSelection();
-	me.down('#detailbtn').setDisabled(selection.length === 0);
-    },
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	},
-	selectionchange: function() {
-	    this.set_button_status();
-	},
-	itemdblclick: function(grid, record) {
-	    var me = this;
-	    me.show_detail(record.get('name'));
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/zfs'
-		},
-		sorters: 'name'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveNodeStatus',
-
-    height: 300,
-    bodyPadding: '20 15 20 15',
-
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 15 5 15'
-    },
-
-    items: [
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpuinfo',
-	    renderer: PVE.Utils.render_node_cpu_usage
-	},
-	{
-	    itemId: 'wait',
-	    iconCls: 'fa fa-fw fa-clock-o',
-	    title: gettext('IO delay'),
-	    valueField: 'wait',
-	    rowspan: 2
-	},
-	{
-	    itemId: 'load',
-	    iconCls: 'fa fa-fw fa-tasks',
-	    title: gettext('Load average'),
-	    printBar: false,
-	    textField: 'loadavg'
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    itemId: 'memory',
-	    title: gettext('RAM usage'),
-	    valueField: 'memory',
-	    maxField: 'memory',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    itemId: 'ksm',
-	    printBar: false,
-	    title: gettext('KSM sharing'),
-	    textField: 'ksm',
-	    renderer: function(record) {
-		return PVE.Utils.render_size(record.shared);
-	    },
-	    padding: '0 15 10 15'
-	},
-	{
-	    iconCls: 'fa fa-fw fa-hdd-o',
-	    itemId: 'rootfs',
-	    title: gettext('HD space') + '(root)',
-	    valueField: 'rootfs',
-	    maxField: 'rootfs',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    iconCls: 'fa fa-fw fa-refresh',
-	    itemId: 'swap',
-	    printSize: true,
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'swap',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    itemId: 'cpus',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('CPU(s)'),
-	    textField: 'cpuinfo',
-	    renderer: function(cpuinfo) {
-		return cpuinfo.cpus + " x " + cpuinfo.model + " (" +
-		cpuinfo.sockets.toString() + " " +
-		(cpuinfo.sockets > 1 ?
-		    gettext('Sockets') :
-		    gettext('Socket')
-		) + ")";
-	    },
-	    value: ''
-	},
-	{
-	    itemId: 'kversion',
-	    colspan: 2,
-	    title: gettext('Kernel Version'),
-	    printBar: false,
-	    textField: 'kversion',
-	    value: ''
-	},
-	{
-	    itemId: 'version',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('PVE Manager Version'),
-	    textField: 'pveversion',
-	    value: ''
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
-	me.setTitle(me.pveSelNode.data.node + ' (' + gettext('Uptime') + ': ' + uptime + ')');
-    }
-
-});
-Ext.define('PVE.node.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    showVersions: function() {
-	var me = this;
-
-	// Note: we use simply text/html here, because ExtJS grid has problems
-	// with cut&paste
-
-	var nodename = me.pveSelNode.data.node;
-
-	var view = Ext.createWidget('component', {
-	    autoScroll: true,
-	    padding: 5,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	});
-
-	var win = Ext.create('Ext.window.Window', {
-	    title: gettext('Package versions'),
-	    width: 600,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [ view ]
-	});
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: "/nodes/" + nodename + "/apt/versions",
-	    method: 'GET',
-	    failure: function(response, opts) {
-		win.close();
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		win.show();
-		var text = '';
-
-		Ext.Array.each(response.result.data, function(rec) {
-		    var version = "not correctly installed";
-		    var pkg = rec.Package;
-		    if (rec.OldVersion && rec.CurrentState === 'Installed') {
-			version = rec.OldVersion;
-		    }
-		    if (rec.RunningKernel) {
-			text += pkg + ': ' + version + ' (running kernel: ' +
-			    rec.RunningKernel + ')\n';
-		    } else if (rec.ManagerVersion) {
-			text += pkg + ': ' + version + ' (running version: ' +
-			    rec.ManagerVersion + ')\n';
-		    } else {
-			text += pkg + ': ' + version + '\n';
-		    }
-		});
-
-		view.update(Ext.htmlEncode(text));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var rstore = me.statusStore;
-
-	var version_btn = new Ext.Button({
-	    text: gettext('Package versions'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { me.showVersions(); });
-	    }
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl: "/api2/json/nodes/" + nodename + "/rrddata",
-	    model: 'pve-rrd-node'
-	});
-
-	Ext.apply(me, {
-	    tbar: [version_btn, '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: 'column',
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: [
-			{
-			    xtype: 'pveNodeStatus',
-			    rstore: rstore,
-			    width: 770,
-			    pveSelNode: me.pveSelNode
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('CPU usage'),
-			    fields: ['cpu','iowait'],
-			    fieldTitles: [gettext('CPU usage'), gettext('IO delay')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Server load'),
-			    fields: ['loadavg'],
-			    fieldTitles: [gettext('Load average')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Memory usage'),
-			    fields: ['memtotal','memused'],
-			    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Network traffic'),
-			    fields: ['netin','netout'],
-			    store: rrdstore
-			}
-		    ]
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*global Blob*/
-Ext.define('PVE.node.SubscriptionKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-    title: gettext('Upload Subscription Key'),
-    width: 300,
-    items: {
-	xtype: 'textfield',
-	name: 'key',
-	value: '',
-	fieldLabel: gettext('Subscription Key')
-    },
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.Subscription', {
-    extend: 'Proxmox.grid.ObjectGrid',
-
-    alias: ['widget.pveNodeSubscription'],
-
-    onlineHelp: 'getting_help',
-
-    viewConfig: {
-	enableTextSelection: true
-    },
-
-    showReport: function() {
-	var me = this;
-	var nodename = me.pveSelNode.data.node;
-
-	var getReportFileName = function() {
-	    var now = Ext.Date.format(new Date(), 'D-d-F-Y-G-i');
-	    return me.nodename + '-report-'  + now + '.txt';
-	};
-
-	var view = Ext.createWidget('component', {
-	    itemId: 'system-report-view',
-	    scrollable: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace',
-		padding: '5px'
-	    }
-	});
-
-	var reportWindow = Ext.create('Ext.window.Window', {
-	    title: gettext('System Report'),
-	    width: 1024,
-	    height: 600,
-	    layout: 'fit',
-	    modal: true,
-	    buttons: [
-		        '->',
-			{
-			    text: gettext('Download'),
-			    handler: function() {
-				var fileContent = reportWindow.getComponent('system-report-view').html;
-				var fileName = getReportFileName();
-
-				// Internet Explorer
-				if (window.navigator.msSaveOrOpenBlob) {
-				    navigator.msSaveOrOpenBlob(new Blob([fileContent]), fileName);
-				} else {
-				    var element = document.createElement('a');
-				    element.setAttribute('href', 'data:text/plain;charset=utf-8,'
-				      + encodeURIComponent(fileContent));
-				    element.setAttribute('download', fileName);
-				    element.style.display = 'none';
-				    document.body.appendChild(element);
-				    element.click();
-				    document.body.removeChild(element);
-				}
-			    }
-			}
-		],
-	    items: view
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/nodes/' + me.nodename + '/report',
-	    method: 'GET',
-	    waitMsgTarget: me,
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var report = Ext.htmlEncode(response.result.data);
-		reportWindow.show();
-		view.update(report);
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = '/nodes/' + me.nodename + '/subscription';
-
-	var render_status = function(value) {
-
-	    var message = me.getObjectValue('message');
-
-	    if (message) {
-		return value + ": " + message;
-	    }
-	    return value;
-	};
-
-	var rows = {
-	    productname: {
-		header: gettext('Type')
-	    },
-	    key: {
-		header: gettext('Subscription Key')
-	    },
-	    status: {
-		header: gettext('Status'),
-		renderer: render_status
-	    },
-	    message: {
-		visible: false
-	    },
-	    serverid: {
-		header: gettext('Server ID')
-	    },
-	    sockets: {
-		header: gettext('Sockets')
-	    },
-	    checktime: {
-		header: gettext('Last checked'),
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    nextduedate: {
-		header: gettext('Next due date')
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json' + baseurl,
-	    cwidth1: 170,
-	    tbar: [ 
-		{
-		    text: gettext('Upload Subscription Key'),
-		    handler: function() {
-			var win = Ext.create('PVE.node.SubscriptionKeyEdit', {
-			    url: '/api2/extjs/' + baseurl 
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		{
-		    text: gettext('Check'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    params: { force: 1 },
-			    url: baseurl,
-			    method: 'POST',
-			    waitMsgTarget: me,
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    },
-			    callback: reload
-			});
-		    }
-		},
-		{
-		    text: gettext('System Report'),
-		    handler: function() {
-			Proxmox.Utils.checked_command(function (){ me.showReport(); });
-		    }
-		}
-	    ],
-	    rows: rows,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CertificateView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCertificatesView',
-
-    onlineHelp: 'sysadmin_certificate_management',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    items: [
-	{
-	    xtype: 'pveCertView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveACMEView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.CertificateViewer', {
-    extend: 'Proxmox.window.Edit',
-
-    title: gettext('Certificate'),
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-    width: 800,
-    resizable: true,
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'filename'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Fingerprint'),
-	    name: 'fingerprint'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Issuer'),
-	    name: 'issuer'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject'),
-	    name: 'subject'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Valid Since'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notbefore'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Expires'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notafter'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject Alternative Names'),
-	    name: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    xtype: 'textarea',
-	    editable: false,
-	    grow: true,
-	    growMax: 200,
-	    fieldLabel: gettext('Certificate'),
-	    name: 'pem'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.cert) {
-	    throw "no cert given";
-	}
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/info';
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		if (Ext.isArray(response.result.data)) {
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.filename === me.cert) {
-			    me.setValues(item);
-			    return false;
-			}
-		    });
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CertUpload', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCertUpload',
-
-    title: gettext('Upload Custom Certificate'),
-    resizable: false,
-    isCreate: true,
-    submitText: gettext('Upload'),
-    method: 'POST',
-    width: 600,
-
-    apiCallDone: function(success, response, options) {
-	if (!success) {
-	    return;
-	}
-
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    items: [
-	{
-	    fieldLabel: gettext('Private Key (Optional)'),
-	    labelAlign: 'top',
-	    emptyText: gettext('No change'),
-	    name: 'key',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=key]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    autoEl: 'hr'
-	},
-	{
-	    fieldLabel: gettext('Certificate Chain'),
-	    labelAlign: 'top',
-	    allowBlank: false,
-	    name: 'certificates',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=certificates]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'restart',
-	    value: '1'
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'force',
-	    value: '1'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/custom';
-
-	me.callParent();
-    }
-});
-
-Ext.define('pve-certificate', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san' ],
-    idProperty: 'filename'
-});
-
-Ext.define('PVE.node.Certificates', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveCertView',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    text: gettext('Upload Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.CertUpload', {
-		    nodename: me.nodename
-		});
-		win.show();
-		win.on('destroy', me.reload, me);
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'deletebtn',
-	    text: gettext('Delete Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/certificates/custom?restart=1',
-		    method: 'DELETE',
-		    success: function(response, opt) {
-			var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-			Ext.getBody().mask(txt, ['pve-static-mask']);
-			// reload after 10 seconds automatically
-			Ext.defer(function() {
-			    window.location.reload(true);
-			}, 10000);
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    itemId: 'viewbtn',
-	    disabled: true,
-	    text: gettext('View Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		me.view_certificate();
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('File'),
-	    width: 150,
-	    dataIndex: 'filename'
-	},
-	{
-	    header: gettext('Issuer'),
-	    flex: 1,
-	    dataIndex: 'issuer'
-	},
-	{
-	    header: gettext('Subject'),
-	    flex: 1,
-	    dataIndex: 'subject'
-	},
-	{
-	    header: gettext('Valid Since'),
-	    width: 150,
-	    dataIndex: 'notbefore',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Expires'),
-	    width: 150,
-	    dataIndex: 'notafter',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Subject Alternative Names'),
-	    flex: 1,
-	    dataIndex: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    header: gettext('Fingerprint'),
-	    dataIndex: 'fingerprint',
-	    hidden: true
-	},
-	{
-	    header: gettext('PEM'),
-	    dataIndex: 'pem',
-	    hidden: true
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var rec = me.rstore.getById('pveproxy-ssl.pem');
-
-	me.down('#deletebtn').setDisabled(!rec);
-    },
-
-    view_certificate: function() {
-	var me = this;
-	var selection = me.getSelection();
-	if (!selection || selection.length < 1) {
-	    return;
-	}
-	var win = Ext.create('PVE.node.CertificateViewer', {
-	    cert: selection[0].data.filename,
-	    nodename : me.nodename
-	});
-	win.show();
-    },
-
-    listeners: {
-	itemdblclick: 'view_certificate'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'certs-' + me.nodename,
-	    model: 'pve-certificate',
-	    proxy: {
-		type: 'proxmox',
-		    url: '/api2/json/nodes/' + me.nodename + '/certificates/info'
-	    }
-	});
-
-	me.store = {
-	    type: 'diff',
-	    rstore: me.rstore
-	};
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-    }
-});
-Ext.define('PVE.node.ACMEEditor', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveACMEEditor',
-
-    subject: gettext('Domains'),
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    items: [
-		{
-		    xtype: 'textarea',
-		    fieldLabel: gettext('Domains'),
-		    emptyText: "domain1.example.com\ndomain2.example.com",
-		    name: 'domains'
-		}
-	    ],
-	    onGetValues: function(values) {
-		if (!values.domains) {
-		    return {
-			'delete': 'acme'
-		    };
-		}
-		var domains = values.domains.split(/\n/).join(';');
-		return {
-		    'acme': 'domains=' + domains
-		};
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		var res = PVE.Parser.parseACME(response.result.data.acme);
-		if (res) {
-		    res.domains = res.domains.join(' ');
-		    me.setValues(res);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACMEAccountCreate', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-    title: gettext('Register Account'),
-    isCreate: true,
-    method: 'POST',
-    submitText: gettext('Register'),
-    url: '/cluster/acme/account',
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'proxmoxComboGrid',
-	    name: 'directory',
-	    allowBlank: false,
-	    valueField: 'url',
-	    displayField: 'name',
-	    fieldLabel: gettext('ACME Directory'),
-	    store: {
-		autoLoad: true,
-		fields: ['name', 'url'],
-		idProperty: ['name'],
-		proxy: {
-		    type: 'proxmox',
-		    url: '/api2/json/cluster/acme/directories'
-		},
-		sorters: {
-		    property: 'name',
-		    order: 'ASC'
-		}
-	    },
-	    listConfig: {
-		columns: [
-		    {
-			header: gettext('Name'),
-			dataIndex: 'name',
-			flex: 1
-		    },
-		    {
-			header: gettext('URL'),
-			dataIndex: 'url',
-			flex: 1
-		    }
-		]
-	    },
-	    listeners: {
-		change: function(combogrid, value) {
-		    var me = this;
-		    if (!value) {
-			return;
-		    }
-
-		    var disp = me.up('window').down('#tos_url_display');
-		    var field = me.up('window').down('#tos_url');
-		    var checkbox = me.up('window').down('#tos_checkbox');
-
-		    disp.setValue(gettext('Loading'));
-		    field.setValue(undefined);
-		    checkbox.setValue(undefined);
-
-		    Proxmox.Utils.API2Request({
-			url: '/cluster/acme/tos',
-			method: 'GET',
-			params: {
-			    directory: value
-			},
-			success: function(response, opt) {
-			    me.up('window').down('#tos_url').setValue(response.result.data);
-			    me.up('window').down('#tos_url_display').setValue(response.result.data);
-			},
-			failure: function(response, opt) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-		}
-	    }
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'tos_url_display',
-	    fieldLabel: gettext('Terms of Service'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos_url_display'
-	},
-	{
-	    xtype: 'hidden',
-	    itemId: 'tos_url',
-	    name: 'tos_url'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'tos_checkbox',
-	    fieldLabel: gettext('Accept TOS'),
-	    submitValue: false,
-	    validateValue: function(value) {
-		if (value && this.checked) {
-		    return true;
-		}
-		return false;
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'contact',
-	    vtype: 'email',
-	    allowBlank: false,
-	    fieldLabel: gettext('E-Mail')
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.ACMEAccountView', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 600,
-    fieldDefaults: {
-	labelWidth: 140
-    },
-
-    title: gettext('Account'),
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('E-Mail'),
-	    name: 'email'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Created'),
-	    name: 'createdAt'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Status'),
-	    name: 'status'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Directory'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'directory'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Terms of Services'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.accountname) {
-	    throw "no account name defined";
-	}
-
-	me.url = '/cluster/acme/account/' + me.accountname;
-
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		var data = response.result.data;
-		data.email = data.account.contact[0];
-		data.createdAt = data.account.createdAt;
-		data.status = data.account.status;
-		me.setValues(data);
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACME', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveACMEView',
-
-    margin: '10 0 0 0',
-    title: 'ACME',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    itemId: 'edit',
-	    text: gettext('Edit Domains'),
-	    handler: function() {
-		this.up('grid').run_editor();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'createaccount',
-	    text: gettext('Register Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountCreate', {
-		    taskDone: function() {
-			me.load_account();
-			me.reload();
-		    }
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'viewaccount',
-	    text: gettext('View Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountView', {
-		    accountname: 'default'
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'order',
-	    text: gettext('Order Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-
-		Proxmox.Utils.API2Request({
-		    method: 'POST',
-		    params: {
-			force: 1
-		    },
-		    url: '/nodes/' + me.nodename + '/certificates/acme/certificate',
-		    success: function(response, opt) {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: response.result.data,
-			    taskDone: function(success) {
-				me.certificate_order_finished(success);
-			    }
-			});
-			win.show();
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ],
-
-    certificate_order_finished: function(success) {
-	if (!success) {
-	    return;
-	}
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    set_button_status: function() {
-	var me = this;
-
-	var account = !!me.account;
-	var acmeObj = PVE.Parser.parseACME(me.getObjectValue('acme'));
-	var domains = acmeObj ? acmeObj.domains.length : 0;
-
-	var order = me.down('#order');
-	order.setVisible(account);
-	order.setDisabled(!account || !domains);
-
-	me.down('#createaccount').setVisible(!account);
-	me.down('#viewaccount').setVisible(account);
-    },
-
-    load_account: function() {
-	var me = this;
-
-	// for now we only use the 'default' account
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/acme/account/default',
-	    success: function(response, opt) {
-		me.account = response.result.data;
-		me.set_button_status();
-	    },
-	    failure: function(response, opt) {
-		me.account = undefined;
-		me.set_button_status();
-	    }
-	});
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create(me.rows.acme.editor, me.editorConfig);
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    listeners: {
-	itemdblclick: 'run_editor'
-    },
-
-    // account data gets loaded here
-    account: undefined,
-
-    disableSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/api2/json/nodes/' + me.nodename + '/config';
-
-	me.editorConfig = {
-	    url: '/api2/extjs/nodes/' + me.nodename + '/config'
-	};
-	/*jslint confusion: true*/
-	/*acme is a string above*/
-	me.rows = {
-	    acme: {
-		defaultValue: '',
-		header: gettext('Domains'),
-		editor: 'PVE.node.ACMEEditor',
-		renderer: function(value) {
-		    var acmeObj = PVE.Parser.parseACME(value);
-		    if (acmeObj) {
-			return acmeObj.domains.join('<br>');
-		    }
-		    return Proxmox.Utils.noneText;
-		}
-	    }
-	};
-	/*jslint confusion: false*/
-
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-	me.load_account();
-    }
-});
-Ext.define('PVE.node.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.node.Config',
-
-    onlineHelp: 'chapter_system_administration',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/status",
-	    interval: 1000
-	});
-
-	var node_command = function(cmd) {
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/status',
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var actionBtn = Ext.create('Ext.Button', {
-	    text: gettext('Bulk Actions'),
-	    iconCls: 'fa fa-fw fa-ellipsis-v',
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    menu: new Ext.menu.Menu({
-		items: [
-		    {
-			text: gettext('Bulk Start'),
-			iconCls: 'fa fa-fw fa-play',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Start'),
-				btnText: gettext('Start'),
-				action: 'startall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Stop'),
-			iconCls: 'fa fa-fw fa-stop',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Stop'),
-				btnText: gettext('Stop'),
-				action: 'stopall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Migrate'),
-			iconCls: 'fa fa-fw fa-send-o',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Migrate'),
-				btnText: gettext('Migrate'),
-				action: 'migrateall'
-			    });
-			    win.show();
-			}
-		    }
-		]
-	    })
-	});
-
-	var restartBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reboot'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Reboot node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('reboot');
-	    },
-	    iconCls: 'fa fa-undo'
-	});
-
-	var shutdownBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Shutdown node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('shutdown');
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var shellBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.nodes['Sys.Console'],
-	    text: gettext('Shell'),
-	    consoleType: 'shell',
-	    nodename: nodename
-	});
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext('Node') + " '" + nodename + "'",
-	    hstateid: 'nodetab',
-	    defaults: { statusStore: me.statusStore },
-	    tbar: [ restartBtn, shutdownBtn, shellBtn, actionBtn]
-	});
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary',
-		    xtype: 'pveNodeSummary'
-		},
-		{
-		    title: gettext('Notes'),
-		    iconCls: 'fa fa-sticky-note-o',
-		    itemId: 'notes',
-		    xtype: 'pveNotesView'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Console']) {
-	    me.items.push(
-		{
-		    title: gettext('Shell'),
-		    iconCls: 'fa fa-terminal',
-		    itemId: 'jsconsole',
-		    xtype: 'pveNoVncConsole',
-		    consoleType: 'shell',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('System'),
-		    iconCls: 'fa fa-cogs',
-		    itemId: 'services',
-		    expandedOnInit: true,
-		    startOnlyServices: {
-			'pveproxy': true,
-			'pvedaemon': true,
-			'pve-cluster': true
-		    },
-		    nodename: nodename,
-		    onlineHelp: 'pve_service_daemons',
-		    xtype: 'proxmoxNodeServiceView'
-		},
-		{
-		    title: gettext('Network'),
-		    iconCls: 'fa fa-exchange',
-		    itemId: 'network',
-		    groups: ['services'],
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeNetworkView'
-		},
-		{
-		    title: gettext('Certificates'),
-		    iconCls: 'fa fa-certificate',
-		    itemId: 'certificates',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'pveCertificatesView'
-		},
-		{
-		    title: gettext('DNS'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'dns',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeDNSView'
-		},
-		{
-		    title: gettext('Hosts'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'hosts',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeHostsView'
-		},
-		{
-		    title: gettext('Time'),
-		    itemId: 'time',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'proxmoxNodeTimeView',
-		    iconCls: 'fa fa-clock-o'
-		});
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push({
-		title: 'Syslog',
-		iconCls: 'fa fa-list',
-		groups: ['services'],
-		disabled: !caps.nodes['Sys.Syslog'],
-		itemId: 'syslog',
-		xtype: 'proxmoxLogView',
-		url: "/api2/extjs/nodes/" + nodename + "/syslog",
-		log_select_timespan: 1
-	    });
-
-	    if (caps.nodes['Sys.Modify']) {
-		me.items.push({
-		    title: gettext('Updates'),
-		    iconCls: 'fa fa-refresh',
-		    disabled: !caps.nodes['Sys.Console'],
-		    // do we want to link to system updates instead?
-		    itemId: 'apt',
-		    xtype: 'proxmoxNodeAPT',
-		    upgradeBtn: {
-			xtype: 'pveConsoleButton',
-			disabled: Proxmox.UserName !== 'root@pam',
-			text: gettext('Upgrade'),
-			consoleType: 'upgrade',
-			nodename: nodename
-		    },
-		    nodename: nodename
-		});
-	    }
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    iconCls: 'fa fa-shield',
-		    title: gettext('Firewall'),
-		    allow_iface: true,
-		    base_url: '/nodes/' + nodename + '/firewall/rules',
-		    list_refs_url: '/cluster/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    title: gettext('Options'),
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_host_specific_configuration',
-		    groups: ['firewall'],
-		    base_url: '/nodes/' + nodename + '/firewall/options',
-		    fwtype: 'node',
-		    itemId: 'firewall-options'
-		});
-	}
-
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Disks'),
-		    itemId: 'storage',
-		    expandedOnInit: true,
-		    iconCls: 'fa fa-hdd-o',
-		    xtype: 'pveNodeDiskList'
-		},
-		{
-		    title: 'LVM',
-		    itemId: 'lvm',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square',
-		    groups: ['storage'],
-		    xtype: 'pveLVMList'
-		},
-		{
-		    title: 'LVM-Thin',
-		    itemId: 'lvmthin',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square-o',
-		    groups: ['storage'],
-		    xtype: 'pveLVMThinList'
-		},
-		{
-		    title: Proxmox.Utils.directoryText,
-		    itemId: 'directory',
-		    onlineHelp: 'chapter_storage',
-		    iconCls: 'fa fa-folder',
-		    groups: ['storage'],
-		    xtype: 'pveDirectoryList'
-		},
-		{
-		    title: 'ZFS',
-		    itemId: 'zfs',
-		    onlineHelp: 'chapter_zfs',
-		    iconCls: 'fa fa-th-large',
-		    groups: ['storage'],
-		    xtype: 'pveZFSList'
-		},
-		{
-		    title: 'Ceph',
-		    itemId: 'ceph',
-		    iconCls: 'fa fa-ceph',
-		    xtype: 'pveNodeCephStatus'
-		},
-		{
-		    xtype: 'pveReplicaView',
-		    iconCls: 'fa fa-retweet',
-		    title: gettext('Replication'),
-		    itemId: 'replication'
-		},
-		{
-		    xtype: 'pveNodeCephConfigCrush',
-		    title: gettext('Configuration'),
-		    iconCls: 'fa fa-gear',
-		    groups: ['ceph'],
-		    itemId: 'ceph-config'
-		},
-		{
-		    xtype: 'pveNodeCephMonList',
-		    title: gettext('Monitor'),
-		    iconCls: 'fa fa-tv',
-		    groups: ['ceph'],
-		    itemId: 'ceph-monlist'
-		},
-		{
-		    xtype: 'pveNodeCephOsdTree',
-		    title: 'OSD',
-		    iconCls: 'fa fa-hdd-o',
-		    groups: ['ceph'],
-		    itemId: 'ceph-osdtree'
-		},
-		{
-		    xtype: 'pveNodeCephFSPanel',
-		    title: 'CephFS',
-		    iconCls: 'fa fa-folder',
-		    groups: ['ceph'],
-		    nodename: nodename,
-		    itemId: 'ceph-cephfspanel'
-		},
-		{
-		    xtype: 'pveNodeCephPoolList',
-		    title: 'Pools',
-		    iconCls: 'fa fa-sitemap',
-		    groups: ['ceph'],
-		    itemId: 'ceph-pools'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push(
-		{
-		    xtype: 'proxmoxLogView',
-		    title: gettext('Log'),
-		    iconCls: 'fa fa-list',
-		    groups: ['firewall'],
-		    onlineHelp: 'chapter_pve_firewall',
-		    url: '/api2/extjs/nodes/' + nodename + '/firewall/log',
-		    itemId: 'firewall-fwlog'
-		},
-		{
-		    title: gettext('Log'),
-		    itemId: 'ceph-log',
-		    iconCls: 'fa fa-list',
-		    groups: ['ceph'],
-		    onlineHelp: 'chapter_pveceph',
-		    xtype: 'cephLogView',
-		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
-		    nodename: nodename
-		});
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Task History'),
-		iconCls: 'fa fa-list',
-		itemId: 'tasks',
-		nodename: nodename,
-		xtype: 'proxmoxNodeTasks'
-	    },
-	    {
-		title: gettext('Subscription'),
-		iconCls: 'fa fa-support',
-		itemId: 'support',
-		xtype: 'pveNodeSubscription',
-		nodename: nodename
-	    }
-	);
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var uptimerec = s.data.get('uptime');
-	    var powermgmt = uptimerec ? uptimerec.data.value : false;
-	    if (!caps.nodes['Sys.PowerMgmt']) {
-		powermgmt = false;
-	    }
-	    restartBtn.setDisabled(!powermgmt);
-	    shutdownBtn.setDisabled(!powermgmt);
-	    shellBtn.setDisabled(!powermgmt);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    config: {
-	vmtype: undefined,
-	nodename: undefined,
-	vmid: undefined
-    },
- // private, used to store the migration mode after checking if the guest runs
-    liveMode: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=formPanel]': {
-		validityChange: function(panel, isValid) {
-		    this.lookup('submitButton').setDisabled(!isValid);
-		}
-	    },
-	    'button[reference=submitButton]': {
-		click: function() {
-		    var me = this;
-		    var view = me.getView();
-
-		    var values = me.lookup('formPanel').getValues();
-		    var params = {
-			target: values.target
-		    };
-
-		    if (view.liveMode) {
-			params[view.liveMode] = 1;
-		    }
-
-		    Proxmox.Utils.API2Request({
-			params: params,
-			url: '/nodes/' + view.nodename + '/' + view.vmtype + '/' + view.vmid + '/migrate',
-			waitMsgTarget: view,
-			method: 'POST',
-			failure: function(response, opts) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var upid = response.result.data;
-			    var extraTitle = Ext.String.format(' ({0} ---> {1})', view.nodename, params.target);
-
-			    Ext.create('Proxmox.window.TaskViewer', {
-				upid: upid,
-				extraTitle: extraTitle
-			    }).show();
-
-			    view.close();
-			}
-		    });
-		}
-	    }
-	}
-    },
-
-    width: 350,
-    modal: true,
-    layout: 'auto',
-    border: false,
-    resizable: false,
-    items: [
-	{
-	    xtype: 'form',
-	    reference: 'formPanel',
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    xtype: 'pveNodeSelector',
-		    reference: 'pveNodeSelector',
-		    name: 'target',
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    disallowedNodes: undefined,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'displayfield',
-		    reference: 'migrationMode',
-		    fieldLabel: gettext('Mode'),
-		    value: gettext('Offline')
-		}
-		]
-	}
-    ],
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    reference: 'proxmoxHelpButton',
-	    onlineHelp: 'pct_migration',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	},
-	'->',
-	{
-	    xtype: 'button',
-	    reference: 'submitButton',
-	    text: gettext('Migrate')
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	me.callParent();
-
-	var title = gettext('Migrate') + (' CT ') + me.vmid;
-	me.liveMode = 'restart';
-
-	if (me.vmtype === 'qemu') {
-	    me.lookup('proxmoxHelpButton').setHelpConfig({
-		onlineHelp: 'qm_migration'
-	    });
-	    title = gettext('Migrate') + (' VM ') + me.vmid;
-	    me.liveMode = 'online';
-	}
-
-	var running = false;
-	var vmrec = PVE.data.ResourceStore.findRecord('vmid', me.vmid,
-	    0, false, false, true);
-	if (vmrec && vmrec.data && vmrec.data.running) {
-	    running = true;
-	}
-
-	if (running) {
-	    var displayField = me.lookup('migrationMode');
-	    if (me.vmtype === 'qemu') {
-		displayField.setValue(gettext('Online'));
-		me.liveMode = 'online';
-	    } else {
-		displayField.setValue(gettext('Restart Mode'));
-		me.liveMode = 'restart';
-	    }
-	}
-
-	me.setTitle(title);
-	me.lookup('pveNodeSelector').disallowedNodes = [me.nodename];
-	me.lookup('formPanel').isValid();
-    }
-});Ext.define('PVE.window.BulkAction', {
-    extend: 'Ext.window.Window',
-
-    resizable: true,
-    width: 800,
-    modal: true,
-    layout: {
-	type: 'fit'
-    },
-    border: false,
-
-    // the action to be set
-    // currently there are
-    // startall
-    // migrateall
-    // stopall
-    action: undefined,
-
-    submit: function(params) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.action,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		me.hide();
-		win.on('destroy', function() {
-		    me.close();
-		});
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.action) {
-	    throw "no action specified";
-	}
-
-	if (!me.btnText) {
-	    throw "no button text specified";
-	}
-
-	if (!me.title) {
-	    throw "no title specified";
-	}
-
-	var items = [];
-
-	if (me.action === 'migrateall') {
-	    /*jslint confusion: true*/
-	    /*value is string and number*/
-	    items.push(
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'target',
-		    disallowedNodes: [me.nodename],
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'maxworkers',
-		    minValue: 1,
-		    maxValue: 100,
-		    value: 1,
-		    fieldLabel: gettext('Parallel jobs'),
-		    allowBlank: false
-		},
-		{
-		    itemId: 'lxcwarning',
-		    xtype: 'displayfield',
-		    userCls: 'pve-hint',
-		    value: 'Warning: Running CTs will be migrated in Restart Mode.',
-		    hidden: true // only visible if running container chosen
-		}
-	    );
-	    /*jslint confusion: false*/
-	} else if (me.action === 'startall') {
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'force',
-		value: 1
-	    });
-	}
-
-	items.push({
-	    xtype: 'vmselector',
-	    itemId: 'vms',
-	    name: 'vms',
-	    flex: 1,
-	    height: 300,
-	    selectAll: true,
-	    allowBlank: false,
-	    nodename: me.nodename,
-	    action: me.action,
-	    listeners: {
-		selectionchange: function(vmselector, records) {
-		    if (me.action == 'migrateall') {
-			var showWarning = records.some(function(item) {
-			    return (item.data.type == 'lxc' &&
-				item.data.status == 'running');
-			});
-			me.down('#lxcwarning').setVisible(showWarning);
-		    }
-		}
-	    }
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    fieldDefaults: {
-		labelWidth: 300,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: me.btnText,
-	    handler: function() {
-		form.isValid();
-		me.submit(form.getValues());
-	    }
-	});
-
-	Ext.apply(me, {
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-
-	form.on('validitychange', function() {
-	    var valid = form.isValid();
-	    submitBtn.setDisabled(!valid);
-	});
-	form.isValid();
-    }
-});
-Ext.define('PVE.window.Clone', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    isTemplate: false,
-
-    onlineHelp: 'qm_copy_and_clone',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=cloneform]': {
-		validitychange: 'disableSubmit'
-	    }
-	},
-	disableSubmit: function(form) {
-	    this.lookupReference('submitBtn').setDisabled(!form.isValid());
-	}
-    },
-
-    statics: {
-	// display a snapshot selector only if needed
-	wrap: function(nodename, vmid, isTemplate, guestType) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var snapshotList = response.result.data;
-		    var hasSnapshots = snapshotList.length === 1 &&
-			snapshotList[0].name === 'current' ? false : true;
-
-		    Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: isTemplate,
-			hasSnapshots: hasSnapshots
-		    }).show();
-		}
-	    });
-	}
-    },
-
-    create_clone: function(values) {
-	var me = this;
-
-	var params = { newid: values.newvmid };
-
-	if (values.snapname && values.snapname !== 'current') {
-	    params.snapname = values.snapname;
-	}
-
-	if (values.pool) {
-	    params.pool = values.pool;
-	}
-
-	if (values.name) {
-	    if (me.guestType === 'lxc') {
-		params.hostname = values.name;
-	    } else {
-		params.name = values.name;
-	    }
-	}
-
-	if (values.target) {
-	    params.target = values.target;
-	}
-
-	if (values.clonemode === 'copy') {
-	    params.full = 1;
-	    if (values.hdstorage) {
-		params.storage = values.hdstorage;
-		if (values.diskformat && me.guestType !== 'lxc') {
-		    params.format = values.diskformat;
-		}
-	    }
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/clone',
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-
-    },
-
-    // disable the Storage selector when clone mode is linked clone
-    updateVisibility: function() {
-	var me = this;
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-	var disksel = me.lookup('diskselector');
-	disksel.setDisabled(clonemode === 'clone');
-    },
-
-    // add to the list of valid nodes each node where
-    // all the VM disks are available
-    verifyFeature: function() {
-	var me = this;
-
-	var snapname = me.lookupReference('snapshotsel').getValue();
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-
-	var params = { feature: clonemode };
-	if (snapname !== 'current') {
-	    params.snapname = snapname;
-	}
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/feature',
-	    params: params,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		me.lookupReference('submitBtn').setDisabled(true);
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var res = response.result.data;
-
-		me.lookupReference('targetsel').allowedNodes = res.nodes;
-		me.lookupReference('targetsel').validate();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.snapname) {
-	    me.snapname = 'current';
-	}
-
-	if (!me.guestType) {
-	    throw "no Guest Type specified";
-	}
-
-	var titletext = me.guestType === 'lxc' ? 'CT' : 'VM';
-	if (me.isTemplate) {
-	    titletext += ' Template';
-	}
-	me.title = "Clone " + titletext + " " + me.vmid;
-
-	var col1 = [];
-	var col2 = [];
-
-	col1.push({
-	    xtype: 'pveNodeSelector',
-	    name: 'target',
-	    reference: 'targetsel',
-	    fieldLabel: gettext('Target node'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    onlineValidator: true,
-	    listeners: {
-		change: function(f, value) {
-		    me.lookupReference('hdstorage').setTargetNode(value);
-		}
-	    }
-	});
-
-	var modelist = [['copy', gettext('Full Clone')]];
-	if (me.isTemplate) {
-	    modelist.push(['clone', gettext('Linked Clone')]);
-	}
-
-	col1.push({
-	    xtype: 'pveGuestIDSelector',
-	    name: 'newvmid',
-	    guestType: me.guestType,
-	    value: '',
-	    loadNextFreeID: true,
-	    validateExists: false
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'name',
-	    allowBlank: true,
-	    fieldLabel: me.guestType === 'lxc' ? gettext('Hostname') : gettext('Name')
-	},
-	{
-	    xtype: 'pvePoolSelector',
-	    fieldLabel: gettext('Resource Pool'),
-	    name: 'pool',
-	    value: '',
-	    allowBlank: true
-	}
-	);
-
-	col2.push({
-	    xtype: 'proxmoxKVComboBox',
-	    fieldLabel: gettext('Mode'),
-	    name: 'clonemode',
-	    reference: 'clonemodesel',
-	    allowBlank: false,
-	    hidden: !me.isTemplate,
-	    value: me.isTemplate ? 'clone' : 'copy',
-		    comboItems: modelist,
-		    listeners: {
-			change: function(t, value) {
-			    me.updateVisibility();
-			    me.verifyFeature();
-			}
-		    }
-	},
-	{
-	    xtype: 'PVE.form.SnapshotSelector',
-	    name: 'snapname',
-	    reference: 'snapshotsel',
-	    fieldLabel: gettext('Snapshot'),
-	    nodename: me.nodename,
-	    guestType: me.guestType,
-	    vmid: me.vmid,
-	    hidden: me.isTemplate || !me.hasSnapshots ? true : false,
-	    disabled: false,
-	    allowBlank: false,
-	    value : me.snapname,
-	    listeners: {
-		change: function(f, value) {
-		    me.verifyFeature();
-		}
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    reference: 'diskselector',
-	    nodename: me.nodename,
-	    autoSelect: false,
-	    hideSize: true,
-	    hideSelection: true,
-	    storageLabel: gettext('Target Storage'),
-	    allowBlank: true,
-	    storageContent: me.guestType === 'qemu' ? 'images' : 'rootdir',
-	    emptyText: gettext('Same as source'),
-	    disabled: me.isTemplate ? true : false // because default mode is clone for templates
-	});
-
-	var formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    reference: 'cloneform',
-	    border: false,
-	    layout: 'column',
-	    defaultType: 'container',
-	    columns: 2,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: col1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: col2
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 600,
-	    height: 250,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ {
-		xtype: 'proxmoxHelpButton',
-		listenToGlobalEvent: false,
-		hidden: false,
-		onlineHelp: me.onlineHelp
-	    },
-	    '->',
-	    {
-		reference: 'submitBtn',
-		text: gettext('Clone'),
-		disabled: true,
-		handler: function() {
-		    var cloneForm = me.lookupReference('cloneform');
-		    if (cloneForm.isValid()) {
-			me.create_clone(cloneForm.getValues());
-		    }
-		}
-	    } ],
-	    items: [ formPanel ]
-	});
-
-	me.callParent();
-
-	me.verifyFeature();
-    }
-});
-Ext.define('PVE.qemu.Monitor', {
-    extend: 'Ext.panel.Panel',
-
-    alias: 'widget.pveQemuMonitor',
-
-    maxLines: 500,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var history = [];
-	var histNum = -1;
-	var lines = [];
-
-	var textbox = Ext.createWidget('panel', {
-	    region: 'center',
-	    xtype: 'panel',
-	    autoScroll: true,
-	    border: true,
-	    margins: '5 5 5 5',
-	    bodyStyle: 'font-family: monospace;'
-	});
-
-	var scrollToEnd = function() {
-	    var el = textbox.getTargetEl();
-	    var dom = Ext.getDom(el);
-
-	    var clientHeight = dom.clientHeight;
-	    // BrowserBug: clientHeight reports 0 in IE9 StrictMode
-            // Instead we are using offsetHeight and hardcoding borders
-            if (Ext.isIE9 && Ext.isStrict) {
-		clientHeight = dom.offsetHeight + 2;
-            }
-	    dom.scrollTop = dom.scrollHeight - clientHeight;
-	};
-
-	var refresh = function() {
-	    textbox.update('<pre>' + lines.join('\n') + '</pre>');
-	    scrollToEnd();
-	};
-
-	var addLine = function(line) {
-	    lines.push(line);
-	    if (lines.length > me.maxLines) {
-		lines.shift();
-	    }
-	};
-
-	var executeCmd = function(cmd) {
-	    addLine("# " + Ext.htmlEncode(cmd));
-	    if (cmd) {
-		history.unshift(cmd);
-		if (history.length > 20) {
-		    history.splice(20);
-		}
-	    }
-	    histNum = -1;
-
-	    refresh();
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor",
-		method: 'POST',
-		waitMsgTarget: me,
-		success: function(response, opts) {
-		    var res = response.result.data; 
-		    Ext.Array.each(res.split('\n'), function(line) {
-			addLine(Ext.htmlEncode(line));
-		    });
-		    refresh();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		textbox,
-		{
-		    region: 'south',
-		    margins:'0 5 5 5',
-		    border: false,
-		    xtype: 'textfield',
-		    name: 'cmd',
-		    value: '',
-		    fieldStyle: 'font-family: monospace;',
-		    allowBlank: true,
-		    listeners: {
-			afterrender: function(f) {
-			    f.focus(false);
-			    addLine("Type 'help' for help.");
-			    refresh();
-			},
-			specialkey: function(f, e) {
-			    var key = e.getKey();
-			    switch (key) {
-				case e.ENTER:
-				    var cmd = f.getValue();
-				    f.setValue('');
-				    executeCmd(cmd);
-				    break;
-				case e.PAGE_UP:
-				    textbox.scrollBy(0, -0.9*textbox.getHeight(), false);
-				    break;
-				case e.PAGE_DOWN:
-				    textbox.scrollBy(0, 0.9*textbox.getHeight(), false);
-				    break;
-				case e.UP:
-				    if (histNum + 1 < history.length) {
-					f.setValue(history[++histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				case e.DOWN:
-				    if (histNum > 0) {
-					f.setValue(history[--histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				default:
-				    break;
-			    }
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		show: function() {
-		    var field = me.query('textfield[name="cmd"]')[0];
-		    field.focus(false, true);
-		}
-	    }
-	});		
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveQemuSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 330,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 330,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.qemu.OSTypeInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuOSTypePanel',
-    onlineHelp: 'qm_os_settings',
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'combobox[name=osbase]': {
-		change: 'onOSBaseChange'
-	    },
-	    'combobox[name=ostype]': {
-		afterrender: 'onOSTypeChange',
-		change: 'onOSTypeChange'
-	    }
-	},
-	onOSBaseChange: function(field, value) {
-	    this.lookup('ostype').getStore().setData(PVE.Utils.kvm_ostypes[value]);
-	},
-	onOSTypeChange: function(field) {
-	    var me = this, ostype = field.getValue();
-	    if (!me.getView().insideWizard) {
-		return;
-	    }
-	    var targetValues = PVE.qemu.OSDefaults.getDefaults(ostype);
-
-	    me.setWidget('pveBusSelector', targetValues.busType);
-	    me.setWidget('pveNetworkCardSelector', targetValues.networkCard);
-	    var scsihw = targetValues.scsihw || '__default__';
-	    this.getViewModel().set('current.scsihw', scsihw);
-	},
-	setWidget: function(widget, newValue) {
-	    // changing a widget is safe only if ComponentQuery.query returns us
-	    // a single value array
-	    var widgets = Ext.ComponentQuery.query('pveQemuCreateWizard ' + widget);
-	    if (widgets.length === 1) {
-		widgets[0].setValue(newValue);
-	    } else {
-		throw 'non unique widget :' + widget + ' in Wizard';
-	    }
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	/*jslint confusion: true */
-	me.items = [
-	    {
-		xtype: 'displayfield',
-		value: gettext('Guest OS') + ':',
-		hidden: !me.insideWizard
-	    },
-	    {
-		xtype: 'combobox',
-		submitValue: false,
-		name: 'osbase',
-		fieldLabel: gettext('Type'),
-		editable: false,
-		queryMode: 'local',
-		value: 'Linux',
-		store: Object.keys(PVE.Utils.kvm_ostypes)
-	    },
-	    {
-		xtype: 'combobox',
-		name: 'ostype',
-		reference: 'ostype',
-		fieldLabel: gettext('Version'),
-		value: 'l26',
-		allowBlank : false,
-		editable: false,
-		queryMode: 'local',
-		valueField: 'val',
-		displayField: 'desc',
-		store: {
-		    fields: ['desc', 'val'],
-		    data: PVE.Utils.kvm_ostypes.Linux,
-		    listeners: {
-			datachanged: function (store) {
-			    var ostype = me.lookup('ostype');
-			    var old_val = ostype.getValue();
-			    if (!me.insideWizard && old_val && store.find('val', old_val) != -1) {
-				ostype.setValue(old_val);
-			    } else {
-				ostype.setValue(store.getAt(0));
-			    }
-			}
-		    }
-		}
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.OSTypeEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: 'OS Type',
-
-    items: [{ xtype: 'pveQemuOSTypePanel' }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var value = response.result.data.ostype || 'other';
-		var osinfo = PVE.Utils.get_kvm_osinfo(value);
-		me.setValues({ ostype: value, osbase: osinfo.base });
-	    }
-	});
-    }
-});
-/*
- * This class holds performance *recommended* settings for the PVE Qemu wizards
- * the *mandatory* settings are set in the PVE::QemuServer
- * config_to_command sub
- * We store this here until we get the data from the API server
-*/
-
-// this is how you would add an hypothetic FreeBSD > 10 entry
-//
-//virtio-blk is stable but virtIO net still
-//   problematic as of 10.3
-// see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059
-//	addOS({
-//	    parent: 'generic', // inherits defaults
-//	    pveOS: 'freebsd10', // must match a radiofield in OSTypeEdit.js
-//	    busType: 'virtio' // must match a pveBusController value
-//			    // networkCard muss match a pveNetworkCardSelector
-
-
-Ext.define('PVE.qemu.OSDefaults', {
-    singleton: true, // will also force creation when loaded
-
-    constructor: function() {
-	var me = this;
-
-	var addOS = function(settings) {
-		if (me.hasOwnProperty(settings.parent)) {
-		    var child = Ext.clone(me[settings.parent]);
-		    me[settings.pveOS] = Ext.apply(child, settings);
-
-		} else {
-		    throw("Could not find your genitor");
-		}
-	    };
-
-	// default values
-	me.generic = {
-	    busType: 'ide',
-	    networkCard: 'e1000',
-	    busPriority: {
-		    ide: 4,
-		    sata: 3,
-		    scsi: 2,
-		    virtio: 1
-	    },
-	    scsihw: 'virtio-scsi-pci'
-	};
-
-       // virtio-net is in kernel since 2.6.25
-       // virtio-scsi since 3.2 but backported in RHEL with 2.6 kernel
-	addOS({
-	    pveOS: 'l26',
-	    parent : 'generic',
-	    busType: 'scsi',
-	    busPriority: {
-		    scsi: 4,
-		    virtio: 3,
-		    sata: 2,
-		    ide: 1
-	    },
-	    networkCard: 'virtio'
-	});
-
-	// recommandation from http://wiki.qemu.org/Windows2000
-	addOS({
-	    pveOS: 'w2k',
-	    parent : 'generic',
-	    networkCard: 'rtl8139',
-	    scsihw: ''
-	});
-	// https://pve.proxmox.com/wiki/Windows_XP_Guest_Notes
-	addOS({
-	    pveOS: 'wxp',
-	    parent : 'w2k'
-	});
-
-	me.getDefaults = function(ostype) {
-	    if (PVE.qemu.OSDefaults[ostype]) {
-		return PVE.qemu.OSDefaults[ostype];
-	    } else {
-		return PVE.qemu.OSDefaults.generic;
-	    }
-	};
-    }
-});
-Ext.define('PVE.qemu.ProcessorInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuProcessorPanel',
-    onlineHelp: 'qm_cpu',
-
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateCores: function() {
-	    var me = this.getView();
-	    var sockets = me.down('field[name=sockets]').getValue();
-	    var cores = me.down('field[name=cores]').getValue();
-	    me.down('field[name=totalcores]').setValue(sockets*cores);
-	    var vcpus = me.down('field[name=vcpus]');
-	    vcpus.setMaxValue(sockets*cores);
-	    vcpus.setEmptyText(sockets*cores);
-	    vcpus.validate();
-	},
-
-	control: {
-	    'field[name=sockets]': {
-		change: 'updateCores'
-	    },
-	    'field[name=cores]': {
-		change: 'updateCores'
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (Array.isArray(values['delete'])) {
-	    values['delete'] = values['delete'].join(',');
-	}
-
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	// build the cpu options:
-	me.cpu.cputype = values.cputype;
-
-	var flags = [];
-
-	['pcid', 'spec-ctrl'].forEach(function(flag) {
-	    if (values[flag]) {
-		flags.push('+' + flag.toString());
-	    }
-	    delete values[flag];
-	});
-
-	me.cpu.flags = flags.length ? flags.join(';') : undefined;
-
-	delete values.cputype;
-	delete values.flags;
-	var cpustring = PVE.Parser.printQemuCpu(me.cpu);
-
-	// remove cputype delete request:
-	var del = values['delete'];
-	delete values['delete'];
-	if (del) {
-	    del = del.split(',');
-	    Ext.Array.remove(del, 'cputype');
-	} else {
-	    del = [];
-	}
-
-	if (cpustring) {
-	    values.cpu = cpustring;
-	} else {
-	    del.push('cpu');
-	}
-
-	var delarr = del.join(',');
-	if (delarr) {
-	    values['delete'] = delarr;
-	}
-
-	return values;
-    },
-
-    cpu: {},
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'sockets',
-	    minValue: 1,
-	    maxValue: 4,
-	    value: '1',
-	    fieldLabel: gettext('Sockets'),
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cores',
-	    minValue: 1,
-	    maxValue: 128,
-	    value: '1',
-	    fieldLabel: gettext('Cores'),
-	    allowBlank: false
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'CPUModelSelector',
-	    name: 'cputype',
-	    value: '__default__',
-	    fieldLabel: gettext('Type')
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Total cores'),
-	    name: 'totalcores',
-	    value: '1'
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'vcpus',
-	    minValue: 1,
-	    maxValue: 1,
-	    value: '',
-	    fieldLabel: gettext('VCPUs'),
-	    deleteEmpty: true,
-	    allowBlank: true,
-	    emptyText: '1'
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    maxValue: 128, // api maximum
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    minValue: 8,
-	    maxValue: 500000,
-	    value: '1024',
-	    deleteEmpty: true,
-	    allowBlank: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Enable NUMA'),
-	    name: 'numa',
-	    uncheckedValue: 0
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'PCID',
-	    name: 'pcid',
-	    uncheckedValue: 0
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: 'SPEC-CTRL',
-	    name: 'spec-ctrl',
-	    uncheckedValue: 0
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.ProcessorEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.ProcessorInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Processors'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		var value = data.cpu;
-		if (value) {
-		    var cpu = PVE.Parser.parseQemuCpu(value);
-		    ipanel.cpu = cpu;
-		    data.cputype = cpu.cputype;
-		    if (cpu.flags) {
-			var flags = cpu.flags.split(';');
-			flags.forEach(function(flag) {
-			    var sign = flag.substr(0,1);
-			    flag = flag.substr(1);
-			    data[flag] = (sign === '+');
-			});
-		    }
-		}
-		me.setValues(data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuBootOrderPanel',
-    vmconfig: {}, // store loaded vm config
-
-    bootdisk: undefined,
-    selection: [],
-    list: [],
-    comboboxes: [],
-
-    isBootDisk: function(value) {
-	return PVE.Utils.bus_match.test(value);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-	var order = me.vmconfig.boot || 'cdn';
-	me.bootdisk = me.vmconfig.bootdisk || undefined;
-
-	// get the first 3 characters
-	// ignore the rest (there should never be more than 3)
-	me.selection = order.split('').slice(0,3);
-
-	// build bootdev list
-	me.list = [];
-	Ext.Object.each(me.vmconfig, function(key, value) {
-	    if (me.isBootDisk(key) &&
-		!(/media=cdrom/).test(value)) {
-		me.list.push([key, "Disk '" + key + "'"]);
-	    }
-	});
-
-	me.list.push(['d', 'CD-ROM']);
-	me.list.push(['n', gettext('Network')]);
-	me.list.push(['__none__', Proxmox.Utils.noneText]);
-
-	me.recomputeList();
-
-	me.comboboxes.forEach(function(box) {
-	    box.resetOriginalValue();
-	});
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var order = me.selection.join('');
-	var res = { boot: order };
-
-	if  (me.bootdisk && order.indexOf('c') !== -1) {
-	    res.bootdisk = me.bootdisk;
-	} else {
-	    res['delete'] = 'bootdisk';
-	}
-
-	return res;
-    },
-
-    recomputeSelection: function(combobox, newVal, oldVal) {
-	var me = this.up('#inputpanel');
-	me.selection = [];
-	me.comboboxes.forEach(function(item) {
-	    var val = item.getValue();
-
-	    // when selecting an already selected item,
-	    // switch it around
-	    if ((val === newVal || (me.isBootDisk(val) && me.isBootDisk(newVal))) &&
-		item.name !== combobox.name &&
-		newVal !== '__none__') {
-		// swap items
-		val = oldVal;
-	    }
-
-	    // push 'c','d' or 'n' in the array
-	    if (me.isBootDisk(val)) {
-		me.selection.push('c');
-		me.bootdisk = val;
-	    } else if (val === 'd' ||
-		       val === 'n') {
-		me.selection.push(val);
-	    }
-	});
-
-	me.recomputeList();
-    },
-
-    recomputeList: function(){
-	var me = this;
-	// set the correct values in the kvcomboboxes
-	var cnt = 0;
-	me.comboboxes.forEach(function(item) {
-	    if (cnt === 0) {
-		// never show 'none' on first combobox
-		item.store.loadData(me.list.slice(0, me.list.length-1));
-	    } else {
-		item.store.loadData(me.list);
-	    }
-	    item.suspendEvent('change');
-	    if (cnt < me.selection.length) {
-		item.setValue((me.selection[cnt] !== 'c')?me.selection[cnt]:me.bootdisk);
-	    } else if (cnt === 0){
-		item.setValue('');
-	    } else {
-		item.setValue('__none__');
-	    }
-	    cnt++;
-	    item.resumeEvent('change');
-	    item.validate();
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	// this has to be done here, because of
-	// the way our inputPanel class handles items
-	me.comboboxes = [
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 1",
-		labelWidth: 120,
-		name: 'bd1',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 2",
-		labelWidth: 120,
-		name: 'bd2',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 3",
-		labelWidth: 120,
-		name: 'bd3',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    })
-	];
-	Ext.apply(me, { items: me.comboboxes });
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    items: [{
-	xtype: 'pveQemuBootOrderPanel',
-	itemId: 'inputpanel'
-    }],
-
-    subject: gettext('Boot Order'),
-
-    initComponent : function() {
-	var me = this;
-	me.callParent();
-	me.load({
-	    success: function(response, options) {
-		me.down('#inputpanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuMemoryPanel',
-    onlineHelp: 'qm_memory',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = {};
-
-	res.memory = values.memory;
-	res.balloon = values.balloon;
-
-	if (!values.ballooning) {
-	    res.balloon = 0;
-	    res['delete'] = 'shares';
-	} else if (values.memory === values.balloon) {
-	    delete res.balloon;
-	    res['delete'] = 'balloon,shares';
-	} else if (Ext.isDefined(values.shares) && (values.shares !== "")) {
-	    res.shares = values.shares;
-	} else {
-	    res['delete'] = "shares";
-	}
-
-	return res;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var labelWidth = 160;
-
-	me.items= [
-	    {
-		xtype: 'pveMemoryField',
-		labelWidth: labelWidth,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		name: 'memory',
-		minValue: 1,
-		step: 32,
-		hotplug: me.hotplug,
-		listeners: {
-		    change: function(f, value, old) {
-			var bf = me.down('field[name=balloon]');
-			var balloon = bf.getValue();
-			bf.setMaxValue(value);
-			if (balloon === old) {
-			    bf.setValue(value);
-			}
-			bf.validate();
-		    }
-		}
-	    }
-	];
-
-	me.advancedItems= [
-	    {
-		xtype: 'pveMemoryField',
-		name: 'balloon',
-		minValue: 1,
-		step: 32,
-		fieldLabel: gettext('Minimum memory') + ' (MiB)',
-		hotplug: me.hotplug,
-		labelWidth: labelWidth,
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			var memory = me.down('field[name=memory]').getValue();
-			var shares = me.down('field[name=shares]');
-			shares.setDisabled(value === memory);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'shares',
-		disabled: true,
-		minValue: 0,
-		maxValue: 50000,
-		value: '',
-		step: 10,
-		fieldLabel: gettext('Shares'),
-		labelWidth: labelWidth,
-		allowBlank: true,
-		emptyText: Proxmox.Utils.defaultText + ' (1000)',
-		submitEmptyText: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		labelWidth: labelWidth,
-		value: '1',
-		name: 'ballooning',
-		fieldLabel: gettext('Ballooning Device'),
-		listeners: {
-		    change: function(f, value) {
-			var bf = me.down('field[name=balloon]');
-			var shares = me.down('field[name=shares]');
-			var memory = me.down('field[name=memory]');
-			bf.setDisabled(!value);
-			shares.setDisabled(!value || (bf.getValue() === memory.getValue()));
-		    }
-		}
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = me.items;
-	    me.items = undefined;
-	    me.advancedColumn1 = me.advancedItems;
-	    me.advancedItems = undefined;
-	}
-	me.callParent();
-    }
-
-});
-
-Ext.define('PVE.qemu.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent: function() {
-	var me = this;
-
-	var memoryhotplug;
-	if(me.hotplug) {
-	    Ext.each(me.hotplug.split(','), function(el) {
-		if (el === 'memory') {
-		    memoryhotplug = 1;
-	        }
-	    });
-	}
-
-	var ipanel = Ext.create('PVE.qemu.MemoryInputPanel', {
-	    hotplug: memoryhotplug
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: [ ipanel ],
-	    // uncomment the following to use the async configiguration API
-	    // backgroundDelay: 5, 
-	    width: 400
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-
-		var values = {
-		    ballooning: data.balloon === 0 ? '0' : '1',
-		    shares: data.shares,
-		    memory: data.memory || '512',
-		    balloon: data.balloon > 0 ? data.balloon : (data.memory || '512')
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuNetworkInputPanel',
-    onlineHelp: 'qm_network_device',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	me.network.model = values.model;
-	if (values.nonetwork) {
-	    return {};
-	} else {
-	    me.network.bridge = values.bridge;
-	    me.network.tag = values.tag;
-	    me.network.firewall = values.firewall;
-	}
-	me.network.macaddr = values.macaddr;
-	me.network.disconnect = values.disconnect;
-	me.network.queues = values.queues;
-
-	if (values.rate) {
-	    me.network.rate = values.rate;
-	} else {
-	    delete me.network.rate;
-	}
-
-	var params = {};
-
-	params[me.confid] = PVE.Parser.printQemuNetwork(me.network);
-
-	return params;
-    },
-
-    setNetwork: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data) {
-	    data.networkmode = data.bridge ? 'bridge' : 'nat';
-	} else {
-	    data = {};
-	    data.networkmode = 'bridge';
-	}
-	me.network = data;
-	
-	me.setValues(me.network);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.bridgesel.setNodename(nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.network = {};
-	me.confid = 'net0';
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.bridgesel = Ext.create('PVE.form.BridgeSelector', {
-	    name: 'bridge',
-	    fieldLabel: gettext('Bridge'),
-	    nodename: me.nodename,
-	    autoSelect: true,
-	    allowBlank: false
-	});
-
-	me.column1 = [
-	    me.bridgesel,
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		checked: (me.insideWizard || me.isCreate)
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Disconnect'),
-		name: 'disconnect'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1.unshift({
-		xtype: 'checkbox',
-		name: 'nonetwork',
-		inputValue: 'none',
-		boxLabel: gettext('No network device'),
-		listeners: {
-		    change: function(cb, value) {
-			var fields = [
-			    'disconnect',
-			    'bridge',
-			    'tag',
-			    'firewall',
-			    'model',
-			    'macaddr',
-			    'rate',
-			    'queues'
-			];
-			fields.forEach(function(fieldname) {
-			    me.down('field[name='+fieldname+']').setDisabled(value);
-			});
-			me.down('field[name=bridge]').validate();
-		    }
-		}
-	    });
-	    me.column2.unshift({
-		xtype: 'displayfield'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'pveNetworkCardSelector',
-		name: 'model',
-		fieldLabel: gettext('Model'),
-		value: PVE.qemu.OSDefaults.generic.networkCard,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'macaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		allowBlank: true,
-		emptyText: 'auto'
-	    });
-	me.advancedColumn2 = [
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: '',
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'queues',
-		fieldLabel: 'Multiqueue',
-		minValue: 1,
-		maxValue: 8,
-		value: '',
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";	    
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.NetworkInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: me.isCreate
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Device'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		if (!me.isCreate) {
-		    var value = me.vmconfig[me.confid];
-		    var network = PVE.Parser.parseQemuNetwork(me.confid, value);
-		    if (!network) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse network options');
-			me.close();
-			return;
-		    }
-		    ipanel.setNetwork(me.confid, network);
-		} else {
-		    for (i = 0; i < 100; i++) {
-			confid = 'net' + i.toString();
-			if (!Ext.isDefined(me.vmconfig[confid])) {
-			    me.confid = confid;
-			    break;
-			}
-		    }
-		    ipanel.setNetwork(me.confid);		    
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Smbios1InputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.PVE.qemu.Smbios1InputPanel',
-
-    insideWizard: false,
-
-    smbios1: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {
-	    smbios1: PVE.Parser.printQemuSmbios1(values)
-	};
-
-	return params;
-    },
-
-    setSmbios1: function(data) {
-	var me = this;
-
-	me.smbios1 = data;
-	
-	me.setValues(me.smbios1);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: 'UUID',
-		regex: /^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$/,
-		name: 'uuid'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Manufacturer'),
-		regex: /^\S+$/,
-		name: 'manufacturer'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Product'),
-		regex: /^\S+$/,
-		name: 'product'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Version'),
-		regex: /^\S+$/,
-		name: 'version'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Serial'),
-		regex: /^\S+$/,
-		name: 'serial'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: 'SKU',
-		regex: /^\S+$/,
-		name: 'sku'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Family'),
-		regex: /^\S+$/,
-		name: 'family'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.Smbios1Edit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.Smbios1InputPanel', {});
-
-	Ext.applyIf(me, {
-	    subject: gettext('SMBIOS settings (type1)'),
-	    width: 450,
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		var value = me.vmconfig.smbios1;
-		if (value) {
-		    var data = PVE.Parser.parseQemuSmbios1(value);
-		    if (!data) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse smbios options');
-			me.close();
-			return;
-		    }
-		    ipanel.setSmbios1(data);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.CDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuCDInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || (values.controller + values.deviceid);
-	
-	me.drive.media = 'cdrom';
-	if (values.mediaType === 'iso') {
-	    me.drive.file = values.cdimage;
-	} else if (values.mediaType === 'cdrom') {
-	    me.drive.file = 'cdrom';
-	} else {
-	    me.drive.file = 'none';
-	}
-
-	var params = {};
-		
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	
-	return params;	
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig, 'cdrom');
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	var values = {};
-	if (drive.file === 'cdrom') {
-	    values.mediaType = 'cdrom';
-	} else if (drive.file === 'none') {
-	    values.mediaType = 'none';
-	} else {
-	    values.mediaType = 'iso';
-	    var match = drive.file.match(/^([^:]+):/);
-	    if (match) {
-		values.cdstorage = match[1];
-		values.cdimage = drive.file;
-	    }
-	}
-
-	me.drive = drive;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.cdstoragesel.setNodename(nodename);
-	me.cdfilesel.setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	var items = [];
-
-	if (!me.confid) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		noVirtIO: true
-	    });
-	    items.push(me.bussel);
-	}
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'iso',
-	    boxLabel: gettext('Use CD/DVD disc image file (iso)'),
-	    checked: true,
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=cdstorage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').validate();
-		}
-	    }
-	});
-
-	me.cdfilesel = Ext.create('PVE.form.FileSelector', {
-	    name: 'cdimage',
-	    nodename: me.nodename,
-	    storageContent: 'iso',
-	    fieldLabel: gettext('ISO image'),
-	    labelAlign: 'right',
-	    allowBlank: false
-	});
-	
-	me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
-	    name: 'cdstorage',
-	    nodename: me.nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'iso',
-	    allowBlank: false,
-	    autoSelect: me.insideWizard,
-	    listeners: {
-		change: function(f, value) {
-		    me.cdfilesel.setStorage(value);
-		}
-	    }
-	});
-
-	items.push(me.cdstoragesel);
-	items.push(me.cdfilesel);
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'cdrom',
-	    boxLabel: gettext('Use physical CD/DVD Drive')
-	});
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'none',
-	    boxLabel: gettext('Do not use any media')
-	});
-
-	me.items = items;
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.CDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'CD/DVD Drive',
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-	
-	me.load({
-	    success:  function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert('Error', 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-/* 'change' property is assigned a string and then a function */
-Ext.define('PVE.qemu.HDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuHDInputPanel',
-    onlineHelp: 'qm_hard_disk',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onControllerChange: function(field) {
-	    var value = field.getValue();
-
-	    var allowIOthread = value.match(/^(virtio|scsi)/);
-	    this.lookup('iothread').setDisabled(!allowIOthread);
-	    if (!allowIOthread) {
-		this.lookup('iothread').setValue(false);
-	    }
-
-	    var virtio = value.match(/^virtio/);
-	    this.lookup('discard').setDisabled(virtio);
-	    this.lookup('ssd').setDisabled(virtio);
-	    if (virtio) {
-		this.lookup('discard').setValue(false);
-		this.lookup('ssd').setValue(false);
-	    }
-
-	    this.lookup('scsiController').setVisible(value.match(/^scsi/));
-	},
-
-	control: {
-	    'field[name=controller]': {
-		change: 'onControllerChange',
-		afterrender: 'onControllerChange'
-	    },
-	    'field[name=iothread]' : {
-		change: function(f, value) {
-		    if (!this.getView().insideWizard) {
-			return;
-		    }
-		    var vmScsiType = value ? 'virtio-scsi-single': 'virtio-scsi-pci';
-		    this.lookupReference('scsiController').setValue(vmScsiType);
-		}
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {};
-	var confid = me.confid || (values.controller + values.deviceid);
-
-	if (me.unused) {
-	    me.drive.file = me.vmconfig[values.unusedId];
-	    confid = values.controller + values.deviceid;
-	} else if (me.isCreate) {
-	    if (values.hdimage) {
-		me.drive.file = values.hdimage;
-	    } else {
-		me.drive.file = values.hdstorage + ":" + values.disksize;
-	    }
-	    me.drive.format = values.diskformat;
-	}
-
-	if (values.nobackup) {
-	    me.drive.backup = 'no';
-	} else {
-	    delete me.drive.backup;
-	}
-
-	if (values.noreplicate) {
-	    me.drive.replicate = 'no';
-	} else {
-	    delete me.drive.replicate;
-	}
-
-	if (values.discard) {
-	    me.drive.discard = 'on';
-	} else {
-	    delete me.drive.discard;
-	}
-
-	if (values.ssd) {
-	    me.drive.ssd = 'on';
-	} else {
-	    delete me.drive.ssd;
-	}
-
-	if (values.iothread) {
-	    me.drive.iothread = 'on';
-	} else {
-	    delete me.drive.iothread;
-	}
-
-	if (values.cache) {
-	    me.drive.cache = values.cache;
-	} else {
-	    delete me.drive.cache;
-	}
-
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            if (values[name]) {
-                me.drive[name] = values[name];
-            } else {
-                delete me.drive[name];
-            }
-            var burst_name = name + '_max';
-            if (values[burst_name] && values[name]) {
-                me.drive[burst_name] = values[burst_name];
-            } else {
-                delete me.drive[burst_name];
-            }
-        });
-
-
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
-	return params;
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	me.vmconfig = vmconfig;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig);
-	    me.scsiController.setValue(vmconfig.scsihw);
-	}
-	if (me.unusedDisks) {
-	    var disklist = [];
-	    Ext.Object.each(vmconfig, function(key, value) {
-		if (key.match(/^unused\d+$/)) {
-		    disklist.push([key, value]);
-		}
-	    });
-	    me.unusedDisks.store.loadData(disklist);
-	    me.unusedDisks.setValue(me.confid);
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	me.drive = drive;
-
-	var values = {};
-	var match = drive.file.match(/^([^:]+):/);
-	if (match) {
-	    values.hdstorage = match[1];
-	}
-
-	values.hdimage = drive.file;
-	values.nobackup = !PVE.Parser.parseBoolean(drive.backup, 1);
-	values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
-	values.diskformat = drive.format || 'raw';
-	values.cache = drive.cache || '__default__';
-	values.discard = (drive.discard === 'on');
-	values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-	values.iothread = PVE.Parser.parseBoolean(drive.iothread);
-
-	values.mbps_rd = drive.mbps_rd;
-	values.mbps_wr = drive.mbps_wr;
-	values.iops_rd = drive.iops_rd;
-	values.iops_wr = drive.iops_wr;
-	values.mbps_rd_max = drive.mbps_rd_max;
-	values.mbps_wr_max = drive.mbps_wr_max;
-	values.iops_rd_max = drive.iops_rd_max;
-	values.iops_wr_max = drive.iops_wr_max;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var labelWidth = 140;
-
-	me.drive = {};
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.advancedColumn1 = [];
-	me.advancedColumn2 = [];
-
-	if (!me.confid || me.unused) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
-	    });
-	    me.column1.push(me.bussel);
-
-	    me.scsiController = Ext.create('Ext.form.field.Display', {
-		fieldLabel: gettext('SCSI Controller'),
-		reference: 'scsiController',
-		bind: me.insideWizard ? {
-		    value: '{current.scsihw}'
-		} : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		submitValue: false,
-		hidden: true
-	    });
-	    me.column1.push(me.scsiController);
-	}
-
-	if (me.unused) {
-	    me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
-		name: 'unusedId',
-		fieldLabel: gettext('Disk image'),
-		matchFieldWidth: false,
-		listConfig: {
-		    width: 350
-		},
-		data: [],
-		allowBlank: false
-	    });
-	    me.column1.push(me.unusedDisks);
-	} else if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveDiskStorageSelector',
-		storageContent: 'images',
-		name: 'disk',
-		nodename: me.nodename,
-		autoSelect: me.insideWizard
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'textfield',
-		disabled: true,
-		submitValue: false,
-		fieldLabel: gettext('Disk image'),
-                name: 'hdimage'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'CacheTypeSelector',
-		name: 'cache',
-		value: '__default__',
-		fieldLabel: gettext('Cache')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Discard'),
-		disabled: me.confid && me.confid.match(/^virtio/),
-		reference: 'discard',
-		name: 'discard'
-	    }
-	);
-
-	me.advancedColumn1.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && me.confid.match(/^virtio/),
-		fieldLabel: gettext('SSD emulation'),
-		labelWidth: labelWidth,
-		name: 'ssd',
-		reference: 'ssd'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && !me.confid.match(/^(virtio|scsi)/),
-		fieldLabel: 'IO thread',
-		labelWidth: labelWidth,
-		reference: 'iothread',
-		name: 'iothread'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    }
-	);
-
-	me.advancedColumn2.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('No backup'),
-		labelWidth: labelWidth,
-		name: 'nobackup'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Skip replication'),
-		labelWidth: labelWidth,
-		name: 'noreplicate'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-/*jslint confusion: false */
-
-Ext.define('PVE.qemu.HDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    backgroundDelay: 5,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    me.subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
-	} else {
-           me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
-	}
-
-	me.items = [ ipanel ];
-
-	me.callParent();
-	/*jslint confusion: true*/
-	/* 'data' is assigned an empty array in same file, and here we
-	 * use it like an object
-	 */
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-	/*jslint confusion: false*/
-    }
-});
-Ext.define('PVE.window.HDResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 140,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 250,
-	    height: 150,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-Ext.define('PVE.window.HDMove', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-
-    move_disk: function(disk, storage, format, delete_disk) {
-	var me = this;
-	var qemu = (me.type === 'qemu');
-	var params = {};
-	params.storage = storage;
-	params[qemu ? 'disk':'volume'] = disk;
-
-	if (format && qemu) {
-	    params.format = format;
-	}
-
-	if (delete_disk) {
-	    params['delete'] = 1;
-	}
-
-	var url = '/nodes/' + me.nodename + '/' + me.type + '/' + me.vmid + '/';
-	url += qemu ? 'move_disk' : 'move_volume';
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: url,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		win.on('destroy', function() { me.close(); });
-	    }
-	});
-
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var diskarray = [];
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    me.type = 'qemu';
-	}
-
-	var qemu = (me.type === 'qemu');
-
-        var items = [
-            {
-                xtype: 'displayfield',
-                name: qemu ? 'disk' : 'volume',
-                value: me.disk,
-                fieldLabel: qemu ? gettext('Disk') : gettext('Mount Point'),
-                vtype: 'StorageId',
-                allowBlank: false
-            }
-        ];
-
-	items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    storageLabel: gettext('Target Storage'),
-	    nodename: me.nodename,
-	    storageContent: qemu ? 'images' : 'rootdir',
-	    hideSize: true
-	});
-
-	items.push({
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Delete source'),
-	    name: 'deleteDisk',
-	    uncheckedValue: 0,
-	    checked: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = qemu ? gettext("Move disk") : gettext('Move Volume');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: me.title,
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.move_disk(me.disk, values.hdstorage, values.diskformat,
-				 values.deleteDisk);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 350,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	me.mon(me.formPanel, 'validitychange', function(fp, isValid) {
-	    submitBtn.setDisabled(!isValid);
-	});
-
-	me.formPanel.isValid();
-    }
-});
-Ext.define('PVE.qemu.EFIDiskInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveEFIDiskInputPanel',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = 'efidisk0';
-
-	if (values.hdimage) {
-	    me.drive.file = values.hdimage;
-	} else {
-	    // we use 1 here, because for efi the size gets overridden from the backend
-	    me.drive.file = values.hdstorage + ":1";
-	}
-
-	me.drive.format = values.diskformat;
-	var params = {};
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items= [];
-
-	me.items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    nodename: me.nodename,
-	    hideSize: true
-	});
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.EFIDiskEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-    subject: gettext('EFI Disk'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveEFIDiskInputPanel',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: true
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.DisplayInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveDisplayInputPanel',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values, 'type');
-	if (ret === '') {
-	    return {
-		'delete': 'vga'
-	    };
-	}
-	return {
-	    vga: ret
-	};
-    },
-
-    items: [{
-	name: 'type',
-	xtype: 'proxmoxKVComboBox',
-	value: '__default__',
-	deleteEmpty: false,
-	fieldLabel: gettext('Graphic card'),
-	comboItems: PVE.Utils.kvm_vga_driver_array(),
-	validator: function() {
-	    var v = this.getValue();
-	    var cfg = this.up('proxmoxWindowEdit').vmconfig || {};
-
-	    if (v.match(/^serial\d+$/) && (!cfg[v] || cfg[v] !== 'socket')) {
-		var fmt = gettext("Serial interface '{0}' is not correctly configured.");
-		return Ext.String.format(fmt, v);
-	    }
-	    return true;
-	},
-	listeners: {
-	    change: function(cb, val) {
-		var me = this.up('panel');
-		if (!val) {
-		    return;
-		}
-		var disable = false;
-		var emptyText = Proxmox.Utils.defaultText;
-		switch (val) {
-		    case "cirrus":
-			emptyText = "4";
-			break;
-		    case "std":
-			emptyText = "16";
-			break;
-		    case "qxl":
-		    case "qxl2":
-		    case "qxl3":
-		    case "qxl4":
-			emptyText = "16";
-			break;
-		    case "vmware":
-			emptyText = "16";
-			break;
-		    case "none":
-		    case "serial0":
-		    case "serial1":
-		    case "serial2":
-		    case "serial3":
-			emptyText = 'N/A';
-			disable = true;
-			break;
-		    case "virtio":
-			emptyText = "256";
-			break;
-		    default:
-			break;
-		}
-		var memoryfield = me.down('field[name=memory]');
-		memoryfield.setEmptyText(emptyText);
-		memoryfield.setDisabled(disable);
-	    }
-	}
-    },{
-	xtype: 'proxmoxintegerfield',
-	emptyText: Proxmox.Utils.defaultText,
-	fieldLabel: gettext('Memory') + ' (MiB)',
-	minValue: 4,
-	maxValue: 512,
-	step: 4,
-	name: 'memory'
-    }]
-});
-
-Ext.define('PVE.qemu.DisplayEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Display'),
-    width: 350,
-
-    items: [{
-	xtype: 'pveDisplayInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-		var vga = me.vmconfig.vga || '__default__';
-		me.setValues(PVE.Parser.parsePropertyString(vga, 'type'));
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.KeyboardEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('Keyboard Layout'),
-	    items: {
-		xtype: 'VNCKeyboardSelector',
-		name: 'keyboard',
-		value: '__default__',
-		fieldLabel: gettext('Keyboard Layout')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.HardwareView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.HardwareView'],
-
-    onlineHelp: 'qm_virtual_machines_settings',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-	var iconCls = rowdef.iconCls;
-	var icon = '';
-	var txt = (rowdef.header || key);
-
-	metaData.tdAttr = "valign=middle";
-
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') { 
-		var value = me.getObjectValue(key, '', false);
-		if (value === '') {
-		    value = me.getObjectValue(key, '', true);
-		}
-		if (value.match(/vm-.*-cloudinit/)) {
-		    metaData.tdCls = 'pve-itype-icon-cloud';
-		    return rowdef.cloudheader;
-		} else if (value.match(/media=cdrom/)) {
-		    metaData.tdCls = 'pve-itype-icon-cdrom';
-		    return rowdef.cdheader;
-		}
-	    }
-	} else if (iconCls) {
-	    icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
-	    metaData.tdCls += " pve-itype-fa";
-	}
-	return icon + txt;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	/*jslint confusion: true */
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
-		never_delete: true,
-		defaultValue: '512',
-		tdCls: 'pve-itype-icon-memory',
-		group: 2,
-		multiKey: ['memory', 'balloon', 'shares'],
-		renderer: function(value, metaData, record, ri, ci, store, pending) {
-		    var res = '';
-
-		    var max = me.getObjectValue('memory', 512, pending);
-		    var balloon =  me.getObjectValue('balloon', undefined, pending);
-		    var shares = me.getObjectValue('shares', undefined, pending);
-
-		    res  = Proxmox.Utils.format_size(max*1024*1024);
-
-		    if (balloon !== undefined && balloon > 0) {
-			res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
-
-			if (shares) {
-			    res += ' [shares=' + shares +']';
-			}
-		    } else if (balloon === 0) {
-			res += ' [balloon=0]';
-		    }
-		    return res;
-		}
-	    },
-	    sockets: {
-		header: gettext('Processors'),
-		never_delete: true,
-		editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? 
-		    'PVE.qemu.ProcessorEdit' : undefined,
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		defaultValue: '1',
-		multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
-		renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
-
-		    var sockets = me.getObjectValue('sockets', 1, pending);
-		    var model = me.getObjectValue('cpu', undefined, pending);
-		    var cores = me.getObjectValue('cores', 1, pending);
-		    var numa = me.getObjectValue('numa', undefined, pending);
-		    var vcpus = me.getObjectValue('vcpus', undefined, pending);
-		    var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
-		    var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
-
-		    var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
-			sockets*cores, sockets, cores);
-
-		    if (model) {
-			res += ' [' + model + ']';
-		    }
-
-		    if (numa) {
-			res += ' [numa=' + numa +']';
-		    }
-
-		    if (vcpus) {
-			res += ' [vcpus=' + vcpus +']';
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit +']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits +']';
-		    }
-
-		    return res;
-		}
-	    },
-	    bios: {
-		header: 'BIOS',
-		group: 4,
-		never_delete: true,
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.BiosEdit' : undefined,
-		defaultValue: '',
-		iconCls: 'microchip',
-		renderer: PVE.Utils.render_qemu_bios
-	    },
-	    vga: {
-		header: gettext('Display'),
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
-		never_delete: true,
-		tdCls: 'pve-itype-icon-display',
-		group:5,
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_vga_driver		
-	    },
-	    machine: {
-		header: gettext('Machine'),
-		editor: caps.vms['VM.Config.HWType'] ?  {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Machine'),
-		    width: 350,
-		    items: [{
-			xtype: 'proxmoxKVComboBox',
-			name: 'machine',
-			value: '__default__',
-			fieldLabel: gettext('Machine'),
-			comboItems: [
-			    ['__default__', PVE.Utils.render_qemu_machine('')],
-			    ['q35', 'q35']
-			]
-		    }]} : undefined,
-		iconCls: 'cogs',
-		never_delete: true,
-		group: 6,
-		defaultValue: '',
-		renderer: PVE.Utils.render_qemu_machine
-	    },
-	    scsihw: {
-		header: gettext('SCSI Controller'),
-		iconCls: 'database',
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.ScsiHwEdit' : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		group: 7,
-		never_delete: true,
-		defaultValue: ''
-	    },
-	    cores: {
-		visible: false
-	    },
-	    cpu: {
-		visible: false
-	    },
-	    numa: {
-		visible: false
-	    },
-	    balloon: {
-		visible: false
-	    },
-	    hotplug: {
-		visible: false
-	    },
-	    vcpus: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    shares: {
-		visible: false
-	    }
-	};
-	/*jslint confusion: false */
-
-	PVE.Utils.forEachBus(undefined, function(type, id) {
-	    var confid = type + id;
-	    rows[confid] = {
-		group: 10,
-		tdCls: 'pve-itype-icon-storage',
-		editor: 'PVE.qemu.HDEdit',
-		never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-		header: gettext('Hard Disk') + ' (' + confid +')',
-		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
-		cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
-	    };
-	});
-	for (i = 0; i < 32; i++) {
-	    confid = "net" + i.toString();
-	    rows[confid] = {
-		group: 15,
-		order: i,
-		tdCls: 'pve-itype-icon-network',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
-		never_delete: caps.vms['VM.Config.Network'] ? false : true,
-		header: gettext('Network Device') + ' (' + confid +')'
-	    };
-	}
-	rows.efidisk0 = {
-	    group: 20,
-	    tdCls: 'pve-itype-icon-storage',
-	    editor: null,
-	    never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-	    header: gettext('EFI Disk')
-	};
-	for (i = 0; i < 5; i++) {
-	    confid = "usb" + i.toString();
-	    rows[confid] = {
-		group: 25,
-		order: i,
-		tdCls: 'pve-itype-icon-usb',
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('USB Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "hostpci" + i.toString();
-	    rows[confid] = {
-		group: 30,
-		order: i,
-		tdCls: 'pve-itype-icon-pci',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
-		header: gettext('PCI Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "serial" + i.toString();
-	    rows[confid] = {
-		group: 35,
-		order: i,
-		tdCls: 'pve-itype-icon-serial',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('Serial Port') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 256; i++) {
-	    rows["unused" + i.toString()] = {
-		group: 99,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
-		header: gettext('Unused Disk') + ' ' + i.toString()
-	    };
-	}
-
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-	    
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var editor = rowdef.editor;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') {
-		if (!diskCap) {
-		    return;
-		}
-		var value = me.getObjectValue(rec.data.key, '', true); 
-		if (value.match(/vm-.*-cloudinit/)) {
-		    return;
-		} else if (value.match(/media=cdrom/)) {
-		    editor = 'PVE.qemu.CDEdit';
-		}
-	    }
-
-	    var win;
-
-	    if (Ext.isString(editor)) {
-		win = Ext.create(editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var run_resize = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var run_move = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_editor
-        });
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_move
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    defaultText: gettext('Remove'),
-	    altText: gettext('Detach'),
-	    selModel: sm,
-	    disabled: true,
-	    dangerous: true,
-	    RESTMethod: 'PUT',
-	    confirmMsg: function(rec) {
-		var warn = gettext('Are you sure you want to remove entry {0}');
-		if (this.text === this.altText) {
-		    warn = gettext('Are you sure you want to detach entry {0}');
-		}
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		if (entry.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: function(b, e, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: b.RESTMethod,
-		    params: {
-			'delete': rec.data.key
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			if (b.RESTMethod === 'POST') {
-			    var upid = response.result.data;
-			    var win = Ext.create('Proxmox.window.TaskProgress', {
-				upid: upid,
-				listeners: {
-				    destroy: function () {
-					me.reload();
-				    }
-				}
-			    });
-			    win.show();
-			}
-		    }
-		});
-	    },
-	    listeners: {
-		render: function(btn) {
-		    // hack: calculate an optimal button width on first display
-		    // to prevent the whole toolbar to move when we switch
-		    // between the "Remove" and "Detach" labels
-		    var def = btn.getSize().width;
-
-		    btn.setText(btn.altText);
-		    var alt = btn.getSize().width;
-
-		    btn.setText(btn.defaultText);
-
-		    var optimal = alt > def ? alt : def;
-		    btn.setSize({ width: optimal });
-		}
-	    }
-	});
-
-	var revert_btn = new Proxmox.button.Button({
-	    text: gettext('Revert'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(b, e, rec) {
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: {
-			'revert': revert
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var efidisk_menuitem = Ext.create('Ext.menu.Item',{
-	    text: gettext('EFI Disk'),
-	    iconCls: 'pve-itype-icon-storage',
-	    disabled: !caps.vms['VM.Config.Disk'],
-	    handler: function() {
-
-		var rstoredata = me.rstore.getData().map;
-		// check if ovmf is configured
-		if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') {
-		    var win = Ext.create('PVE.qemu.EFIDiskEdit', {
-			url: '/api2/extjs/' + baseurl,
-			pveSelNode: me.pveSelNode
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		} else {
-		    Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
-		}
-
-	    }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    // disable button when we have an efidisk already
-	    // disable is ok in this case, because you can instantly
-	    // see that there is already one
-	    efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined);
-	    // en/disable usb add button
-	    var usbcount = 0;
-	    var pcicount = 0;
-	    var hasCloudInit = false;
-	    me.rstore.getData().items.forEach(function(item){
-		if (/^usb\d+/.test(item.id)) {
-		    usbcount++;
-		} else if (/^hostpci\d+/.test(item.id)) {
-		    pcicount++;
-		}
-		if (!hasCloudInit && /vm-.*-cloudinit/.test(item.data.value)) {
-		    hasCloudInit = true;
-		}
-	    });
-
-	    // heuristic only for disabling some stuff, the backend has the final word.
-	    var noSysConsolePerm = !caps.nodes['Sys.Console'];
-
-	    me.down('#addusb').setDisabled(noSysConsolePerm || (usbcount >= 5));
-	    me.down('#addpci').setDisabled(noSysConsolePerm || (pcicount >= 4));
-	    me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
-
-	    if (!rec) {
-		remove_btn.disable();
-		edit_btn.disable();
-		resize_btn.disable();
-		move_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isUnusedDisk = key.match(/^unused\d+/);
-	    var isUsedDisk = !isUnusedDisk &&
-		rowdef.tdCls == 'pve-itype-icon-storage' &&
-		(value && !value.match(/media=cdrom/));
-
-	    var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
-
-	    var isEfi = (key === 'efidisk0');
-
-	    remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true) || (isUnusedDisk && !diskCap));
-	    remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
-	    remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
-
-	    edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit || !diskCap);
-
-	    resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    move_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    revert_btn.setDisabled(!pending);
-
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
-	    interval: 5000,
-	    selModel: sm,
-	    run_editor: run_editor,
-	    tbar: [ 
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Hard Disk'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.HDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CD/DVD Drive'),
-				iconCls: 'pve-itype-icon-cdrom',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Network Device'),
-				iconCls: 'pve-itype-icon-network',
-				disabled: !caps.vms['VM.Config.Network'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.NetworkEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode,
-					isCreate: true
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    efidisk_menuitem,
-			    {
-				text: gettext('USB Device'),
-				itemId: 'addusb',
-				iconCls: 'pve-itype-icon-usb',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.USBEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('PCI Device'),
-				itemId: 'addpci',
-				iconCls: 'pve-itype-icon-pci',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.PCIEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Serial Port'),
-				itemId: 'addserial',
-				iconCls: 'pve-itype-icon-serial',
-				disabled: !caps.vms['VM.Config.Options'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.SerialEdit', {
-					url: '/api2/extjs/' + baseurl
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CloudInit Drive'),
-				itemId: 'addci',
-				iconCls: 'pve-itype-icon-cloud',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CIDriveEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn,
-		edit_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-	me.mon(me.rstore, 'refresh', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.qemu.ScsiHwEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('SCSI Controller Type'),
-	    items: {
-		xtype: 'pveScsiHwSelector',
-		name: 'scsihw',
-		value: '__default__',
-		fieldLabel: gettext('Type')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.BiosEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveQemuBiosEdit',
-
-    initComponent : function() {
-	var me = this;
-
-	var EFIHint = Ext.createWidget({
-	    xtype: 'displayfield', //submitValue is false, so we don't get submitted
-	    userCls: 'pve-hint',
-	    value: 'You need to add an EFI disk for storing the ' +
-	    'EFI settings. See the online help for details.',
-	    hidden: true
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'BIOS',
-	    items: [ {
-		xtype: 'pveQemuBiosSelector',
-		onlineHelp: 'qm_bios_and_uefi',
-		name: 'bios',
-		value: '__default__',
-		fieldLabel: 'BIOS',
-		listeners: {
-		    'change' : function(field, newValue) {
-			if (newValue == 'ovmf') {
-			    Proxmox.Utils.API2Request({
-				url : me.url,
-				method : 'GET',
-				failure : function(response, opts) {
-				    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				},
-				success : function(response, opts) {
-				    var vmConfig = response.result.data;
-				    // there can be only one
-				    if (!vmConfig.efidisk0) {
-					EFIHint.setVisible(true);
-				    }
-				}
-			    });
-			} else {
-			    if (EFIHint.isVisible()) {
-				EFIHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    EFIHint
-	    ] });
-
-	me.callParent();
-
-	me.load();
-
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.Options'],
-
-    onlineHelp: 'qm_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    name: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Name'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Name'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    xtype: 'textfield',
-			    name: 'name',
-			    vtype: 'DnsName',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: true
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.name === undefined ||
-				values.name === null ||
-				values.name === '') {
-				params = { 'delete':'name'};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ?
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'qm_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.OSTypeEdit' : undefined,
-		renderer: PVE.Utils.render_kvm_ostype,
-		defaultValue: 'other'
-	    },
-	    bootdisk: {
-		visible: false
-	    },
-	    boot: {
-		header: gettext('Boot Order'),
-		defaultValue: 'cdn',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.BootOrderEdit' : undefined,
-		multiKey: ['boot', 'bootdisk'],
-		renderer: function(order, metaData, record, rowIndex, colIndex, store, pending) {
-		    var i;
-		    var text = '';
-		    var bootdisk = me.getObjectValue('bootdisk', undefined, pending);
-		    order = order || 'cdn';
-		    for (i = 0; i < order.length; i++) {
-			var sel = order.substring(i, i + 1);
-			if (text) {
-			    text += ', ';
-			}
-			if (sel === 'c') {
-			    if (bootdisk) {
-				text += "Disk '" + bootdisk + "'";
-			    } else {
-				text += "Disk";
-			    }
-			} else if (sel === 'n') {
-			    text += 'Network';
-			} else if (sel === 'a') {
-			    text += 'Floppy';
-			} else if (sel === 'd') {
-			    text += 'CD-ROM';
-			} else {
-			    text += sel;
-			}
-		    }
-		    return text;
-		}
-	    },
-	    tablet: {
-		header: gettext('Use tablet for pointer'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use tablet for pointer'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'tablet',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hotplug: {
-		header: gettext('Hotplug'),
-		defaultValue: 'disk,network,usb',
-		renderer:  PVE.Utils.render_hotplug_features,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hotplug'),
-		    items: {
-			xtype: 'pveHotplugFeatureSelector',
-			name: 'hotplug',
-			value: '',
-			multiSelect: true,
-			fieldLabel: gettext('Hotplug'),
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    acpi: {
-		header: gettext('ACPI support'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('ACPI support'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'acpi',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    kvm: {
-		header: gettext('KVM hardware virtualization'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('KVM hardware virtualization'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'kvm',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    freeze: {
-		header: gettext('Freeze CPU at startup'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.PowerMgmt'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Freeze CPU at startup'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'freeze',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Freeze CPU at startup')
-		    }
-		} : undefined
-	    },
-	    localtime: {
-		header: gettext('Use local time for RTC'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use local time for RTC'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'localtime',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Use local time for RTC')
-		    }
-		} : undefined
-	    },
-	    startdate: {
-		header: gettext('RTC start date'),
-		defaultValue: 'now',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('RTC start date'),
-		    items: {
-			xtype: 'proxmoxtextfield',
-			name: 'startdate',
-			deleteEmpty: true,
-			value: 'now',
-			fieldLabel: gettext('RTC start date'),
-			vtype: 'QemuStartDate',
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    smbios1: {
-		header: gettext('SMBIOS settings (type1)'),
-		defaultValue: '',
-		renderer: Ext.String.htmlEncode,
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.Smbios1Edit' : undefined
-	    },
-	    agent: {
-		header: gettext('Qemu Agent'),
-		defaultValue: false,
-		renderer: PVE.Utils.render_qga_features,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Qemu Agent'),
-		    items: {
-			xtype: 'pveAgentFeatureSelector',
-			name: 'agent'
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-        var revert_btn = new Proxmox.button.Button({
-            text: gettext('Revert'),
-            disabled: true,
-            handler: function() {
-		var sm = me.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-
-                Proxmox.Utils.API2Request({
-                    url: '/api2/extjs/' + baseurl,
-                    waitMsgTarget: me,
-                    method: 'PUT',
-                    params: {
-                        'revert': revert
-                    },
-                    callback: function() {
-                        me.reload();
-                    },
-                    failure: function (response, opts) {
-                        Ext.Msg.alert('Error',response.htmlStatus);
-                    }
-                });
-            }
-        });
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/pending",
-	    interval: 5000,
-	    cwidth1: 250,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.rstore.on('datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-
-Ext.define('PVE.window.Snapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname, vmstate: vmstate ? 1 : 0 };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	} else {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'vmstate',
-		uncheckedValue: 0,
-		defaultValue: 0,
-		checked: 1,
-		fieldLabel: gettext('Include RAM')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description, values.vmstate);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}	 
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveQemuSnapshotTree'],
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-qemu-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-        var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-        Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-            method: 'GET',
-            success: function(response, options) {
-                var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-            }
-        });
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) { 
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		return Proxmox.Utils.format_task_description('qmrollback', me.vmid) +
-		    " '" +  rec.data.name + "'";
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', { 
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [ 
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-		{
-		    text: gettext('RAM'),
-		    align: 'center',
-		    resizable: false,
-		    dataIndex: 'vmstate',
-		    width: 50,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name !== 'current') {
-			    return Proxmox.Utils.format_boolean(value);
-			}
-		    }
-		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{ 
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true, // will work in 4.1?
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-
-Ext.define('PVE.qemu.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.qemu.Config',
-
-    onlineHelp: 'chapter_virtual_machines',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + "/qemu/" + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + '/status/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var resumeBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resume'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    hidden: true,
-	    handler: function() {
-		vm_command('resume');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'qemu',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    itemId: 'removeBtn',
-		    disabled: !caps.vms['VM.Allocate'],
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'VM', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items: [{
-		    text: gettext('Pause'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid),
-		    handler: function() {
-			vm_command("suspend");
-		    },
-		    iconCls: 'fa fa-pause'
-		},{
-		    text: gettext('Hibernate'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid),
-		    tooltip: gettext('Suspend to disk'),
-		    handler: function() {
-			vm_command("suspend", { todisk: 1 });
-		    },
-		    iconCls: 'fa fa-download'
-		},{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    dangerous: true,
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid),
-		    handler: function() {
-			vm_command("stop", { timeout: 30 });
-		    },
-		    iconCls: 'fa fa-stop'
-		},{
-		    text: gettext('Reset'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid),
-		    handler: function() {
-			vm_command("reset");
-		    },
-		    iconCls: 'fa fa-bolt'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    hidden: template,
-	    consoleType: 'kvm',
-	    consoleName: vm.name,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'kvmtab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveQemuSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push({
-		title: gettext('Console'),
-		itemId: 'console',
-		iconCls: 'fa fa-terminal',
-		xtype: 'pveNoVncConsole',
-		vmid: vmid,
-		consoleType: 'kvm',
-		nodename: nodename
-	    });
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Hardware'),
-		itemId: 'hardware',
-		iconCls: 'fa fa-desktop',
-		xtype: 'PVE.qemu.HardwareView'
-	    },
-	    {
-		title: 'Cloud-Init',
-		itemId: 'cloudinit',
-		iconCls: 'fa fa-cloud',
-		xtype: 'pveCiPanel'
-	    },
-	    {
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options',
-		xtype: 'PVE.qemu.Options'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		xtype: 'proxmoxNodeTasks',
-		iconCls: 'fa fa-list',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Monitor'] && !template) {
-	    me.items.push({
-		title: gettext('Monitor'),
-		iconCls: 'fa fa-eye',
-		itemId: 'monitor',
-		xtype: 'pveQemuMonitor'
-	    });
-	}
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveQemuSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-        me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var qmpstatus;
-	    var spice = false;
-	    var xtermjs = false;
-	    var lock;
-
-	    if (!success) {
-		status = qmpstatus = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('qmpstatus');
-		qmpstatus = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-
-		spice = s.data.get('spice') ? true : false;
-		xtermjs = s.data.get('serial') ? true : false;
-
-	    }
-
-	    if (template) {
-		return;
-	    }
-
-	    var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1);
-
-	    if (resume || lock === 'suspended') {
-		startBtn.setVisible(false);
-		resumeBtn.setVisible(true);
-	    } else {
-		startBtn.setVisible(true);
-		resumeBtn.setVisible(false);
-	    }
-
-	    consoleBtn.setEnableSpice(spice);
-	    consoleBtn.setEnableXtermJS(xtermjs);
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-   }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    alias: 'widget.pveQemuCreateWizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    current: {
-		scsihw: ''
-	    }
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('Virtual Machine'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'qm_general_settings',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid',
-		    guestType: 'qemu',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'name',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: true
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		}
-	    ],
-	    advancedColumn1: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'onboot',
-		    uncheckedValue: 0,
-		    defaultValue: 0,
-		    deleteDefaultValue: true,
-		    fieldLabel: gettext('Start at boot')
-		}
-	    ],
-	    advancedColumn2: [
-		{
-		    xtype: 'textfield',
-		    name: 'order',
-		    defaultValue: '',
-		    emptyText: 'any',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Start/Shutdown order')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'up',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Startup delay')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'down',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Shutdown timeout')
-		}
-	    ],
-	    onGetValues: function(values) {
-
-		['name', 'pool', 'onboot', 'agent'].forEach(function(field) {
-		    if (!values[field]) {
-			delete values[field];
-		    }
-		});
-
-		var res = PVE.Parser.printStartup({
-		    order: values.order,
-		    up: values.up,
-		    down: values.down
-		});
-
-		if (res) {
-		    values.startup = res;
-		}
-
-		delete values.order;
-		delete values.up;
-		delete values.down;
-
-		return values;
-	    }
-	},
-	{
-	    xtype: 'container',
-	    layout: 'hbox',
-	    defaults: {
-		flex: 1,
-		padding: '0 10'
-	    },
-	    title: gettext('OS'),
-	    items: [
-		{
-		    xtype: 'pveQemuCDInputPanel',
-		    bind: {
-			nodename: '{nodename}'
-		    },
-		    confid: 'ide2',
-		    insideWizard: true
-		},
-		{
-		    xtype: 'pveQemuOSTypePanel',
-		    insideWizard: true
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveQemuSystemPanel',
-	    title: gettext('System'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuHDInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Hard Disk'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuProcessorPanel',
-	    insideWizard: true,
-	    title: gettext('CPU')
-	},
-	{
-	    xtype: 'pveQemuMemoryPanel',
-	    insideWizard: true,
-	    title: gettext('Memory')
-	},
-	{
-	    xtype: 'pveQemuNetworkInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Network'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-			    property : 'key',
-			    direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var kv = this.up('window').getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete') { // ignore
-			    return;
-			}
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/qemu',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response){
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-
-Ext.define('PVE.qemu.USBInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    autoComplete: false,
-    onlineHelp: 'qm_usb_passthrough',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=usb]': {
-		change: function(field, newValue, oldValue) {
-		    var hwidfield = this.lookupReference('hwid');
-		    var portfield = this.lookupReference('port');
-		    var usb3field = this.lookupReference('usb3');
-		    if (field.inputValue === 'hostdevice') {
-			hwidfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'port') {
-			portfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'spice') {
-			usb3field.setDisabled(newValue);
-		    }
-		}
-	    },
-	    'pveUSBSelector': {
-		change: function(field, newValue, oldValue) {
-		    var usbval = field.getUSBValue();
-		    var usb3field = this.lookupReference('usb3');
-		    var usb3 = /usb3/.test(usbval);
-		    if(usb3 && !usb3field.isDisabled()) {
-			usb3field.savedVal = usb3field.getValue();
-			usb3field.setValue(true);
-			usb3field.setDisabled(true);
-		    } else if(!usb3 && usb3field.isDisabled()){
-			var val = (usb3field.savedVal === undefined)?usb3field.originalValue:usb3field.savedVal;
-			usb3field.setValue(val);
-			usb3field.setDisabled(false);
-		    }
-		}
-	    }
-	}
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 6; i++) {
-		if (!me.vmconfig['usb' +  i.toString()]) {
-		    me.confid = 'usb' + i.toString();
-		    break;
-		}
-	    }
-	}
-	var val = "";
-	var type = me.down('radiofield').getGroupValue();
-	switch (type) {
-	    case 'spice':
-		val = 'spice'; break;
-	    case 'hostdevice':
-	    case 'port':
-		val = me.down('pveUSBSelector[name=' + type + ']').getUSBValue();
-		if (!/usb3/.test(val) && me.down('field[name=usb3]').getValue() === true) {
-		    val += ',usb3=1';
-		}
-		break;
-	    default:
-		throw "invalid type selected";
-	}
-
-	values[me.confid] = val;
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'fieldcontainer',
-	    defaultType: 'radiofield',
-	    items:[
-		{
-		    name: 'usb',
-		    inputValue: 'spice',
-		    boxLabel: gettext('Spice Port'),
-		    submitValue: false,
-		    checked: true
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'hostdevice',
-		    boxLabel: gettext('Use USB Vendor/Device ID'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    type: 'device',
-		    name: 'hostdevice',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    reference: 'hwid',
-		    allowBlank: false,
-		    fieldLabel: 'Choose Device',
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'port',
-		    boxLabel: gettext('Use USB Port'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    name: 'port',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    type: 'port',
-		    reference: 'port',
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Port'),
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    xtype: 'checkbox',
-		    name: 'usb3',
-		    submitValue: false,
-		    reference: 'usb3',
-		    fieldLabel: gettext('Use USB3')
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.USBEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('USB Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var data = response.result.data[me.confid].split(',');
-		    var port, hostdevice, usb3 = false;
-		    var type = 'spice';
-		    var i;
-		    for (i = 0; i < data.length; i++) {
-			if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
-			    hostdevice = data[i];
-			    hostdevice = hostdevice.replace('host=', '').replace('0x','');
-			    type = 'hostdevice';
-			} else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
-			    port = data[i];
-			    port = port.replace('host=','');
-			    type = 'port';
-			}
-
-			if (/^usb3=(1|on|true)$/.test(data[i])) {
-			    usb3 = true;
-			}
-		    }
-		    var values = {
-			usb : type,
-			hostdevice: hostdevice,
-			port: port,
-			usb3: usb3
-		    };
-
-		    ipanel.setValues(values);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.PCIInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    onlineHelp: 'qm_pci_passthrough',
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-
-	var hostpci = me.vmconfig[me.confid] || '';
-
-	var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-	if (values.host && values.host.length < 6) { // 00:00 format not 00:00.0
-	    values.host += ".0";
-	    values.multifunction = true;
-	}
-	values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
-	values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
-	values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
-
-	me.setValues(values);
-	if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
-	    // machine is not set to some variant of q35, so we disable pcie
-	    var pcie = me.down('field[name=pcie]');
-	    pcie.setDisabled(true);
-	    pcie.setBoxLabel(gettext('Q35 only'));
-	}
-
-	if (values.romfile) {
-	    me.down('field[name=romfile]').setVisible(true);
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var ret = {};
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 5; i++) {
-		if (!me.vmconfig['hostpci' +  i.toString()]) {
-		    me.confid = 'hostpci' + i.toString();
-		    break;
-		}
-	    }
-	}
-	if (values.multifunction) {
-	    // modify host to skip the '.X'
-	    values.host = values.host.substring(0,5);
-	    delete values.multifunction;
-	}
-
-	if (values.rombar) {
-	    delete values.rombar;
-	} else {
-	    values.rombar = 0;
-	}
-
-	if (!values.romfile) {
-	    delete values.romfile;
-	}
-
-	ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-	return ret;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.column1 = [
-	    {
-		xtype: 'pvePCISelector',
-		fieldLabel: gettext('Device'),
-		name: 'host',
-		nodename: me.nodename,
-		allowBlank: false,
-		onLoadCallBack: function(store, records, success) {
-		    if (!success || !records.length) {
-			return;
-		    }
-
-		    var first = records[0];
-		    if (first.data.iommugroup === -1) {
-			// no iommu groups
-			var warning = Ext.create('Ext.form.field.Display', {
-			    columnWidth: 1,
-			    padding: '0 0 10 0',
-			    value: 'No IOMMU detected, please activate it.' +
-				   'See Documentation for further information.',
-			    userCls: 'pve-hint'
-			});
-			me.items.insert(0, warning);
-			me.updateLayout(); // insert does not trigger that
-		    }
-		},
-		listeners: {
-		    change: function(pcisel, value) {
-			if (!value) {
-			    return;
-			}
-			var pcidev = pcisel.getStore().getById(value);
-			var mdevfield = me.down('field[name=mdev]');
-			mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
-			if (!pcidev) {
-			    return;
-			}
-			var id = pcidev.data.id.substring(0,5); // 00:00
-			var iommu = pcidev.data.iommugroup;
-			// try to find out if there are more devices
-			// in that iommu group
-			if (iommu !== -1) {
-			    var count = 0;
-			    pcisel.getStore().each(function(record) {
-				if (record.data.iommugroup === iommu &&
-				    record.data.id.substring(0,5) !== id)
-				{
-				    count++;
-				    return false;
-				}
-			    });
-			    var warning = me.down('#iommuwarning');
-			    if (count && !warning) {
-				warning = Ext.create('Ext.form.field.Display', {
-				    columnWidth: 1,
-				    padding: '0 0 10 0',
-				    itemId: 'iommuwarning',
-				    value: 'The selected Device is not in a seperate' +
-					   'IOMMU group, make sure this is intended.',
-				    userCls: 'pve-hint'
-				});
-				me.items.insert(0, warning);
-				me.updateLayout(); // insert does not trigger that
-			    } else if (!count && warning) {
-				me.remove(warning);
-			    }
-			}
-			if (pcidev.data.mdev) {
-			    mdevfield.setPciID(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('All Functions'),
-		name: 'multifunction'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'pveMDevSelector',
-		name: 'mdev',
-		disabled: true,
-		fieldLabel: gettext('MDev Type'),
-		nodename: me.nodename,
-		listeners: {
-		    change: function(field, value) {
-			var mf = me.down('field[name=multifunction]');
-			if (!!value) {
-			    mf.setValue(false);
-			}
-			mf.setDisabled(!!value);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Primary GPU'),
-		name: 'x-vga'
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'ROM-Bar',
-		name: 'rombar'
-	    },
-	    {
-		xtype: 'displayfield',
-		submitValue: true,
-		hidden: true,
-		fieldLabel: 'ROM-File',
-		name: 'romfile'
-	    }
-	];
-
-	me.advancedColumn2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'PCI-Express',
-		name: 'pcie'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.PCIEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('PCI Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.SerialnputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    autoComplete: false,
-
-    setVMConfig: function(vmconfig) {
-	var me = this, i;
-	me.vmconfig = vmconfig;
-
-	for (i = 0; i < 4; i++) {
-	    var port = 'serial' +  i.toString();
-	    if (!me.vmconfig[port]) {
-		me.down('field[name=serialid]').setValue(i);
-		break;
-	    }
-	}
-
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id = 'serial' + values.serialid;
-	delete values.serialid;
-	values[id] = 'socket';
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'serialid',
-	    fieldLabel: gettext('Serial Port'),
-	    minValue: 0,
-	    maxValue: 3,
-	    allowBlank: false,
-	    validator: function(id) {
-		if (!this.rendered) {
-		    return true;
-		}
-		var me = this.up('panel');
-		if (me.vmconfig !== undefined && Ext.isDefined(me.vmconfig['serial' + id])) {
-			return "This device is already in use.";
-		}
-		return true;
-	    }
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.SerialEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('Serial Port'),
-
-    initComponent : function() {
-	var me = this;
-
-	// for now create of (socket) serial port only
-	me.isCreate = true;
-
-	var ipanel = Ext.create('PVE.qemu.SerialnputPanel', {});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.IPInfo', {
-    extend: 'Ext.window.Window',
-    width: 600,
-    title: gettext('Guest Agent Network Information'),
-    height: 300,
-    layout: {
-	type: 'fit'
-    },
-    modal: true,
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: gettext('No network information'),
-	    columns: [
-		{
-		    dataIndex: 'name',
-		    text: gettext('Name'),
-		    flex: 3
-		},
-		{
-		    dataIndex: 'hardware-address',
-		    text: gettext('MAC address'),
-		    width: 140
-		},
-		{
-		    dataIndex: 'ip-addresses',
-		    text: gettext('IP address'),
-		    align: 'right',
-		    flex: 4,
-		    renderer: function(val) {
-			if (!Ext.isArray(val)) {
-			    return '';
-			}
-			var ips = [];
-			val.forEach(function(ip) {
-			    var addr = ip['ip-address'];
-			    var pref = ip.prefix;
-			    if  (addr && pref) {
-				ips.push(addr + '/' + pref);
-			    }
-			});
-			return ips.join('<br>');
-		    }
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.AgentIPView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveAgentIPView',
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    nics: [],
-
-    items: [
-	{
-	    xtype: 'box',
-	    html: '<i class="fa fa-exchange"></i> IPs'
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'right',
-		pack: 'end'
-	    },
-	    items: [
-		{
-		    xtype: 'label',
-		    flex: 1,
-		    itemId: 'ipBox',
-		    style: {
-			'text-align': 'right'
-		    }
-		},
-		{
-		    xtype: 'button',
-		    itemId: 'moreBtn',
-		    hidden: true,
-		    ui: 'default-toolbar',
-		    handler: function(btn) {
-			var me = this.up('pveAgentIPView');
-
-			var win = Ext.create('PVE.window.IPInfo');
-			win.down('grid').getStore().setData(me.nics);
-			win.show();
-		    },
-		    text: gettext('More')
-		}
-	    ]
-	}
-    ],
-
-    getDefaultIps: function(nics) {
-	var me = this;
-	var ips = [];
-	nics.forEach(function(nic) {
-	    if (nic['hardware-address'] &&
-		nic['hardware-address'] != '00:00:00:00:00:00') {
-
-		var nic_ips = nic['ip-addresses'] || [];
-		nic_ips.forEach(function(ip) {
-		    var p = ip['ip-address'];
-		    // show 2 ips at maximum
-		    if (ips.length < 2) {
-			ips.push(p);
-		    }
-		});
-	    }
-	});
-
-	return ips;
-    },
-
-    startIPStore: function(store, records, success) {
-	var me = this;
-	var agentRec = store.getById('agent');
-	/*jslint confusion: true*/
-	/* value is number and string */
-	me.agent = (agentRec && agentRec.data.value === 1);
-	me.running = (store.getById('status').data.value === 'running');
-	/*jslint confusion: false*/
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!caps.vms['VM.Monitor']) {
-	    var errorText = gettext("Requires '{0}' Privileges");
-	    me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
-	    return;
-	}
-
-	if (me.agent && me.running && me.ipStore.isStopped) {
-	    me.ipStore.startUpdate();
-	} else if (me.ipStore.isStopped) {
-	    me.updateStatus();
-	}
-    },
-
-    updateStatus: function(unsuccessful, defaulttext) {
-	var me = this;
-	var text = defaulttext || gettext('No network information');
-	var more = false;
-	if (unsuccessful) {
-	    text = gettext('Guest Agent not running');
-	} else if (me.agent && me.running) {
-	    if (Ext.isArray(me.nics) && me.nics.length) {
-		more = true;
-		var ips = me.getDefaultIps(me.nics);
-		if (ips.length !== 0) {
-		    text = ips.join('<br>');
-		}
-	    } else if (me.nics && me.nics.error) {
-		var msg = gettext('Cannot get info from Guest Agent<br>Error: {0}');
-		text = Ext.String.format(text, me.nics.error.desc);
-	    }
-	} else if (me.agent) {
-	    text = gettext('Guest Agent not running');
-	} else {
-	    text = gettext('No Guest Agent configured');
-	}
-
-	var ipBox = me.down('#ipBox');
-	ipBox.update(text);
-
-	var moreBtn = me.down('#moreBtn');
-	moreBtn.setVisible(more);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw 'rstore not given';
-	}
-
-	if (!me.pveSelNode) {
-	    throw 'pveSelNode not given';
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	var vmid = me.pveSelNode.data.vmid;
-
-	me.ipStore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 10000,
-	    storeid: 'pve-qemu-agent-' + vmid,
-	    method: 'POST',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces'
-	    }
-	});
-
-	me.callParent();
-
-	me.mon(me.ipStore, 'load', function(store, records, success) {
-	    if (records && records.length) {
-		me.nics = records[0].data.result;
-	    } else {
-		me.nics = undefined;
-	    }
-	    me.updateStatus(!success);
-	});
-
-	me.on('destroy', me.ipStore.stopUpdate);
-
-	// if we already have info about the vm, use it immediately
-	if (me.rstore.getCount()) {
-	    me.startIPStore(me.rstore, me.rstore.getData(), false);
-	}
-
-	// check if the guest agent is there on every statusstore load
-	me.mon(me.rstore, 'load', me.startIPStore, me);
-    }
-});
-Ext.define('PVE.qemu.CloudInit', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    xtype: 'pveCiPanel',
-
-    onlineHelp: 'qm_cloud_init',
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var me = this.up('grid');
-		var warn = gettext('Are you sure you want to remove entry {0}');
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		return msg;
-	    },
-	    enableFn: function(record) {
-		var me = this.up('grid');
-		var caps = Ext.state.Manager.get('GuiCap');
-		if (me.rows[record.data.key].never_delete ||
-		    !caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-
-		if (record.data.key === 'cipassword' && !record.data.value) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		var records = me.getSelection();
-		if (!records ||  !records.length) {
-		    return;
-		}
-
-		var id = records[0].data.key;
-		var match = id.match(/^net(\d+)$/);
-		if (match) {
-		    id = 'ipconfig' + match[1];
-		}
-
-		var params = {};
-		params['delete'] = id;
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: params,
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    callback: function() {
-			me.reload();
-		    }
-		});
-	    },
-	    text: gettext('Remove')
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('grid');
-		me.run_editor();
-	    },
-	    text: gettext('Edit')
-	},
-	'-',
-	{
-	    xtype: 'button',
-	    itemId: 'savebtn',
-	    text: gettext('Regenerate Image'),
-	    handler: function() {
-		var me = this.up('grid');
-		var eject_params = {};
-		var insert_params = {};
-		var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
-		var storage = '';
-		var stormatch = disk.file.match(/^([^\:]+)\:/);
-		if (stormatch) {
-		    storage = stormatch[1];
-		}
-		eject_params[me.ciDriveId] = 'none,media=cdrom';
-		insert_params[me.ciDriveId] = storage + ':cloudinit';
-
-		var failure = function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		};
-
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: eject_params,
-		    failure: failure,
-		    callback: function() {
-			Proxmox.Utils.API2Request({
-			    url: me.baseurl + '/config',
-			    waitMsgTarget: me,
-			    method: 'PUT',
-			    params: insert_params,
-			    failure: failure,
-			    callback: function() {
-				me.reload();
-			    }
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    border: false,
-
-    set_button_status: function(rstore, records, success) {
-	if (!success || records.length < 1) {
-	    return;
-	}
-	var me = this;
-	var found;
-	records.forEach(function(record) {
-	    if (found) {
-		return;
-	    }
-	    var id = record.data.key;
-	    var value = record.data.value;
-	    var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
-		if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
-		    found = id;
-		    me.ciDriveId = found;
-		    me.ciDrive = value;
-		}
-	});
-
-	me.down('#savebtn').setDisabled(!found);
-	me.setDisabled(!found);
-	if (!found) {
-	    me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
-	} else {
-	    me.getView().unmask();
-	}
-    },
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-
-	var icon = "";
-	if (rowdef.iconCls) {
-	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
-	}
-	return icon + (rowdef.header || key);
-    },
-
-    listeners: {
-	activate: function () {
-	    var me = this;
-	    me.rstore.startUpdate();
-	},
-	itemdblclick: function() {
-	    var me = this;
-	    me.run_editor();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-	var caps = Ext.state.Manager.get('GuiCap');
-	me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
-	me.url =  me.baseurl + '/pending';
-	me.editorConfig.url = me.baseurl + '/config';
-	me.editorConfig.pveSelNode = me.pveSelNode;
-
-	/*jslint confusion: true*/
-	/* editor is string and object */
-	me.rows = {
-	    ciuser: {
-		header: gettext('User'),
-		iconCls: 'fa fa-user',
-		never_delete: true,
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('User'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('User'),
-			    name: 'ciuser'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.defaultText;
-		}
-	    },
-	    cipassword: {
-		header: gettext('Password'),
-		iconCls: 'fa fa-unlock',
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Password'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    inputType: 'password',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.noneText,
-			    fieldLabel: gettext('Password'),
-			    name: 'cipassword'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.noneText;
-		}
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    nameserver: {
-		header: gettext('DNS servers'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    sshkeys: {
-		header: gettext('SSH public key'),
-		iconCls: 'fa fa-key',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.SSHKeyEdit' : undefined,
-		never_delete: true,
-		renderer: function(value) {
-		    value = decodeURIComponent(value);
-		    var keys = value.split('\n');
-		    var text = [];
-		    keys.forEach(function(key) {
-			if (key.length) {
-			    // First erase all quoted strings (eg. command="foo"
-			    var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
-			    // Now try to detect the comment:
-			    var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
-			    if (res) {
-				key = Ext.String.htmlEncode(res[2]);
-				if (res[1]) {
-				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
-				}
-				text.push(key);
-				return;
-			    }
-			    // Most likely invalid at this point, so just stick to
-			    // the old value.
-			    text.push(Ext.String.htmlEncode(key));
-			}
-		    });
-		    if (text.length) {
-			return text.join('<br>');
-		    } else {
-			return Proxmox.Utils.noneText;
-		    }
-		},
-		defaultValue: ''
-	    }
-	};
-	var i;
-	var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
-	    var id = record.data.key;
-	    var match = id.match(/^net(\d+)$/);
-	    var val = '';
-	    if (match) {
-		val = me.getObjectValue('ipconfig'+match[1], '', pending);
-	    }
-	    return val;
-	};
-	for (i = 0; i < 32; i++) {
-	    // we want to show an entry for every network device
-	    // even if it is empty
-	    me.rows['net' + i.toString()] = {
-		multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
-		header: gettext('IP Config') + ' (net' + i.toString() +')',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
-		iconCls: 'fa fa-exchange',
-		renderer: ipconfig_renderer
-	    };
-	    me.rows['ipconfig' + i.toString()] = {
-		visible: false
-	    };
-	}
-	/*jslint confusion: false*/
-
-	PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
-	    me.rows[type+id] = {
-		visible: false
-	    };
-	});
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-    }
-});
-Ext.define('PVE.qemu.CIDriveInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveCIDriveInputPanel',
-
-    insideWizard: false,
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var drive = {};
-	var params = {};
-	drive.file = values.hdstorage + ":cloudinit";
-	drive.format = values.diskformat;
-	params[values.controller + values.deviceid] = PVE.Parser.printQemuDrive(drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.down('#drive').setVMConfig(config, 'cdrom');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items = [
-	    {
-		xtype: 'pveControllerSelector',
-		noVirtIO: true,
-		itemId: 'drive',
-		fieldLabel: gettext('CloudInit Drive'),
-		name: 'drive'
-	    },
-	    {
-		xtype: 'pveDiskStorageSelector',
-		itemId: 'storselector',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    }
-	];
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CIDriveEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCIDriveEdit',
-
-    isCreate: true,
-    subject: gettext('CloudInit Drive'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveCIDriveInputPanel',
-	    itemId: 'cipanel',
-	    nodename: nodename
-	}];
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		me.down('#cipanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SSHKeyInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSSHKeyInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-	if (values.sshkeys) {
-	    values.sshkeys.trim();
-	}
-	if (!values.sshkeys.length) {
-	    values = {};
-	    values['delete'] = 'sshkeys';
-	    return values;
-	} else {
-	    values.sshkeys = encodeURIComponent(values.sshkeys);
-	}
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'sshkeys',
-	    name: 'sshkeys',
-	    height: 250
-	},
-	{
-	    xtype: 'filebutton',
-	    itemId: 'filebutton',
-	    name: 'file',
-	    text: gettext('Load SSH Key File'),
-	    fieldLabel: 'test',
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('inputpanel');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    var keysField = me.down('#sshkeys');
-			    var old = keysField.getValue();
-			    keysField.setValue(old + res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-	if (!window.FileReader) {
-	    me.down('#filebutton').setVisible(false);
-	}
-
-    }
-});
-
-Ext.define('PVE.qemu.SSHKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 800,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.SSHKeyInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('SSH Keys'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.create) {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.sshkeys) {
-			data.sshkeys = decodeURIComponent(data.sshkeys);
-			ipanel.setValues(data);
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.qemu.IPConfigPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveIPConfigPanel',
-
-    insideWizard: false,
-
-    vmconfig: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-
-	var params = {};
-
-	var cfg = PVE.Parser.printIPConfig(values);
-	if (cfg === '') {
-	    params['delete'] = [me.confid];
-	} else {
-	    params[me.confid] = cfg;
-	}
-	return params;
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.vmconfig = config;
-    },
-
-    setIPConfig: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data.ip === 'dhcp') {
-	    data.ipv4mode = data.ip;
-	    data.ip = '';
-	} else {
-	    data.ipv4mode = 'static';
-	}
-	if (data.ip6 === 'dhcp' || data.ip6 === 'auto') {
-	    data.ipv6mode = data.ip6;
-	    data.ip6 = '';
-	} else {
-	    data.ipv6mode = 'static';
-	}
-
-	me.ipconfig = data;
-	me.setValues(me.ipconfig);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.ipconfig = {};
-
-	me.column1 = [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Network Device'),
-		value: me.netid
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv4') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('IPv4/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: '',
-		vtype: 'IPAddress',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv4') +')'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'displayfield'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv6') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: '',
-		vtype: 'IP6CIDRAddress',
-		disabled: true,
-		fieldLabel: gettext('IPv6/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv6') +')'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.IPConfigEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	// convert confid from netX to ipconfigX
-	var match = me.confid.match(/^net(\d+)$/);
-	if (match) {
-	    me.netid = me.confid;
-	    me.confid = 'ipconfig' + match[1];
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.IPConfigPanel', {
-	    confid: me.confid,
-	    netid: me.netid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Config'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		me.vmconfig = response.result.data;
-		var ipconfig = {};
-		var value = me.vmconfig[me.confid];
-		if (value) {
-		    ipconfig = PVE.Parser.parseIPConfig(me.confid, value);
-		    if (!ipconfig) {
-			Ext.Msg.alert(gettext('Error'), gettext('Unable to parse network configuration'));
-			me.close();
-			return;
-		    }
-		}
-		ipanel.setIPConfig(me.confid, ipconfig);
-		ipanel.setVMConfig(me.vmconfig);
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.SystemInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSystemPanel',
-
-    onlineHelp: 'qm_system_settings',
-
-    viewModel: {
-	data: {
-	    efi: false,
-	    addefi: true
-	},
-
-	formulas: {
-	    efidisk: function(get) {
-		return get('efi') && get('addefi');
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	if (values.vga && values.vga.substr(0,6) === 'serial') {
-	    values['serial' + values.vga.substr(6,1)] = 'socket';
-	}
-
-	var efidrive = {};
-	if (values.hdimage) {
-	    efidrive.file = values.hdimage;
-	} else if (values.hdstorage) {
-	    efidrive.file = values.hdstorage + ":1";
-	}
-
-	if (values.diskformat) {
-	    efidrive.format = values.diskformat;
-	}
-
-	delete values.hdimage;
-	delete values.hdstorage;
-	delete values.diskformat;
-
-	if (efidrive.file) {
-	    values.efidisk0 = PVE.Parser.printQemuDrive(efidrive);
-	}
-
-	return values;
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	scsihwChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('current.scsihw', value);
-	    }
-	},
-
-	biosChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('efi', value === 'ovmf');
-	    }
-	},
-
-	control: {
-	    'pveScsiHwSelector': {
-		change: 'scsihwChange'
-	    },
-	    'pveQemuBiosSelector': {
-		change: 'biosChange'
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: gettext('Graphic card'),
-	    name: 'vga',
-	    comboItems: PVE.Utils.kvm_vga_driver_array()
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'agent',
-	    uncheckedValue: 0,
-	    defaultValue: 0,
-	    deleteDefaultValue: true,
-	    fieldLabel: gettext('Qemu Agent')
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'pveScsiHwSelector',
-	    name: 'scsihw',
-	    value: '__default__',
-	    bind: {
-		value: '{current.scsihw}'
-	    },
-	    fieldLabel: gettext('SCSI Controller')
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    name: 'bios',
-	    value: '__default__',
-	    fieldLabel: 'BIOS'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    bind: {
-		value: '{addefi}',
-		hidden: '{!efi}',
-		disabled: '{!efi}'
-	    },
-	    hidden: true,
-	    submitValue: false,
-	    disabled: true,
-	    fieldLabel: gettext('Add EFI Disk')
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    bind: {
-		nodename: '{nodename}',
-		hidden: '{!efi}',
-		disabled: '{!efidisk}'
-	    },
-	    autoSelect: false,
-	    disabled: true,
-	    hidden: true,
-	    hideSize: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'machine',
-	    value: '__default__',
-	    fieldLabel: gettext('Machine'),
-	    comboItems: [
-		['__default__', PVE.Utils.render_qemu_machine('')],
-		['q35', 'q35']
-	    ]
-	}
-    ]
-
-});
-Ext.define('PVE.lxc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveLxcSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 320,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.lxc.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcNetworkInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_network',
-
-    setNodename: function(nodename) {
-	var me = this;
-	
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	var bridgesel = me.query("[isFormField][name=bridge]")[0];
-	bridgesel.setNodename(nodename);
-    },
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	var id;
-	if (me.isCreate) {
-	    id = values.id;
-	    delete values.id;
-	} else {
-	    id = me.ifname;
-	}
-
-	if (!id) {
-	    return {};
-	}
-
-	var newdata = {};
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-	newdata[id] = PVE.Parser.printLxcNetwork(values);
-	return newdata;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var cdata = {};
-
-	if (me.insideWizard) {
-	    me.ifname = 'net0';
-	    cdata.name = 'eth0';
-	    me.dataCache = {};
-	}
-	cdata.firewall =  (me.insideWizard || me.isCreate);
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.isCreate) {
-	    if (!me.ifname) {
-		throw "no interface name specified";
-	    }
-	    if (!me.dataCache[me.ifname]) {
-		throw "no such interface '" + me.ifname + "'";
-	    }
-
-	    cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
-	}
-
-	var i;
-	for (i = 0; i < 10; i++) {
-	    if (me.isCreate && !me.dataCache['net'+i.toString()]) {
-		me.ifname = 'net' + i.toString();
-		break;
-	    }
-	}
-
-	var idselector = {
-	    xtype: 'hidden',
-	    name: 'id',
-	    value: me.ifname
-	};
-
-	me.column1 = [
-	    idselector,
-	    {
-		xtype: 'textfield',
-		name: 'name',
-		fieldLabel: gettext('Name'),
-		emptyText: '(e.g., eth0)',
-		allowBlank: false,
-		value: cdata.name,
-		validator: function(value) {
-		    var result = '';
-		    Ext.Object.each(me.dataCache, function(key, netstr) {
-			if (!key.match(/^net\d+/) || key === me.ifname) {
-			    return; // continue
-			}
-			var net = PVE.Parser.parseLxcNetwork(netstr);
-			if (net.name === value) {
-			    result = "interface name already in use";
-			    return false;
-			}
-		    });
-		    if (result !== '') {
-			return result;
-		    }
-		    // validator can return bool/string
-		    /*jslint confusion:true*/
-		    return true;
-		}
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'hwaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		value: cdata.hwaddr,
-		allowBlank: true,
-		emptyText: 'auto'
-	    },
-	    {
-		xtype: 'PVE.form.BridgeSelector',
-		name: 'bridge',
-		nodename: me.nodename,
-		fieldLabel: gettext('Bridge'),
-		value: cdata.bridge,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: cdata.tag
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: cdata.rate,
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		value: cdata.firewall
-	    }
-	];
-
-	var dhcp4 = (cdata.ip === 'dhcp');
-	if (dhcp4) {
-	    cdata.ip = '';
-	    cdata.gw = '';
-	}
-
-	var auto6 = (cdata.ip6 === 'auto');
-	var dhcp6 = (cdata.ip6 === 'dhcp');
-	if (auto6 || dhcp6) {
-	    cdata.ip6 = '';
-	    cdata.gw6 = '';
-	}
-	
-	me.column2 = [
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv4:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: !dhcp4,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: dhcp4,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: cdata.ip,
-		disabled: dhcp4,
-		fieldLabel: 'IPv4/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: cdata.gw,
-		vtype: 'IPAddress',
-		disabled: dhcp4,
-		fieldLabel: gettext('Gateway') + ' (IPv4)',
-		margin: '0 0 3 0' // override bottom margin to account for the menuseparator
-	    },
-	    {
-		xtype: 'menuseparator',
-		height: '3',
-		margin: '0'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv6:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: !(auto6 || dhcp6),
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: dhcp6,
-			margin: '0 0 0 10'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'SLAAC', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'auto',
-			checked: auto6,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: cdata.ip6,
-		vtype: 'IP6CIDRAddress',
-		disabled: (dhcp6 || auto6),
-		fieldLabel: 'IPv6/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: cdata.gw6,
-		disabled: (dhcp6 || auto6),
-		fieldLabel: gettext('Gateway') + ' (IPv6)'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-	
-
-Ext.define('PVE.lxc.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
-	    ifname: me.ifname,
-	    nodename: me.nodename,
-	    dataCache: me.dataCache,
-	    isCreate: me.isCreate
-	});
-	   
-	Ext.apply(me, {
-	    subject: gettext('Network Device') + ' (veth)',
-	    digest: me.dataCache.digest,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveLxcNetworkView',
-
-    onlineHelp: 'pct_container_network',
-
-    dataCache: {}, // used to store result of last load
-
-    stateful: true,
-    stateId: 'grid-lxc-network',
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.setErrorMask(me, true);
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		me.dataCache = data;
-		var records = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (!key.match(/^net\d+/)) {
-			return; // continue
-		    }
-		    var net = PVE.Parser.parseLxcNetwork(value);
-		    net.id = key;
-		    records.push(net);
-		});
-		me.store.loadData(records);
-		me.down('button[name=addButton]').setDisabled((records.length >= 10));
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var store = new Ext.data.Store({
-	    model: 'pve-lxc-network',
-	    sorters: [
-		{
-		    property : 'id',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!caps.vms['VM.Config.Network'];
-	    },
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: me.url,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: { 'delete': rec.data.id,  digest: me.dataCache.digest },
-		    callback: function() {
-			me.load();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!caps.vms['VM.Config.Network']) {
-		return false;
-	    }
-
-	    var win = Ext.create('PVE.lxc.NetworkEdit', {
-		url: me.url,
-		nodename: nodename,
-		dataCache: me.dataCache,
-		ifname: rec.data.id
-	    });
-	    win.on('destroy', me.load, me);
-	    win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    name: 'addButton',
-		    disabled: !caps.vms['VM.Config.Network'],
-		    handler: function() {
-			var win = Ext.create('PVE.lxc.NetworkEdit', {
-			    url: me.url,
-			    nodename: nodename,
-			    isCreate: true,
-			    dataCache: me.dataCache
-			});
-			win.on('destroy', me.load, me);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 50,
-		    dataIndex: 'id'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 80,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Bridge'),
-		    width: 80,
-		    dataIndex: 'bridge'
-		},
-		{
-		    header: gettext('Firewall'),
-		    width: 80,
-		    dataIndex: 'firewall',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('VLAN Tag'),
-		    width: 80,
-		    dataIndex: 'tag'
-		},
-		{
-		    header: gettext('MAC address'),
-		    width: 110,
-		    dataIndex: 'hwaddr'
-		},
-		{
-		    header: gettext('IP address'),
-		    width: 150,
-		    dataIndex: 'ip',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.ip && rec.data.ip6) {
-			    return rec.data.ip + "<br>" + rec.data.ip6;
-			} else if (rec.data.ip6) {
-			    return rec.data.ip6;
-			} else {
-			    return rec.data.ip;
-			}
-		    }
-		},
-		{
-		    header: gettext('Gateway'),
-		    width: 150,
-		    dataIndex: 'gw',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.gw && rec.data.gw6) {
-			    return rec.data.gw + "<br>" + rec.data.gw6;
-			} else if (rec.data.gw6) {
-			    return rec.data.gw6;
-			} else {
-			    return rec.data.gw;
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: me.load,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-   }
-}, function() {
-
-    Ext.define('pve-lxc-network', {
-	extend: "Ext.data.Model",
-	proxy: { type: 'memory' },
-	fields: [ 'id', 'name', 'hwaddr', 'bridge',
-		  'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
-    });
-
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.RessourceView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcRessourceView'],
-
-    onlineHelp: 'pct_configuration',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rowdef = me.rows[key] || {};
-
-	metaData.tdAttr = "valign=middle";
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	}
-	return rowdef.header || key;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	var mpeditor = caps.vms['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
-
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-memory',
-		group: 1,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    swap: {
-		header: gettext('Swap'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-swap',
-		group: 2,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    cores: {
-		header: gettext('Cores'),
-		editor: caps.vms['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
-		defaultValue: '',
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		renderer: function(value) {
-		    var cpulimit = me.getObjectValue('cpulimit');
-		    var cpuunits = me.getObjectValue('cpuunits');
-		    var res;
-		    if (value) {
-			res = value;
-		    } else {
-			res = gettext('unlimited');
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit + ']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits + ']';
-		    }
-		    return res;
-		}
-	    },
-	    rootfs: {
-		header: gettext('Root Disk'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: mpeditor,
-		tdCls: 'pve-itype-icon-storage',
-		group: 4
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    unprivileged: {
-		visible: false
-	    }
-	};
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    confid = bus + i;
-	    var group = 5;
-	    var header;
-	    if (bus === 'mp') {
-		header = gettext('Mount Point') + ' (' + confid + ')';
-	    } else {
-		header = gettext('Unused Disk') + ' ' + i;
-		group += 1;
-	    }
-	    rows[confid] = {
-		group: group,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: mpeditor,
-		header: header
-	    };
-	}, true);
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	var run_resize = function() {
-	    var rec = me.selModel.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.MPResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-	};
-
-	var run_remove = function(b, e, rec) {
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/' + baseurl,
-		waitMsgTarget: me,
-		method: 'PUT',
-		params: {
-		    'delete': rec.data.key
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var run_move = function(b, e, rec) {
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid,
-		type: 'lxc'
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec) {
-		    return false;
-		}
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + me.renderKey(rec.data.key, {}, rec) + "'");
-		if (rec.data.key.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: run_remove
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move Volume'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    handler: run_move
-	});
-
-	var set_button_status = function() {
-	    var rec = me.selModel.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		remove_btn.disable();
-		resize_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var isDisk = (rowdef.tdCls == 'pve-itype-icon-storage');
-
-	    var noedit = rec.data['delete'] || !rowdef.editor;
-	    if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) {
-		var mp = PVE.Parser.parseLxcMountPoint(value);
-		if (mp.type !== 'volume') {
-		    noedit = true;
-		}
-	    }
-	    edit_btn.setDisabled(noedit);
-
-	    remove_btn.setDisabled(!isDisk || rec.data.key === 'rootfs' || !diskCap);
-	    resize_btn.setDisabled(!isDisk || !diskCap);
-	    move_btn.setDisabled(!isDisk || !diskCap);
-
-	};
-	
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + baseurl,
-	    selModel: me.selModel,
-	    interval: 2000,
-	    cwidth1: 170,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Mount Point'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.lxc.MountPointEdit', {
-					url: '/api2/extjs/' + baseurl,
-					unprivileged: me.getObjectValue('unprivileged'),
-					pveSelNode: me.pveSelNode
-				    });
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		edit_btn,
-		remove_btn,
-		resize_btn,
-		move_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    editorConfig: {
-		pveSelNode: me.pveSelNode,
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	Ext.apply(me.editorConfig, { unprivileged: me.getObjectValue('unprivileged') });
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.FeaturesInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcFeaturesInputPanel',
-
-    // used to save the mounts fstypes until sending
-    mounts: [],
-
-    fstypes: ['nfs', 'cifs'],
-
-    viewModel: {
-	parent: null,
-	data: {
-	    unprivileged: false
-	},
-	formulas: {
-	    privilegedOnly: function(get) {
-		return (get('unprivileged') ? gettext('privileged only') : '');
-	    },
-	    unprivilegedOnly: function(get) {
-		return (!get('unprivileged') ? gettext('unprivileged only') : '');
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('keyctl'),
-	    name: 'keyctl',
-	    bind: {
-		disabled: '{!unprivileged}',
-		boxLabel: '{unprivilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Nesting'),
-	    name: 'nesting'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'nfs',
-	    fieldLabel: 'NFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cifs',
-	    fieldLabel: 'CIFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'fuse',
-	    fieldLabel: 'FUSE'
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-	var mounts = me.mounts;
-	me.fstypes.forEach(function(fs) {
-	    if (values[fs]) {
-		mounts.push(fs);
-	    }
-	    delete values[fs];
-	});
-
-	if (mounts.length) {
-	    values.mount = mounts.join(';');
-	}
-
-	var featuresstring = PVE.Parser.printPropertyString(values, undefined);
-	if (featuresstring == '') {
-	    return { 'delete': 'features' };
-	}
-	return { features: featuresstring };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	me.viewModel.set({ unprivileged: values.unprivileged });
-
-	if (values.features) {
-	    var res = PVE.Parser.parsePropertyString(values.features);
-	    me.mounts = [];
-	    if (res.mount) {
-		res.mount.split(/[; ]/).forEach(function(item) {
-		    if (me.fstypes.indexOf(item) === -1) {
-			me.mounts.push(item);
-		    } else {
-			res[item] = 1;
-		    }
-		});
-	    }
-	    this.callParent([res]);
-	}
-    }
-});
-
-Ext.define('PVE.lxc.FeaturesEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveLxcFeaturesEdit',
-
-    subject: gettext('Features'),
-
-    items: [{
-	xtype: 'pveLxcFeaturesInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.lxc.Options', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcOptions'],
-
-    onlineHelp: 'pct_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ? 
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'pct_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    arch: {
-		header: gettext('Architecture'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    console: {
-		header: '/dev/console',
-		defaultValue: 1,
-		renderer: Proxmox.Utils.format_enabled_toggle,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: '/dev/console',
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'console',
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			checked: true,
-			fieldLabel: '/dev/console'
-		    }
-		} : undefined
-	    },
-	    tty: {
-		header: gettext('TTY count'),
-		defaultValue: 2,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('TTY count'),
-		    items: {
-			xtype: 'proxmoxintegerfield',
-			name: 'tty',
-			minValue: 0,
-			maxValue: 6,
-			value: 2,
-			fieldLabel: gettext('TTY count'),
-			emptyText: gettext('Default'),
-			deleteEmpty: true
-		    }
-		} : undefined
-	    },
-	    cmode: {
-		header: gettext('Console mode'),
-		defaultValue: 'tty',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Console mode'),
-		    items: {
-			xtype: 'proxmoxKVComboBox',
-			name: 'cmode',
-			deleteEmpty: true,
-			value: '__default__',
-			comboItems: [
-			    ['__default__', Proxmox.Utils.defaultText + " (tty)"],
-			    ['tty', "/dev/tty[X]"],
-			    ['console', "/dev/console"],
-			    ['shell', "shell"]
-			],
-			fieldLabel: gettext('Console mode')
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    unprivileged: {
-		header: gettext('Unprivileged container'),
-		renderer: Proxmox.Utils.format_boolean,
-		defaultValue: 0
-	    },
-	    features: {
-		header: gettext('Features'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: Proxmox.UserName === 'root@pam' ?
-		    'PVE.lxc.FeaturesEdit' : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	Ext.apply(me, {
-	    url: "/api2/json/" + baseurl,
-	    selModel: sm,
-	    interval: 5000,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-    }
-});
-
-Ext.define('PVE.lxc.DNSInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcDNSInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var deletes = [];
-	if (!values.searchdomain && !me.insideWizard) {
-	    deletes.push('searchdomain');
-	}
-
-	if (values.nameserver) {
-	    var list = values.nameserver.split(/[\ \,\;]+/);
-	    values.nameserver = list.join(' ');
-	} else if(!me.insideWizard) {
-	    deletes.push('nameserver');
-	}
-
-	if (deletes.length) {
-	    values['delete'] = deletes.join(',');
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxtextfield',
-		name: 'searchdomain',
-		skipEmptyText: true,
-		fieldLabel: gettext('DNS domain'),
-		emptyText: gettext('use host settings'),
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS servers'),
-		vtype: 'IP64AddressList',
-		allowBlank: true,
-		emptyText: gettext('use host settings'),
-		name: 'nameserver',
-		itemId: 'nameserver'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.lxc.DNSInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Resources'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-
-		    if (values.nameserver) {
-			values.nameserver.replace(/[,;]/, ' ');
-			values.nameserver.replace(/^\s+/, '');
-		    }
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.DNS', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcDNS'],
-
-    onlineHelp: 'pct_container_network',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    hostname: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Hostname'),
-		editor: caps.vms['VM.Config.Network'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hostname'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    fieldLabel: gettext('Hostname'),
-			    xtype: 'textfield',
-			    name: 'hostname',
-			    vtype: 'DnsName',
-			    allowBlank: true,
-			    emptyText: 'CT' + vmid.toString()
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.hostname === undefined ||
-				values.hostname === null ||
-				values.hostname === '') {
-				params = { hostname: 'CT'+vmid.toString()};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    },
-	    nameserver: {
-		header: gettext('DNS server'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var win;
-	    if (Ext.isString(rowdef.editor)) {
-		win = Ext.create(rowdef.editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-	    //win.load();
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: run_editor
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/config",
-	    selModel: sm,
-	    cwidth1: 150,
-	    run_editor: run_editor,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status,
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.lxc.Config',
-
-    onlineHelp: 'chapter_pct',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + "/status/" + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var stopBtn = Ext.create('Ext.menu.Item',{
-	    text: gettext('Stop'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
-	    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-	    dangerous: true,
-	    handler: function() {
-		vm_command("stop");
-	    },
-	    iconCls: 'fa fa-stop'
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items:[stopBtn]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'lxc',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    guestType: 'ct',
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    disabled: !caps.vms['VM.Allocate'],
-		    itemId: 'removeBtn',
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'CT', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    consoleType: 'lxc',
-	    consoleName: vm.name,
-	    hidden: template,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'lxctab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveLxcSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push(
-		{
-		    title: gettext('Console'),
-		    itemId: 'consolejs',
-		    iconCls: 'fa fa-terminal',
-		    xtype: 'pveNoVncConsole',
-		    vmid: vmid,
-		    consoleType: 'lxc',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Resources'),
-		itemId: 'resources',
-		expandedOnInit: true,
-		iconCls: 'fa fa-cube',
-		xtype: 'pveLxcRessourceView'
-	    },
-	    {
-		title: gettext('Network'),
-		iconCls: 'fa fa-exchange',
-		itemId: 'network',
-		xtype: 'pveLxcNetworkView'
-	    },
-	    {
-		title: gettext('DNS'),
-		iconCls: 'fa fa-globe',
-		itemId: 'dns',
-		xtype: 'pveLxcDNS'
-	    },
-	    {
-		title: gettext('Options'),
-		itemId: 'options',
-		iconCls: 'fa fa-gear',
-		xtype: 'pveLxcOptions'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		iconCls: 'fa fa-list',
-		xtype: 'proxmoxNodeTasks',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveLxcSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		itemId: 'permissions',
-		iconCls: 'fa fa-unlock',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var lock;
-	    if (!success) {
-		status = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-	    }
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    stopBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'stopped');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    storage: '',
-	    unprivileged: true
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('LXC Container'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'pct_general',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid', // backend only knows vmid
-		    guestType: 'lxc',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'hostname',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Hostname'),
-		    skipEmptyText: true,
-		    allowBlank: true
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unprivileged',
-		    value: true,
-		    bind: {
-			value: '{unprivileged}'
-		    },
-		    fieldLabel: gettext('Unprivileged container')
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'password',
-		    value: '',
-		    fieldLabel: gettext('Password'),
-		    allowBlank: false,
-		    minLength: 5,
-		    change: function(f, value) {
-			if (f.rendered) {
-			    f.up().down('field[name=confirmpw]').validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'confirmpw',
-		    value: '',
-		    fieldLabel: gettext('Confirm password'),
-		    allowBlank: true,
-		    submitValue: false,
-		    validator: function(value) {
-			var pw = this.up().down('field[name=password]').getValue();
-			if (pw !== value) {
-			    return "Passwords do not match!";
-			}
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'ssh-public-keys',
-		    value: '',
-		    fieldLabel: gettext('SSH public key'),
-		    allowBlank: true,
-		    validator: function(value) {
-			var pwfield = this.up().down('field[name=password]');
-			if (value.length) {
-			    var key = PVE.Parser.parseSSHKey(value);
-			    if (!key) {
-				return "Failed to recognize ssh key";
-			    }
-			    pwfield.allowBlank = true;
-			} else {
-			    pwfield.allowBlank = false;
-			}
-			pwfield.validate();
-			return true;
-		    },
-		    afterRender: function() {
-			if (!window.FileReader) {
-			    // No FileReader support in this browser
-			    return;
-			}
-			var cancel = function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			};
-			var field = this;
-			field.inputEl.on('dragover', cancel);
-			field.inputEl.on('dragenter', cancel);
-			field.inputEl.on('drop', function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			    var files = ev.dataTransfer.files;
-			    PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
-				field.setValue(v);
-			    });
-			});
-		    }
-		},
-		{
-		    xtype: 'filebutton',
-		    name: 'file',
-		    hidden: !window.FileReader,
-		    text: gettext('Load SSH Key File'),
-		    listeners: {
-			change: function(btn, e, value) {
-			    e = e.event;
-			    var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
-			    PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
-				field.setValue(v);
-			    });
-			    btn.reset();
-			}
-		    }
-		}
-	    ]
-	},
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('Template'),
-	    onlineHelp: 'pct_container_images',
-	    column1: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'tmplstorage',
-		    fieldLabel: gettext('Storage'),
-		    storageContent: 'vztmpl',
-		    autoSelect: true,
-		    allowBlank: false,
-		    bind: {
-			value: '{storage}',
-			nodename: '{nodename}'
-		    }
-		},
-		{
-		    xtype: 'pveFileSelector',
-		    name: 'ostemplate',
-		    storageContent: 'vztmpl',
-		    fieldLabel: gettext('Template'),
-		    bind: {
-			storage: '{storage}',
-			nodename: '{nodename}'
-		    },
-		    allowBlank: false
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveLxcMountPointInputPanel',
-	    title: gettext('Root Disk'),
-	    insideWizard: true,
-	    isCreate: true,
-	    unused: false,
-	    bind: {
-		nodename: '{nodename}',
-		unprivileged: '{unprivileged}'
-	    },
-	    confid: 'rootfs'
-	},
-	{
-	    xtype: 'pveLxcCPUInputPanel',
-	    title: gettext('CPU'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcMemoryInputPanel',
-	    title: gettext('Memory'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcNetworkInputPanel',
-	    title: gettext('Network'),
-	    insideWizard: true,
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    isCreate: true
-	},
-	{
-	    xtype: 'pveLxcDNSInputPanel',
-	    title: gettext('DNS'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-				property : 'key',
-				direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var wizard = this.up('window');
-		    var kv = wizard.getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete' || key === 'tmplstorage') { // ignore
-			    return;
-			}
-			if (key === 'password') { // don't show pw
-			    return;
-			}
-			var html = Ext.htmlEncode(Ext.JSON.encode(value));
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-		delete kv.tmplstorage;
-
-		if (!kv.pool.length) {
-		    delete kv.pool;
-		}
-
-		if (!kv.password.length && kv['ssh-public-keys']) {
-		    delete kv.password;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/lxc',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response, opts){
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid
-			});
-			win.show();
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-Ext.define('PVE.lxc.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveLxcSnapshotTree'],
-
-    onlineHelp: 'pct_snapshots',
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-lxc-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-	    method: 'GET',
-	    success: function(response, options) {
-		var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-	    }
-	});
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    dangerous: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		var taskdescription = Proxmox.Utils.format_task_description('vzrollback', me.vmid);
-		var snaptime = Ext.Date.format(rec.data.snaptime,'Y-m-d H:i:s');
-		var snapname = rec.data.name;
-
-		var msg = Ext.String.format(gettext('{0} to {1} ({2})'),
-		                            taskdescription, snapname, snaptime);
-		msg += '<p>' + gettext('Note: Rollback stops CT') + '</p>';
-
-		return msg;
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', {
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-//		{
-//		    text: gettext('RAM'),
-//		    align: 'center',
-//		    resizable: false,
-//		    dataIndex: 'vmstate',
-//		    width: 50,
-//		    renderer: function(value, metaData, record) {
-//			if (record.data.name !== 'current') {
-//			    return Proxmox.Utils.format_boolean(value);
-//			}
-//		    }
-//		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    resizable: false,
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true,
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-Ext.define('PVE.window.LxcSnapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-var labelWidth = 120;
-
-Ext.define('PVE.lxc.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: Ext.create('PVE.lxc.MemoryInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-
-Ext.define('PVE.lxc.CPUEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('CPU'),
-	    items: Ext.create('PVE.lxc.CPUInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.lxc.CPUInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcCPUInputPanel',
-
-    onlineHelp: 'pct_cpu',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	PVE.Utils.delete_if_default(values, 'cores', '', me.insideWizard);
-	// cpu{limit,unit} aren't in the wizard so create is always false
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	return values;
-    },
-
-    advancedColumn1: [
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    value: 1024,
-	    minValue: 8,
-	    maxValue: 500000,
-	    labelWidth: labelWidth,
-	    allowBlank: false
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'cores',
-		minValue: 1,
-		maxValue: 128,
-		value: me.insideWizard ? 1 : '',
-		fieldLabel: gettext('Cores'),
-		allowBlank: true,
-		deleteEmpty: true,
-		emptyText: gettext('unlimited')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcMemoryInputPanel',
-
-    onlineHelp: 'pct_memory',
-
-    insideWizard: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'memory',
-		minValue: 16,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'swap',
-		minValue: 0,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Swap') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
- 
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.MPResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 120,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-/*jslint confusion: true*/
-/* hidden: boolean and string
- * bind: function and object
- * disabled: boolean and string
- */
-Ext.define('PVE.lxc.MountPointInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcMountPointInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_storage',
-
-    unused: false, // add unused disk imaged
-
-    unprivileged: false,
-
-    vmconfig: {}, // used to select unused disks
-
-    setUnprivileged: function(unprivileged) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.unprivileged = unprivileged;
-	vm.set('unpriv', unprivileged);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || "mp"+values.mpid;
-	values.file = me.down('field[name=file]').getValue();
-
-	if (me.unused) {
-	    confid = "mp"+values.mpid;
-	} else if (me.isCreate) {
-	    values.file = values.hdstorage + ':' + values.disksize;
-	}
-
-	// delete unnecessary fields
-	delete values.mpid;
-	delete values.hdstorage;
-	delete values.disksize;
-	delete values.diskformat;
-
-	var res = {};
-	res[confid] = PVE.Parser.printLxcMountPoint(values);
-	return res;
-    },
-
-
-    setMountPoint: function(mp) {
-	var me = this;
-	var vm = this.getViewModel();
-	vm.set('mptype', mp.type);
-	me.setValues(mp);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.vmconfig = vmconfig;
-	vm.set('unpriv', vmconfig.unprivileged);
-	vm.notify();
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    var name = "mp" + i.toString();
-	    if (!Ext.isDefined(vmconfig[name])) {
-		me.down('field[name=mpid]').setValue(i);
-		return false;
-	    }
-	});
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var vm = me.getViewModel();
-	vm.set('node', nodename);
-	vm.notify();
-	me.down('#diskstorage').setNodename(nodename);
-    },
-
-    controller:  {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=mpid]': {
-		change: function(field, value) {
-		    field.validate();
-		}
-	    },
-	    '#hdstorage': {
-		change: function(field, newValue) {
-		    var me = this;
-		    if (!newValue) {
-			return;
-		    }
-
-		    var rec = field.store.getById(newValue);
-		    if (!rec) {
-			return;
-		    }
-
-		    var vm = me.getViewModel();
-		    vm.set('type', rec.data.type);
-		    vm.notify();
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    vm.set('confid', view.confid);
-	    vm.set('unused', view.unused);
-	    vm.set('node', view.nodename);
-	    vm.set('unpriv', view.unprivileged);
-	    vm.set('hideStorSelector', view.unused || !view.isCreate);
-	    vm.notify();
-	}
-    },
-
-    viewModel: {
-	data: {
-	    unpriv: false,
-	    unused: false,
-	    showStorageSelector: false,
-	    mptype: '',
-	    type: '',
-	    confid: '',
-	    node: ''
-	},
-
-	formulas: {
-	    quota: function(get) {
-		return !(get('type') === 'zfs' ||
-			 get('type') === 'zfspool' ||
-			 get('unpriv') ||
-			 get('isBind'));
-	    },
-	    hasMP: function(get) {
-		return !!get('confid') && !get('unused');
-	    },
-	    isRoot: function(get) {
-		return get('confid') === 'rootfs';
-	    },
-	    isBind: function(get) {
-		return get('mptype') === 'bind';
-	    },
-	    isBindOrRoot: function(get) {
-		return get('isBind') || get('isRoot');
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'mpid',
-	    fieldLabel: gettext('Mount Point ID'),
-	    minValue: 0,
-	    maxValue: PVE.Utils.mp_counts.mps - 1,
-	    hidden: true,
-	    allowBlank: false,
-	    disabled: true,
-	    bind: {
-		hidden: '{hasMP}',
-		disabled: '{hasMP}'
-	    },
-	    validator: function(value) {
-		var me = this.up('inputpanel');
-		if (!me.rendered) {
-		    return;
-		}
-		if (Ext.isDefined(me.vmconfig["mp"+value])) {
-		    return "Mount point is already in use.";
-		}
-		/*jslint confusion: true*/
-		/* returns a string above */
-		return true;
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    itemId: 'diskstorage',
-	    storageContent: 'rootdir',
-	    hidden: true,
-	    autoSelect: true,
-	    selectformat: false,
-	    defaultSize: 8,
-	    bind: {
-		hidden: '{hideStorSelector}',
-		disabled: '{hideStorSelector}',
-		nodename: '{node}'
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    disabled: true,
-	    submitValue: false,
-	    fieldLabel: gettext('Disk image'),
-	    name: 'file',
-	    bind: {
-		hidden: '{!hideStorSelector}'
-	    }
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'textfield',
-	    name: 'mp',
-	    value: '',
-	    emptyText:  gettext('/some/path'),
-	    allowBlank: false,
-	    disabled: true,
-	    fieldLabel: gettext('Path'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'backup',
-	    fieldLabel: gettext('Backup'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isBindOrRoot}'
-	    }
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'quota',
-	    defaultValue: 0,
-	    bind: {
-		disabled: '{!quota}'
-	    },
-	    fieldLabel: gettext('Enable quota'),
-	    listeners: {
-		disable: function() {
-		    this.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'ro',
-	    defaultValue: 0,
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    },
-	    fieldLabel: gettext('Read-only')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'acl',
-	    fieldLabel: 'ACLs',
-	    deleteEmpty: false,
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText],
-		['1', Proxmox.Utils.enabledText],
-		['0', Proxmox.Utils.disabledText]
-	    ],
-	    value: '__default__',
-	    bind: {
-		disabled: '{isBind}'
-	    },
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    inputValue: '0', // reverses the logic
-	    name: 'replicate',
-	    fieldLabel: gettext('Skip replication')
-	}
-    ]
-});
-
-Ext.define('PVE.lxc.MountPointEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    unprivileged: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    unprivileged: me.unprivileged,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-	    subject = gettext('Mount Point');
-	} else {
-	    subject = gettext('Mount Point') + ' (' + me.confid + ')';
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    /*jslint confusion: true*/
-		    /*data is defined as array above*/
-		    var value = response.result.data[me.confid];
-		    /*jslint confusion: false*/
-		    var mp = PVE.Parser.parseLxcMountPoint(value);
-
-		    if (!mp) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
-			me.close();
-			return;
-		    }
-
-		    ipanel.setMountPoint(mp);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.pool.StatusView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-    disabled: true,
-
-    title: gettext('Status'),
-    cwidth1: 150,
-    interval: 30000,
-    //height: 195,
-    initComponent : function() {
-	var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var rows = {
-	    comment: {
-		header: gettext('Comment'), 
-		renderer: Ext.String.htmlEncode,
-		required: true
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/pools/" + pool,
-	    rows: rows
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var statusview = Ext.create('PVE.pool.StatusView', {
-	    pveSelNode: me.pveSelNode,
-	    style: 'padding-top:0px'
-	});
-
-	var rstore = statusview.rstore;
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    defaults: {
-		style: 'padding-top:10px',
-		width: 800
-	    },
-	    items: [ statusview ]
-	});
-
-	me.on('activate', rstore.startUpdate);
-	me.on('destroy', rstore.stopUpdate);	
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    onlineHelp: 'pveum_pools',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-	    hstateid: 'pooltab',
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    xtype: 'pvePoolSummary',
-		    itemId: 'summary'
-		},
-		{
-		    title: gettext('Members'),
-		    xtype: 'pvePoolMembers',
-		    iconCls: 'fa fa-th',
-		    pool: pool,
-		    itemId: 'members'
-		},
-		{
-		    xtype: 'pveACLView',
-		    title: gettext('Permissions'),
-		    iconCls: 'fa fa-unlock',
-		    itemId: 'permissions',
-		    path: '/pool/' + pool
-		}
-	    ]
-	});
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.panel.StorageBase', {
-    extend: 'Proxmox.panel.InputPanel',
-    controller: 'storageEdit',
-
-    type: '',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = me.type;
-	} else {
-	    delete values.storage;
-	}
-
-	values.disable = values.enable ? 0 : 1;
-	delete values.enable;
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1.unshift({
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    name: 'storage',
-	    value: me.storageId || '',
-	    fieldLabel: 'ID',
-	    vtype: 'StorageId',
-	    allowBlank: false
-	});
-
-	me.column2.unshift(
-	    {
-		xtype: 'pveNodeSelector',
-		name: 'nodes',
-		disabled: me.storageId === 'local',
-		fieldLabel: gettext('Nodes'),
-		emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
-		multiSelect: true,
-		autoSelect: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.storageId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/storage';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/storage/' + me.storageId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create(me.paneltype, {
-	    type: me.type,
-	    isCreate: me.isCreate,
-	    storageId: me.storageId
-	});
-
-	Ext.apply(me, {
-            subject: PVE.Utils.format_storage_type(me.type),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    var ctypes = values.content || '';
-
-		    values.content = ctypes.split(',');
-
-		    if (values.nodes) {
-			values.nodes = values.nodes.split(',');
-		    }
-		    values.enable = values.disable ? 0 : 1;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.Upload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveStorageUpload',
-
-    resizable: false,
-
-    modal: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var xhr;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
-
-	var pbar = Ext.create('Ext.ProgressBar', {
-            text: 'Ready',
-	    hidden: true
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    method: 'POST',
-	    waitMsgTarget: true,
-	    bodyPadding: 10,
-	    border: false,
-	    width: 300,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-            },
-	    items: [
-		{
-		    xtype: 'pveContentTypeSelector',
-		    cts: me.contents,
-		    fieldLabel: gettext('Content'),
-		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
-		    allowBlank: false
-		},
-		pbar
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doStandardSubmit = function() {
-	    form.submit({
-		url: "/api2/htmljs" + baseurl,
-		waitMsg: gettext('Uploading file...'),
-		success: function(f, action) {
-		    me.close();
-		},
-		failure: function(f, action) {
-		    var msg = PVE.Utils.extractFormActionError(action);
-                    Ext.Msg.alert(gettext('Error'), msg);
-		}
-	    });
-	};
-
-	var updateProgress = function(per, bytes) {
-	    var text = (per * 100).toFixed(2) + '%';
-	    if (bytes) {
-		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
-	    }
-	    pbar.updateProgress(per, text);
-	};
-
-	var abortBtn = Ext.create('Ext.Button', {
-	    text: gettext('Abort'),
-	    disabled: true,
-	    handler: function() {
-		me.close();
-	    }
-	});
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Upload'),
-	    disabled: true,
-	    handler: function(button) {
-		var fd;
-		try {
-		    fd = new FormData();
-		} catch (err) {
-		    doStandardSubmit();
-		    return;
-		}
-
-		button.setDisabled(true);
-		abortBtn.setDisabled(false);
-
-		var field = form.findField('content');
-		fd.append("content", field.getValue());
-		field.setDisabled(true);
-
-		field = form.findField('filename');
-		var file = field.fileInputEl.dom;
-		fd.append("filename", file.files[0]);
-		field.setDisabled(true);
-
-		pbar.setVisible(true);
-		updateProgress(0);
-
-		xhr = new XMLHttpRequest();
-
-		xhr.addEventListener("load", function(e) {
-		    if (xhr.status == 200) {
-			me.close();
-		    } else {
-			var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
-			var result = Ext.decode(xhr.responseText);
-			result.message = msg;
-			var htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.Msg.alert(gettext('Error'), htmlStatus, function(btn) {
-			    me.close();
-			});
-
-		    }
-		}, false);
-
-		xhr.addEventListener("error", function(e) {
-		    var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
-		    Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			me.close();
-		    });
-		});
-
-		xhr.upload.addEventListener("progress", function(evt) {
-		    if (evt.lengthComputable) {
-			var percentComplete = evt.loaded / evt.total;
-			updateProgress(percentComplete, evt.loaded);
-		    }
-		}, false);
-
-		xhr.open("POST", "/api2/json" + baseurl, true);
-		xhr.send(fd);
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-        Ext.apply(me, {
-            title: gettext('Upload'),
-	    items: me.formPanel,
-	    buttons: [ abortBtn, submitBtn ],
-	    listeners: {
-		close: function() {
-		    if (xhr) {
-			xhr.abort();
-		    }
-		}
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ContentView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveStorageContentView',
-
-    stateful: true,
-    stateId: 'grid-storage-content',
-    viewConfig: {
-	trackOver: false,
-	loadMask: false
-    },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-storage-content',
-	    groupField: 'content',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    },
-	    sorters: {
-		property: 'volid',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	    me.statusStore.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-
-	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
-	    text: gettext('Upload'),
-	    handler: function() {
-		var me = this;
-		var win = Ext.create('PVE.storage.Upload', {
-		    nodename: nodename,
-		    storage: storage,
-		    contents: me.contents
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var imageRemoveButton;
-	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: baseurl + '/'
-	});
-
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && rec.data.content === 'images') {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		me = this;
-
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
-		    reload();
-
-		});
-	    }
-	});
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (rec.data.volid.match(/vzdump-qemu-/)) {
-			    vmtype = 'qemu';
-			} else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
-		    }
-		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s,records,succes) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
-    }
-}, function() {
-
-    Ext.define('pve-storage-content', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'volid', 'content', 'format', 'size', 'used', 'vmid',
-	    'channel', 'id', 'lun',
-	    {
-		name: 'text',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    return PVE.Utils.render_storage_content(value, {}, record);
-		}
-	    }
-	],
-	idProperty: 'volid'
-    });
-
-});
-Ext.define('PVE.storage.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveStorageStatusView',
-
-    height: 230,
-    title: gettext('Status'),
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 30 5 30'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 30
-	},
-	{
-	    itemId: 'enabled',
-	    title: gettext('Enabled'),
-	    printBar: false,
-	    textField: 'disabled',
-	    renderer: Proxmox.Utils.format_neg_boolean
-	},
-	{
-	    itemId: 'active',
-	    title: gettext('Active'),
-	    printBar: false,
-	    textField: 'active',
-	    renderer: Proxmox.Utils.format_boolean
-	},
-	{
-	    itemId: 'content',
-	    title: gettext('Content'),
-	    printBar: false,
-	    textField: 'content',
-	    renderer: PVE.Utils.format_content_types
-	},
-	{
-	    itemId: 'type',
-	    title: gettext('Type'),
-	    printBar: false,
-	    textField: 'type',
-	    renderer: PVE.Utils.format_storage_type
-	},
-	{
-	    xtype: 'box',
-	    height: 10
-	},
-	{
-	    itemId: 'usage',
-	    title: gettext('Usage'),
-	    valueField: 'used',
-	    maxField: 'total'
-	}
-    ],
-
-    updateTitle: function() {
-	return;
-    }
-});
-Ext.define('PVE.storage.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStorageSummary',
-    scrollable: true,
-    bodyPadding: 5,
-    tbar: [
-	'->',
-	{
-	    xtype: 'proxmoxRRDTypeSelector'
-	}
-    ],
-    layout: {
-	type: 'column'
-    },
-    defaults: {
-	padding: 5,
-	columnWidth: 1
-    },
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var rstore  = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/storage/" + storage + "/status",
-	    interval: 1000
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl:  "/api2/json/nodes/" + nodename + "/storage/" + storage + "/rrddata",
-	    model: 'pve-rrd-storage'
-	});
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'pveStorageStatusView',
-		    pveSelNode: me.pveSelNode,
-		    rstore: rstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Usage'),
-		    fields: ['total','used'],
-		    fieldTitles: ['Total Size', 'Used Size'],
-		    store: rrdstore
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.Browser', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.storage.Browser',
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storeid = me.pveSelNode.data.storage;
-	if (!storeid) {
-	    throw "no storage ID specified";
-	}
-
-
-	me.items = [
-	    {
-		title: gettext('Summary'),
-		xtype: 'pveStorageSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    }
-	];
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Storage {0} on node {1}"),
-				     "'" + storeid + "'", "'" + nodename + "'"),
-	    hstateid: 'storagetab'
-	});
-
-	if (caps.storage['Datastore.Allocate'] ||
-	    caps.storage['Datastore.AllocateSpace'] ||
-	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
-	}
-
-	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.storage.DirInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_directory',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'path',
-		value: '',
-		fieldLabel: gettext('Directory'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.NFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveNFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'path',
-    displayField: 'path',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.nfsServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.nfsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.nfsServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'path', 'options' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/nfs'
-	    }
-	});
-
-	store.sort('path', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.NFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_nfs',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    // hack: for now we always create nvf v3
-	    // fixme: make this configurable
-	    values.options = 'vers=3';
-	}
-
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=export]');
-			    exportField.setServer(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'pveNFSScan' : 'displayfield',
-		name: 'export',
-		value: '',
-		fieldLabel: 'Export',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.CIFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCIFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'share',
-    displayField: 'share',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.cifsServer) {
-	    me.store.removeAll();
-	}
-
-	var params = {};
-	if (me.cifsUsername && me.cifsPassword) {
-	    params.username =  me.cifsUsername;
-	    params.password = me.cifsPassword;
-	}
-
-	if (me.cifsDomain) {
-	    params.domain = me.cifsDomain;
-	}
-
-	me.store.getProxy().setExtraParams(params);
-	me.allQuery = me.cifsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	this.cifsServer = server;
-    },
-
-    setUsername: function(username) {
-	this.cifsUsername = username;
-    },
-
-    setPassword: function(password) {
-	this.cifsPassword = password;
-    },
-
-    setDomain: function(domain) {
-	this.cifsDomain = domain;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['description', 'share'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/cifs'
-	    }
-	});
-	store.sort('share', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.CIFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_cifs',
-
-    initComponent : function() {
-	var me = this;
-
-	var passwordfield = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    inputType: 'password',
-	    name: 'password',
-	    value: me.isCreate ? '' : '********',
-	    fieldLabel: gettext('Password'),
-	    allowBlank: false,
-	    disabled: me.isCreate,
-	    minLength: 1,
-	    listeners: {
-		change: function(f, value) {
-
-		    if (me.isCreate) {
-			var exportField = me.down('field[name=share]');
-			exportField.setPassword(value);
-		    }
-		}
-	    }
-	});
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=share]');
-			    exportField.setServer(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: '',
-		fieldLabel: gettext('Username'),
-		emptyText: gettext('Guest user'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (!me.isCreate) {
-			    return;
-			}
-			var exportField = me.down('field[name=share]');
-			exportField.setUsername(value);
-
-			if (value == "") {
-			    passwordfield.disable();
-			} else {
-			    passwordfield.enable();
-			}
-			passwordfield.validate();
-		    }
-		}
-	    },
-	    passwordfield,
-	    {
-		xtype: me.isCreate ? 'pveCIFSScan' : 'displayfield',
-		name: 'share',
-		value: '',
-		fieldLabel: 'Share',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'domain',
-		value: me.isCreate ? '' : undefined,
-		fieldLabel: gettext('Domain'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-
-			    var exportField = me.down('field[name=share]');
-			    exportField.setDomain(value);
-			}
-		    }
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.GlusterFsScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveGlusterFsScan',
-
-    queryParam: 'server',
-
-    valueField: 'volname',
-    displayField: 'volname',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: 'Scanning...',
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.glusterServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.glusterServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.glusterServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'volname' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/glusterfs'
-	    }
-	});
-
-	store.sort('volname', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.GlusterFsInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_glusterfs',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var volumeField = me.down('field[name=volume]');
-			    volumeField.setServer(value);
-			    volumeField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		name: 'server2',
-		value: '',
-		fieldLabel: gettext('Second Server'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'pveGlusterFsScan' : 'displayfield',
-		name: 'volume',
-		value: '',
-		fieldLabel: 'Volume name',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'iso', 'backup', 'vztmpl', 'snippets'],
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.IScsiScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveIScsiScan',
-
-    queryParam: 'portal',
-    valueField: 'target',
-    displayField: 'target',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.portal) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.portal;
-
-	me.callParent();
-    },
-
-    setPortal: function(portal) {
-	var me = this;
-
-	me.portal = portal;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'target', 'portal' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/iscsi'
-	    }
-	});
-
-	store.sort('target', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.IScsiInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_open_iscsi',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	values.content = values.luns ? 'images' : 'none';
-	delete values.luns;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	values.luns = (values.content.indexOf('images') !== -1) ? true : false;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: 'Portal',
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=target]');
-			    exportField.setPortal(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		readOnly: !me.isCreate,
-		xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: 'Target',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'checkbox',
-		name: 'luns',
-		checked: true,
-		fieldLabel: gettext('Use LUNs directly')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.VgSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveVgSelector',
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'vg', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	store.sort('vg', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseStorageSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseStorageSelector',
-
-    existingGroupsText: gettext("Existing volume groups"),
-    queryMode: 'local',
-    editable: false,
-    value: '',
-    valueField: 'storage',
-    displayField: 'text',
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {
-		addRecords: true,
-		params: {
-		    type: 'iscsi'
-		}
-	    },
-	    fields: [ 'storage', 'type', 'content',
-		      {
-			  name: 'text',
-			  convert: function(value, record) {
-			      if (record.data.storage) {
-				  return record.data.storage + " (iSCSI)";
-			      } else {
-				  return me.existingGroupsText;
-			      }
-			  }
-		      }],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/storage/'
-	    }
-	});
-
-	store.loadData([{ storage: '' }], true);
-
-	store.sort('storage', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LVMInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvm',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.VgSelector', {
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		allowBlank: false
-	    });
-
-	    var baseField = Ext.createWidget('pveFileSelector', {
-		name: 'base',
-		hidden: true,
-		disabled: true,
-		nodename: 'localhost',
-		storageContent: 'images',
-		fieldLabel: gettext('Base volume'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseStorageSelector',
-		name: 'basesel',
-		fieldLabel: gettext('Base storage'),
-		submitValue: false,
-		listeners: {
-		    change: function(f, value) {
-			if (value) {
-			    vgnameField.setVisible(true);
-			    vgnameField.setDisabled(false);
-			    vgField.setVisible(false);
-			    vgField.setDisabled(true);
-			    baseField.setVisible(true);
-			    baseField.setDisabled(false);
-			} else {
-			    vgnameField.setVisible(false);
-			    vgnameField.setDisabled(true);
-			    vgField.setVisible(true);
-			    vgField.setDisabled(false);
-			    baseField.setVisible(false);
-			    baseField.setDisabled(true);
-			}
-			baseField.setStorage(value);
-		    }
-		}
-	    });
-
-	    me.column1.push(baseField);
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	// here value is an array, 
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.TPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveTPSelector',
-
-    queryParam: 'vg',
-    valueField: 'lv',
-    displayField: 'lv',
-    editable: false,
-
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.vg) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.vg;
-
-	me.callParent();
-    },
-
-    setVG: function(myvg) {
-	var me = this;
-
-	me.vg = myvg;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'lv' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin'
-	    }
-	});
-
-	store.sort('lv', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseVGSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseVGSelector',
-
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {},
-	    fields: [ 'vg', 'size', 'free'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LvmThinInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvmthin',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	var thinpoolField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'thinpool',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Thin Pool'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.TPoolSelector', {
-		name: 'thinpool',
-		fieldLabel: gettext('Thin Pool'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseVGSelector',
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    vgField.setVG(value);
-			    vgField.setValue('');
-			}
-		    }
-		}
-	    });
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	me.column1.push(thinpoolField);
-
-	// here value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.CephFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'storage_cephfs',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'cephfs';
-
-	me.column1 = [];
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		value: '',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: 'admin',
-		bind:  {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['backup', 'iso', 'vztmpl', 'snippets'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: 'backup',
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged cephFS')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.Ceph.Model', {
-    extend: 'Ext.app.ViewModel',
-    alias: 'viewmodel.cephstorage',
-
-    data: {
-	pveceph: true,
-	pvecephPossible: true
-    }
-});
-
-Ext.define('PVE.storage.Ceph.Controller', {
-    extend: 'PVE.controller.StorageEdit',
-    alias: 'controller.cephstorage',
-
-    control: {
-	'#': {
-	    afterrender: 'queryMonitors'
-	},
-	'textfield[name=username]': {
-	    disable: 'resetField'
-	},
-	'displayfield[name=monhost]': {
-	    enable: 'queryMonitors'
-	},
-	'textfield[name=monhost]': {
-	    disable: 'resetField',
-	    enable: 'resetField'
-	}
-    },
-    resetField: function(field) {
-	field.reset();
-    },
-    queryMonitors: function(field, newVal, oldVal) {
-	// we get called with two signatures, the above one for a field
-	// change event and the afterrender from the view, this check only
-	// can be true for the field change one and omit the API request if
-	// pveceph got unchecked - as it's not needed there.
-	if (field && !newVal && oldVal) {
-	    return;
-	}
-	var view = this.getView();
-	var vm = this.getViewModel();
-	if (!(view.isCreate || vm.get('pveceph'))) {
-	    return; // only query on create or if editing a pveceph store
-	}
-
-	var monhostField = this.lookupReference('monhost');
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/json/nodes/localhost/ceph/mon',
-	    method: 'GET',
-	    scope: this,
-	    callback: function(options, success, response) {
-		var data = response.result.data;
-		if (response.status === 200) {
-		    if (data.length > 0) {
-			var monhost = Ext.Array.pluck(data, 'name').sort().join(',');
-			monhostField.setValue(monhost);
-			monhostField.resetOriginalValue();
-			if (view.isCreate) {
-			    vm.set('pvecephPossible', true);
-			}
-		    } else {
-			vm.set('pveceph', false);
-		    }
-		} else {
-		    vm.set('pveceph', false);
-		    vm.set('pvecephPossible', false);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.storage.RBDInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'ceph_rados_block_devices',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'rbd';
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveCephPoolSelector',
-		nodename: me.nodename,
-		name: 'pool',
-		bind: {
-		    disabled: '{!pveceph}',
-		    submitValue: '{pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },{
-		xtype: 'textfield',
-		name: 'pool',
-		value: 'rbd',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		nodename: me.nodename,
-		name: 'pool',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		value: 'admin',
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'rootdir'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: ['images'],
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'krbd',
-		uncheckedValue: 0,
-		fieldLabel: 'KRBD'
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool')
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.SheepdogInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-            values.content = 'images';
-	}
-
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '127.0.0.1:7000',
-		fieldLabel: gettext('Gateway'),
-		allowBlank: false
-	    }
-	];
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.ZFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    isLIO: false,
-	    isComstar: true,
-	    hasWriteCacheOption: true
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[name=iscsiprovider]': {
-		change: 'changeISCSIProvider'
-	    }
-	},
-	changeISCSIProvider: function(f, newVal, oldVal) {
-	    var vm = this.getViewModel();
-	    vm.set('isLIO', newVal === 'LIO');
-	    vm.set('isComstar', newVal === 'comstar');
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.content = 'images';
-	}
-
-	values.nowritecache = values.writecache ? 0 : 1;
-	delete values.writecache;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function diff(values) {
-	values.writecache = values.nowritecache ? 0 : 1;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: gettext('Portal'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'blocksize',
-		value: '4k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: gettext('Target'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_tg',
-		value: '',
-		fieldLabel: gettext('Target group'),
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		allowBlank: true
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: me.isCreate ? 'pveiScsiProviderSelector' : 'displayfield',
-		name: 'iscsiprovider',
-		value: 'comstar',
-		fieldLabel: gettext('iSCSI Provider'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'writecache',
-		checked: true,
-		bind: me.isCreate ? { disabled: '{!hasWriteCacheOption}' } : { hidden: '{!hasWriteCacheOption}' },
-		uncheckedValue: 0,
-		fieldLabel: gettext('Write cache')
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_hg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		fieldLabel: gettext('Host group'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'lio_tpg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
-		allowBlank: false,
-		fieldLabel: gettext('Target portal group')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.ZFSPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveZFSPoolSelector',
-    valueField: 'pool',
-    displayField: 'pool',
-    queryMode: 'local',
-    editable: false,
-    listConfig: {
-	loadingText: gettext('Scanning...')
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'pool', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/zfs'
-	    }
-	});
-
-	store.sort('pool', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ZFSPoolInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_zfspool',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
-		name: 'pool',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	} else {
-	    me.column1.push(Ext.createWidget('displayfield', {
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	}
-
-	// value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push(
-	    {xtype: 'pveContentTypeSelector',
-	     cts: ['images', 'rootdir'],
-	     fieldLabel: gettext('Content'),
-	     name: 'content',
-	     value: ['images', 'rootdir'],
-	     multiSelect: true,
-	     allowBlank: false
-	});
-	/*jslint confusion: false*/
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'blocksize',
-		emptyText: '8k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.StatusView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAStatusView'],
-
-    onlineHelp: 'chapter_ha_manager',
-
-    sortPriority: {
-	quorum: 1,
-	master: 2,
-	lrm: 3,
-	service: 4
-    },
-    
-    initComponent : function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sortAfterUpdate: true,
-	    sorters: [{
-		sorterFn: function(rec1, rec2) {
-		    var p1 = me.sortPriority[rec1.data.type];
-		    var p2 = me.sortPriority[rec2.data.type];
-		    return (p1 !== p2) ? ((p1 > p2) ? 1 : -1) : 0;
-		}
-	    }],
-	    filters: {
-		property: 'type',
-		value: 'service',
-		operator: '!='
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 80,
-		    flex: 1,
-		    dataIndex: 'status'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-    }
-}, function() {
-
-    Ext.define('pve-ha-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'type', 'node', 'status', 'sid',
-	    'state', 'group', 'comment',
-	    'max_restart', 'max_relocate', 'type',
-	    'crm_state', 'request_state'
-	],
-	idProperty: 'id'
-    });
-
-});
-Ext.define('PVE.ha.Status', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveHAStatus',
-
-    onlineHelp: 'chapter_ha_manager',
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-	    interval: me.interval,
-	    model: 'pve-ha-status',
-	    storeid: 'pve-store-' + (++Ext.idSeed),
-	    groupField: 'type',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/ha/status/current'
-	    }
-	});
-
-	me.items = [{
-	    xtype: 'pveHAStatusView',
-	    title: gettext('Status'),
-	    rstore: me.rstore,
-	    border: 0,
-	    collapsible: true,
-	    padding: '0 0 20 0'
-	},{
-	    xtype: 'pveHAResourcesView',
-	    flex: 1,
-	    collapsible: true,
-	    title: gettext('Resources'),
-	    border: 0,
-	    rstore: me.rstore
-	}];
-
-	me.callParent();
-	me.on('activate', me.rstore.startUpdate);
-    }
-});
-Ext.define('PVE.ha.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveHAGroupSelector'],
-
-    value: [],
-    autoSelect: false,
-    valueField: 'group',
-    displayField: 'group',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		width: 100,
-		sortable: true,
-		dataIndex: 'group'
-	    },
-	    {
-		header: gettext('Nodes'),
-		width: 100,
-		sortable: false,
-		dataIndex: 'nodes'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 1,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode
-	    }
-	]
-    },
-    store: {
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getStore().load();
-    }
-
-}, function() {
-
-    Ext.define('pve-ha-groups', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'group', 'type', 'digest', 'nodes', 'comment',
-	    {
-		name : 'restricted',
-		type: 'boolean'
-	    },
-	    {
-		name : 'nofailback',
-		type: 'boolean'
-	    }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/cluster/ha/groups"
-	},
-	idProperty: 'group'
-    });
-});
-Ext.define('PVE.ha.VMResourceInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_resource_config',
-    vmid: undefined,
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.vmid) {
-	    values.sid = values.vmid;
-	}
-	delete values.vmid;
-
-	PVE.Utils.delete_if_default(values, 'group', '', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_restart', '1', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_relocate', '1', me.isCreate);
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var MIN_QUORUM_VOTES = 3;
-
-	var disabledHint = Ext.createWidget({
-	    xtype: 'displayfield', // won't get submitted by default
-	    userCls: 'pve-hint',
-	    value: 'Disabling the resource will stop the guest system. ' +
-	    'See the online help for details.',
-	    hidden: true
-	});
-
-	var fewVotesHint = Ext.createWidget({
-	    itemId: 'fewVotesHint',
-	    xtype: 'displayfield',
-	    userCls: 'pve-hint',
-	    value: 'At least three quorum votes are recommended for reliable HA.',
-	    hidden: true
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/config/nodes',
-	    method: 'GET',
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var nodes = response.result.data;
-		var votes = 0;
-		Ext.Array.forEach(nodes, function(node) {
-		    var vote = parseInt(node.quorum_votes, 10); // parse as base 10
-		    votes += vote || 0; // parseInt might return NaN, which is false
-		});
-
-		if (votes < MIN_QUORUM_VOTES) {
-		    fewVotesHint.setVisible(true);
-		}
-	    }
-	});
-
-	/*jslint confusion: true */
-	var vmidStore = (me.vmid) ? {} : {
-	    model: 'PVEResources',
-	    autoLoad: true,
-	    sorters: 'vmid',
-	    filters: [
-		{
-		    property: 'type',
-		    value: /lxc|qemu/
-		},
-		{
-		    property: 'hastate',
-		    value: /unmanaged/
-		}
-	    ]
-	};
-
-	// value is a string above, but a number below
-	me.column1 = [
-	    {
-		xtype: me.vmid ? 'displayfield' : 'vmComboSelector',
-		submitValue: me.isCreate,
-		name: 'vmid',
-		fieldLabel: (me.vmid && me.guestType === 'ct') ? 'CT' : 'VM',
-		value: me.vmid,
-		store: vmidStore,
-		validateExists: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_restart',
-		fieldLabel: gettext('Max. Restart'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_relocate',
-		fieldLabel: gettext('Max. Relocate'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.column2 = [
-	    {
-		xtype: 'pveHAGroupSelector',
-		name: 'group',
-		fieldLabel: gettext('Group')
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'state',
-		value: 'started',
-		fieldLabel: gettext('Request State'),
-		comboItems: [
-		    ['started', 'started'],
-		    ['stopped', 'stopped'],
-		    ['ignored', 'ignored'],
-		    ['disabled', 'disabled']
-		],
-		listeners: {
-		    'change': function(field, newValue) {
-			if (newValue === 'disabled') {
-			    disabledHint.setVisible(true);
-			}
-			else {
-			    if (disabledHint.isVisible()) {
-				disabledHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    disabledHint
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    fewVotesHint
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.VMResourceEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmid: undefined,
-    guestType: undefined,
-    isCreate: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	if (me.isCreate === undefined) {
-	    me.isCreate = !me.vmid;
-	}
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/resources';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/resources/' + me.vmid;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.VMResourceInputPanel', {
-	    isCreate: me.isCreate,
-	    vmid: me.vmid,
-	    guestType: me.guestType
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Resource') + ': ' + gettext('Container') +
-	    '/' + gettext('Virtual Machine'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    var regex =  /^(\S+):(\S+)$/;
-		    var res = regex.exec(values.sid);
-
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			throw "got unexpected resource type";
-		    }
-
-		    values.vmid = res[2];
-		    
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.ResourcesView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAResourcesView'],
-
-    onlineHelp: 'ha_manager_resources',
-
-    stateful: true,
-    stateId: 'grid-ha-resources',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!me.rstore) {
-	    throw "no store given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    filters: {
-		property: 'type',
-		value: 'service'
-	    }
-	});
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var render_error = function(dataIndex, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors[dataIndex];
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    var sid = rec.data.sid;
-	    
-	    var regex =  /^(\S+):(\S+)$/;
-	    var res = regex.exec(sid);
-
-	    if (res[1] !== 'vm' && res[1] !== 'ct') {
-		return;
-	    }
-	    var guestType = res[1];
-	    var vmid = res[2];
-	    
-            var win = Ext.create('PVE.ha.VMResourceEdit',{
-                guestType: guestType,
-                vmid: vmid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/resources/',
-	    getUrl: function(rec) {
-		var me = this;
-		return me.baseurl + '/' + rec.get('sid');
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.VMResourceEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'sid'
-		},
-		{
-		    header: gettext('State'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Request State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'started';
-		    },
-		    dataIndex: 'request_state'
-		},
-		{
-		    header: gettext('CRM State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    dataIndex: 'crm_state'
-		},
-		{
-		    header: gettext('Max. Restart'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || '1';
-		    },
-		    dataIndex: 'max_restart'
-		},
-		{
-		    header: gettext('Max. Relocate'),
-		    width: 100,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || '1';
-		    },
-		    dataIndex: 'max_relocate'
-		},
-		{
-		    header: gettext('Group'),
-		    width: 200,
-		    sortable: true,
-		    renderer: function(value, metaData, record) {
-			return render_error('group', value, metaData, record);
-		    },
-		    dataIndex: 'group'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-resources', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	  'sid', 'state', 'digest', 'errors', 'group', 'comment',
-	  'max_restart', 'max_relocate', 'type', 'status', 'node',
-	  'crm_state', 'request_state'
-	],
-	idProperty: 'sid'
-    });
-
-});
-Ext.define('PVE.ha.GroupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_groups',
-
-    groupId: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = 'group';
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var update_nodefield, update_node_selection;
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    update_nodefield(selected);
-		}
-	    }
-	});
-
-	// use already cached data to avoid an API call
-	var data = PVE.data.ResourceStore.getNodes();
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'node', 'mem', 'cpu', 'priority' ],
-	    data: data,
-	    proxy: {
-		type: 'memory',
-		reader: {type: 'json'}
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var nodegrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Node'),
-		    flex: 1,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Memory usage') + " %",
-		    renderer: PVE.Utils.render_mem_usage_percent,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'mem'
-		},
-		{
-		    header: gettext('CPU usage'),
-		    renderer: PVE.Utils.render_cpu,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'cpu'
-		},
-		{
-		    header: 'Priority',
-		    xtype: 'widgetcolumn',
-		    dataIndex: 'priority',
-		    sortable: true,
-		    stopSelection: true,
-		    widget: {
-			xtype: 'proxmoxintegerfield',
-			minValue: 0,
-			maxValue: 1000,
-			isFormField: false,
-			listeners: {
-			    change: function(numberfield, value, old_value) {
-				var record = numberfield.getWidgetRecord();
-				record.set('priority', value);
-				update_nodefield(sm.getSelection());
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	var nodefield = Ext.create('Ext.form.field.Hidden', {
-	    name: 'nodes',
-	    value: '',
-	    listeners: {
-		change: function (nodefield, value) {
-		    update_node_selection(value);
-		}
-	    },
-	    isValid: function () {
-		var value = nodefield.getValue();
-		return (value && 0 !== value.length);
-	    }
-	});
-
-	update_node_selection = function(string) {
-	    sm.deselectAll(true);
-
-	    string.split(',').forEach(function (e, idx, array) {
-		var res = e.split(':');
-
-		store.each(function(record) {
-		    var node = record.get('node');
-
-		    if (node == res[0]) {
-			sm.select(record, true);
-			record.set('priority', res[1]);
-			record.commit();
-		    }
-		});
-	    });
-	    nodegrid.reconfigure(store);
-
-	};
-
-	update_nodefield = function(selected) {
-	    var nodes = '';
-	    var first_iteration = true;
-	    Ext.Array.each(selected, function(record) {
-		if (!first_iteration) {
-		    nodes += ',';
-		}
-		first_iteration = false;
-
-		nodes += record.data.node;
-		if (record.data.priority) {
-		    nodes += ':' + record.data.priority;
-		}
-	    });
-
-	    // nodefield change listener calls us again, which results in a
-	    // endless recursion, suspend the event temporary to avoid this
-	    nodefield.suspendEvent('change');
-	    nodefield.setValue(nodes);
-	    nodefield.resumeEvent('change');
-	};
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'group',
-		value: me.groupId || '',
-		fieldLabel: 'ID',
-		vtype: 'StorageId',
-		allowBlank: false
-	    },
-	    nodefield
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'restricted',
-		uncheckedValue: 0,
-		fieldLabel: 'restricted'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'nofailback',
-		uncheckedValue: 0,
-		fieldLabel: 'nofailback'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    nodegrid
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    groupId: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	me.isCreate = !me.groupId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/groups';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
-	    isCreate: me.isCreate,
-	    groupId: me.groupId
-	});
-
-	Ext.apply(me, {
-            subject: gettext('HA Group'),
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.GroupsView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAGroupsView'],
-
-    onlineHelp: 'ha_manager_groups',
-
-    stateful: true,
-    stateId: 'grid-ha-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-	});
-	
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-            var win = Ext.create('PVE.ha.GroupEdit',{
-                groupId: rec.data.group
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/groups/',
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.GroupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Group'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'group'
-		},
-		{
-		    header: 'restricted',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'restricted'
-		},
-		{
-		    header: 'nofailback',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'nofailback'
-		},
-		{
-		    header: gettext('Nodes'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'nodes'
-		},
-		{
-		    header: gettext('Comment'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.FencingView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveFencingView'],
-
-    onlineHelp: 'ha_manager_fencing',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-fencing',
-	    data: []
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false,
-		deferEmptyText: false,
-		emptyText: 'Use watchdog based fencing.'
-	    },
-	    columns: [
-		{
-		    header: 'Node',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Command'),
-		    flex: 1,
-		    dataIndex: 'command'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-fencing', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'node', 'command', 'digest'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSummary',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: 'column',
-
-    defaults: {
-	padding: 5,
-	plugins: 'responsive',
-	responsiveConfig: {
-	    'width < 1900': {
-		columnWidth: 1
-	    },
-	    'width >= 1900': {
-		columnWidth: 0.5
-	    }
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'dcHealth',
-	    xtype: 'pveDcHealth'
-	},
-	{
-	    itemId: 'dcGuests',
-	    xtype: 'pveDcGuests'
-	},
-	{
-	    title: gettext('Resources'),
-	    xtype: 'panel',
-	    minHeight: 250,
-	    bodyPadding: 5,
-	    layout: 'hbox',
-	    defaults: {
-		xtype: 'proxmoxGauge',
-		flex: 1
-	    },
-	    items:[
-		{
-		    title: gettext('CPU'),
-		    itemId: 'cpu'
-		},
-		{
-		    title: gettext('Memory'),
-		    itemId: 'memory'
-		},
-		{
-		    title: gettext('Storage'),
-		    itemId: 'storage'
-		}
-	    ]
-	},
-	{
-	    itemId: 'nodeview',
-	    xtype: 'pveDcNodeView',
-	    height: 250
-	},
-	{
-	    title: gettext('Subscriptions'),
-	    height: 220,
-	    items: [
-		{
-		    itemId: 'subscriptions',
-		    xtype: 'pveHealthWidget',
-		    userCls: 'pointer',
-		    listeners: {
-			element: 'el',
-			click: function() {
-			    if (this.component.userCls === 'pointer') {
-				window.open('https://www.proxmox.com/en/proxmox-ve/pricing', '_blank');
-			    }
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-status',
-	    model: 'pve-dc-nodes',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/cluster/status"
-	    }
-	});
-
-	var gridstore = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    filters: {
-		property: 'type',
-		value: 'node'
-	    },
-	    sorters: {
-		property: 'id',
-		direction: 'ASC'
-	    }
-	});
-
-	me.callParent();
-
-	me.getComponent('nodeview').setStore(gridstore);
-
-	var gueststatus = me.getComponent('dcGuests');
-
-	var cpustat = me.down('#cpu');
-	var memorystat = me.down('#memory');
-	var storagestat = me.down('#storage');
-	var sp = Ext.state.Manager.getProvider();
-
-	me.mon(PVE.data.ResourceStore, 'load', function(curstore, results) {
-	    me.suspendLayout = true;
-
-	    var cpu = 0;
-	    var maxcpu = 0;
-
-	    var nodes = 0;
-
-	    var memory = 0;
-	    var maxmem = 0;
-
-	    var countedStorages = {};
-	    var used = 0;
-	    var total = 0;
-	    var usableStorages = {};
-	    var storages = sp.get('dash-storages') || '';
-	    storages.split(',').forEach(function(storage){
-		if (storage !== '') {
-		    usableStorages[storage] = true;
-		}
-	    });
-
-	    var qemu = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var lxc = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var error = 0;
-
-	    var i;
-
-	    for (i = 0; i < results.length; i++) {
-		var item = results[i];
-		switch(item.data.type) {
-		    case 'node':
-			cpu += (item.data.cpu * item.data.maxcpu);
-			maxcpu += item.data.maxcpu || 0;
-			memory += item.data.mem || 0;
-			maxmem += item.data.maxmem || 0;
-			nodes++;
-
-			// update grid also
-			var griditem = gridstore.getById(item.data.id);
-			if (griditem) {
-			    griditem.set('cpuusage', item.data.cpu);
-			    var max = item.data.maxmem || 1;
-			    var val = item.data.mem || 0;
-			    griditem.set('memoryusage', val/max);
-			    griditem.set('uptime', item.data.uptime);
-			    griditem.commit(); //else it marks the fields as dirty
-			}
-			break;
-		    case 'storage':
-			if (!Ext.Object.isEmpty(usableStorages)) {
-			    if (usableStorages[item.data.id] === true) {
-				used += item.data.disk;
-				total += item.data.maxdisk;
-			    }
-			    break;
-			}
-			if (!countedStorages[item.data.storage] ||
-			    (item.data.storage === 'local' &&
-			    !countedStorages[item.data.id])) {
-			    used += item.data.disk;
-			    total += item.data.maxdisk;
-
-			    countedStorages[item.data.storage === 'local'?item.data.id:item.data.storage] = true;
-			}
-			break;
-		    case 'qemu':
-			qemu[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    case 'lxc':
-			lxc[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    default: break;
-		}
-	    }
-
-	    var text = Ext.String.format(gettext('of {0} CPU(s)'), maxcpu);
-	    cpustat.updateValue((cpu/maxcpu), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(memory), PVE.Utils.render_size(maxmem));
-	    memorystat.updateValue((memory/maxmem), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(used), PVE.Utils.render_size(total));
-	    storagestat.updateValue((used/total), text);
-
-	    gueststatus.updateValues(qemu,lxc,error);
-
-	    me.suspendLayout = false;
-	    me.updateLayout(true);
-	});
-
-	var dcHealth = me.getComponent('dcHealth');
-	me.mon(rstore, 'load', dcHealth.updateStatus, dcHealth);
-
-	var subs = me.down('#subscriptions');
-	me.mon(rstore, 'load', function(store, records, success) {
-	    var i;
-	    var level;
-	    var curlevel;
-	    for (i = 0; i < records.length; i++) {
-		if (records[i].get('type') !== 'node') {
-		    continue;
-		}
-
-		curlevel = records[i].get('level');
-		if (level === undefined || !curlevel) {
-		    level = curlevel;
-		    continue;
-		}
-
-		if (level !== curlevel) {
-		    break;
-		}
-	    }
-
-	    if (level === '') {
-		subs.setData({
-		    title: gettext('No Subscription'),
-		    iconCls: PVE.Utils.get_health_icon('critical', true),
-		    text: gettext('You have at least one node without subscription.')
-		});
-		subs.setUserCls('pointer');
-	    } else if (level !== curlevel) {
-		subs.setData({
-		    title: gettext('Mixed Subscriptions'),
-		    iconCls: PVE.Utils.get_health_icon('warning', true),
-		    text: gettext('Warning: Your subscription levels are not the same.')
-		});
-		subs.setUserCls('pointer');
-	    } else {
-		subs.setData({
-		    title: PVE.Utils.render_support_level(level),
-		    iconCls: PVE.Utils.get_health_icon('good', true),
-		    text: gettext('Your subscription status is valid.')
-		});
-		subs.setUserCls('');
-	    }
-	});
-
-	me.on('destroy', function(){
-	    rstore.stopUpdate();
-	});
-
-	rstore.startUpdate();
-    }
-
-});
-Ext.define('PVE.window.ReplicaEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveReplicaEdit',
-
-    subject: gettext('Replication Job'),
-
-
-    url: '/cluster/replication',
-    method: 'POST',
-
-    initComponent: function() {
-	var me = this;
-
-	var vmid = me.pveSelNode.data.vmid;
-	var nodename = me.pveSelNode.data.node;
-
-	var items = [];
-
-	items.push({
-	    xtype: (me.isCreate && !vmid)?'pveGuestIDSelector':'displayfield',
-	    name: 'guest',
-	    fieldLabel: 'CT/VM ID',
-	    value: vmid || ''
-	});
-
-	items.push(
-	    {
-		xtype: me.isCreate ? 'pveNodeSelector':'displayfield',
-		name: 'target',
-		disallowedNodes: [nodename],
-		allowBlank: false,
-		onlineValidator: true,
-		fieldLabel: gettext("Target")
-	    },
-	    {
-		xtype: 'pveCalendarEvent',
-		fieldLabel: gettext('Schedule'),
-		emptyText: '*/15 - ' + Ext.String.format(gettext('Every {0} minutes'), 15),
-		name: 'schedule'
-	    },
-	    {
-		xtype: 'numberfield',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		step: 1,
-		minValue: 1,
-		emptyText: gettext('unlimited'),
-		name: 'rate'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Comment'),
-		name: 'comment'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enabled',
-		defaultValue: 'on',
-		checked: true,
-		fieldLabel: gettext('Enabled')
-	    }
-	);
-
-	me.items = [
-	    {
-		xtype: 'inputpanel',
-		itemId: 'ipanel',
-		onlineHelp: 'pvesr_schedule_time_format',
-
-		onGetValues: function(values) {
-		    var me = this.up('window');
-
-		    values.disable = values.enabled ? 0 : 1;
-		    delete values.enabled;
-
-		    PVE.Utils.delete_if_default(values, 'rate', '', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'disable', 0, me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'schedule', '*/15', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'comment', '', me.isCreate);
-
-		    if (me.isCreate) {
-			values.type = 'local';
-			var vm = vmid || values.guest;
-			var id = -1;
-			if (me.highestids[vm] !== undefined) {
-			    id = me.highestids[vm];
-			}
-			id++;
-			values.id = vm + '-' + id.toString();
-			delete values.guest;
-		    }
-		    return values;
-		},
-		items: items
-	    }
-	];
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var jobs = response.result.data;
-		    var highestids = {};
-		    Ext.Array.forEach(jobs, function(job) {
-			var match = /^([0-9]+)\-([0-9]+)$/.exec(job.id);
-			if (match) {
-			    var vmid = parseInt(match[1],10);
-			    var id = parseInt(match[2],10);
-			    if (highestids[vmid] < id ||
-				highestids[vmid] === undefined) {
-				highestids[vmid] = id;
-			    }
-			}
-		    });
-
-		    me.highestids = highestids;
-		}
-	    });
-
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    response.result.data.enabled = !response.result.data.disable;
-		    me.setValues(response.result.data);
-		    me.digest = response.result.data.digest;
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-/* callback is a function and string */
-Ext.define('PVE.grid.ReplicaView', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveReplicaView',
-
-    onlineHelp: 'chapter_pvesr',
-
-    stateful: true,
-    stateId: 'grid-pve-replication-status',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	addJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		isCreate: true,
-		method: 'POST',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	editJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var data = rec.data;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		url: '/cluster/replication/' + data.id,
-		method: 'PUT',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	scheduleJobNow: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-
-	    Proxmox.Utils.API2Request({
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/schedule_now",
-		method: 'POST',
-		waitMsgTarget: me,
-		callback: function() { controller.reload(); },
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	showLog: function(button, event, rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var logView = Ext.create('Proxmox.panel.LogView', {
-		border: false,
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/log"
-	    });
-	    var win = Ext.create('Ext.window.Window', {
-		items: [ logView ],
-		layout: 'fit',
-		width: 800,
-		height: 400,
-		modal: true,
-		title: gettext("Replication Log")
-	    });
-	    var task = {
-		run: function() {
-		    logView.requestUpdate();
-		},
-		interval: 1000
-	    };
-	    Ext.TaskManager.start(task);
-	    win.on('destroy', function() {
-		Ext.TaskManager.stop(task);
-		controller.reload();
-	    });
-	    win.show();
-	},
-
-	reload: function() {
-	    var me = this.getView();
-	    me.rstore.load();
-	},
-
-	dblClick: function(grid, record, item) {
-	    var me = this;
-	    me.editJob(undefined, undefined, record);
-	},
-
-	// check for cluster
-	// currently replication is for cluster only, so we disable the whole
-	// component
-	checkPrerequisites: function() {
-	    var me = this.getView();
-	    if (PVE.data.ResourceStore.getNodes().length < 2) {
-		me.mask(gettext("Replication needs at least two nodes"), ['pve-static-mask']);
-	    }
-	},
-
-	control: {
-	    '#': {
-		itemdblclick: 'dblClick',
-		afterlayout: 'checkPrerequisites'
-	    }
-	}
-    },
-
-    tbar: [
-	{
-	    text: gettext('Add'),
-	    itemId: 'addButton',
-	    handler: 'addJob'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    itemId: 'editButton',
-	    handler: 'editJob',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxStdRemoveButton',
-	    itemId: 'removeButton',
-	    baseurl: '/api2/extjs/cluster/replication/',
-	    dangerous: true,
-	    callback: 'reload'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Log'),
-	    itemId: 'logButton',
-	    handler: 'showLog',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Schedule now'),
-	    itemId: 'scheduleNowButton',
-	    handler: 'scheduleJobNow',
-	    disabled: true
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	var mode = '';
-	var url = '/cluster/replication';
-
-	me.nodename = me.pveSelNode.data.node;
-	me.vmid = me.pveSelNode.data.vmid;
-
-	me.columns = [
-	    {
-		text: gettext('Enabled'),
-		dataIndex: 'enabled',
-		xtype: 'checkcolumn',
-		sortable: true,
-		disabled: true
-	    },
-	    {
-		text: 'ID',
-		dataIndex: 'id',
-		width: 60,
-		hidden: true
-	    },
-	    {
-		text: gettext('Guest'),
-		dataIndex: 'guest',
-		width: 75
-	    },
-	    {
-		text: gettext('Job'),
-		dataIndex: 'jobnum',
-		width: 60
-	    },
-	    {
-		text: gettext('Target'),
-		dataIndex: 'target'
-	    }
-	];
-
-	if (!me.nodename) {
-	    mode = 'dc';
-	    me.stateId = 'grid-pve-replication-dc';
-	} else if (!me.vmid) {
-	    mode = 'node';
-	    url = '/nodes/' + me.nodename + '/replication';
-	} else {
-	    mode = 'vm';
-	    url = '/nodes/' + me.nodename + '/replication' + '?guest=' + me.vmid;
-	}
-
-	if (mode !== 'dc') {
-	    me.columns.push(
-		{
-		    text: gettext('Status'),
-		    dataIndex: 'state',
-		    minWidth: 160,
-		    flex: 1,
-		    renderer: function(value, metadata, record) {
-
-			if (record.data.pid) {
-			    metadata.tdCls = 'x-grid-row-loading';
-			    return '';
-			}
-
-			var icons = [];
-			var states = [];
-
-			if (record.data.remove_job) {
-			    icons.push('<i class="fa fa-ban warning" title="'
-					+ gettext("Removal Scheduled") + '"></i>');
-			    states.push(gettext("Removal Scheduled"));
-			}
-
-			if (record.data.error) {
-			    icons.push('<i class="fa fa-times critical" title="'
-					+ gettext("Error") + '"></i>');
-			    states.push(record.data.error);
-			}
-
-			if (icons.length == 0) {
-			    icons.push('<i class="fa fa-check good"></i>');
-			    states.push(gettext('OK'));
-			}
-
-			return icons.join(',') + ' ' + states.join(',');
-		    }
-		},
-		{
-		    text: gettext('Last Sync'),
-		    dataIndex: 'last_sync',
-		    width: 150,
-		    renderer: function(value, metadata, record) {
-			if (!value) {
-			    return '-';
-			}
-
-			if (record.data.pid) {
-			    return gettext('syncing');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		},
-		{
-		    text: gettext('Duration'),
-		    dataIndex: 'duration',
-		    width: 60,
-		    renderer: PVE.Utils.render_duration
-		},
-		{
-		    text: gettext('Next Sync'),
-		    dataIndex: 'next_sync',
-		    width: 150,
-		    renderer: function(value) {
-			if (!value) {
-			    return '-';
-			}
-
-			var now = new Date();
-			var next = new Date(value*1000);
-
-			if (next < now) {
-			    return gettext('pending');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		}
-	    );
-	}
-
-	me.columns.push(
-	    {
-		text: gettext('Schedule'),
-		width: 75,
-		dataIndex: 'schedule'
-	    },
-	    {
-		text: gettext('Rate limit'),
-		dataIndex: 'rate',
-		renderer: function(value) {
-		    if (!value) {
-			return gettext('unlimited');
-		    }
-
-		    return value.toString() + ' MB/s';
-		},
-		hidden: true
-	    },
-	    {
-		text: gettext('Comment'),
-		dataIndex: 'comment',
-		renderer: Ext.htmlEncode
-	    }
-	);
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-replica-' + me.nodename + me.vmid,
-	    model: (mode === 'dc')? 'pve-replication' : 'pve-replication-state',
-	    interval: 3000,
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + url
-	    }
-	});
-
-	me.store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sorters: [
-		{
-		    property: 'guest'
-		},
-		{
-		    property: 'jobnum'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	// we cannot access the log and scheduleNow button
-	// in the datacenter, because
-	// we do not know where/if the jobs runs
-	if (mode === 'dc') {
-	    me.down('#logButton').setHidden(true);
-	    me.down('#scheduleNowButton').setHidden(true);
-	}
-
-	// if we set the warning mask, we do not want to load
-	// or set the mask on store errors
-	if (PVE.data.ResourceStore.getNodes().length < 2) {
-	    return;
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.on('destroy', me.rstore.stopUpdate);
-	me.rstore.startUpdate();
-    }
-}, function() {
-
-    Ext.define('pve-replication', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'target', 'comment', 'rate', 'type',
-	    { name: 'guest', type: 'integer' },
-	    { name: 'jobnum', type: 'integer' },
-	    { name: 'schedule', defaultValue: '*/15' },
-	    { name: 'disable', defaultValue: '' },
-	    { name: 'enabled', calculate: function(data) { return !data.disable; } }
-	]
-    });
-
-    Ext.define('pve-replication-state', {
-	extend: 'pve-replication',
-	fields: [
-	    'last_sync', 'next_sync', 'error', 'duration', 'state',
-	    'fail_count', 'remove_job', 'pid'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Health', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcHealth',
-
-    title: gettext('Health'),
-
-    bodyPadding: 10,
-    height: 220,
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	flex: 1,
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    nodeList: [],
-    nodeIndex: 0,
-
-    updateStatus: function(store, records, success) {
-	var me = this;
-	if (!success) {
-	    return;
-	}
-
-	var cluster = {
-	    iconCls: PVE.Utils.get_health_icon('good', true),
-	    text: gettext("Standalone node - no cluster defined")
-	};
-
-	var nodes = {
-	    online: 0,
-	    offline: 0
-	};
-
-	// by default we have one node
-	var numNodes = 1;
-	var i;
-
-	for (i = 0; i < records.length; i++) {
-	    var item = records[i];
-	    if (item.data.type === 'node') {
-		nodes[item.data.online === 1 ? 'online':'offline']++;
-	    } else if(item.data.type === 'cluster') {
-		cluster.text = gettext("Cluster") + ": ";
-		cluster.text += item.data.name + ", ";
-		cluster.text += gettext("Quorate") + ": ";
-		cluster.text += Proxmox.Utils.format_boolean(item.data.quorate);
-		if (item.data.quorate != 1) {
-		    cluster.iconCls = PVE.Utils.get_health_icon('critical', true);
-		}
-
-		numNodes = item.data.nodes;
-	    }
-	}
-
-	if (numNodes !== (nodes.online + nodes.offline)) {
-	    nodes.offline = numNodes - nodes.online;
-	}
-
-	me.getComponent('clusterstatus').updateHealth(cluster);
-	me.getComponent('nodestatus').update(nodes);
-    },
-
-    updateCeph: function(store, records, success) {
-	var me = this;
-	var cephstatus = me.getComponent('ceph');
-	if (!success || records.length < 1) {
-
-	    // if ceph status is already visible
-	    // dont stop to update
-	    if (cephstatus.isVisible()) {
-		return;
-	    }
-
-	    // try all nodes until we either get a successfull api call,
-	    // or we tried all nodes
-	    if (++me.nodeIndex >= me.nodeList.length) {
-		me.cephstore.stopUpdate();
-	    } else {
-		store.getProxy().setUrl('/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status');
-	    }
-
-	    return;
-	}
-
-	var state = PVE.Utils.render_ceph_health(records[0].data.health || {});
-	cephstatus.updateHealth(state);
-	cephstatus.setVisible(true);
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    me.cephstore.stopUpdate();
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'clusterstatus',
-	    xtype: 'pveHealthWidget',
-	    title: gettext('Status')
-	},
-	{
-	    itemId: 'nodestatus',
-	    data: {
-		online: 0,
-		offline: 0
-	    },
-	    tpl: [
-		'<h3>' + gettext('Nodes') + '</h3><br />',
-		'<div style="width: 150px;margin: auto;font-size: 12pt">',
-		'<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-check">&nbsp;</i>',
-		gettext('Online'),
-		'</div>',
-		'<div class="right-aligned">{online}</div>',
-		'<br /><br />',
-		'<div class="left-aligned">',
-		'<i class="critical fa fa-fw fa-times">&nbsp;</i>',
-		gettext('Offline'),
-		'</div>',
-		'<div class="right-aligned">{offline}</div>',
-		'</div>'
-	    ]
-	},
-	{
-	    itemId: 'ceph',
-	    width: 250,
-	    columnWidth: undefined,
-	    userCls: 'pointer',
-	    title: 'Ceph',
-	    xtype: 'pveHealthWidget',
-	    hidden: true,
-	    listeners: {
-		element: 'el',
-		click: function() {
-		    var me = this.component.up('pveDcHealth');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // preselect the ceph tab
-		    sp.set('nodetab', {value:'ceph'});
-
-		    // select the node that had the successfull api call
-		    var id = me.nodeList[me.nodeIndex].id;
-		    Ext.ComponentQuery.query('pveResourceTree')[0].selectById(id);
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodeList = PVE.data.ResourceStore.getNodes();
-	me.nodeIndex = 0;
-	me.cephstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-ceph',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status'
-	    }
-	});
-	me.callParent();
-	me.mon(me.cephstore, 'load', me.updateCeph, me);
-	me.cephstore.startUpdate();
-    }
-});
-Ext.define('PVE.dc.Guests', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcGuests',
-
-
-    title: gettext('Guests'),
-    height: 220,
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-    bodyPadding: '0 20 20 20',
-
-    defaults: {
-	xtype: 'box',
-	padding: '0 50 0 50',
-	style: {
-	    'text-align':'center',
-	    'line-height':'1.2'
-	}
-    },
-    items: [{
-	itemId: 'qemu',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("Virtual Machines") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'lxc',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("LXC Container") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'error',
-	colspan: 2,
-	data: {
-	    num: 0
-	},
-	columnWidth: 1,
-	padding: '10 250 0 250',
-	tpl: [
-	    '<tpl if="num &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="critical fa fa-fw fa-times-circle">&nbsp;</i>',
-		    gettext('Error'),
-		'</div>',
-		'<div class="right-aligned">{num}</div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateValues: function(qemu, lxc, error) {
-	var me = this;
-	me.getComponent('qemu').update(qemu);
-	me.getComponent('lxc').update(lxc);
-	me.getComponent('error').update({num: error});
-    }
-});
- /*jslint confusion: true*/
-Ext.define('PVE.dc.OptionView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    onlineHelp: 'datacenter_configuration_file',
-
-    monStoreErrors: true,
-
-    add_inputpanel_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	var canEdit = (opts.caps === undefined || opts.caps);
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: canEdit ? {
-		xtype: 'proxmoxWindowEdit',
-		width: 350,
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		setValues: function(values) {
-		    // FIXME: run through parsePropertyString if not an object?
-		    var edit_value = values[name];
-		    Ext.Array.each(this.query('inputpanel'), function(panel) {
-			panel.setValues(edit_value);
-		    });
-		},
-		url: opts.url,
-		items: [{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			if (values === undefined || Object.keys(values).length === 0) {
-			    return { 'delete': name };
-			}
-			var ret_val = {};
-			ret_val[name] = PVE.Parser.printPropertyString(values);
-			return ret_val;
-		    },
-		    items: opts.items
-		}]
-	    } : undefined
-	};
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.add_combobox_row('keyboard', gettext('Keyboard Layout'), {
-	    renderer: PVE.Utils.render_kvm_language,
-	    comboItems: PVE.Utils.kvm_keymap_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('http_proxy', gettext('HTTP proxy'), {
-	    defaultValue: Proxmox.Utils.noneText,
-	    vtype: 'HttpProxy',
-	    deleteEmpty: true
-	});
-	me.add_combobox_row('console', gettext('Console Viewer'), {
-	    renderer: PVE.Utils.render_console_viewer,
-	    comboItems: PVE.Utils.console_viewer_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('email_from', gettext('Email from address'), {
-	    deleteEmpty: true,
-	    vtype: 'proxmoxMail',
-	    defaultValue: 'root@$hostname'
-	});
-	me.add_text_row('mac_prefix', gettext('MAC address prefix'), {
-	    deleteEmpty: true,
-	    vtype: 'MacPrefix',
-	    defaultValue: Proxmox.Utils.noneText
-	});
-	me.add_inputpanel_row('migration', gettext('Migration Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    defaultKey: 'type',
-	    items: [{
-		xtype: 'displayfield',
-		name: 'type',
-		fieldLabel: gettext('Type'),
-		value: 'secure',
-		submitValue: true,
-		vtype: 'IPCIDRAddress'
-	    }, {
-		xtype: 'textfield',
-		name: 'network',
-		fieldLabel: gettext('Network'),
-		vtype: 'IPCIDRAddress',
-		emptyText: Proxmox.Utils.defaultText,
-		value: ''
-	    }]
-	});
-	me.add_inputpanel_row('ha', gettext('HA Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    items: [{
-		xtype: 'proxmoxKVComboBox',
-		name: 'shutdown_policy',
-		fieldLabel: gettext('Shutdown Policy'),
-		deleteEmpty: false,
-		value: '__default__',
-		comboItems: [
-		    ['__default__', Proxmox.Utils.defaultText + ' (conditional)' ],
-		    ['freeze', 'freeze'],
-		    ['failover', 'failover'],
-		    ['conditional', 'conditional']
-		],
-		defaultValue: '__default__'
-	    }]
-	});
-
-	// TODO: bwlimits, migration net, u2f?
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    tbar: [{
-		text: gettext('Edit'),
-		xtype: 'proxmoxButton',
-		disabled: true,
-		handler: function() { me.run_editor(); },
-		selModel: me.selModel
-	    }],
-	    url: "/api2/json/cluster/options",
-	    editorConfig: {
-		url: "/api2/extjs/cluster/options"
-	    },
-	    interval: 5000,
-	    cwidth1: 200,
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	// set the new value for the default console
-	me.mon(me.rstore, 'load', function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-
-	    var rec = store.getById('console');
-	    PVE.VersionInfo.console = rec.data.value;
-	    if (rec.data.value === '__default__') {
-		delete PVE.VersionInfo.console;
-	    }
-	});
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    onlineHelp: 'chapter_storage',
-
-    stateful: true,
-    stateId: 'grid-dc-storage',
-
-    createStorageEditWindow: function(type, sid) {
-	var schema = PVE.Utils.storageSchema[type];
-	if (!schema || !schema.ipanel) {
-	    throw "no editor registered for storage type: " + type;
-	}
-
-	Ext.create('PVE.storage.BaseEdit', {
-	    paneltype: 'PVE.storage.' + schema.ipanel,
-	    type: type,
-	    storageId: sid,
-	    autoShow: true,
-	    listeners: {
-		destroy: this.reloadStore
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-storage',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/storage"
-	    },
-	    sorters: {
-		property: 'storage',
-		order: 'DESC'
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type,
-	        sid = rec.data.storage;
-
-	    me.createStorageEditWindow(type, sid);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/storage/',
-	    callback: reload
-	});
-
-	// else we cannot dynamically generate the add menu handlers
-	var addHandleGenerator = function(type) {
-	    return function() { me.createStorageEditWindow(type); };
-	};
-	var addMenuItems = [], type;
-	/*jslint forin: true */
-	for (type in PVE.Utils.storageSchema) {
-	    var storage = PVE.Utils.storageSchema[type];
-	    if (storage.hideAdd) {
-		continue;
-	    }
-	    addMenuItems.push({
-		text:  PVE.Utils.format_storage_type(type),
-		iconCls: 'fa fa-fw fa-' + storage.faIcon,
-		handler: addHandleGenerator(type)
-	    });
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    reloadStore: reload,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: addMenuItems
-		    })
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Type'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'type',
-		    renderer: PVE.Utils.format_storage_type
-		},
-		{
-		    header: gettext('Content'),
-		    flex: 3,
-		    sortable: true,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Path') + '/' + gettext('Target'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'path',
-		    renderer: function(value, metaData, record) {
-			if (record.data.target) {
-			    return record.data.target;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Shared'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'shared',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Enabled'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'disable',
-		    renderer: Proxmox.Utils.format_neg_boolean
-		},
-		{
-		    header: gettext('Bandwidth Limit'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'bwlimit'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-	    { name: 'shared', type: 'boolean'},
-	    { name: 'disable', type: 'boolean'}
-	],
-	idProperty: 'storage'
-    });
-
-});
-/*global u2f,QRCode,Uint8Array*/
-/*jslint confusion: true*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' + encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer)
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    PVE.Utils.render_u2f_error(error)
-	);
-    },
-
-    doU2FChallenge: function(response) {
-	var me = this;
-
-	var data = response.result.data;
-	me.lookup('password').setDisabled(true);
-	var msg = Ext.Msg.show({
-	    title: 'U2F: '+gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: []
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(data.appId, [data], [], function(data) {
-		msg.close();
-		if (data.errorCode) {
-		    me.showError(data.errorCode);
-		} else {
-		    me.respondToU2FChallenge(data);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data)
-	};
-	if (Proxmox.UserName !== 'root@pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    has_tfa: false,
-	    valid: false,
-	    u2f_available: true
-	},
-	formulas: {
-	    canDeleteTFA: function(get) {
-		return (get('has_tfa') && !get('tfa_required'));
-	    }
-	}
-    },
-
-    afterLoadingRealm: function(realm_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type
-		)
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    var me = this.getView();
-		    me.updateQrCode();
-		}
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		}
-	    },
-	    '#': {
-		show: function() {
-		    var me = this.getView();
-		    var viewmodel = this.getViewModel();
-
-		    me.qrdiv = document.createElement('center');
-		    me.qrcode = new QRCode(me.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M
-		    });
-		    me.down('#qrbox').getEl().appendChild(me.qrdiv);
-
-		    viewmodel.set('has_tfa', me.hasTFA);
-		    if (!me.hasTFA) {
-			this.randomizeSecret();
-		    } else {
-			me.down('#qrbox').setVisible(false);
-			me.lookup('challenge').setVisible(false);
-		    }
-
-		    if (Proxmox.UserName === 'root@pam') {
-			me.lookup('password').setVisible(false);
-			me.lookup('password').setDisabled(true);
-		    }
-		}
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    var viewmodel = this.getViewModel();
-		    viewmodel.set('in_totp_tab', newcard.itemId === 'totp-panel');
-		}
-	    }
-	},
-
-	applySettings: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	deleteTFA: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'delete'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	randomizeSecret: function() {
-	    var me = this;
-	    var rnd = new Uint8Array(16);
-	    window.crypto.getRandomValues(rnd);
-	    var data = '';
-	    rnd.forEach(function(b) {
-		// just use the first 5 bit
-		b = b & 0x1f;
-		if (b < 26) {
-		    // A..Z
-		    data += String.fromCharCode(b + 0x41);
-		} else {
-		    // 2..7
-		    data += String.fromCharCode(b-26 + 0x32);
-		}
-	    });
-	    me.lookup('tfa_secret').setValue(data);
-	},
-
-	startU2FRegistration: function() {
-	    var me = this;
-
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    border: false,
-		    layout: {
-			type: 'vbox',
-			align: 'stretch'
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5'
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    cbind: {
-					value: '{userid}'
-				    }
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					flex: 4
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1
-				    }]
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true
-				}
-			    ]
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    style: {
-				'background-color': 'white',
-				padding: '5px',
-				width: '266px',
-				height: '266px'
-			    }
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify')
-			}
-		    ]
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle'
-		    },
-		    bind: {
-			disabled: '{!u2f_available}'
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.')
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password')
-	}
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton'
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}'
-	    }
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}'
-	    }
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}'
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    autoLoad: true
-	});
-
-	store.on('load', function() {
-	    var user_realm = me.userid.split('@')[1];
-	    var realm = me.store.findRecord('realm', user_realm);
-	    me.afterLoadingRealm(realm && realm.data && realm.data.tfa);
-	}, me);
-
-	Ext.apply(me, { store: store });
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    }
-});
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + me.userid;
-            method = 'PUT';
-	}
-
-	var verifypw;
-	var pwfield;
-
-	var validate_pw = function() {
-	    if (verifypw.getValue() !== pwfield.getValue()) {
-		return gettext("Passwords do not match");
-	    }
-	    return true;
-	};
-
-	verifypw = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'), 
-	    name: 'verifypassword',
-	    submitValue: false,
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	pwfield = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'), 
-	    minLength: 5,
-	    name: 'password',
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	var update_passwd_field = function(realm) {
-	    if (realm === 'pve') {
-		pwfield.setVisible(true);
-		pwfield.setDisabled(false);
-		verifypw.setVisible(true);
-		verifypw.setDisabled(false);
-	    } else {
-		pwfield.setVisible(false);
-		pwfield.setDisabled(true);
-		verifypw.setVisible(false);
-		verifypw.setDisabled(true);
-	    }
-
-	};
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.isCreate ? true : false
-            },
-	    pwfield, verifypw,
-	    {
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		multiSelect: true,
-		allowBlank: true,
-		fieldLabel: gettext('Group')
-	    },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-		emptyText: 'never',
-		format: 'Y-m-d',
-		submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enabled'),
-		name: 'enable',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    }
-        ];
-
-        var column2 = [
-	    {
-		xtype: 'textfield',
-		name: 'firstname',
-		fieldLabel: gettext('First Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'lastname',
-		fieldLabel: gettext('Last Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'email',
-		fieldLabel: gettext('E-Mail'),
-		vtype: 'proxmoxMail'
-	    }
-	];
-
-        if (me.isCreate) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-		matchFieldWidth: false,
-		listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-			update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    fieldLabel: gettext('Comment')
-		}
-	    ],
-	    advancedItems: [
-		{
-		    xtype: 'textfield',
-		    name: 'keys',
-		    fieldLabel: gettext('Key IDs')
-		}
-	    ],
-	    onGetValues: function(values) {
-		// hack: ExtJS datefield does not submit 0, so we need to set that
-		if (!values.expire) {
-		    values.expire = 0;
-		}
-
-		if (realm) {
-		    values.userid = values.userid + '@' + realm;
-		}
-
-		if (!values.password) {
-		    delete values.password;
-		}
-
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 110 // for spanish translation 
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (Ext.isDefined(data.expire)) {
-			if (data.expire) {
-			    data.expire = new Date(data.expire * 1000);
-			} else {
-			    // display 'never' instead of '1970-01-01'
-			    data.expire = null;
-			}
-		    }
-		    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    onlineHelp: 'pveum_users',
-
-    stateful: true,
-    stateId: 'grid-users',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-            id: "users",
-	    model: 'pve-users',
-	    sorters: { 
-		property: 'userid', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/access/users/',
-	    enableFn: function(rec) {
-		if (!caps.access['User.Modify']) {
-		    return false;
-		}
-		return rec.data.userid !== 'root@pam';
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
- 
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec || !caps.access['User.Modify']) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    enableFn: function(rec) {
-		return !!caps.access['User.Modify'];
-	    },
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var pwchange_btn = new Proxmox.button.Button({
-	    text: gettext('Password'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('Proxmox.window.PasswordEdit', {
-                    userid: rec.data.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var win = Ext.create('PVE.window.TFAEdit',{
-                    hasTFA: d.keys != undefined && d.keys.length,
-                    userid: d.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-        var tbar = [
-            {
-		text: gettext('Add'),
-		disabled: !caps.access['User.Modify'],
-		handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-		}
-            },
-	    edit_btn, remove_btn, pwchange_btn, tfachange_btn
-        ];
-
-	var render_username = function(userid) {
-	    return userid.match(/^(.+)(@[^@]+)$/)[1];
-	};
-
-	var render_realm = function(userid) {
-	    return userid.match(/@([^@]+)$/)[1];
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('User name'),
-		    width: 200,
-		    sortable: true,
-		    renderer: render_username,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    renderer: render_realm,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'enable'
-		},
-		{
-		    header: gettext('Expire'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_expire, 
-		    dataIndex: 'expire'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    renderer: PVE.Utils.render_full_name,
-		    dataIndex: 'firstname'
-		},
-		{
-		    header: 'TFA',
-		    width: 50,
-		    sortable: true,
-		    renderer: function(v) {
-			return Proxmox.Utils.format_boolean(v !== undefined && v.length);
-		    },
-		    dataIndex: 'keys'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    onlineHelp: 'pveum_pools',
-
-    stateful: true,
-    stateId: 'grid-pools',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: { 
-		property: 'poolid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/pools/',
-	    callback: function () {
-		reload();
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.PoolEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'poolid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'poolid',
-		    value: me.poolid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    onlineHelp: 'pveum_groups',
-
-    stateful: true,
-    stateId: 'grid-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: { 
-		property: 'groupid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: '/access/groups/'
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.GroupEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'groupid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'groupid',
-		    value: me.groupid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    onlineHelp: 'pveum_roles',
-
-    stateful: true,
-    stateId: 'grid-roles',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: {
-		property: 'roleid',
-		order: 'DESC'
-	    }
-	});
-
-	var render_privs = function(value, metaData) {
-
-	    if (!value) {
-		return '-';
-	    }
-
-	    // allow word wrap
-	    metaData.style = 'white-space:normal;';
-
-	    return value.replace(/\,/g, ' ');
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-		store.load();
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (rec.data.special === "1") {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.RoleEdit',{
-		roleid: rec.data.roleid,
-		privs: rec.data.privs
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Built-In'),
-		    width: 65,
-		    sortable: true,
-		    dataIndex: 'special',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'roleid'
-		},
-		{
-		    itemid: 'privs',
-		    header: gettext('Privileges'),
-		    sortable: false,
-		    renderer: render_privs,
-		    dataIndex: 'privs',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: function() {
-		    store.load();
-		},
-		itemdblclick: run_editor
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.RoleEdit', {});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Edit'),
-		    disabled: true,
-		    selModel: sm,
-		    handler: run_editor,
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		},
-		{
-		    xtype: 'proxmoxStdRemoveButton',
-		    selModel: sm,
-		    callback: function() {
-			reload();
-		    },
-		    baseurl: '/access/roles/',
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.RoleEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveDcRoleEdit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.roleid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = '/api2/extjs/access/roles';
-	    method = 'POST';
-	} else {
-	    url = '/api2/extjs/access/roles/' + me.roleid;
-	    method = 'PUT';
-	}
-
-	Ext.applyIf(me, {
-	    subject: gettext('Role'),
-	    url: url,
-	    method: method,
-	    items: [
-		{
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    name: 'roleid',
-		    value: me.roleid,
-		    allowBlank: false,
-		    fieldLabel: gettext('Name')
-		},
-		{
-		    xtype: 'pvePrivilegesSelector',
-		    name: 'privs',
-		    value: me.privs,
-		    allowBlank: false,
-		    fieldLabel: gettext('Privileges')
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var data = response.result.data;
-		    var keys = Ext.Object.getKeys(data);
-
-		    me.setValues({
-			privs: keys,
-			roleid: me.roleid
-		    });
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveACLAdd'],
-    url: '/access/acl',
-    method: 'PUT',
-    isAdd: true,
-    initComponent : function() {
-
-        var me = this;
-
-	me.isCreate = true;
-
-	var items = [
-	    {
-		xtype: me.path ? 'hiddenfield' : 'pvePermPathSelector',
-		name: 'path',
-		value: me.path,
-		allowBlank: false,
-		fieldLabel: gettext('Path')
-	    }
-	];
-
-	if (me.aclType === 'group') {
-	    me.subject = gettext("Group Permission");
-	    items.push({
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		fieldLabel: gettext('Group')
-	    });
-	} else if (me.aclType === 'user') {
-	    me.subject = gettext("User Permission");
-	    items.push({
-		xtype: 'pveUserSelector',
-		name: 'users',
-		fieldLabel: gettext('User')
-	    });
-	} else {
-	    throw "unknown ACL type";
-	}
-
-	items.push({
-	    xtype: 'pveRoleSelector',
-	    name: 'roles',
-	    value: 'NoAccess',
-	    fieldLabel: gettext('Role')
-	});
-
-	if (!me.path) {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'propagate',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Propagate')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    items: items,
-	    onlineHelp: 'pveum_permission_management'
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    onlineHelp: 'chapter_user_management',
-
-    stateful: true,
-    stateId: 'grid-acls',
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-acl',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/access/acl"
-	    },
-	    sorters: {
-		property: 'path',
-		order: 'DESC'
-	    }
-	});
-
-	if (me.path) {
-	    store.addFilter(Ext.create('Ext.util.Filter',{
-		filterFn: function(item) {
-		    if (item.data.path === me.path) {
-			return true;
-		    }
-		}
-	    }));
-	}
-
-	var render_ugid = function(ugid, metaData, record) {
-	    if (record.data.type == 'group') {
-		return '@' + ugid;
-	    }
-
-	    return ugid;
-	};
-
-	var columns = [
-	    {
-		header: gettext('User') + '/' + gettext('Group'),
-		flex: 1,
-		sortable: true,
-		renderer: render_ugid,
-		dataIndex: 'ugid'
-	    },
-	    {
-		header: gettext('Role'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'roleid'
-	    }
-	];
-
-	if (!me.path) {
-	    columns.unshift({
-		header: gettext('Path'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'path'
-	    });
-	    columns.push({
-		header: gettext('Propagate'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'propagate'
-	    });
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: gettext('Are you sure you want to remove this entry'),
-	    handler: function(btn, event, rec) {
-		var params = {
-		    'delete': 1,
-		    path: rec.data.path,
-		    roles: rec.data.roleid
-		};
-		if (rec.data.type === 'group') {
-		    params.groups = rec.data.ugid;
-		} else if (rec.data.type === 'user') {
-		    params.users = rec.data.ugid;
-		} else {
-		    throw 'unknown data type';
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/access/acl',
-		    params: params,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: {
-			xtype: 'menu',
-			items: [
-			    {
-				text: gettext('Group Permission'),
-				iconCls: 'fa fa-fw fa-group',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'group',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('User Permission'),
-				iconCls: 'fa fa-fw fa-user',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'user',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    }
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'ugid', 'roleid',
-	    {
-		name: 'propagate',
-		type: 'boolean'
-	    }
-	]
-    });
-
-});
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    onlineHelp: 'pveum_authentication_realms',
-
-    stateful: true,
-    stateId: 'grid-authrealms',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    sorters: { 
-		property: 'realm', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-		authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    baseurl: '/access/domains/',
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
-
-        var tbar = [
-	    {
-		text: gettext('Add'),
-		menu: new Ext.menu.Menu({
-		    items: [
-			{
-			    text: gettext('Active Directory Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit', {
-				    authType: 'ad'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			},
-			{
-			    text: gettext('LDAP Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit',{
-				    authType: 'ldap'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			}
-		    ]
-		})
-	    },
-	    edit_btn, remove_btn
-        ];
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-            tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'realm'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('TFA'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'tfa'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-	];
-
-	if (me.authType === 'ad') {
-
-	    me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-	} else if (me.authType === 'ldap') {
-
-	    me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-		emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-	} else if (me.authType === 'pve') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'Proxmox VE authentication server';
-
-	} else if (me.authType === 'pam') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'linux PAM';
-
-	} else {
-	    throw 'unknown auth type ';
-	}
-
-        column1.push({
-            xtype: 'proxmoxcheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-	if (me.authType === 'ldap' || me.authType === 'ad') {
-	    column2.push(
-		{
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-		},
-		{
-                    xtype: 'proxmoxtextfield',
-                    fieldLabel: gettext('Fallback Server'),
-		    deleteEmpty: !me.isCreate,
-		    name: 'server2'
-		},
-		{
-                    xtype: 'proxmoxintegerfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-		    emptyText: gettext('Default'),
-		    submitEmptyText: false
-		},
-		{
-                    xtype: 'proxmoxcheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-		}
-            );
-	}
-
-	// Two Factor Auth settings
-
-        column2.push({
-            xtype: 'proxmoxKVComboBox',
-            name: 'tfa',
-	    deleteEmpty: !me.isCreate,
-	    value: '',
-            fieldLabel: gettext('TFA'),
-	    comboItems: [ ['__default__', Proxmox.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=oath_step]').setVisible(value === 'oath');
-		    me.down('field[name=oath_digits]').setVisible(value === 'oath');
-		    me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-		}
-	    }
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_step',
-	    value: '',
-	    minValue: 10,
-	    emptyText: Proxmox.Utils.defaultText + ' (30)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_digits',
-	    value: '',
-	    minValue: 6,
-	    maxValue: 8,
-	    emptyText: Proxmox.Utils.defaultText + ' (6)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-	    hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-	    hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-	    hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [{
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-            }],
-	    onGetValues: function(values) {
-		if (!values.port) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'port' });
-		    }
-		    delete values.port;
-		}
-
-		if (me.isCreate) {
-		    values.type = me.authType;
-		}
-
-		if (values.tfa === 'oath') {
-		    values.tfa = "type=oath";
-		    if (values.oath_step) {
-			values.tfa += ",step=" + values.oath_step;
-		    }
-		    if (values.oath_digits) {
-			values.tfa += ",digits=" + values.oath_digits;
-		    }
-		} else if (values.tfa === 'yubico') {
-		    values.tfa = "type=yubico";
-		    values.tfa += ",id=" + values.yubico_api_id;
-		    values.tfa += ",key=" + values.yubico_api_key;
-		    if (values.yubico_url) {
-			values.tfa += ",url=" + values.yubico_url;
-		    }
-		} else {
-		    delete values.tfa;
-		}
-
-		delete values.oath_step;
-		delete values.oath_digits;
-		delete values.yubico_api_id;
-		delete values.yubico_api_key;
-		delete values.yubico_url;
-		
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-                success: function(response, options) {
-		    var data = response.result.data || {};
-		    // just to be sure (should not happen)
-		    if (data.type !== me.authType) {
-			me.close();
-			throw "got wrong auth type";
-		    }
-
-		    if (data.tfa) {
-			var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-			data.tfa = tfacfg.type;
-			if (tfacfg.type === 'yubico') {
-			    data.yubico_api_key = tfacfg.key;
-			    data.yubico_api_id = tfacfg.id;
-			    data.yubico_url = tfacfg.url;
-			} else if (tfacfg.type === 'oath') {
-			    // step is a number before
-			    /*jslint confusion: true*/
-			    data.oath_step = tfacfg.step;
-			    data.oath_digits = tfacfg.digits;
-			    /*jslint confusion: false*/
-			}
-		    }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    defaultFocus: undefined,
-
-    initComponent : function() {
-         var me = this;
-
-        me.isCreate = !me.jobid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-	var vmidField = Ext.create('Ext.form.field.Hidden', {
-	    name: 'vmid'
-	});
-
-	/*jslint confusion: true*/
-	// 'value' can be assigned a string or an array
-	var selModeField =  Ext.create('Proxmox.form.KVComboBox', {
-	    xtype: 'proxmoxKVComboBox',
-	    comboItems: [
-		['include', gettext('Include selected VMs')],
-		['all', gettext('All')],
-		['exclude', gettext('Exclude selected VMs')]
-	    ],
-	    fieldLabel: gettext('Selection mode'),
-	    name: 'selMode',
-	    value: ''
-	});
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    var sel = [];
-		    Ext.Array.each(selected, function(record) {
-			sel.push(record.data.vmid);
-		    });
-
-		    // to avoid endless recursion suspend the vmidField change
-		    // event temporary as it calls us again
-		    vmidField.suspendEvent('change');
-		    vmidField.setValue(sel);
-		    vmidField.resumeEvent('change');
-		}
-	    }
-	});
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    fieldLabel: gettext('Storage'),
-	    nodename: 'localhost',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    name: 'storage'
-	});
-
-	var store = new Ext.data.Store({
-	    model: 'PVEResources',
-	    sorters: { 
-		property: 'vmid', 
-		order: 'ASC' 
-	    }
-	});
-
-	var vmgrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    disabled: true,
-	    columns: [
-		{ 
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{ 
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{ 
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{ 
-		    header: gettext('Name'), 
-		    dataIndex: 'name',
-		    flex: 1 
-		},
-		{ 
-		    header: gettext('Type'), 
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-
-	var nodesel = Ext.create('PVE.form.NodeSelector', {
-	    name: 'node',
-	    fieldLabel: gettext('Node'),
-	    allowBlank: true,
-	    editable: true,
-	    autoSelect: false,
-	    emptyText: '-- ' + gettext('All') + ' --',
-	    listeners: {
-		change: function(f, value) {
-		    storagesel.setNodename(value || 'localhost');
-		    var mode = selModeField.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!value || rec.get('node') === value);
-		    });
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    }
-		}
-	    }
-	});
-
-	var column1 = [
-	    nodesel,
-	    storagesel,
-	    {
-		xtype: 'pveDayOfWeekSelector',
-		name: 'dow',
-		fieldLabel: gettext('Day of week'),
-		multiSelect: true,
-		value: ['sat'],
-		allowBlank: false
-	    },
-	    {
-		xtype: 'timefield',
-		fieldLabel: gettext('Start Time'),
-		name: 'starttime',
-		format: 'H:i',
-		formatText: 'HH:MM',
-		value: '00:00',
-		allowBlank: false
-	    },
-	    selModeField
-	];
-
-	var column2 = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Send email to'),
-		name: 'mailto'
-	    },
-	    {
-		xtype: 'pveEmailNotificationSelector',
-		fieldLabel: gettext('Email notification'),
-		name: 'mailnotification',
-		deleteEmpty: me.isCreate ? false : true,
-		value: me.isCreate ? 'always' : ''
-	    },
-	    {
-		xtype: 'pveCompressionSelector',
-		fieldLabel: gettext('Compression'),
-		name: 'compress',
-		deleteEmpty: me.isCreate ? false : true,
-		value: 'lzo'
-	    },
-	    {
-		xtype: 'pveBackupModeSelector',
-		fieldLabel: gettext('Mode'),
-		value: 'snapshot',
-		name: 'mode'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enable'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    },
-	    vmidField
-	];
-	/*jslint confusion: false*/
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    onlineHelp: 'chapter_vzdump',
-	    column1: column1,
-	    column2:  column2,
-	    onGetValues: function(values) {
-		if (!values.node) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'node' }); 
-		    }
-		    delete values.node;
-		}
-
-		var selMode = values.selMode;
-		delete values.selMode;
-
-		if (selMode === 'all') {
-		    values.all = 1;
-		    values.exclude = '';
-		    delete values.vmid;
-		} else if (selMode === 'exclude') {
-		    values.all = 1;
-		    values.exclude = values.vmid;
-		    delete values.vmid;
-		}
-		return values;
-	    }
-	});
-
-	var update_vmid_selection = function(list, mode) {
-	    if (mode !== 'all') {
-		sm.deselectAll(true);
-		if (list) {
-		    Ext.Array.each(list.split(','), function(vmid) {
-			var rec = store.findRecord('vmid', vmid);
-			if (rec) {
-			    sm.select(rec, true);
-			}
-		    });
-		}
-	    }
-	};
-
-	vmidField.on('change', function(f, value) {
-	    var mode = selModeField.getValue();
-	    update_vmid_selection(value, mode);
-	});
-
-	selModeField.on('change', function(f, value, oldValue) {
-	    if (value === 'all') {
-		sm.selectAll(true);
-		vmgrid.setDisabled(true);
-	    } else {
-		vmgrid.setDisabled(false);
-	    }
-	    if (oldValue === 'all') {
-		sm.deselectAll(true);
-		vmidField.setValue('');
-	    }
-	    var list = vmidField.getValue();
-	    update_vmid_selection(list, value);
-	});
-		 
-	var reload = function() {
-	    store.load({
-		params: { type: 'vm' },
-		callback: function() {
-		    var node = nodesel.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!node || node.length === 0 || rec.get('node') === node);
-		    });
-		    var list = vmidField.getValue();
-		    var mode = selModeField.getValue();
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    } else {
-			update_vmid_selection(list, mode);
-		    }
-		}
-	    });
-	};
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-	    items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.isCreate) {
-	    selModeField.setValue('include');
-	} else {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-
-		    data.dow = data.dow.split(',');
-
-		    if (data.all || data.exclude) {
-			if (data.exclude) {
-			    data.vmid = data.exclude;
-			    data.selMode = 'exclude';
-			} else {
-			    data.vmid = '';
-			    data.selMode = 'all';
-			}
-		    } else {
-			data.selMode = 'include';
-		    }
-
-		    me.setValues(data);
-               }
-            });
-        }
-
-	reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-cluster-backup',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/cluster/backup"
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.BackupEdit',{
-                jobid: rec.data.id
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/backup',
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    stateful: true,
-	    stateId: 'grid-dc-backup',
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.BackupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],		
-	    columns: [
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    dataIndex: 'enabled',
-		    xtype: 'checkcolumn',
-		    sortable: true,
-		    disabled: true,
-		    disabledCls: 'x-item-enabled',
-		    stopSelection: false
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node',
-		    renderer: function(value) {
-			if (value) {
-			    return value;
-			}
-			return me.allText;
-		    }
-		},
-		{
-		    header: gettext('Day of week'),
-		    width: 200,
-		    sortable: false,
-		    dataIndex: 'dow',
-		    renderer: function(val) {
-			var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-			var selected = [];
-			var cur = -1;
-			val.split(',').forEach(function(day){
-			    cur++;
-			    var dow = (dows.indexOf(day)+6)%7;
-			    if (cur === dow) {
-				if (selected.length === 0 || selected[selected.length-1] === 0) {
-				    selected.push(1);
-				} else {
-				    selected[selected.length-1]++;
-				}
-			    } else {
-				while (cur < dow) {
-				    cur++;
-				    selected.push(0);
-				}
-				selected.push(1);
-			    }
-			});
-
-			cur = -1;
-			var days = [];
-			selected.forEach(function(item) {
-			    cur++;
-			    if (item > 2) {
-				days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
-				cur += item-1;
-			    } else if (item == 2) {
-				days.push(Ext.Date.dayNames[cur+1]);
-				days.push(Ext.Date.dayNames[(cur+2)%7]);
-				cur++;
-			    } else if (item == 1) {
-				days.push(Ext.Date.dayNames[(cur+1)%7]);
-			    }
-			});
-			return days.join(', ');
-		    }
-		},
-		{
-		    header: gettext('Start Time'),
-		    width: 60,
-		    sortable: true,
-		    dataIndex: 'starttime'
-		},
-		{
-		    header: gettext('Storage'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Selection'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'vmid',
-		    renderer: function(value, metaData, record) {
-			/*jslint confusion: true */
-			if (record.data.all) {
-			    if (record.data.exclude) {
-				return Ext.String.format(me.allExceptText, record.data.exclude);
-			    }
-			    return me.allText;
-			}
-			if (record.data.vmid) {
-			    return record.data.vmid;
-			}
-
-			return "-";
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-	
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'starttime', 'dow',
-	    'storage', 'node', 'vmid', 'exclude',
-	    'mailto',
-	    { name: 'enabled', type: 'boolean' },
-	    { name: 'all', type: 'boolean' },
-	    { name: 'snapshot', type: 'boolean' },
-	    { name: 'stop', type: 'boolean' },
-	    { name: 'suspend', type: 'boolean' },
-	    { name: 'compress', type: 'boolean' }
-	]
-    });
-});
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-    pveGuidePath: '/pve-docs/index.html',
-    onlineHelp: 'getting_help',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="http://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: function() {
-	var me = this;
-	var guideUrl = window.location.origin + me.pveGuidePath;
-	var text = Ext.String.format('<h1>Documentation</h1>'
-	+ 'The official Proxmox VE Administration Guide'
-	+ ' is included with this installation and can be browsed at '
-	+ '<a target="_blank" href="{0}">{0}</a>', guideUrl);
-	return text;
-    },
-
-    updateActive: function(data) {
-	var me = this;
-	
-	var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-
-    updateCommunity: function(data) {
-	var me = this;
-
-	var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-	 
-    updateInactive: function(data) {
-	var me = this;
-	me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/localhost/subscription',
-		method: 'GET',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.update('Unable to load subscription status' + ": " + response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-
-		    if (data.status === 'Active') {
-			if (data.level === 'c') {
-			    me.updateCommunity(data);
-			} else {
-			    me.updateActive(data);
-			}
-		    } else {
-			me.updateInactive(data);
-		    }
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('pve-security-groups', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'group', 'comment', 'digest' ],
-    idProperty: 'group'
-});
-
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = (me.group_name === undefined);
-
-	var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-	
-	var items = [	    
-	    {
-		xtype: 'textfield',
-		name: 'group',
-		value: me.group_name || '',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: me.group_comment || '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	if (me.isCreate) {
-	    subject = gettext('Security Group');
-        } else {
-	    subject = gettext('Security Group') + " '" + me.group_name + "'";
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'rename',
-		value: me.group_name
-	    });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	// InputPanel does not have a 'create' property, does it need a 'isCreate'
-	    isCreate: me.isCreate,
-	    items: items 
-	});
-
-
-	Ext.apply(me, {
-            subject: subject,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    stateful: true,
-    stateId: 'grid-securitygroups',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (me.rule_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-security-groups',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json' + me.base_url
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('group', oldrec.data.group);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.SecurityGroupEdit', {
-		digest: rec.data.digest,
-		group_name: rec.data.group,
-		group_comment: rec.data.comment
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('PVE.SecurityGroupEdit', {});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    enableFn: function(rec) {
-		return (rec && me.base_url);
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Group'), dataIndex: 'group', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = '/cluster/firewall/groups/' + rec.data.group;
-		    me.rule_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.rule_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-	var me = this;
-
-	var rule_panel = Ext.createWidget('pveFirewallRules', {
-	    region: 'center',
-	    allow_groups: false,
-	    list_refs_url: '/cluster/firewall/refs',
-	    tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-	    border: false
-	});
-
-	var sglist = Ext.createWidget('pveSecurityGroupList', {
-	    region: 'west',
-	    rule_panel: rule_panel,
-	    width: '25%',
-	    border: false,
-	    split: true
-	});
-
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-	    listeners: {
-		show: function() {
-		    sglist.fireEvent('show', sglist);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    onlineHelp: 'pve_admin_guide',
-
-    initComponent: function() {
-        var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext("Datacenter"),
-	    hstateid: 'dctab'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		title: gettext('Summary'),
-		xtype: 'pveDcSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    },
-	    {
-		title: gettext('Cluster'),
-		xtype: 'pveClusterAdministration',
-		iconCls: 'fa fa-server',
-		itemId: 'cluster'
-	    },
-	    {
-		xtype: 'pveDcOptionView',
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options'
-	    });
-	}
-
-	if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageView',
-		title: gettext('Storage'),
-		iconCls: 'fa fa-database',
-		itemId: 'storage'
-	    });
-	}
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveDcBackupView',
-		iconCls: 'fa fa-floppy-o',
-		title: gettext('Backup'),
-		itemId: 'backup'
-	    },
-	    {
-		xtype: 'pveReplicaView',
-		iconCls: 'fa fa-retweet',
-		title: gettext('Replication'),
-		itemId: 'replication'
-	    },
-	    {
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		expandedOnInit: true
-	    });
-	}
-
-	me.items.push({
-	    xtype: 'pveUserView',
-	    groups: ['permissions'],
-	    iconCls: 'fa fa-user',
-	    title: gettext('Users'),
-	    itemId: 'users'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveGroupView',
-		title: gettext('Groups'),
-		iconCls: 'fa fa-users',
-		groups: ['permissions'],
-		itemId: 'groups'
-	    },
-	    {
-		xtype: 'pvePoolView',
-		title: gettext('Pools'),
-		iconCls: 'fa fa-tags',
-		groups: ['permissions'],
-		itemId: 'pools'
-	    },
-	    {
-		xtype: 'pveRoleView',
-		title: gettext('Roles'),
-		iconCls: 'fa fa-male',
-		groups: ['permissions'],
-		itemId: 'roles'
-	    },
-	    {
-		xtype: 'pveAuthView',
-		title: gettext('Authentication'),
-		groups: ['permissions'],
-		iconCls: 'fa fa-key',
-		itemId: 'domains'
-	    },
-	    {
-		xtype: 'pveHAStatus',
-		title: 'HA',
-		iconCls: 'fa fa-heartbeat',
-		itemId: 'ha'
-	    },
-	    {
-		title: gettext('Groups'),
-		groups: ['ha'],
-		xtype: 'pveHAGroupsView',
-		iconCls: 'fa fa-object-group',
-		itemId: 'ha-groups'
-	    },
-	    {
-		title: gettext('Fencing'),
-		groups: ['ha'],
-		iconCls: 'fa fa-bolt',
-		xtype: 'pveFencingView',
-		itemId: 'ha-fencing'
-	    },
-	    {
-		xtype: 'pveFirewallRules',
-		title: gettext('Firewall'),
-		allow_iface: true,
-		base_url: '/cluster/firewall/rules',
-		list_refs_url: '/cluster/firewall/refs',
-		iconCls: 'fa fa-shield',
-		itemId: 'firewall'
-	    },
-	    {
-		xtype: 'pveFirewallOptions',
-		title: gettext('Options'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-gear',
-		base_url: '/cluster/firewall/options',
-		onlineHelp: 'pve_firewall_cluster_wide_setup',
-		fwtype: 'dc',
-		itemId: 'firewall-options'
-	    },
-	    {
-		xtype: 'pveSecurityGroups',
-		title: gettext('Security Group'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-group',
-		itemId: 'firewall-sg'
-	    },
-	    {
-		xtype: 'pveFirewallAliases',
-		title: gettext('Alias'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-external-link',
-		base_url: '/cluster/firewall/aliases',
-		itemId: 'firewall-aliases'
-	    },
-	    {
-		xtype: 'pveIPSet',
-		title: 'IPSet',
-		groups: ['firewall'],
-		iconCls: 'fa fa-list-ol',
-		base_url: '/cluster/firewall/ipset',
-		list_refs_url: '/cluster/firewall/refs',
-		itemId: 'firewall-ipset'
-	    },
-	    {
-		xtype: 'pveDcSupport',
-		title: gettext('Support'),
-		itemId: 'support',
-		iconCls: 'fa fa-comments-o'
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveDcNodeView',
-
-    title: gettext('Nodes'),
-    disableSelection: true,
-    scrollable: true,
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    dataIndex: 'name'
-	},
-	{
-	    header: 'ID',
-	    width: 40,
-	    sortable: true,
-	    dataIndex: 'nodeid'
-	},
-	{
-	    header: gettext('Online'),
-	    width: 60,
-	    sortable: true,
-	    dataIndex: 'online',
-	    renderer: function(value) {
-		var cls = (value)?'good':'critical';
-		return  '<i class="fa ' + PVE.Utils.get_health_icon(cls) + '"><i/>';
-	    }
-	},
-	{
-	    header: gettext('Support'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'level',
-	    renderer: PVE.Utils.render_support_level
-	},
-	{
-	    header: gettext('Server Address'),
-	    width: 115,
-	    sortable: true,
-	    dataIndex: 'ip'
-	},
-	{
-	    header: gettext('CPU usage'),
-	    sortable: true,
-	    width: 110,
-	    dataIndex: 'cpuusage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Memory usage'),
-	    width: 110,
-	    sortable: true,
-	    tdCls: 'x-progressbar-default-cell',
-	    dataIndex: 'memoryusage',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Uptime'),
-	    sortable: true,
-	    dataIndex: 'uptime',
-	    align: 'right',
-	    renderer: Proxmox.Utils.render_uptime
-	}
-    ],
-
-    stateful: true,
-    stateId: 'grid-cluster-nodes',
-    tools: [
-	{
-	    type: 'up',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = Math.max(me.getHeight()-50, 250);
-		me.setHeight(height);
-	    }
-	},
-	{
-	    type: 'down',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = me.getHeight()+50;
-		me.setHeight(height);
-	    }
-	}
-    ]
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-	extend: 'Ext.data.Model',
-	fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-	idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.widget.ProgressBar',{
-    extend: 'Ext.Progress',
-    alias: 'widget.pveProgressBar',
-
-    animate: true,
-    textTpl: [
-	'{percent}%'
-    ],
-
-    setValue: function(value){
-	var me = this;
-	me.callParent([value]);
-
-	me.removeCls(['warning', 'critical']);
-
-	if (value > 0.89) {
-	    me.addCls('critical');
-	} else if (value > 0.59) {
-	    me.addCls('warning');
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('pve-cluster-nodes', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
-	{ type: 'integer', name: 'quorum_votes' }
-    ],
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/nodes"
-    },
-    idProperty: 'nodeid'
-});
-
-Ext.define('pve-cluster-info', {
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/join"
-    }
-});
-
-Ext.define('PVE.ClusterAdministration', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveClusterAdministration',
-
-    title: gettext('Cluster Administration'),
-    onlineHelp: 'chapter_pvecm',
-
-    border: false,
-    defaults: { border: false },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    totem: {},
-	    nodelist: [],
-	    preferred_node: {
-		name: '',
-		fp: '',
-		addr: ''
-	    },
-	    isInCluster: false,
-	    nodecount: 0
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Cluster Information'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.store = Ext.create('Proxmox.data.UpdateStore', {
-			autoStart: true,
-			interval: 15 * 1000,
-			storeid: 'pve-cluster-info',
-			model: 'pve-cluster-info'
-		    });
-		    view.store.on('load', this.onLoad, this);
-		    view.on('destroy', view.store.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records || !records[0].data) {
-			vm.set('totem', {});
-			vm.set('isInCluster', false);
-			vm.set('nodelist', []);
-			vm.set('preferred_node', {
-			    name: '',
-			    addr: '',
-			    fp: ''
-			});
-			return;
-		    }
-		    var data = records[0].data;
-		    vm.set('totem', data.totem);
-		    vm.set('isInCluster', !!data.totem.cluster_name);
-		    vm.set('nodelist', data.nodelist);
-
-		    var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
-			return el.name === data.preferred_node;
-		    });
-
-		    vm.set('preferred_node', {
-			name: data.preferred_node,
-			addr: nodeinfo.pve_addr,
-			ring_addr: [ nodeinfo.ring0_addr, nodeinfo.ring1_addr ],
-			fp: nodeinfo.pve_fp
-		    });
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterCreateWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onClusterInfo: function() {
-		    var vm = this.getViewModel();
-		    var win = Ext.create('PVE.ClusterInfoWindow', {
-			joinInfo: {
-			    ipAddress: vm.get('preferred_node.addr'),
-			    fingerprint: vm.get('preferred_node.fp'),
-			    ring_addr: vm.get('preferred_node.ring_addr'),
-			    totem: vm.get('totem')
-			}
-		    });
-		    win.show();
-		},
-
-		onJoin: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create Cluster'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Information'),
-		    reference: 'addButton',
-		    handler: 'onClusterInfo',
-		    bind: {
-			disabled: '{!isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Cluster'),
-		    reference: 'joinButton',
-		    handler: 'onJoin',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		}
-	    ],
-	    layout: 'hbox',
-	    bodyPadding: 5,
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Cluster Name'),
-		    bind: {
-			value: '{totem.cluster_name}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Config Version'),
-		    bind: {
-			value: '{totem.config_version}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Number of Nodes'),
-		    labelWidth: 120,
-		    bind: {
-			value: '{nodecount}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    value: gettext('Standalone node - no cluster defined'),
-		    bind: {
-			hidden: '{isInCluster}'
-		    },
-		    flex: 1
-		}
-	    ]
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Cluster Nodes'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-cluster-nodes',
-			model: 'pve-cluster-nodes'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'nodeid',
-			    order: 'DESC'
-			}
-		    }));
-		    Proxmox.Utils.monStoreErrors(view, view.rstore);
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('nodecount', 0);
-			return;
-		    }
-		    vm.set('nodecount', records.length);
-		}
-	    },
-	    columns: [
-		{
-		    header: gettext('Nodename'),
-		    flex: 2,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('ID'),
-		    flex: 1,
-		    dataIndex: 'nodeid'
-		},
-		{
-		    header: gettext('Votes'),
-		    flex: 1,
-		    dataIndex: 'quorum_votes'
-		},
-		{
-		    header: gettext('Ring 0'),
-		    flex: 2,
-		    dataIndex: 'ring0_addr'
-		},
-		{
-		    header: gettext('Ring 1'),
-		    flex: 2,
-		    dataIndex: 'ring1_addr'
-		}
-	    ]
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ClusterCreateWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterCreateWindow',
-
-    title: gettext('Create Cluster'),
-    width: 600,
-
-    method: 'POST',
-    url: '/cluster/config',
-
-    isCreate: true,
-    subject: gettext('Cluster'),
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Cluster Name'),
-	    allowBlank: false,
-	    name: 'clustername'
-	},
-	{
-	    xtype: 'proxmoxtextfield',
-	    fieldLabel: gettext('Ring 0 Address'),
-	    emptyText: gettext("Optional, defaults to IP resolved by node's hostname"),
-	    name: 'ring0_addr',
-	    skipEmptyText: true
-	}
-	// TODO: for advanced options: ring1_addr
-    ]
-});
-
-Ext.define('PVE.ClusterInfoWindow', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveClusterInfoWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 800,
-    modal: true,
-    resizable: false,
-    title: gettext('Cluster Join Information'),
-
-    joinInfo: {
-	ipAddress: undefined,
-	fingerprint: undefined,
-	totem: {}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    border: false,
-	    padding: '10 10 10 10',
-	    html: gettext("Copy the Join Information here and use it on the node you want to add.")
-	},
-	{
-	    xtype: 'container',
-	    layout: 'form',
-	    border: false,
-	    padding: '0 10 10 10',
-	    items: [
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('IP Address'),
-		    cbind: { value: '{joinInfo.ipAddress}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Fingerprint'),
-		    cbind: { value: '{joinInfo.fingerprint}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textarea',
-		    inputId: 'pveSerializedClusterInfo',
-		    fieldLabel: gettext('Join Information'),
-		    grow: true,
-		    cbind: { joinInfo: '{joinInfo}' },
-		    editable: false,
-		    listeners: {
-			afterrender: function(field) {
-			    if (!field.joinInfo) {
-				return;
-			    }
-			    var jsons = Ext.JSON.encode(field.joinInfo);
-			    var base64s = Ext.util.Base64.encode(jsons);
-			    field.setValue(base64s);
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-    dockedItems: [{
-	dock: 'bottom',
-	xtype: 'toolbar',
-	items: [{
-	    xtype: 'button',
-	    handler: function(b) {
-		var el = document.getElementById('pveSerializedClusterInfo');
-		el.select();
-		document.execCommand("copy");
-	    },
-	    text: gettext('Copy Information')
-	}]
-    }]
-});
-
-Ext.define('PVE.ClusterJoinNodeWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterJoinNodeWindow',
-
-    title: gettext('Cluster Join'),
-    width: 800,
-
-    method: 'POST',
-    url: '/cluster/config/join',
-
-    defaultFocus: 'textarea[name=serializedinfo]',
-    isCreate: true,
-    submitText: gettext('Join'),
-    showTaskViewer: true,
-
-    onlineHelp: 'chapter_pvecm',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    info: {
-		fp: '',
-		ip: '',
-		ring0Needed: false,
-		ring1Possible: false,
-		ring1Needed: false
-	    }
-	},
-	formulas: {
-	    ring0EmptyText: function(get) {
-		if (get('info.ring0Needed')) {
-		    return gettext("Cannot use default address safely");
-		} else {
-		    return gettext("Default: IP resolved by node's hostname");
-		}
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#': {
-		close: function() {
-		    delete PVE.Utils.silenceAuthFailures;
-		}
-	    },
-	    'proxmoxcheckbox[name=assistedEntry]': {
-		change: 'onInputTypeChange'
-	    },
-	    'textarea[name=serializedinfo]': {
-		change: 'recomputeSerializedInfo',
-		enable: 'resetField'
-	    },
-	    'proxmoxtextfield[name=ring1_addr]': {
-		enable: 'ring1Needed'
-	    },
-	    'textfield': {
-		disable: 'resetField'
-	    }
-	},
-	resetField: function(field) {
-	    field.reset();
-	},
-	ring1Needed: function(f) {
-	    var vm = this.getViewModel();
-	    f.allowBlank = !vm.get('info.ring1Needed');
-	},
-	onInputTypeChange: function(field, assistedInput) {
-	    var vm = this.getViewModel();
-	    if (!assistedInput) {
-		vm.set('info.ring1Possible', true);
-	    }
-	},
-	recomputeSerializedInfo: function(field, value) {
-	    var vm = this.getViewModel();
-	    var jsons = Ext.util.Base64.decode(value);
-	    var joinInfo = Ext.JSON.decode(jsons, true);
-
-	    var info = {
-		fp: '',
-		ring1Needed: false,
-		ring1Possible: false,
-		ip: ''
-	    };
-
-	    var totem = {};
-	    if (!(joinInfo && joinInfo.totem)) {
-		field.valid = false;
-	    } else {
-		var ring0Needed = false;
-		if (joinInfo.ring_addr !== undefined) {
-		    ring0Needed = joinInfo.ring_addr[0] !== joinInfo.ipAddress;
-		}
-
-		info = {
-		    ip: joinInfo.ipAddress,
-		    fp: joinInfo.fingerprint,
-		    ring0Needed: ring0Needed,
-		    ring1Possible: !!joinInfo.totem['interface']['1'],
-		    ring1Needed: !!joinInfo.totem['interface']['1']
-		};
-		totem = joinInfo.totem;
-		field.valid = true;
-	    }
-
-	    vm.set('info', info);
-	}
-    },
-
-    submit: function() {
-	// joining may produce temporarily auth failures, ignore as long the task runs
-	PVE.Utils.silenceAuthFailures = true;
-	this.callParent();
-    },
-
-    taskDone: function(success) {
-	delete PVE.Utils.silenceAuthFailures;
-	if (success) {
-	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
-	    // ensure user cannot do harm
-	    Ext.getBody().mask(txt, ['pve-static-mask']);
-	    // TaskView may hide above mask, so tell him directly
-	    Ext.Msg.show({
-		title: gettext('Join Task Finished'),
-		icon: Ext.Msg.INFO,
-		msg: txt
-	    });
-	    // reload always (if user wasn't faster), but wait a bit for pveproxy
-	    Ext.defer(function() {
-		window.location.reload(true);
-	    }, 5000);
-	}
-    },
-
-    items: [{
-	xtype: 'proxmoxcheckbox',
-	reference: 'assistedEntry',
-	name: 'assistedEntry',
-	submitValue: false,
-	value: true,
-	autoEl: {
-	    tag: 'div',
-	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
-	},
-	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
-    },
-    {
-	xtype: 'textarea',
-	name: 'serializedinfo',
-	submitValue: false,
-	allowBlank: false,
-	fieldLabel: gettext('Information'),
-	emptyText: gettext('Paste encoded Cluster Information here'),
-	validator: function(val) {
-	    return val === '' || this.valid ||
-	       gettext('Does not seem like a valid encoded Cluster Information!');
-	},
-	bind: {
-	    disabled: '{!assistedEntry.checked}',
-	    hidden: '{!assistedEntry.checked}'
-	},
-	value: ''
-    },
-    {
-	xtype: 'inputpanel',
-	column1: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Peer Address'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.ip}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'hostname'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		emptyText: gettext("Peer's root password"),
-		fieldLabel: gettext('Password'),
-		allowBlank: false,
-		name: 'password'
-	    }
-	],
-	column2: [
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('Corosync Ring 0'),
-		bind: {
-		    emptyText: '{ring0EmptyText}',
-		    allowBlank: '{!info.ring0Needed}'
-		},
-		skipEmptyText: true,
-		name: 'ring0_addr'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('Corosync Ring 1'),
-		skipEmptyText: true,
-		bind: {
-		    disabled: '{!info.ring1Possible}'
-		},
-		name: 'ring1_addr'
-	    }
-	],
-	columnB: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Fingerprint'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.fp}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'fingerprint'
-	    }
-	]
-    }]
-});
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-	var me = this;
-	me.loginData = loginData;
-	Proxmox.Utils.setAuthData(loginData);
-
-	var rt = me.down('pveResourceTree');
-	rt.setDatacenterText(loginData.clustername);
-
-	if (loginData.cap) {
-	    Ext.state.Manager.set('GuiCap', loginData.cap);
-	}
-
-	me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-	var me = this;
-
-	Proxmox.Utils.authClear();
-	Proxmox.UserName = null;
-	me.loginData = null;
-
-	if (!me.login) {
-	    me.login = Ext.create('PVE.window.LoginWindow', {
-		handler: function(data) {
-		    me.login = null;
-		    me.updateLoginData(data);
-		    Proxmox.Utils.checked_command(function() {}); // display subscription status
-		}
-	    });
-	}
-	me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.tip.QuickTipManager.init();
-
-	// fixme: what about other errors
-	Ext.Ajax.on('requestexception', function(conn, response, options) {
-	    if (response.status == 401 && !PVE.Utils.silenceAuthFailures) { // auth failure
-		me.showLogin();
-	    }
-	});
-
-	me.callParent();
-
-        if (!Proxmox.Utils.authOK()) {
-	    me.showLogin();
-	} else { 
-	    if (me.loginData) {
-		me.onLogin(me.loginData);
-	    }
-	}
-
-	Ext.TaskManager.start({
-	    run: function() {
-		var ticket = Proxmox.Utils.authOK();
-		if (!ticket || !Proxmox.UserName) {
-		    return;
-		}
-
-		Ext.Ajax.request({
-		    params: { 
-			username: Proxmox.UserName,
-			password: ticket
-		    },
-		    url: '/api2/json/access/ticket',
-		    method: 'POST',
-		    success: function(response, opts) {
-			var obj = Ext.decode(response.responseText);
-			me.updateLoginData(obj.data);
-		    }
-		});
-	    },
-	    interval: 15*60*1000
-	});
-
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-	var me = this;
-	
-	var cont = me.child('#content');
-
-	var lay = cont.getLayout();
-
-	var cur = lay.getActiveItem();
-
-	if (comp) {
-	    Proxmox.Utils.setErrorMask(cont, false);
-	    comp.border = false;
-	    cont.add(comp);
-	    if (cur !== null && lay.getNext()) {
-		lay.next();
-		var task = Ext.create('Ext.util.DelayedTask', function(){
-		    cont.remove(cur);
-		});
-		task.delay(10);
-	    }
-	}
-	else {
-	    // helper for cleaning the content when logging out
-	    cont.removeAll();
-	}
-    },
-
-    selectById: function(nodeid) {
-	var me = this;
-	var tree = me.down('pveResourceTree');
-	tree.selectById(nodeid);
-    },
-
-    onLogin: function(loginData) {
-	var me = this;
-
-	me.updateUserInfo();
-
-	if (loginData) {
-	    PVE.data.ResourceStore.startUpdate();
-
-	    Proxmox.Utils.API2Request({
-		url: '/version',
-		method: 'GET',
-		success: function(response) {
-		    PVE.VersionInfo = response.result.data;
-		    me.updateVersionInfo();
-		}
-	    });
-	}
-    },
-
-    updateUserInfo: function() {
-	var me = this;
-
-	var ui = me.query('#userinfo')[0];
-
-	if (Proxmox.UserName) {
-	    var msg =  Ext.String.format(gettext("You are logged in as {0}"), "'" + Proxmox.UserName + "'");
-	    ui.update('<div class="x-unselectable" style="white-space:nowrap;">' + msg + '</div>');
-	} else {
-	    ui.update('');
-	}
-	ui.updateLayout();
-    },
-
-    updateVersionInfo: function() {
-	var me = this;
-
-	var ui = me.query('#versioninfo')[0];
-
-	if (PVE.VersionInfo) {
-	    var version = PVE.VersionInfo.version + '-' + PVE.VersionInfo.release;
-	    ui.update('Virtual Environment ' + version);
-	} else {
-	    ui.update('Virtual Environment');
-	}
-	ui.updateLayout();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.History.init();
-
-	var sprovider = Ext.create('PVE.StateProvider');
-	Ext.state.Manager.setProvider(sprovider);
-
-	var selview = Ext.create('PVE.form.ViewSelector');
-
-	var rtree = Ext.createWidget('pveResourceTree', {
-	    viewFilter: selview.getViewFilter(),
-	    flex: 1,
-	    selModel: {
-		selType: 'treemodel',
-		listeners: {
-		    selectionchange: function(sm, selected) {
-			if (selected.length > 0) {
-			    var n = selected[0];
-			    var tlckup = {
-				root: 'PVE.dc.Config',
-				node: 'PVE.node.Config',
-				qemu: 'PVE.qemu.Config',
-				lxc: 'PVE.lxc.Config',
-				storage: 'PVE.storage.Browser',
-				pool: 'pvePoolConfig'
-			    };
-			    var comp = {
-				xtype: tlckup[n.data.type || 'root'] || 
-				    'pvePanelConfig',
-				showSearch: (n.data.id === 'root') ||
-				    Ext.isDefined(n.data.groupbyid),
-				pveSelNode: n,
-				workspace: me,
-				viewFilter: selview.getViewFilter()
-			    };
-			    PVE.curSelectedNode = n;
-			    me.setContent(comp);
-			}
-		    }
-		}
-	    }
-	});
-
-	selview.on('select', function(combo, records) { 
-	    if (records) {
-		var view = combo.getViewFilter();
-		rtree.setViewFilter(view);
-	    }
-	});
-
-	var caps = sprovider.get('GuiCap');
-
-	var createVM = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-desktop',
-	    text: gettext("Create VM"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	var createCT = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-cube',
-	    text: gettext("Create CT"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	sprovider.on('statechange', function(sp, key, value) {
-	    if (key === 'GuiCap' && value) {
-		caps = value;
-		createVM.setDisabled(!caps.vms['VM.Allocate']);
-		createCT.setDisabled(!caps.vms['VM.Allocate']);
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		{
-		    region: 'north',
-		    layout: { 
-			type: 'hbox',
-			align: 'middle'
-		    },
-		    baseCls: 'x-plain',		
-		    defaults: {
-			baseCls: 'x-plain'			
-		    },
-		    border: false,
-		    margin: '2 0 2 5',
-		    items: [
-			{
-			    html: '<a class="x-unselectable" target=_blank href="http://www.proxmox.com">' +
-				'<img style="padding-top:4px;padding-right:5px" src="/pve2/images/proxmox_logo.png"/></a>'
-			},
-			{
-			    minWidth: 150,
-			    id: 'versioninfo',
-			    html: 'Virtual Environment'
-			},
-			{
-			    xtype: 'pveGlobalSearchField',
-			    tree: rtree
-			},
-			{
-			    flex: 1
-			},
-			{
-			    pack: 'end',
-			    id: 'userinfo',
-			    stateful: false
-			},
-			{
-			    xtype: 'button',
-			    margin: '0 10 0 3',
-			    iconCls: 'fa black fa-gear',
-			    userCls: 'pointer',
-			    handler: function() {
-				var win = Ext.create('PVE.window.Settings');
-				win.show();
-			    }
-			},
-			{
-			    xtype: 'proxmoxHelpButton',
-			    hidden: false,
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
-			    listenToGlobalEvent: false,
-			    onlineHelp: 'pve_documentation_index',
-			    text: gettext('Documentation'),
-			    margin: '0 5 0 0'
-			},
-			createVM, 
-			createCT,
-			{
-			    pack: 'end',
-			    margin: '0 5 0 0',
-			    xtype: 'button',
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-sign-out',
-			    text: gettext("Logout"),
-			    handler: function() { 
-				PVE.data.ResourceStore.loadData([], false);
-				me.showLogin(); 
-				me.setContent(null);
-				var rt = me.down('pveResourceTree');
-				rt.setDatacenterText(undefined);
-				rt.clearTree();
-
-				// empty the stores of the StatusPanel child items
-				var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
-				Ext.Array.forEach(statusPanels, function(comp) {
-				    if (comp.getStore()) {
-					comp.getStore().loadData([], false);
-				    }
-				});
-			    }
-			}
-		    ]
-		},
-		{
-		    region: 'center',
-		    stateful: true,
-		    stateId: 'pvecenter',
-		    minWidth: 100,
-		    minHeight: 100,
-		    id: 'content',
-		    xtype: 'container',
-		    layout: { type: 'card' },
-		    border: false,
-		    margin: '0 5 0 0',
-		    items: []
-		},
-		{
-		    region: 'west',
-		    stateful: true,
-		    stateId: 'pvewest',
-		    itemId: 'west',
-		    xtype: 'container',
-		    border: false,
-		    layout: { type: 'vbox', align: 'stretch' },
-		    margin: '0 0 0 5',
-		    split: true,
-		    width: 200,
-		    items: [ selview, rtree ],
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewWidth = me.getSize().width;
-			    if (width > viewWidth - 100) {
-				panel.setWidth(viewWidth - 100);
-			    }
-			}
-		    }
-		},
-		{
-		    xtype: 'pveStatusPanel',
-		    stateful: true,
-		    stateId: 'pvesouth',
-		    itemId: 'south',
-		    region: 'south',
-		    margin:'0 5 5 5',
-		    title: gettext('Logs'),
-		    collapsible: true,
-		    header: false,
-		    height: 200,
-		    split:true,
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewHeight = me.getSize().height;
-			    if (height > (viewHeight - 150)) {
-				panel.setHeight(viewHeight - 150);
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.updateUserInfo();
-
-	// on resize, center all modal windows
-	Ext.on('resize', function(){
-	    var wins = Ext.ComponentQuery.query('window[modal]');
-	    if (wins.length > 0) {
-		wins.forEach(function(win){
-		    win.alignTo(me, 'c-c');
-		});
-	    }
-	});
-    }
-});
-
diff --git a/serverside/jsmod/6.0-4.sh b/serverside/jsmod/6.0-4.sh
deleted file mode 100644
index 66c0f54f3c9e952e9caa0f98246c349742230150..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/bash
-
-Say () {
-    printf "\e[1;34m $1  \e[0m \n";
-}
-
-DotSay () {
-    printf "[\e[1;34m*\e[0m] \e[1;34m $1  \e[0m \n"; 
-}
-
-
-Say '[PVE Discord Dark UI Theme JSMOD Installer]'
-Say 'Internet connection REQUIRED.'
-Say '!!ONLY FOR PVE 6.0-4 - 6.1-x!!'
-Say '>Press any key to begin installation'
-read -p ""
-Say ' '
-DotSay 'Backing up files'
-cp /usr/share/pve-manager/js/pvemanagerlib.js /usr/share/pve-manager/js/pvemanagerlib.js.bak 
-cp /usr/share/javascript/extjs/charts.js /usr/share/javascript/extjs/charts.js.bak
-cp /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.bak
-DotSay 'Replacing files with modded versions'
-rm /usr/share/pve-manager/js/pvemanagerlib.js
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/6.0-4/pvemanagerlib.js -P /usr/share/pve-manager/js/ &> /dev/null 
-rm /usr/share/javascript/extjs/charts.js
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/6.0-4/charts.js -P /usr/share/javascript/extjs/ &> /dev/null 
-rm /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js 
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/6.0-4/proxmoxlib.js -P /usr/share/javascript/proxmox-widget-toolkit/ &> /dev/null 
-DotSay 'Applied successfully.'
-Say ''
-Say 'Installation finished!'
-Say 'o7'  
diff --git a/serverside/jsmod/6.0-4/charts.js b/serverside/jsmod/6.0-4/charts.js
deleted file mode 100644
index 713bec3b2c8b56c8dac86cc7955bb464a438bf3d..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/charts.js
+++ /dev/null
@@ -1,22013 +0,0 @@
-Ext.define("Ext.draw.ContainerBase", {
-    extend: "Ext.panel.Panel",
-    requires: ["Ext.window.Window"],
-    previewTitleText: "Chart Preview",
-    previewAltText: "Chart preview",
-    layout: "container",
-    addElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.on.apply(b.el, a)
-        } else {
-            b.on("render", function() {
-                b.el.on.apply(b.el, a)
-            })
-        }
-    },
-    removeElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.un.apply(b.el, a)
-        }
-    },
-    afterRender: function() {
-        this.callParent(arguments);
-        this.initAnimator()
-    },
-    getItems: function() {
-        var b = this,
-            a = b.items;
-        if (!a || !a.isMixedCollection) {
-            b.initItems()
-        }
-        return b.items
-    },
-    onRender: function() {
-        this.callParent(arguments);
-        this.element = this.el;
-        this.innerElement = this.body
-    },
-    setItems: function(a) {
-        this.items = a;
-        return a
-    },
-    setSurfaceSize: function(b, a) {
-        this.resizeHandler({
-            width: b,
-            height: a
-        });
-        this.renderFrame()
-    },
-    onResize: function(c, a, b, e) {
-        var d = this;
-        d.callParent([c, a, b, e]);
-        d.setBodySize({
-            width: c,
-            height: a
-        })
-    },
-    preview: function() {
-        var a = this.getImage();
-        new Ext.window.Window({
-            title: this.previewTitleText,
-            closeable: true,
-            renderTo: Ext.getBody(),
-            autoShow: true,
-            maximizeable: true,
-            maximized: true,
-            border: true,
-            layout: {
-                type: "hbox",
-                pack: "center",
-                align: "middle"
-            },
-            items: {
-                xtype: "container",
-                items: {
-                    xtype: "image",
-                    mode: "img",
-                    cls: Ext.baseCSSPrefix + "chart-image",
-                    alt: this.previewAltText,
-                    src: a.data,
-                    listeners: {
-                        afterrender: function() {
-                            var e = this,
-                                b = e.imgEl.dom,
-                                d = a.type === "svg" ? 1 : (window.devicePixelRatio || 1),
-                                c;
-                            if (!b.naturalWidth || !b.naturalHeight) {
-                                b.onload = function() {
-                                    var g = b.naturalWidth,
-                                        f = b.naturalHeight;
-                                    e.setWidth(Math.floor(g / d));
-                                    e.setHeight(Math.floor(f / d))
-                                }
-                            } else {
-                                c = e.getSize();
-                                e.setWidth(Math.floor(c.width / d));
-                                e.setHeight(Math.floor(c.height / d))
-                            }
-                        }
-                    }
-                }
-            }
-        })
-    },
-    privates: {
-        getTargetEl: function() {
-            return this.innerElement
-        },
-        reattachToBody: function() {
-            var a = this;
-            if (a.pendingDetachSize) {
-                a.onBodyResize()
-            }
-            a.pendingDetachSize = false;
-            a.callParent()
-        }
-    }
-});
-Ext.define("Ext.draw.SurfaceBase", {
-    extend: "Ext.Widget",
-    getOwnerBody: function() {
-        return this.ownerCt.body
-    },
-    destroy: function() {
-        var a = this;
-        if (a.hasListeners.destroy) {
-            a.fireEvent("destroy", a)
-        }
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.Color", {
-    statics: {
-        colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbToHexRe: /\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbaToHexRe: /\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,
-        hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,
-        NONE: "none",
-        RGBA_NONE: "rgba(0, 0, 0, 0)"
-    },
-    isColor: true,
-    lightnessFactor: 0.2,
-    constructor: function(d, b, a, c) {
-        this.setRGB(d, b, a, c)
-    },
-    setRGB: function(e, c, a, d) {
-        var b = this;
-        b.r = Math.min(255, Math.max(0, e));
-        b.g = Math.min(255, Math.max(0, c));
-        b.b = Math.min(255, Math.max(0, a));
-        if (d === undefined) {
-            b.a = 1
-        } else {
-            b.a = Math.min(1, Math.max(0, d))
-        }
-    },
-    getGrayscale: function() {
-        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11
-    },
-    getHSL: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            m = k - d,
-            e, n = 0,
-            c = 0.5 * (k + d);
-        if (d !== k) {
-            n = (c <= 0.5) ? m / (k + d) : m / (2 - k - d);
-            if (a === k) {
-                e = 60 * (f - j) / m
-            } else {
-                if (f === k) {
-                    e = 120 + 60 * (j - a) / m
-                } else {
-                    e = 240 + 60 * (a - f) / m
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, n, c]
-    },
-    getHSV: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            c = k - d,
-            e, m = 0,
-            l = k;
-        if (d != k) {
-            m = l ? c / l : 0;
-            if (a === k) {
-                e = 60 * (f - j) / c
-            } else {
-                if (f === k) {
-                    e = 60 * (j - a) / c + 120
-                } else {
-                    e = 60 * (a - f) / c + 240
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, m, l]
-    },
-    setHSL: function(g, f, e) {
-        var i = this,
-            d = Math.abs,
-            j, b, a;
-        g = (g % 360 + 360) % 360;
-        f = f > 1 ? 1 : f < 0 ? 0 : f;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        if (f === 0 || g === null) {
-            e *= 255;
-            i.setRGB(e, e, e)
-        } else {
-            g /= 60;
-            j = f * (1 - d(2 * e - 1));
-            b = j * (1 - d(g % 2 - 1));
-            a = e - j / 2;
-            a *= 255;
-            j *= 255;
-            b *= 255;
-            switch (Math.floor(g)) {
-                case 0:
-                    i.setRGB(j + a, b + a, a);
-                    break;
-                case 1:
-                    i.setRGB(b + a, j + a, a);
-                    break;
-                case 2:
-                    i.setRGB(a, j + a, b + a);
-                    break;
-                case 3:
-                    i.setRGB(a, b + a, j + a);
-                    break;
-                case 4:
-                    i.setRGB(b + a, a, j + a);
-                    break;
-                case 5:
-                    i.setRGB(j + a, a, b + a);
-                    break
-            }
-        }
-        return i
-    },
-    setHSV: function(f, e, d) {
-        var g = this,
-            i, b, a;
-        f = (f % 360 + 360) % 360;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        d = d > 1 ? 1 : d < 0 ? 0 : d;
-        if (e === 0 || f === null) {
-            d *= 255;
-            g.setRGB(d, d, d)
-        } else {
-            f /= 60;
-            i = d * e;
-            b = i * (1 - Math.abs(f % 2 - 1));
-            a = d - i;
-            a *= 255;
-            i *= 255;
-            b *= 255;
-            switch (Math.floor(f)) {
-                case 0:
-                    g.setRGB(i + a, b + a, a);
-                    break;
-                case 1:
-                    g.setRGB(b + a, i + a, a);
-                    break;
-                case 2:
-                    g.setRGB(a, i + a, b + a);
-                    break;
-                case 3:
-                    g.setRGB(a, b + a, i + a);
-                    break;
-                case 4:
-                    g.setRGB(b + a, a, i + a);
-                    break;
-                case 5:
-                    g.setRGB(i + a, a, b + a);
-                    break
-            }
-        }
-        return g
-    },
-    createLighter: function(b) {
-        if (!b && b !== 0) {
-            b = this.lightnessFactor
-        }
-        var a = this.getHSL();
-        a[2] = Ext.Number.constrain(a[2] + b, 0, 1);
-        return Ext.draw.Color.fromHSL(a[0], a[1], a[2])
-    },
-    createDarker: function(a) {
-        if (!a && a !== 0) {
-            a = this.lightnessFactor
-        }
-        return this.createLighter(-a)
-    },
-    toString: function() {
-        var f = this,
-            c = Math.round;
-        if (f.a === 1) {
-            var e = c(f.r).toString(16),
-                d = c(f.g).toString(16),
-                a = c(f.b).toString(16);
-            e = (e.length === 1) ? "0" + e : e;
-            d = (d.length === 1) ? "0" + d : d;
-            a = (a.length === 1) ? "0" + a : a;
-            return ["#", e, d, a].join("")
-        } else {
-            return "rgba(" + [c(f.r), c(f.g), c(f.b), f.a === 0 ? 0 : f.a.toFixed(15)].join(", ") + ")"
-        }
-    },
-    toHex: function(b) {
-        if (Ext.isArray(b)) {
-            b = b[0]
-        }
-        if (!Ext.isString(b)) {
-            return ""
-        }
-        if (b.substr(0, 1) === "#") {
-            return b
-        }
-        var e = Ext.draw.Color.colorToHexRe.exec(b);
-        if (Ext.isArray(e)) {
-            var f = parseInt(e[2], 10),
-                d = parseInt(e[3], 10),
-                a = parseInt(e[4], 10),
-                c = a | (d << 8) | (f << 16);
-            return e[1] + "#" + ("000000" + c.toString(16)).slice(-6)
-        } else {
-            return ""
-        }
-    },
-    setFromString: function(j) {
-        var e, h, f, c, d = 1,
-            i = parseInt;
-        if (j === Ext.draw.Color.NONE) {
-            this.r = this.g = this.b = this.a = 0;
-            return this
-        }
-        if ((j.length === 4 || j.length === 7) && j.substr(0, 1) === "#") {
-            e = j.match(Ext.draw.Color.hexRe);
-            if (e) {
-                h = i(e[1], 16) >> 0;
-                f = i(e[2], 16) >> 0;
-                c = i(e[3], 16) >> 0;
-                if (j.length === 4) {
-                    h += (h * 16);
-                    f += (f * 16);
-                    c += (c * 16)
-                }
-            }
-        } else {
-            if ((e = j.match(Ext.draw.Color.rgbToHexRe))) {
-                h = +e[1];
-                f = +e[2];
-                c = +e[3]
-            } else {
-                if ((e = j.match(Ext.draw.Color.rgbaToHexRe))) {
-                    h = +e[1];
-                    f = +e[2];
-                    c = +e[3];
-                    d = +e[4]
-                } else {
-                    if (Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())) {
-                        return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])
-                    }
-                }
-            }
-        }
-        if (typeof h === "undefined") {
-            return this
-        }
-        this.r = h;
-        this.g = f;
-        this.b = c;
-        this.a = d;
-        return this
-    }
-}, function() {
-    var a = new this();
-    this.addStatics({
-        fly: function(f, e, c, d) {
-            switch (arguments.length) {
-                case 1:
-                    a.setFromString(f);
-                    break;
-                case 3:
-                case 4:
-                    a.setRGB(f, e, c, d);
-                    break;
-                default:
-                    return null
-            }
-            return a
-        },
-        ColorList: {
-            aliceblue: "#f0f8ff",
-            antiquewhite: "#faebd7",
-            aqua: "#00ffff",
-            aquamarine: "#7fffd4",
-            azure: "#f0ffff",
-            beige: "#f5f5dc",
-            bisque: "#ffe4c4",
-            black: "#000000",
-            blanchedalmond: "#ffebcd",
-            blue: "#0000ff",
-            blueviolet: "#8a2be2",
-            brown: "#a52a2a",
-            burlywood: "#deb887",
-            cadetblue: "#5f9ea0",
-            chartreuse: "#7fff00",
-            chocolate: "#d2691e",
-            coral: "#ff7f50",
-            cornflowerblue: "#6495ed",
-            cornsilk: "#fff8dc",
-            crimson: "#dc143c",
-            cyan: "#00ffff",
-            darkblue: "#00008b",
-            darkcyan: "#008b8b",
-            darkgoldenrod: "#b8860b",
-            darkgray: "#a9a9a9",
-            darkgreen: "#006400",
-            darkkhaki: "#bdb76b",
-            darkmagenta: "#8b008b",
-            darkolivegreen: "#556b2f",
-            darkorange: "#ff8c00",
-            darkorchid: "#9932cc",
-            darkred: "#8b0000",
-            darksalmon: "#e9967a",
-            darkseagreen: "#8fbc8f",
-            darkslateblue: "#483d8b",
-            darkslategray: "#2f4f4f",
-            darkturquoise: "#00ced1",
-            darkviolet: "#9400d3",
-            deeppink: "#ff1493",
-            deepskyblue: "#00bfff",
-            dimgray: "#696969",
-            dodgerblue: "#1e90ff",
-            firebrick: "#b22222",
-            floralwhite: "#fffaf0",
-            forestgreen: "#228b22",
-            fuchsia: "#ff00ff",
-            gainsboro: "#dcdcdc",
-            ghostwhite: "#f8f8ff",
-            gold: "#ffd700",
-            goldenrod: "#daa520",
-            gray: "#808080",
-            green: "#008000",
-            greenyellow: "#adff2f",
-            honeydew: "#f0fff0",
-            hotpink: "#ff69b4",
-            indianred: "#cd5c5c",
-            indigo: "#4b0082",
-            ivory: "#fffff0",
-            khaki: "#f0e68c",
-            lavender: "#e6e6fa",
-            lavenderblush: "#fff0f5",
-            lawngreen: "#7cfc00",
-            lemonchiffon: "#fffacd",
-            lightblue: "#add8e6",
-            lightcoral: "#f08080",
-            lightcyan: "#e0ffff",
-            lightgoldenrodyellow: "#fafad2",
-            lightgray: "#d3d3d3",
-            lightgrey: "#d3d3d3",
-            lightgreen: "#90ee90",
-            lightpink: "#ffb6c1",
-            lightsalmon: "#ffa07a",
-            lightseagreen: "#20b2aa",
-            lightskyblue: "#87cefa",
-            lightslategray: "#778899",
-            lightsteelblue: "#b0c4de",
-            lightyellow: "#ffffe0",
-            lime: "#00ff00",
-            limegreen: "#32cd32",
-            linen: "#faf0e6",
-            magenta: "#ff00ff",
-            maroon: "#800000",
-            mediumaquamarine: "#66cdaa",
-            mediumblue: "#0000cd",
-            mediumorchid: "#ba55d3",
-            mediumpurple: "#9370d8",
-            mediumseagreen: "#3cb371",
-            mediumslateblue: "#7b68ee",
-            mediumspringgreen: "#00fa9a",
-            mediumturquoise: "#48d1cc",
-            mediumvioletred: "#c71585",
-            midnightblue: "#191970",
-            mintcream: "#f5fffa",
-            mistyrose: "#ffe4e1",
-            moccasin: "#ffe4b5",
-            navajowhite: "#ffdead",
-            navy: "#000080",
-            oldlace: "#fdf5e6",
-            olive: "#808000",
-            olivedrab: "#6b8e23",
-            orange: "#ffa500",
-            orangered: "#ff4500",
-            orchid: "#da70d6",
-            palegoldenrod: "#eee8aa",
-            palegreen: "#98fb98",
-            paleturquoise: "#afeeee",
-            palevioletred: "#d87093",
-            papayawhip: "#ffefd5",
-            peachpuff: "#ffdab9",
-            peru: "#cd853f",
-            pink: "#ffc0cb",
-            plum: "#dda0dd",
-            powderblue: "#b0e0e6",
-            purple: "#800080",
-            red: "#ff0000",
-            rosybrown: "#bc8f8f",
-            royalblue: "#4169e1",
-            saddlebrown: "#8b4513",
-            salmon: "#fa8072",
-            sandybrown: "#f4a460",
-            seagreen: "#2e8b57",
-            seashell: "#fff5ee",
-            sienna: "#a0522d",
-            silver: "#c0c0c0",
-            skyblue: "#87ceeb",
-            slateblue: "#6a5acd",
-            slategray: "#708090",
-            snow: "#fffafa",
-            springgreen: "#00ff7f",
-            steelblue: "#4682b4",
-            tan: "#d2b48c",
-            teal: "#008080",
-            thistle: "#d8bfd8",
-            tomato: "#ff6347",
-            turquoise: "#40e0d0",
-            violet: "#ee82ee",
-            wheat: "#f5deb3",
-            white: "#ffffff",
-            whitesmoke: "#f5f5f5",
-            yellow: "#ffff00",
-            yellowgreen: "#9acd32"
-        },
-        fromHSL: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromHSV: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromString: function(b) {
-            return (new this(0, 0, 0, 0)).setFromString(b)
-        },
-        create: function(b) {
-            if (b instanceof this) {
-                return b
-            } else {
-                if (Ext.isArray(b)) {
-                    return new Ext.draw.Color(b[0], b[1], b[2], b[3])
-                } else {
-                    if (Ext.isString(b)) {
-                        return Ext.draw.Color.fromString(b)
-                    } else {
-                        if (arguments.length > 2) {
-                            return new Ext.draw.Color(arguments[0], arguments[1], arguments[2], arguments[3])
-                        } else {
-                            return new Ext.draw.Color(0, 0, 0, 0)
-                        }
-                    }
-                }
-            }
-        }
-    })
-});
-Ext.define("Ext.draw.sprite.AnimationParser", function() {
-    function a(d, c, b) {
-        return d + (c - d) * b
-    }
-    return {
-        singleton: true,
-        attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-        requires: ["Ext.draw.Color"],
-        color: {
-            parseInitial: function(c, b) {
-                if (Ext.isString(c)) {
-                    c = Ext.draw.Color.create(c)
-                }
-                if (Ext.isString(b)) {
-                    b = Ext.draw.Color.create(b)
-                }
-                if ((c instanceof Ext.draw.Color) && (b instanceof Ext.draw.Color)) {
-                    return [
-                        [c.r, c.g, c.b, c.a],
-                        [b.r, b.g, b.b, b.a]
-                    ]
-                } else {
-                    return [c || b, b || c]
-                }
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isArray(d) || !Ext.isArray(c)) {
-                    return c || d
-                } else {
-                    return [a(d[0], c[0], b), a(d[1], c[1], b), a(d[2], c[2], b), a(d[3], c[3], b)]
-                }
-            },
-            serve: function(c) {
-                var b = Ext.draw.Color.fly(c[0], c[1], c[2], c[3]);
-                return b.toString()
-            }
-        },
-        number: {
-            parse: function(b) {
-                return b === null ? null : +b
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        angle: {
-            parseInitial: function(c, b) {
-                if (b - c > Math.PI) {
-                    b -= Math.PI * 2
-                } else {
-                    if (b - c < -Math.PI) {
-                        b += Math.PI * 2
-                    }
-                }
-                return [c, b]
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        path: {
-            parseInitial: function(m, n) {
-                var c = m.toStripes(),
-                    o = n.toStripes(),
-                    e, d, k = c.length,
-                    p = o.length,
-                    h, f, b, g = o[p - 1],
-                    l = [g[g.length - 2], g[g.length - 1]];
-                for (e = k; e < p; e++) {
-                    c.push(c[k - 1].slice(0))
-                }
-                for (e = p; e < k; e++) {
-                    o.push(l.slice(0))
-                }
-                b = c.length;
-                o.path = n;
-                o.temp = new Ext.draw.Path();
-                for (e = 0; e < b; e++) {
-                    h = c[e];
-                    f = o[e];
-                    k = h.length;
-                    p = f.length;
-                    o.temp.commands.push("M");
-                    for (d = p; d < k; d += 6) {
-                        f.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    g = o[o.length - 1];
-                    l = [g[g.length - 2], g[g.length - 1]];
-                    for (d = k; d < p; d += 6) {
-                        h.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    for (e = 0; e < f.length; e++) {
-                        f[e] -= h[e]
-                    }
-                    for (e = 2; e < f.length; e += 6) {
-                        o.temp.commands.push("C")
-                    }
-                }
-                return [c, o]
-            },
-            compute: function(c, l, m) {
-                if (m >= 1) {
-                    return l.path
-                }
-                var e = 0,
-                    f = c.length,
-                    d = 0,
-                    b, k, h, n = l.temp.params,
-                    g = 0;
-                for (; e < f; e++) {
-                    k = c[e];
-                    h = l[e];
-                    b = k.length;
-                    for (d = 0; d < b; d++) {
-                        n[g++] = h[d] * m + k[d]
-                    }
-                }
-                return l.temp
-            }
-        },
-        data: {
-            compute: function(h, j, k, g) {
-                var m = h.length - 1,
-                    b = j.length - 1,
-                    e = Math.max(m, b),
-                    d, l, c;
-                if (!g || g === h) {
-                    g = []
-                }
-                g.length = e + 1;
-                for (c = 0; c <= e; c++) {
-                    d = h[Math.min(c, m)];
-                    l = j[Math.min(c, b)];
-                    if (Ext.isNumber(d)) {
-                        if (!Ext.isNumber(l)) {
-                            l = 0
-                        }
-                        g[c] = (l - d) * k + d
-                    } else {
-                        g[c] = l
-                    }
-                }
-                return g
-            }
-        },
-        text: {
-            compute: function(d, c, b) {
-                return d.substr(0, Math.round(d.length * (1 - b))) + c.substr(Math.round(c.length * (1 - b)))
-            }
-        },
-        limited: "number",
-        limited01: "number"
-    }
-});
-(function() {
-    if (!Ext.global.Float32Array) {
-        var a = function(d) {
-            if (typeof d === "number") {
-                this.length = d
-            } else {
-                if ("length" in d) {
-                    this.length = d.length;
-                    for (var c = 0, b = d.length; c < b; c++) {
-                        this[c] = +d[c]
-                    }
-                }
-            }
-        };
-        a.prototype = [];
-        Ext.global.Float32Array = a
-    }
-})();
-Ext.define("Ext.draw.Draw", {
-    singleton: true,
-    radian: Math.PI / 180,
-    pi2: Math.PI * 2,
-    reflectFn: function(b) {
-        return b
-    },
-    rad: function(a) {
-        return (a % 360) * this.radian
-    },
-    degrees: function(a) {
-        return (a / this.radian) % 360
-    },
-    isBBoxIntersect: function(b, a, c) {
-        c = c || 0;
-        return (Math.max(b.x, a.x) - c > Math.min(b.x + b.width, a.x + a.width)) || (Math.max(b.y, a.y) - c > Math.min(b.y + b.height, a.y + a.height))
-    },
-    isPointInBBox: function(a, c, b) {
-        return !!b && a >= b.x && a <= (b.x + b.width) && c >= b.y && c <= (b.y + b.height)
-    },
-    spline: function(m) {
-        var e, c, k = m.length,
-            b, h, l, f, a = 0,
-            g = new Float32Array(m.length),
-            n = new Float32Array(m.length * 3 - 2);
-        g[0] = 0;
-        g[k - 1] = 0;
-        for (e = 1; e < k - 1; e++) {
-            g[e] = (m[e + 1] + m[e - 1] - 2 * m[e]) - g[e - 1];
-            a = 1 / (4 - a);
-            g[e] *= a
-        }
-        for (e = k - 2; e > 0; e--) {
-            a = 3.732050807568877 + 48.248711305964385 / (-13.928203230275537 + Math.pow(0.07179676972449123, e));
-            g[e] -= g[e + 1] * a
-        }
-        f = m[0];
-        b = f - g[0];
-        for (e = 0, c = 0; e < k - 1; c += 3) {
-            l = f;
-            h = b;
-            e++;
-            f = m[e];
-            b = f - g[e];
-            n[c] = l;
-            n[c + 1] = (b + 2 * h) / 3;
-            n[c + 2] = (b * 2 + h) / 3
-        }
-        n[c] = f;
-        return n
-    },
-    getAnchors: function(e, d, i, h, t, s, o) {
-        o = o || 4;
-        var n = Math.PI,
-            p = n / 2,
-            k = Math.abs,
-            a = Math.sin,
-            b = Math.cos,
-            f = Math.atan,
-            r, q, g, j, m, l, v, u, c;
-        r = (i - e) / o;
-        q = (t - i) / o;
-        if ((h >= d && h >= s) || (h <= d && h <= s)) {
-            g = j = p
-        } else {
-            g = f((i - e) / k(h - d));
-            if (d < h) {
-                g = n - g
-            }
-            j = f((t - i) / k(h - s));
-            if (s < h) {
-                j = n - j
-            }
-        }
-        c = p - ((g + j) % (n * 2)) / 2;
-        if (c > p) {
-            c -= n
-        }
-        g += c;
-        j += c;
-        m = i - r * a(g);
-        l = h + r * b(g);
-        v = i + q * a(j);
-        u = h + q * b(j);
-        if ((h > d && l < d) || (h < d && l > d)) {
-            m += k(d - l) * (m - i) / (l - h);
-            l = d
-        }
-        if ((h > s && u < s) || (h < s && u > s)) {
-            v -= k(s - u) * (v - i) / (u - h);
-            u = s
-        }
-        return {
-            x1: m,
-            y1: l,
-            x2: v,
-            y2: u
-        }
-    },
-    smooth: function(l, j, o) {
-        var k = l.length,
-            h, g, c, b, q, p, n, m, f = [],
-            e = [],
-            d, a;
-        for (d = 0; d < k - 1; d++) {
-            h = l[d];
-            g = j[d];
-            if (d === 0) {
-                n = h;
-                m = g;
-                f.push(n);
-                e.push(m);
-                if (k === 1) {
-                    break
-                }
-            }
-            c = l[d + 1];
-            b = j[d + 1];
-            q = l[d + 2];
-            p = j[d + 2];
-            if (!Ext.isNumber(q + p)) {
-                f.push(n, c, c);
-                e.push(m, b, b);
-                break
-            }
-            a = this.getAnchors(h, g, c, b, q, p, o);
-            f.push(n, a.x1, c);
-            e.push(m, a.y1, b);
-            n = a.x2;
-            m = a.y2
-        }
-        return {
-            smoothX: f,
-            smoothY: e
-        }
-    },
-    beginUpdateIOS: Ext.os.is.iOS ? function() {
-        this.iosUpdateEl = Ext.getBody().createChild({
-            style: "position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"
-        })
-    } : Ext.emptyFn,
-    endUpdateIOS: function() {
-        this.iosUpdateEl = Ext.destroy(this.iosUpdateEl)
-    }
-});
-Ext.define("Ext.draw.gradient.Gradient", {
-    requires: ["Ext.draw.Color"],
-    isGradient: true,
-    config: {
-        stops: []
-    },
-    applyStops: function(f) {
-        var e = [],
-            d = f.length,
-            c, b, a;
-        for (c = 0; c < d; c++) {
-            b = f[c];
-            a = b.color;
-            if (!(a && a.isColor)) {
-                a = Ext.draw.Color.fly(a || Ext.draw.Color.NONE)
-            }
-            e.push({
-                offset: Math.min(1, Math.max(0, "offset" in b ? b.offset : b.position || 0)),
-                color: a.toString()
-            })
-        }
-        e.sort(function(h, g) {
-            return h.offset - g.offset
-        });
-        return e
-    },
-    onClassExtended: function(a, b) {
-        if (!b.alias && b.type) {
-            b.alias = "gradient." + b.type
-        }
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    generateGradient: Ext.emptyFn
-});
-Ext.define("Ext.draw.gradient.GradientDefinition", {
-    singleton: true,
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    gradients: {},
-    add: function(a) {
-        var b = this.gradients,
-            c, e, d;
-        for (c = 0, e = a.length; c < e; c++) {
-            d = a[c];
-            if (Ext.isString(d.id)) {
-                b[d.id] = d
-            }
-        }
-    },
-    get: function(d) {
-        var a = this.gradients,
-            b = d.match(this.urlStringRe),
-            c;
-        if (b && b[1] && (c = a[b[1]])) {
-            return c || d
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeParser", {
-    singleton: true,
-    attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-    requires: ["Ext.draw.Color", "Ext.draw.gradient.GradientDefinition"],
-    "default": Ext.identityFn,
-    string: function(a) {
-        return String(a)
-    },
-    number: function(a) {
-        if (Ext.isNumber(+a)) {
-            return a
-        }
-    },
-    angle: function(a) {
-        if (Ext.isNumber(a)) {
-            a %= Math.PI * 2;
-            if (a < -Math.PI) {
-                a += Math.PI * 2
-            } else {
-                if (a >= Math.PI) {
-                    a -= Math.PI * 2
-                }
-            }
-            return a
-        }
-    },
-    data: function(a) {
-        if (Ext.isArray(a)) {
-            return a.slice()
-        } else {
-            if (a instanceof Float32Array) {
-                return new Float32Array(a)
-            }
-        }
-    },
-    bool: function(a) {
-        return !!a
-    },
-    color: function(a) {
-        if (a instanceof Ext.draw.Color) {
-            return a.toString()
-        } else {
-            if (a instanceof Ext.draw.gradient.Gradient) {
-                return a
-            } else {
-                if (!a) {
-                    return Ext.draw.Color.NONE
-                } else {
-                    if (Ext.isString(a)) {
-                        if (a.substr(0, 3) === "url") {
-                            a = Ext.draw.gradient.GradientDefinition.get(a);
-                            if (Ext.isString(a)) {
-                                return a
-                            }
-                        } else {
-                            return Ext.draw.Color.fly(a).toString()
-                        }
-                    }
-                }
-            }
-        }
-        if (a.type === "linear") {
-            return Ext.create("Ext.draw.gradient.Linear", a)
-        } else {
-            if (a.type === "radial") {
-                return Ext.create("Ext.draw.gradient.Radial", a)
-            } else {
-                if (a.type === "pattern") {
-                    return Ext.create("Ext.draw.gradient.Pattern", a)
-                } else {
-                    return Ext.draw.Color.NONE
-                }
-            }
-        }
-    },
-    limited: function(a, b) {
-        return function(c) {
-            c = +c;
-            return Ext.isNumber(c) ? Math.min(Math.max(c, a), b) : undefined
-        }
-    },
-    limited01: function(a) {
-        a = +a;
-        return Ext.isNumber(a) ? Math.min(Math.max(a, 0), 1) : undefined
-    },
-    enums: function() {
-        var d = {},
-            a = Array.prototype.slice.call(arguments, 0),
-            b, c;
-        for (b = 0, c = a.length; b < c; b++) {
-            d[a[b]] = true
-        }
-        return function(e) {
-            return e in d ? e : undefined
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeDefinition", {
-    requires: ["Ext.draw.sprite.AttributeParser", "Ext.draw.sprite.AnimationParser"],
-    config: {
-        defaults: {
-            $value: {},
-            lazy: true
-        },
-        aliases: {},
-        animationProcessors: {},
-        processors: {
-            $value: {},
-            lazy: true
-        },
-        dirtyTriggers: {},
-        triggers: {},
-        updaters: {}
-    },
-    inheritableStatics: {
-        processorFactoryRe: /^(\w+)\(([\w\-,]*)\)$/
-    },
-    spriteClass: null,
-    constructor: function(a) {
-        var b = this;
-        b.initConfig(a)
-    },
-    applyDefaults: function(b, a) {
-        a = Ext.apply(a || {}, this.normalize(b));
-        return a
-    },
-    applyAliases: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    applyProcessors: function(e, i) {
-        this.getAnimationProcessors();
-        var j = i || {},
-            h = Ext.draw.sprite.AttributeParser,
-            a = this.self.processorFactoryRe,
-            g = {},
-            d, b, c, f;
-        for (b in e) {
-            f = e[b];
-            if (typeof f === "string") {
-                c = f.match(a);
-                if (c) {
-                    f = h[c[1]].apply(h, c[2].split(","))
-                } else {
-                    if (h[f]) {
-                        g[b] = f;
-                        d = true;
-                        f = h[f]
-                    }
-                }
-            }
-            j[b] = f
-        }
-        if (d) {
-            this.setAnimationProcessors(g)
-        }
-        return j
-    },
-    applyAnimationProcessors: function(c, a) {
-        var e = Ext.draw.sprite.AnimationParser,
-            b, d;
-        if (!a) {
-            a = {}
-        }
-        for (b in c) {
-            d = c[b];
-            if (d === "none") {
-                a[b] = null
-            } else {
-                if (Ext.isString(d) && !(b in a)) {
-                    if (d in e) {
-                        while (Ext.isString(e[d])) {
-                            d = e[d]
-                        }
-                        a[b] = e[d]
-                    }
-                } else {
-                    if (Ext.isObject(d)) {
-                        a[b] = d
-                    }
-                }
-            }
-        }
-        return a
-    },
-    updateDirtyTriggers: function(a) {
-        this.setTriggers(a)
-    },
-    applyTriggers: function(b, c) {
-        if (!c) {
-            c = {}
-        }
-        for (var a in b) {
-            c[a] = b[a].split(",")
-        }
-        return c
-    },
-    applyUpdaters: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    batchedNormalize: function(f, n) {
-        if (!f) {
-            return {}
-        }
-        var j = this.getProcessors(),
-            d = this.getAliases(),
-            a = f.translation || f.translate,
-            o = {},
-            g, h, b, e, p, c, m, l, k;
-        if ("rotation" in f) {
-            p = f.rotation
-        } else {
-            p = ("rotate" in f) ? f.rotate : undefined
-        }
-        if ("scaling" in f) {
-            c = f.scaling
-        } else {
-            c = ("scale" in f) ? f.scale : undefined
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                o.scalingX = c;
-                o.scalingY = c
-            } else {
-                if ("x" in c) {
-                    o.scalingX = c.x
-                }
-                if ("y" in c) {
-                    o.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    o.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    o.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof p !== "undefined") {
-            if (Ext.isNumber(p)) {
-                p = Ext.draw.Draw.rad(p);
-                o.rotationRads = p
-            } else {
-                if ("rads" in p) {
-                    o.rotationRads = p.rads
-                } else {
-                    if ("degrees" in p) {
-                        if (Ext.isArray(p.degrees)) {
-                            o.rotationRads = Ext.Array.map(p.degrees, function(i) {
-                                return Ext.draw.Draw.rad(i)
-                            })
-                        } else {
-                            o.rotationRads = Ext.draw.Draw.rad(p.degrees)
-                        }
-                    }
-                }
-                if ("centerX" in p) {
-                    o.rotationCenterX = p.centerX
-                }
-                if ("centerY" in p) {
-                    o.rotationCenterY = p.centerY
-                }
-            }
-        }
-        if (typeof a !== "undefined") {
-            if ("x" in a) {
-                o.translationX = a.x
-            }
-            if ("y" in a) {
-                o.translationY = a.y
-            }
-        }
-        if ("matrix" in f) {
-            m = Ext.draw.Matrix.create(f.matrix);
-            k = m.split();
-            o.matrix = m;
-            o.rotationRads = k.rotation;
-            o.rotationCenterX = 0;
-            o.rotationCenterY = 0;
-            o.scalingX = k.scaleX;
-            o.scalingY = k.scaleY;
-            o.scalingCenterX = 0;
-            o.scalingCenterY = 0;
-            o.translationX = k.translateX;
-            o.translationY = k.translateY
-        }
-        for (b in f) {
-            e = f[b];
-            if (typeof e === "undefined") {
-                continue
-            } else {
-                if (Ext.isArray(e)) {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        o[b] = [];
-                        for (g = 0, h = e.length; g < h; g++) {
-                            l = j[b].call(this, e[g]);
-                            if (typeof l !== "undefined") {
-                                o[b][g] = l
-                            }
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                } else {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        e = j[b].call(this, e);
-                        if (typeof e !== "undefined") {
-                            o[b] = e
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                }
-            }
-        }
-        return o
-    },
-    normalize: function(i, j) {
-        if (!i) {
-            return {}
-        }
-        var f = this.getProcessors(),
-            d = this.getAliases(),
-            a = i.translation || i.translate,
-            k = {},
-            b, e, l, c, h, g;
-        if ("rotation" in i) {
-            l = i.rotation
-        } else {
-            l = ("rotate" in i) ? i.rotate : undefined
-        }
-        if ("scaling" in i) {
-            c = i.scaling
-        } else {
-            c = ("scale" in i) ? i.scale : undefined
-        }
-        if (a) {
-            if ("x" in a) {
-                k.translationX = a.x
-            }
-            if ("y" in a) {
-                k.translationY = a.y
-            }
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                k.scalingX = c;
-                k.scalingY = c
-            } else {
-                if ("x" in c) {
-                    k.scalingX = c.x
-                }
-                if ("y" in c) {
-                    k.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    k.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    k.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof l !== "undefined") {
-            if (Ext.isNumber(l)) {
-                l = Ext.draw.Draw.rad(l);
-                k.rotationRads = l
-            } else {
-                if ("rads" in l) {
-                    k.rotationRads = l.rads
-                } else {
-                    if ("degrees" in l) {
-                        k.rotationRads = Ext.draw.Draw.rad(l.degrees)
-                    }
-                }
-                if ("centerX" in l) {
-                    k.rotationCenterX = l.centerX
-                }
-                if ("centerY" in l) {
-                    k.rotationCenterY = l.centerY
-                }
-            }
-        }
-        if ("matrix" in i) {
-            h = Ext.draw.Matrix.create(i.matrix);
-            g = h.split();
-            k.matrix = h;
-            k.rotationRads = g.rotation;
-            k.rotationCenterX = 0;
-            k.rotationCenterY = 0;
-            k.scalingX = g.scaleX;
-            k.scalingY = g.scaleY;
-            k.scalingCenterX = 0;
-            k.scalingCenterY = 0;
-            k.translationX = g.translateX;
-            k.translationY = g.translateY
-        }
-        for (b in i) {
-            e = i[b];
-            if (typeof e === "undefined") {
-                continue
-            }
-            if (b in d) {
-                b = d[b]
-            }
-            if (b in f) {
-                e = f[b].call(this, e);
-                if (typeof e !== "undefined") {
-                    k[b] = e
-                }
-            } else {
-                if (j) {
-                    k[b] = e
-                }
-            }
-        }
-        return k
-    },
-    setBypassingNormalization: function(a, c, b) {
-        return c.pushDown(a, b)
-    },
-    set: function(a, c, b) {
-        b = this.normalize(b);
-        return this.setBypassingNormalization(a, c, b)
-    }
-});
-Ext.define("Ext.draw.Matrix", {
-    isMatrix: true,
-    statics: {
-        createAffineMatrixFromTwoPair: function(h, t, g, s, k, o, i, j) {
-            var v = g - h,
-                u = s - t,
-                e = i - k,
-                q = j - o,
-                d = 1 / (v * v + u * u),
-                p = v * e + u * q,
-                n = e * u - v * q,
-                m = -p * h - n * t,
-                l = n * h - p * t;
-            return new this(p * d, -n * d, n * d, p * d, m * d + k, l * d + o)
-        },
-        createPanZoomFromTwoPair: function(q, e, p, c, h, s, n, g) {
-            if (arguments.length === 2) {
-                return this.createPanZoomFromTwoPair.apply(this, q.concat(e))
-            }
-            var k = p - q,
-                j = c - e,
-                d = (q + p) * 0.5,
-                b = (e + c) * 0.5,
-                o = n - h,
-                a = g - s,
-                f = (h + n) * 0.5,
-                l = (s + g) * 0.5,
-                m = k * k + j * j,
-                i = o * o + a * a,
-                t = Math.sqrt(i / m);
-            return new this(t, 0, 0, t, f - t * d, l - t * b)
-        },
-        fly: (function() {
-            var a = null,
-                b = function(c) {
-                    a.elements = c;
-                    return a
-                };
-            return function(c) {
-                if (!a) {
-                    a = new Ext.draw.Matrix()
-                }
-                a.elements = c;
-                Ext.draw.Matrix.fly = b;
-                return a
-            }
-        })(),
-        create: function(a) {
-            if (a instanceof this) {
-                return a
-            }
-            return new this(a)
-        }
-    },
-    constructor: function(e, d, a, f, c, b) {
-        if (e && e.length === 6) {
-            this.elements = e.slice()
-        } else {
-            if (e !== undefined) {
-                this.elements = [e, d, a, f, c, b]
-            } else {
-                this.elements = [1, 0, 0, 1, 0, 0]
-            }
-        }
-    },
-    prepend: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + h * j;
-        b[1] = l * d + g * j;
-        b[2] = a * e + h * c;
-        b[3] = l * e + g * c;
-        b[4] = a * i + h * f + m;
-        b[5] = l * i + g * f + k;
-        return this
-    },
-    prependMatrix: function(a) {
-        return this.prepend.apply(this, a.elements)
-    },
-    append: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + l * e;
-        b[1] = a * j + l * c;
-        b[2] = h * d + g * e;
-        b[3] = h * j + g * c;
-        b[4] = m * d + k * e + i;
-        b[5] = m * j + k * c + f;
-        return this
-    },
-    appendMatrix: function(a) {
-        return this.append.apply(this, a.elements)
-    },
-    set: function(f, e, a, g, c, b) {
-        var d = this.elements;
-        d[0] = f;
-        d[1] = e;
-        d[2] = a;
-        d[3] = g;
-        d[4] = c;
-        d[5] = b;
-        return this
-    },
-    inverse: function(i) {
-        var g = this.elements,
-            o = g[0],
-            m = g[1],
-            l = g[2],
-            k = g[3],
-            j = g[4],
-            h = g[5],
-            n = 1 / (o * k - m * l);
-        o *= n;
-        m *= n;
-        l *= n;
-        k *= n;
-        if (i) {
-            i.set(k, -m, -l, o, l * h - k * j, m * j - o * h);
-            return i
-        } else {
-            return new Ext.draw.Matrix(k, -m, -l, o, l * h - k * j, m * j - o * h)
-        }
-    },
-    translate: function(a, c, b) {
-        if (b) {
-            return this.prepend(1, 0, 0, 1, a, c)
-        } else {
-            return this.append(1, 0, 0, 1, a, c)
-        }
-    },
-    scale: function(f, e, c, a, b) {
-        var d = this;
-        if (e == null) {
-            e = f
-        }
-        if (c === undefined) {
-            c = 0
-        }
-        if (a === undefined) {
-            a = 0
-        }
-        if (b) {
-            return d.prepend(f, 0, 0, e, c - c * f, a - a * e)
-        } else {
-            return d.append(f, 0, 0, e, c - c * f, a - a * e)
-        }
-    },
-    rotate: function(g, e, c, b) {
-        var d = this,
-            f = Math.cos(g),
-            a = Math.sin(g);
-        e = e || 0;
-        c = c || 0;
-        if (b) {
-            return d.prepend(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        } else {
-            return d.append(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        }
-    },
-    rotateFromVector: function(a, h, c) {
-        var e = this,
-            g = Math.sqrt(a * a + h * h),
-            f = a / g,
-            b = h / g;
-        if (c) {
-            return e.prepend(f, b, -b, f, 0, 0)
-        } else {
-            return e.append(f, b, -b, f, 0, 0)
-        }
-    },
-    clone: function() {
-        return new Ext.draw.Matrix(this.elements)
-    },
-    flipX: function() {
-        return this.append(-1, 0, 0, 1, 0, 0)
-    },
-    flipY: function() {
-        return this.append(1, 0, 0, -1, 0, 0)
-    },
-    skewX: function(a) {
-        return this.append(1, 0, Math.tan(a), 1, 0, 0)
-    },
-    skewY: function(a) {
-        return this.append(1, Math.tan(a), 0, 1, 0, 0)
-    },
-    shearX: function(a) {
-        return this.append(1, 0, a, 1, 0, 0)
-    },
-    shearY: function(a) {
-        return this.append(1, a, 0, 1, 0, 0)
-    },
-    reset: function() {
-        return this.set(1, 0, 0, 1, 0, 0)
-    },
-    precisionCompensate: function(j, g) {
-        var c = this.elements,
-            f = c[0],
-            e = c[1],
-            i = c[2],
-            h = c[3],
-            d = c[4],
-            b = c[5],
-            a = e * i - f * h;
-        g.b = j * e / f;
-        g.c = j * i / h;
-        g.d = j;
-        g.xx = f / j;
-        g.yy = h / j;
-        g.dx = (b * f * i - d * f * h) / a / j;
-        g.dy = (d * e * h - b * f * h) / a / j
-    },
-    precisionCompensateRect: function(j, g) {
-        var b = this.elements,
-            f = b[0],
-            e = b[1],
-            i = b[2],
-            h = b[3],
-            c = b[4],
-            a = b[5],
-            d = i / f;
-        g.b = j * e / f;
-        g.c = j * d;
-        g.d = j * h / f;
-        g.xx = f / j;
-        g.yy = f / j;
-        g.dx = (a * i - c * h) / (e * d - h) / j;
-        g.dy = -(a * f - c * e) / (e * d - h) / j
-    },
-    x: function(a, c) {
-        var b = this.elements;
-        return a * b[0] + c * b[2] + b[4]
-    },
-    y: function(a, c) {
-        var b = this.elements;
-        return a * b[1] + c * b[3] + b[5]
-    },
-    get: function(b, a) {
-        return +this.elements[b + a * 2].toFixed(4)
-    },
-    transformPoint: function(b) {
-        var c = this.elements,
-            a, d;
-        if (b.isPoint) {
-            a = b.x;
-            d = b.y
-        } else {
-            a = b[0];
-            d = b[1]
-        }
-        return [a * c[0] + d * c[2] + c[4], a * c[1] + d * c[3] + c[5]]
-    },
-    transformBBox: function(q, i, j) {
-        var b = this.elements,
-            d = q.x,
-            r = q.y,
-            g = q.width * 0.5,
-            o = q.height * 0.5,
-            a = b[0],
-            s = b[1],
-            n = b[2],
-            k = b[3],
-            e = d + g,
-            c = r + o,
-            p, f, m;
-        if (i) {
-            g -= i;
-            o -= i;
-            m = [Math.sqrt(b[0] * b[0] + b[2] * b[2]), Math.sqrt(b[1] * b[1] + b[3] * b[3])];
-            p = Math.abs(g * a) + Math.abs(o * n) + Math.abs(m[0] * i);
-            f = Math.abs(g * s) + Math.abs(o * k) + Math.abs(m[1] * i)
-        } else {
-            p = Math.abs(g * a) + Math.abs(o * n);
-            f = Math.abs(g * s) + Math.abs(o * k)
-        }
-        if (!j) {
-            j = {}
-        }
-        j.x = e * a + c * n + b[4] - p;
-        j.y = e * s + c * k + b[5] - f;
-        j.width = p + p;
-        j.height = f + f;
-        return j
-    },
-    transformList: function(e) {
-        var b = this.elements,
-            a = b[0],
-            h = b[2],
-            l = b[4],
-            k = b[1],
-            g = b[3],
-            j = b[5],
-            f = e.length,
-            c, d;
-        for (d = 0; d < f; d++) {
-            c = e[d];
-            e[d] = [c[0] * a + c[1] * h + l, c[0] * k + c[1] * g + j]
-        }
-        return e
-    },
-    isIdentity: function() {
-        var a = this.elements;
-        return a[0] === 1 && a[1] === 0 && a[2] === 0 && a[3] === 1 && a[4] === 0 && a[5] === 0
-    },
-    isEqual: function(a) {
-        var c = a && a.isMatrix ? a.elements : a,
-            b = this.elements;
-        return b[0] === c[0] && b[1] === c[1] && b[2] === c[2] && b[3] === c[3] && b[4] === c[4] && b[5] === c[5]
-    },
-    equals: function(a) {
-        return this.isEqual(a)
-    },
-    toArray: function() {
-        var a = this.elements;
-        return [a[0], a[2], a[4], a[1], a[3], a[5]]
-    },
-    toVerticalArray: function() {
-        return this.elements.slice()
-    },
-    toString: function() {
-        var a = this;
-        return [a.get(0, 0), a.get(0, 1), a.get(1, 0), a.get(1, 1), a.get(2, 0), a.get(2, 1)].join(",")
-    },
-    toContext: function(a) {
-        a.transform.apply(a, this.elements);
-        return this
-    },
-    toSvg: function() {
-        var a = this.elements;
-        return "matrix(" + a[0].toFixed(9) + "," + a[1].toFixed(9) + "," + a[2].toFixed(9) + "," + a[3].toFixed(9) + "," + a[4].toFixed(9) + "," + a[5].toFixed(9) + ")"
-    },
-    getScaleX: function() {
-        var a = this.elements;
-        return Math.sqrt(a[0] * a[0] + a[2] * a[2])
-    },
-    getScaleY: function() {
-        var a = this.elements;
-        return Math.sqrt(a[1] * a[1] + a[3] * a[3])
-    },
-    getXX: function() {
-        return this.elements[0]
-    },
-    getXY: function() {
-        return this.elements[1]
-    },
-    getYX: function() {
-        return this.elements[2]
-    },
-    getYY: function() {
-        return this.elements[3]
-    },
-    getDX: function() {
-        return this.elements[4]
-    },
-    getDY: function() {
-        return this.elements[5]
-    },
-    split: function() {
-        var b = this.elements,
-            d = b[0],
-            c = b[1],
-            e = b[3],
-            a = {
-                translateX: b[4],
-                translateY: b[5]
-            };
-        a.rotate = a.rotation = Math.atan2(c, d);
-        a.scaleX = d / Math.cos(a.rotate);
-        a.scaleY = e / d * a.scaleX;
-        return a
-    }
-}, function() {
-    function b(e, c, d) {
-        e[c] = {
-            get: function() {
-                return this.elements[d]
-            },
-            set: function(f) {
-                this.elements[d] = f
-            }
-        }
-    }
-    if (Object.defineProperties) {
-        var a = {};
-        b(a, "a", 0);
-        b(a, "b", 1);
-        b(a, "c", 2);
-        b(a, "d", 3);
-        b(a, "e", 4);
-        b(a, "f", 5);
-        Object.defineProperties(this.prototype, a)
-    }
-    this.prototype.multiply = this.prototype.appendMatrix
-});
-Ext.define("Ext.draw.modifier.Modifier", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        previous: null,
-        next: null,
-        sprite: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    updateNext: function(a) {
-        if (a) {
-            a.setPrevious(this)
-        }
-    },
-    updatePrevious: function(a) {
-        if (a) {
-            a.setNext(this)
-        }
-    },
-    prepareAttributes: function(a) {
-        if (this._previous) {
-            this._previous.prepareAttributes(a)
-        }
-    },
-    popUp: function(a, b) {
-        if (this._next) {
-            this._next.popUp(a, b)
-        } else {
-            Ext.apply(a, b)
-        }
-    },
-    pushDown: function(a, c) {
-        if (this._previous) {
-            return this._previous.pushDown(a, c)
-        } else {
-            for (var b in c) {
-                if (c[b] === a[b]) {
-                    delete c[b]
-                }
-            }
-            return c
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Target", {
-    requires: ["Ext.draw.Matrix"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.target",
-    statics: {
-        uniqueId: 0
-    },
-    prepareAttributes: function(a) {
-        var b = this.getPrevious();
-        if (b) {
-            b.prepareAttributes(a)
-        }
-        a.attributeId = "attribute-" + Ext.draw.modifier.Target.uniqueId++;
-        if (!a.hasOwnProperty("canvasAttributes")) {
-            a.bbox = {
-                plain: {
-                    dirty: true
-                },
-                transform: {
-                    dirty: true
-                }
-            };
-            a.dirty = true;
-            a.pendingUpdaters = {};
-            a.canvasAttributes = {};
-            a.matrix = new Ext.draw.Matrix();
-            a.inverseMatrix = new Ext.draw.Matrix()
-        }
-    },
-    applyChanges: function(f, k) {
-        Ext.apply(f, k);
-        var l = this.getSprite(),
-            o = f.pendingUpdaters,
-            h = l.self.def.getTriggers(),
-            p, a, m, b, e, n, d, c, g;
-        for (b in k) {
-            e = true;
-            if ((p = h[b])) {
-                l.scheduleUpdaters(f, p, [b])
-            }
-            if (f.template && k.removeFromInstance && k.removeFromInstance[b]) {
-                delete f[b]
-            }
-        }
-        if (!e) {
-            return
-        }
-        if (o.canvas) {
-            n = o.canvas;
-            delete o.canvas;
-            for (d = 0, g = n.length; d < g; d++) {
-                b = n[d];
-                f.canvasAttributes[b] = f[b]
-            }
-        }
-        if (f.hasOwnProperty("children")) {
-            a = f.children;
-            for (d = 0, g = a.length; d < g; d++) {
-                m = a[d];
-                Ext.apply(m.pendingUpdaters, o);
-                if (n) {
-                    for (c = 0; c < n.length; c++) {
-                        b = n[c];
-                        m.canvasAttributes[b] = m[b]
-                    }
-                }
-                l.callUpdaters(m)
-            }
-        }
-        l.setDirty(true);
-        l.callUpdaters(f)
-    },
-    popUp: function(a, b) {
-        this.applyChanges(a, b)
-    },
-    pushDown: function(a, b) {
-        var c = this.getPrevious();
-        if (c) {
-            b = c.pushDown(a, b)
-        }
-        this.applyChanges(a, b);
-        return b
-    }
-});
-Ext.define("Ext.draw.TimingFunctions", function() {
-    var g = Math.pow,
-        j = Math.sin,
-        m = Math.cos,
-        l = Math.sqrt,
-        e = Math.PI,
-        b = ["quad", "cube", "quart", "quint"],
-        c = {
-            pow: function(o, i) {
-                return g(o, i || 6)
-            },
-            expo: function(i) {
-                return g(2, 8 * (i - 1))
-            },
-            circ: function(i) {
-                return 1 - l(1 - i * i)
-            },
-            sine: function(i) {
-                return 1 - j((1 - i) * e / 2)
-            },
-            back: function(i, o) {
-                o = o || 1.616;
-                return i * i * ((o + 1) * i - o)
-            },
-            bounce: function(q) {
-                for (var o = 0, i = 1; 1; o += i, i /= 2) {
-                    if (q >= (7 - 4 * o) / 11) {
-                        return i * i - g((11 - 6 * o - 11 * q) / 4, 2)
-                    }
-                }
-            },
-            elastic: function(o, i) {
-                return g(2, 10 * --o) * m(20 * o * e * (i || 1) / 3)
-            }
-        },
-        k = {},
-        a, f, d;
-
-    function h(i) {
-        return function(o) {
-            return g(o, i)
-        }
-    }
-
-    function n(i, o) {
-        k[i + "In"] = function(p) {
-            return o(p)
-        };
-        k[i + "Out"] = function(p) {
-            return 1 - o(1 - p)
-        };
-        k[i + "InOut"] = function(p) {
-            return (p <= 0.5) ? o(2 * p) / 2 : (2 - o(2 * (1 - p))) / 2
-        }
-    }
-    for (d = 0, f = b.length; d < f; ++d) {
-        c[b[d]] = h(d + 2)
-    }
-    for (a in c) {
-        n(a, c[a])
-    }
-    k.linear = Ext.identityFn;
-    k.easeIn = k.quadIn;
-    k.easeOut = k.quadOut;
-    k.easeInOut = k.quadInOut;
-    return {
-        singleton: true,
-        easingMap: k
-    }
-}, function(a) {
-    Ext.apply(a, a.easingMap)
-});
-Ext.define("Ext.draw.Animator", {
-    uses: ["Ext.draw.Draw"],
-    singleton: true,
-    frameCallbacks: {},
-    frameCallbackId: 0,
-    scheduled: 0,
-    frameStartTimeOffset: Ext.now(),
-    animations: [],
-    running: false,
-    animationTime: function() {
-        return Ext.AnimationQueue.frameStartTime - this.frameStartTimeOffset
-    },
-    add: function(b) {
-        var a = this;
-        if (!a.contains(b)) {
-            a.animations.push(b);
-            a.ignite();
-            if ("fireEvent" in b) {
-                b.fireEvent("animationstart", b)
-            }
-        }
-    },
-    remove: function(d) {
-        var c = this,
-            e = c.animations,
-            b = 0,
-            a = e.length;
-        for (; b < a; ++b) {
-            if (e[b] === d) {
-                e.splice(b, 1);
-                if ("fireEvent" in d) {
-                    d.fireEvent("animationend", d)
-                }
-                return
-            }
-        }
-    },
-    contains: function(a) {
-        return Ext.Array.indexOf(this.animations, a) > -1
-    },
-    empty: function() {
-        return this.animations.length === 0
-    },
-    step: function(d) {
-        var c = this,
-            f = c.animations,
-            e, a = 0,
-            b = f.length;
-        for (; a < b; a++) {
-            e = f[a];
-            e.step(d);
-            if (!e.animating) {
-                f.splice(a, 1);
-                a--;
-                b--;
-                if (e.fireEvent) {
-                    e.fireEvent("animationend", e)
-                }
-            }
-        }
-    },
-    schedule: function(c, a) {
-        a = a || this;
-        var b = "frameCallback" + (this.frameCallbackId++);
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a,
-            once: true
-        };
-        this.scheduled++;
-        Ext.draw.Animator.ignite();
-        return b
-    },
-    scheduleIf: function(e, b) {
-        b = b || this;
-        var c = Ext.draw.Animator.frameCallbacks,
-            a, d;
-        if (Ext.isString(e)) {
-            e = b[e]
-        }
-        for (d in c) {
-            a = c[d];
-            if (a.once && a.fn === e && a.scope === b) {
-                return null
-            }
-        }
-        return this.schedule(e, b)
-    },
-    cancel: function(a) {
-        if (Ext.draw.Animator.frameCallbacks[a] && Ext.draw.Animator.frameCallbacks[a].once) {
-            this.scheduled--;
-            delete Ext.draw.Animator.frameCallbacks[a]
-        }
-    },
-    addFrameCallback: function(c, a) {
-        a = a || this;
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        var b = "frameCallback" + (this.frameCallbackId++);
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a
-        };
-        return b
-    },
-    removeFrameCallback: function(a) {
-        delete Ext.draw.Animator.frameCallbacks[a]
-    },
-    fireFrameCallbacks: function() {
-        var c = this.frameCallbacks,
-            d, b, a;
-        for (d in c) {
-            a = c[d];
-            b = a.fn;
-            if (Ext.isString(b)) {
-                b = a.scope[b]
-            }
-            b.call(a.scope);
-            if (c[d] && a.once) {
-                this.scheduled--;
-                delete c[d]
-            }
-        }
-    },
-    handleFrame: function() {
-        this.step(this.animationTime());
-        this.fireFrameCallbacks();
-        if (!this.scheduled && this.empty()) {
-            Ext.AnimationQueue.stop(this.handleFrame, this);
-            this.running = false;
-            Ext.draw.Draw.endUpdateIOS()
-        }
-    },
-    ignite: function() {
-        if (!this.running) {
-            this.running = true;
-            Ext.AnimationQueue.start(this.handleFrame, this);
-            Ext.draw.Draw.beginUpdateIOS()
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Animation", {
-    requires: ["Ext.draw.TimingFunctions", "Ext.draw.Animator"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.animation",
-    config: {
-        easing: Ext.identityFn,
-        duration: 0,
-        customEasings: {},
-        customDurations: {},
-        customDuration: null
-    },
-    constructor: function(a) {
-        var b = this;
-        b.anyAnimation = b.anySpecialAnimations = false;
-        b.animating = 0;
-        b.animatingPool = [];
-        b.callParent([a])
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("timers")) {
-            a.animating = false;
-            a.timers = {};
-            a.animationOriginal = Ext.Object.chain(a);
-            a.animationOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.animationOriginal)
-        }
-    },
-    updateSprite: function(a) {
-        this.setConfig(a.config.fx)
-    },
-    updateDuration: function(a) {
-        this.anyAnimation = a > 0
-    },
-    applyEasing: function(a) {
-        if (typeof a === "string") {
-            a = Ext.draw.TimingFunctions.easingMap[a]
-        }
-        return a
-    },
-    applyCustomEasings: function(a, e) {
-        e = e || {};
-        var g, d, b, h, c, f;
-        for (d in a) {
-            g = true;
-            h = a[d];
-            b = d.split(",");
-            if (typeof h === "string") {
-                h = Ext.draw.TimingFunctions.easingMap[h]
-            }
-            for (c = 0, f = b.length; c < f; c++) {
-                e[b[c]] = h
-            }
-        }
-        if (g) {
-            this.anySpecialAnimations = g
-        }
-        return e
-    },
-    setEasingOn: function(a, e) {
-        a = Ext.Array.from(a).slice();
-        var c = {},
-            d = a.length,
-            b = 0;
-        for (; b < d; b++) {
-            c[a[b]] = e
-        }
-        this.setCustomEasings(c)
-    },
-    clearEasingOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customEasings[a[b]]
-        }
-    },
-    applyCustomDurations: function(g, h) {
-        h = h || {};
-        var e, c, f, a, b, d;
-        for (c in g) {
-            e = true;
-            f = g[c];
-            a = c.split(",");
-            for (b = 0, d = a.length; b < d; b++) {
-                h[a[b]] = f
-            }
-        }
-        if (e) {
-            this.anySpecialAnimations = e
-        }
-        return h
-    },
-    applyCustomDuration: function(a, b) {
-        if (a) {
-            this.getCustomDurations();
-            this.setCustomDurations(a)
-        }
-    },
-    setDurationOn: function(b, e) {
-        b = Ext.Array.from(b).slice();
-        var a = {},
-            c = 0,
-            d = b.length;
-        for (; c < d; c++) {
-            a[b[c]] = e
-        }
-        this.setCustomDurations(a)
-    },
-    clearDurationOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customDurations[a[b]]
-        }
-    },
-    setAnimating: function(a, b) {
-        var e = this,
-            d = e.animatingPool;
-        if (a.animating !== b) {
-            a.animating = b;
-            if (b) {
-                d.push(a);
-                if (e.animating === 0) {
-                    Ext.draw.Animator.add(e)
-                }
-                e.animating++
-            } else {
-                for (var c = d.length; c--;) {
-                    if (d[c] === a) {
-                        d.splice(c, 1)
-                    }
-                }
-                e.animating = d.length
-            }
-        }
-    },
-    setAttrs: function(r, t) {
-        var s = this,
-            m = r.timers,
-            h = s._sprite.self.def._animationProcessors,
-            f = s._easing,
-            e = s._duration,
-            j = s._customDurations,
-            i = s._customEasings,
-            g = s.anySpecialAnimations,
-            n = s.anyAnimation || g,
-            o = r.animationOriginal,
-            d = false,
-            k, u, l, p, c, q, a;
-        if (!n) {
-            for (u in t) {
-                if (r[u] === t[u]) {
-                    delete t[u]
-                } else {
-                    r[u] = t[u]
-                }
-                delete o[u];
-                delete m[u]
-            }
-            return t
-        } else {
-            for (u in t) {
-                l = t[u];
-                p = r[u];
-                if (l !== p && p !== undefined && p !== null && (c = h[u])) {
-                    q = f;
-                    a = e;
-                    if (g) {
-                        if (u in i) {
-                            q = i[u]
-                        }
-                        if (u in j) {
-                            a = j[u]
-                        }
-                    }
-                    if (p && p.isGradient || l && l.isGradient) {
-                        a = 0
-                    }
-                    if (a) {
-                        if (!m[u]) {
-                            m[u] = {}
-                        }
-                        k = m[u];
-                        k.start = 0;
-                        k.easing = q;
-                        k.duration = a;
-                        k.compute = c.compute;
-                        k.serve = c.serve || Ext.identityFn;
-                        k.remove = t.removeFromInstance && t.removeFromInstance[u];
-                        if (c.parseInitial) {
-                            var b = c.parseInitial(p, l);
-                            k.source = b[0];
-                            k.target = b[1]
-                        } else {
-                            if (c.parse) {
-                                k.source = c.parse(p);
-                                k.target = c.parse(l)
-                            } else {
-                                k.source = p;
-                                k.target = l
-                            }
-                        }
-                        o[u] = l;
-                        delete t[u];
-                        d = true;
-                        continue
-                    } else {
-                        delete o[u]
-                    }
-                } else {
-                    delete o[u]
-                }
-                delete m[u]
-            }
-        }
-        if (d && !r.animating) {
-            s.setAnimating(r, true)
-        }
-        return t
-    },
-    updateAttributes: function(g) {
-        if (!g.animating) {
-            return {}
-        }
-        var h = {},
-            e = false,
-            d = g.timers,
-            f = g.animationOriginal,
-            c = Ext.draw.Animator.animationTime(),
-            a, b, i;
-        if (g.lastUpdate === c) {
-            return null
-        }
-        for (a in d) {
-            b = d[a];
-            if (!b.start) {
-                b.start = c;
-                i = 0
-            } else {
-                i = (c - b.start) / b.duration
-            }
-            if (i >= 1) {
-                h[a] = f[a];
-                delete f[a];
-                if (d[a].remove) {
-                    h.removeFromInstance = h.removeFromInstance || {};
-                    h.removeFromInstance[a] = true
-                }
-                delete d[a]
-            } else {
-                h[a] = b.serve(b.compute(b.source, b.target, b.easing(i), g[a]));
-                e = true
-            }
-        }
-        g.lastUpdate = c;
-        this.setAnimating(g, e);
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.animationOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    },
-    step: function(g) {
-        var f = this,
-            c = f.animatingPool.slice(),
-            e = c.length,
-            b = 0,
-            a, d;
-        for (; b < e; b++) {
-            a = c[b];
-            d = f.updateAttributes(a);
-            if (d && f._next) {
-                f._next.popUp(a, d)
-            }
-        }
-    },
-    stop: function() {
-        this.step();
-        var d = this,
-            b = d.animatingPool,
-            a, c;
-        for (a = 0, c = b.length; a < c; a++) {
-            b[a].animating = false
-        }
-        d.animatingPool.length = 0;
-        d.animating = 0;
-        Ext.draw.Animator.remove(d)
-    },
-    destroy: function() {
-        this.animatingPool.length = 0;
-        this.animating = 0;
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.modifier.Highlight", {
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.highlight",
-    config: {
-        enabled: false,
-        highlightStyle: null
-    },
-    preFx: true,
-    applyHighlightStyle: function(b, a) {
-        a = a || {};
-        if (this.getSprite()) {
-            Ext.apply(a, this.getSprite().self.def.normalize(b))
-        } else {
-            Ext.apply(a, b)
-        }
-        return a
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("highlightOriginal")) {
-            a.highlighted = false;
-            a.highlightOriginal = Ext.Object.chain(a);
-            a.highlightOriginal.prototype = a;
-            a.highlightOriginal.removeFromInstance = {}
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.highlightOriginal)
-        }
-    },
-    updateSprite: function(b, a) {
-        if (b) {
-            if (this.getHighlightStyle()) {
-                this._highlightStyle = b.self.def.normalize(this.getHighlightStyle())
-            }
-            this.setHighlightStyle(b.config.highlight)
-        }
-        b.self.def.setConfig({
-            defaults: {
-                highlighted: false
-            },
-            processors: {
-                highlighted: "bool"
-            }
-        });
-        this.setSprite(b)
-    },
-    filterChanges: function(a, d) {
-        var e = this,
-            f = a.highlightOriginal,
-            c = e.getHighlightStyle(),
-            b;
-        if (a.highlighted) {
-            for (b in d) {
-                if (c.hasOwnProperty(b)) {
-                    f[b] = d[b];
-                    delete d[b]
-                }
-            }
-        }
-        for (b in d) {
-            if (b !== "highlighted" && f[b] === d[b]) {
-                delete d[b]
-            }
-        }
-        return d
-    },
-    pushDown: function(e, g) {
-        var f = this.getHighlightStyle(),
-            c = e.highlightOriginal,
-            i = c.removeFromInstance,
-            d, a, h, b;
-        if (g.hasOwnProperty("highlighted")) {
-            d = g.highlighted;
-            delete g.highlighted;
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g);
-            if (d !== e.highlighted) {
-                if (d) {
-                    for (a in f) {
-                        if (a in g) {
-                            c[a] = g[a]
-                        } else {
-                            h = e.template && e.template.ownAttr;
-                            if (h && !e.prototype.hasOwnProperty(a)) {
-                                i[a] = true;
-                                c[a] = h.animationOriginal[a]
-                            } else {
-                                b = c.timers[a];
-                                if (b && b.remove) {
-                                    i[a] = true
-                                }
-                                c[a] = e[a]
-                            }
-                        }
-                        if (c[a] !== f[a]) {
-                            g[a] = f[a]
-                        }
-                    }
-                } else {
-                    for (a in f) {
-                        if (!(a in g)) {
-                            g[a] = c[a]
-                        }
-                        delete c[a]
-                    }
-                    g.removeFromInstance = g.removeFromInstance || {};
-                    Ext.apply(g.removeFromInstance, i);
-                    c.removeFromInstance = {}
-                }
-                g.highlighted = d
-            }
-        } else {
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g)
-        }
-        return g
-    },
-    popUp: function(a, b) {
-        b = this.filterChanges(a, b);
-        Ext.draw.modifier.Modifier.prototype.popUp.call(this, a, b)
-    }
-});
-Ext.define("Ext.draw.sprite.Sprite", {
-    alias: "sprite.sprite",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.draw.Draw", "Ext.draw.gradient.Gradient", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.modifier.Target", "Ext.draw.modifier.Animation", "Ext.draw.modifier.Highlight"],
-    isSprite: true,
-    statics: {
-        defaultHitTestOptions: {
-            fill: true,
-            stroke: true
-        }
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                strokeStyle: "color",
-                fillStyle: "color",
-                strokeOpacity: "limited01",
-                fillOpacity: "limited01",
-                lineWidth: "number",
-                lineCap: "enums(butt,round,square)",
-                lineJoin: "enums(round,bevel,miter)",
-                lineDash: "data",
-                lineDashOffset: "number",
-                miterLimit: "number",
-                shadowColor: "color",
-                shadowOffsetX: "number",
-                shadowOffsetY: "number",
-                shadowBlur: "number",
-                globalAlpha: "limited01",
-                globalCompositeOperation: "enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",
-                hidden: "bool",
-                transformFillStroke: "bool",
-                zIndex: "number",
-                translationX: "number",
-                translationY: "number",
-                rotationRads: "number",
-                rotationCenterX: "number",
-                rotationCenterY: "number",
-                scalingX: "number",
-                scalingY: "number",
-                scalingCenterX: "number",
-                scalingCenterY: "number",
-                constrainGradients: "bool"
-            },
-            aliases: {
-                stroke: "strokeStyle",
-                fill: "fillStyle",
-                color: "fillStyle",
-                "stroke-width": "lineWidth",
-                "stroke-linecap": "lineCap",
-                "stroke-linejoin": "lineJoin",
-                "stroke-miterlimit": "miterLimit",
-                "text-anchor": "textAlign",
-                opacity: "globalAlpha",
-                translateX: "translationX",
-                translateY: "translationY",
-                rotateRads: "rotationRads",
-                rotateCenterX: "rotationCenterX",
-                rotateCenterY: "rotationCenterY",
-                scaleX: "scalingX",
-                scaleY: "scalingY",
-                scaleCenterX: "scalingCenterX",
-                scaleCenterY: "scalingCenterY"
-            },
-            defaults: {
-                hidden: false,
-                zIndex: 0,
-                strokeStyle: "none",
-                fillStyle: "none",
-                lineWidth: 1,
-                lineDash: [],
-                lineDashOffset: 0,
-                lineCap: "butt",
-                lineJoin: "miter",
-                miterLimit: 10,
-                shadowColor: "none",
-                shadowOffsetX: 0,
-                shadowOffsetY: 0,
-                shadowBlur: 0,
-                globalAlpha: 1,
-                strokeOpacity: 1,
-                fillOpacity: 1,
-                transformFillStroke: false,
-                translationX: 0,
-                translationY: 0,
-                rotationRads: 0,
-                rotationCenterX: null,
-                rotationCenterY: null,
-                scalingX: 1,
-                scalingY: 1,
-                scalingCenterX: null,
-                scalingCenterY: null,
-                constrainGradients: false
-            },
-            triggers: {
-                zIndex: "zIndex",
-                globalAlpha: "canvas",
-                globalCompositeOperation: "canvas",
-                transformFillStroke: "canvas",
-                strokeStyle: "canvas",
-                fillStyle: "canvas",
-                strokeOpacity: "canvas",
-                fillOpacity: "canvas",
-                lineWidth: "canvas",
-                lineCap: "canvas",
-                lineJoin: "canvas",
-                lineDash: "canvas",
-                lineDashOffset: "canvas",
-                miterLimit: "canvas",
-                shadowColor: "canvas",
-                shadowOffsetX: "canvas",
-                shadowOffsetY: "canvas",
-                shadowBlur: "canvas",
-                translationX: "transform",
-                translationY: "transform",
-                rotationRads: "transform",
-                rotationCenterX: "transform",
-                rotationCenterY: "transform",
-                scalingX: "transform",
-                scalingY: "transform",
-                scalingCenterX: "transform",
-                scalingCenterY: "transform",
-                constrainGradients: "canvas"
-            },
-            updaters: {
-                bbox: "bboxUpdater",
-                zIndex: function(a) {
-                    a.dirtyZIndex = true
-                },
-                transform: function(a) {
-                    a.dirtyTransform = true;
-                    a.bbox.transform.dirty = true
-                }
-            }
-        }
-    },
-    config: {
-        parent: null,
-        surface: null
-    },
-    onClassExtended: function(d, c) {
-        var b = d.superclass.self.def.initialConfig,
-            e = c.inheritableStatics && c.inheritableStatics.def,
-            a;
-        if (e) {
-            a = Ext.Object.merge({}, b, e);
-            d.def = new Ext.draw.sprite.AttributeDefinition(a);
-            delete c.inheritableStatics.def
-        } else {
-            d.def = new Ext.draw.sprite.AttributeDefinition(b)
-        }
-        d.def.spriteClass = d
-    },
-    constructor: function(b) {
-        var d = this,
-            c = d.self.def,
-            e = c.getDefaults(),
-            a;
-        b = Ext.isObject(b) ? b : {};
-        d.id = b.id || Ext.id(null, "ext-sprite-");
-        d.attr = {};
-        d.mixins.observable.constructor.apply(d, arguments);
-        a = Ext.Array.from(b.modifiers, true);
-        d.prepareModifiers(a);
-        d.initializeAttributes();
-        d.setAttributes(e, true);
-        d.setAttributes(b)
-    },
-    getDirty: function() {
-        return this.attr.dirty
-    },
-    setDirty: function(b) {
-        this.attr.dirty = b;
-        if (b) {
-            var a = this.getParent();
-            if (a) {
-                a.setDirty(true)
-            }
-        }
-    },
-    addModifier: function(a, b) {
-        var c = this;
-        if (!(a instanceof Ext.draw.modifier.Modifier)) {
-            a = Ext.factory(a, null, null, "modifier")
-        }
-        a.setSprite(c);
-        if (a.preFx || a.config && a.config.preFx) {
-            if (c.fx.getPrevious()) {
-                c.fx.getPrevious().setNext(a)
-            }
-            a.setNext(c.fx)
-        } else {
-            c.topModifier.getPrevious().setNext(a);
-            a.setNext(c.topModifier)
-        }
-        if (b) {
-            c.initializeAttributes()
-        }
-        return a
-    },
-    prepareModifiers: function(d) {
-        var c = this,
-            a, b;
-        c.topModifier = new Ext.draw.modifier.Target({
-            sprite: c
-        });
-        c.fx = new Ext.draw.modifier.Animation({
-            sprite: c
-        });
-        c.fx.setNext(c.topModifier);
-        for (a = 0, b = d.length; a < b; a++) {
-            c.addModifier(d[a], false)
-        }
-    },
-    getAnimation: function() {
-        return this.fx
-    },
-    setAnimation: function(a) {
-        this.fx.setConfig(a)
-    },
-    initializeAttributes: function() {
-        this.topModifier.prepareAttributes(this.attr)
-    },
-    callUpdaters: function(d) {
-        var e = this,
-            h = d.pendingUpdaters,
-            i = e.self.def.getUpdaters(),
-            c = false,
-            a = false,
-            b, g, f;
-        e.callUpdaters = Ext.emptyFn;
-        do {
-            c = false;
-            for (g in h) {
-                c = true;
-                b = h[g];
-                delete h[g];
-                f = i[g];
-                if (typeof f === "string") {
-                    f = e[f]
-                }
-                if (f) {
-                    f.call(e, d, b)
-                }
-            }
-            a = a || c
-        } while (c);
-        delete e.callUpdaters;
-        if (a) {
-            e.setDirty(true)
-        }
-    },
-    scheduleUpdaters: function(a, e, c) {
-        var f;
-        if (c) {
-            for (var b = 0, d = e.length; b < d; b++) {
-                f = e[b];
-                this.scheduleUpdater(a, f, c)
-            }
-        } else {
-            for (f in e) {
-                c = e[f];
-                this.scheduleUpdater(a, f, c)
-            }
-        }
-    },
-    scheduleUpdater: function(a, c, b) {
-        b = b || [];
-        var d = a.pendingUpdaters;
-        if (c in d) {
-            if (b.length) {
-                d[c] = Ext.Array.merge(d[c], b)
-            }
-        } else {
-            d[c] = b
-        }
-    },
-    setAttributes: function(d, g, c) {
-        var a = this.attr,
-            b, e, f;
-        if (g) {
-            if (c) {
-                this.topModifier.pushDown(a, d)
-            } else {
-                f = {};
-                for (b in d) {
-                    e = d[b];
-                    if (e !== a[b]) {
-                        f[b] = e
-                    }
-                }
-                this.topModifier.pushDown(a, f)
-            }
-        } else {
-            this.topModifier.pushDown(a, this.self.def.normalize(d))
-        }
-    },
-    setAttributesBypassingNormalization: function(b, a) {
-        return this.setAttributes(b, true, a)
-    },
-    bboxUpdater: function(b) {
-        var c = b.rotationRads !== 0,
-            a = b.scalingX !== 1 || b.scalingY !== 1,
-            d = b.rotationCenterX === null || b.rotationCenterY === null,
-            e = b.scalingCenterX === null || b.scalingCenterY === null;
-        b.bbox.plain.dirty = true;
-        b.bbox.transform.dirty = true;
-        if (c && d || a && e) {
-            this.scheduleUpdater(b, "transform")
-        }
-    },
-    getBBox: function(d) {
-        var e = this,
-            a = e.attr,
-            f = a.bbox,
-            c = f.plain,
-            b = f.transform;
-        if (c.dirty) {
-            e.updatePlainBBox(c);
-            c.dirty = false
-        }
-        if (!d) {
-            e.applyTransformations();
-            if (b.dirty) {
-                e.updateTransformedBBox(b, c);
-                b.dirty = false
-            }
-            return b
-        }
-        return c
-    },
-    updatePlainBBox: Ext.emptyFn,
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, 0, a)
-    },
-    getBBoxCenter: function(a) {
-        var b = this.getBBox(a);
-        if (b) {
-            return [b.x + b.width * 0.5, b.y + b.height * 0.5]
-        } else {
-            return [0, 0]
-        }
-    },
-    hide: function() {
-        this.attr.hidden = true;
-        this.setDirty(true);
-        return this
-    },
-    show: function() {
-        this.attr.hidden = false;
-        this.setDirty(true);
-        return this
-    },
-    useAttributes: function(i, f) {
-        this.applyTransformations();
-        var d = this.attr,
-            h = d.canvasAttributes,
-            e = h.strokeStyle,
-            g = h.fillStyle,
-            b = h.lineDash,
-            c = h.lineDashOffset,
-            a;
-        if (e) {
-            if (e.isGradient) {
-                i.strokeStyle = "black";
-                i.strokeGradient = e
-            } else {
-                i.strokeGradient = false
-            }
-        }
-        if (g) {
-            if (g.isGradient) {
-                i.fillStyle = "black";
-                i.fillGradient = g
-            } else {
-                i.fillGradient = false
-            }
-        }
-        if (b) {
-            i.setLineDash(b)
-        }
-        if (Ext.isNumber(c + i.lineDashOffset)) {
-            i.lineDashOffset = c
-        }
-        for (a in h) {
-            if (h[a] !== undefined && h[a] !== i[a]) {
-                i[a] = h[a]
-            }
-        }
-        this.setGradientBBox(i, f)
-    },
-    setGradientBBox: function(b, c) {
-        var a = this.attr;
-        if (a.constrainGradients) {
-            b.setGradientBBox({
-                x: c[0],
-                y: c[1],
-                width: c[2],
-                height: c[3]
-            })
-        } else {
-            b.setGradientBBox(this.getBBox(a.transformFillStroke))
-        }
-    },
-    applyTransformations: function(b) {
-        if (!b && !this.attr.dirtyTransform) {
-            return
-        }
-        var r = this,
-            k = r.attr,
-            p = r.getBBoxCenter(true),
-            g = p[0],
-            f = p[1],
-            q = k.translationX,
-            o = k.translationY,
-            j = k.scalingX,
-            i = k.scalingY === null ? k.scalingX : k.scalingY,
-            m = k.scalingCenterX === null ? g : k.scalingCenterX,
-            l = k.scalingCenterY === null ? f : k.scalingCenterY,
-            s = k.rotationRads,
-            e = k.rotationCenterX === null ? g : k.rotationCenterX,
-            d = k.rotationCenterY === null ? f : k.rotationCenterY,
-            c = Math.cos(s),
-            a = Math.sin(s),
-            n, h;
-        if (j === 1 && i === 1) {
-            m = 0;
-            l = 0
-        }
-        if (s === 0) {
-            e = 0;
-            d = 0
-        }
-        n = m * (1 - j) - e;
-        h = l * (1 - i) - d;
-        k.matrix.elements = [c * j, a * j, -a * i, c * i, c * n - a * h + e + q, a * n + c * h + d + o];
-        k.matrix.inverse(k.inverseMatrix);
-        k.dirtyTransform = false;
-        k.bbox.transform.dirty = true
-    },
-    transform: function(b, c) {
-        var a = this.attr,
-            e = a.matrix,
-            d;
-        if (b && b.isMatrix) {
-            d = b.elements
-        } else {
-            d = b
-        }
-        e.prepend.apply(e, d.slice());
-        e.inverse(a.inverseMatrix);
-        if (c) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    updateTransformAttributes: function() {
-        var a = this.attr,
-            b = a.matrix.split();
-        a.rotationRads = b.rotate;
-        a.rotationCenterX = 0;
-        a.rotationCenterY = 0;
-        a.scalingX = b.scaleX;
-        a.scalingY = b.scaleY;
-        a.scalingCenterX = 0;
-        a.scalingCenterY = 0;
-        a.translationX = b.translateX;
-        a.translationY = b.translateY
-    },
-    resetTransform: function(b) {
-        var a = this.attr;
-        a.matrix.reset();
-        a.inverseMatrix.reset();
-        if (!b) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    setTransform: function(a, b) {
-        this.resetTransform(true);
-        this.transform.call(this, a, b);
-        return this
-    },
-    preRender: Ext.emptyFn,
-    render: Ext.emptyFn,
-    hitTest: function(b, c) {
-        if (this.isVisible()) {
-            var a = b[0],
-                f = b[1],
-                e = this.getBBox(),
-                d = e && a >= e.x && a <= (e.x + e.width) && f >= e.y && f <= (e.y + e.height);
-            if (d) {
-                return {
-                    sprite: this
-                }
-            }
-        }
-        return null
-    },
-    isVisible: function() {
-        var e = this.attr,
-            f = this.getParent(),
-            g = f && (f.isSurface || f.isVisible()),
-            d = g && !e.hidden && e.globalAlpha,
-            b = Ext.draw.Color.NONE,
-            a = Ext.draw.Color.RGBA_NONE,
-            c = e.fillOpacity && e.fillStyle !== b && e.fillStyle !== a,
-            i = e.strokeOpacity && e.strokeStyle !== b && e.strokeStyle !== a,
-            h = d && (c || i);
-        return !!h
-    },
-    repaint: function() {
-        var a = this.getSurface();
-        if (a) {
-            a.renderFrame()
-        }
-    },
-    remove: function() {
-        var a = this.getSurface();
-        if (a && a.isSurface) {
-            return a.remove(this)
-        }
-        return null
-    },
-    destroy: function() {
-        var b = this,
-            a = b.topModifier,
-            c;
-        while (a) {
-            c = a;
-            a = a.getPrevious();
-            c.destroy()
-        }
-        delete b.attr;
-        b.remove();
-        if (b.fireEvent("beforedestroy", b) !== false) {
-            b.fireEvent("destroy", b)
-        }
-        b.callParent()
-    }
-}, function() {
-    this.def = new Ext.draw.sprite.AttributeDefinition(this.def);
-    this.def.spriteClass = this
-});
-Ext.define("Ext.draw.Path", {
-    requires: ["Ext.draw.Draw"],
-    statics: {
-        pathRe: /,?([achlmqrstvxz]),?/gi,
-        pathRe2: /-/gi,
-        pathSplitRe: /\s|,/g
-    },
-    svgString: "",
-    constructor: function(a) {
-        var b = this;
-        b.commands = [];
-        b.params = [];
-        b.cursor = null;
-        b.startX = 0;
-        b.startY = 0;
-        if (a) {
-            b.fromSvgString(a)
-        }
-    },
-    clear: function() {
-        var a = this;
-        a.params.length = 0;
-        a.commands.length = 0;
-        a.cursor = null;
-        a.startX = 0;
-        a.startY = 0;
-        a.dirt()
-    },
-    dirt: function() {
-        this.svgString = ""
-    },
-    moveTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c]
-        }
-        b.params.push(a, c);
-        b.commands.push("M");
-        b.startX = a;
-        b.startY = c;
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    lineTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c];
-            b.params.push(a, c);
-            b.commands.push("M")
-        } else {
-            b.params.push(a, c);
-            b.commands.push("L")
-        }
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    bezierCurveTo: function(c, e, b, d, a, g) {
-        var f = this;
-        if (!f.cursor) {
-            f.moveTo(c, e)
-        }
-        f.params.push(c, e, b, d, a, g);
-        f.commands.push("C");
-        f.cursor[0] = a;
-        f.cursor[1] = g;
-        f.dirt()
-    },
-    quadraticCurveTo: function(b, e, a, d) {
-        var c = this;
-        if (!c.cursor) {
-            c.moveTo(b, e)
-        }
-        c.bezierCurveTo((2 * b + c.cursor[0]) / 3, (2 * e + c.cursor[1]) / 3, (2 * b + a) / 3, (2 * e + d) / 3, a, d)
-    },
-    closePath: function() {
-        var a = this;
-        if (a.cursor) {
-            a.cursor = null;
-            a.commands.push("Z");
-            a.dirt()
-        }
-    },
-    arcTo: function(A, f, z, d, j, i, v) {
-        var E = this;
-        if (i === undefined) {
-            i = j
-        }
-        if (v === undefined) {
-            v = 0
-        }
-        if (!E.cursor) {
-            E.moveTo(A, f);
-            return
-        }
-        if (j === 0 || i === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        z -= A;
-        d -= f;
-        var B = E.cursor[0] - A,
-            g = E.cursor[1] - f,
-            C = z * g - d * B,
-            b, a, l, r, k, q, x = Math.sqrt(B * B + g * g),
-            u = Math.sqrt(z * z + d * d),
-            t, e, c;
-        if (C === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        if (i !== j) {
-            b = Math.cos(v);
-            a = Math.sin(v);
-            l = b / j;
-            r = a / i;
-            k = -a / j;
-            q = b / i;
-            var D = l * B + r * g;
-            g = k * B + q * g;
-            B = D;
-            D = l * z + r * d;
-            d = k * z + q * d;
-            z = D
-        } else {
-            B /= j;
-            g /= i;
-            z /= j;
-            d /= i
-        }
-        e = B * u + z * x;
-        c = g * u + d * x;
-        t = 1 / (Math.sin(Math.asin(Math.abs(C) / (x * u)) * 0.5) * Math.sqrt(e * e + c * c));
-        e *= t;
-        c *= t;
-        var o = (e * B + c * g) / (B * B + g * g),
-            m = (e * z + c * d) / (z * z + d * d);
-        var n = B * o - e,
-            p = g * o - c,
-            h = z * m - e,
-            y = d * m - c,
-            w = Math.atan2(p, n),
-            s = Math.atan2(y, h);
-        if (C > 0) {
-            if (s < w) {
-                s += Math.PI * 2
-            }
-        } else {
-            if (w < s) {
-                w += Math.PI * 2
-            }
-        }
-        if (i !== j) {
-            e = b * e * j - a * c * i + A;
-            c = a * c * i + b * c * i + f;
-            E.lineTo(b * j * n - a * i * p + e, a * j * n + b * i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        } else {
-            e = e * j + A;
-            c = c * i + f;
-            E.lineTo(j * n + e, i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        }
-    },
-    ellipse: function(h, f, c, a, q, n, d, e) {
-        var o = this,
-            g = o.params,
-            b = g.length,
-            m, l, k;
-        if (d - n >= Math.PI * 2) {
-            o.ellipse(h, f, c, a, q, n, n + Math.PI, e);
-            o.ellipse(h, f, c, a, q, n + Math.PI, d, e);
-            return
-        }
-        if (!e) {
-            if (d < n) {
-                d += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, n, d)
-        } else {
-            if (n < d) {
-                n += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, d, n);
-            for (l = b, k = g.length - 2; l < k; l += 2, k -= 2) {
-                var p = g[l];
-                g[l] = g[k];
-                g[k] = p;
-                p = g[l + 1];
-                g[l + 1] = g[k + 1];
-                g[k + 1] = p
-            }
-        }
-        if (!o.cursor) {
-            o.cursor = [g[g.length - 2], g[g.length - 1]];
-            o.commands.push("M")
-        } else {
-            o.cursor[0] = g[g.length - 2];
-            o.cursor[1] = g[g.length - 1];
-            o.commands.push("L")
-        }
-        for (l = 2; l < m; l += 6) {
-            o.commands.push("C")
-        }
-        o.dirt()
-    },
-    arc: function(b, f, a, d, c, e) {
-        this.ellipse(b, f, a, a, 0, d, c, e)
-    },
-    rect: function(b, e, c, a) {
-        if (c == 0 || a == 0) {
-            return
-        }
-        var d = this;
-        d.moveTo(b, e);
-        d.lineTo(b + c, e);
-        d.lineTo(b + c, e + a);
-        d.lineTo(b, e + a);
-        d.closePath()
-    },
-    approximateArc: function(s, i, f, o, n, d, x, v) {
-        var e = Math.cos(d),
-            z = Math.sin(d),
-            k = Math.cos(x),
-            l = Math.sin(x),
-            q = e * k * o - z * l * n,
-            y = -e * l * o - z * k * n,
-            p = z * k * o + e * l * n,
-            w = -z * l * o + e * k * n,
-            m = Math.PI / 2,
-            r = 2,
-            j = q,
-            u = y,
-            h = p,
-            t = w,
-            b = 0.547443256150549,
-            C, g, A, a, B, c;
-        v -= x;
-        if (v < 0) {
-            v += Math.PI * 2
-        }
-        s.push(q + i, p + f);
-        while (v >= m) {
-            s.push(j + u * b + i, h + t * b + f, j * b + u + i, h * b + t + f, u + i, t + f);
-            r += 6;
-            v -= m;
-            C = j;
-            j = u;
-            u = -C;
-            C = h;
-            h = t;
-            t = -C
-        }
-        if (v) {
-            g = (0.3294738052815987 + 0.012120855841304373 * v) * v;
-            A = Math.cos(v);
-            a = Math.sin(v);
-            B = A + g * a;
-            c = a - g * A;
-            s.push(j + u * g + i, h + t * g + f, j * B + u * c + i, h * B + t * c + f, j * A + u * a + i, h * A + t * a + f);
-            r += 6
-        }
-        return r
-    },
-    arcSvg: function(j, h, r, m, w, t, c) {
-        if (j < 0) {
-            j = -j
-        }
-        if (h < 0) {
-            h = -h
-        }
-        var x = this,
-            u = x.cursor[0],
-            f = x.cursor[1],
-            a = (u - t) / 2,
-            y = (f - c) / 2,
-            d = Math.cos(r),
-            s = Math.sin(r),
-            o = a * d + y * s,
-            v = -a * s + y * d,
-            i = o / j,
-            g = v / h,
-            p = i * i + g * g,
-            e = (u + t) * 0.5,
-            b = (f + c) * 0.5,
-            l = 0,
-            k = 0;
-        if (p >= 1) {
-            p = Math.sqrt(p);
-            j *= p;
-            h *= p
-        } else {
-            p = Math.sqrt(1 / p - 1);
-            if (m === w) {
-                p = -p
-            }
-            l = p * j * g;
-            k = -p * h * i;
-            e += d * l - s * k;
-            b += s * l + d * k
-        }
-        var q = Math.atan2((v - k) / h, (o - l) / j),
-            n = Math.atan2((-v - k) / h, (-o - l) / j) - q;
-        if (w) {
-            if (n <= 0) {
-                n += Math.PI * 2
-            }
-        } else {
-            if (n >= 0) {
-                n -= Math.PI * 2
-            }
-        }
-        x.ellipse(e, b, j, h, r, q, q + n, 1 - w)
-    },
-    fromSvgString: function(e) {
-        if (!e) {
-            return
-        }
-        var m = this,
-            h, l = {
-                a: 7,
-                c: 6,
-                h: 1,
-                l: 2,
-                m: 2,
-                q: 4,
-                s: 4,
-                t: 2,
-                v: 1,
-                z: 0,
-                A: 7,
-                C: 6,
-                H: 1,
-                L: 2,
-                M: 2,
-                Q: 4,
-                S: 4,
-                T: 2,
-                V: 1,
-                Z: 0
-            },
-            k = "",
-            g, f, c = 0,
-            b = 0,
-            d = false,
-            j, n, a;
-        if (Ext.isString(e)) {
-            h = e.replace(Ext.draw.Path.pathRe, " $1 ").replace(Ext.draw.Path.pathRe2, " -").split(Ext.draw.Path.pathSplitRe)
-        } else {
-            if (Ext.isArray(e)) {
-                h = e.join(",").split(Ext.draw.Path.pathSplitRe)
-            }
-        }
-        for (j = 0, n = 0; j < h.length; j++) {
-            if (h[j] !== "") {
-                h[n++] = h[j]
-            }
-        }
-        h.length = n;
-        m.clear();
-        for (j = 0; j < h.length;) {
-            k = d;
-            d = h[j];
-            a = (d.toUpperCase() !== d);
-            j++;
-            switch (d) {
-                case "M":
-                    m.moveTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "L":
-                    m.lineTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "A":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c = +h[j + 5], b = +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "C":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(+h[j], +h[j + 1], g = +h[j + 2], f = +h[j + 3], c = +h[j + 4], b = +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "Z":
-                    m.closePath();
-                    break;
-                case "m":
-                    m.moveTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "l":
-                    m.lineTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "a":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c += +h[j + 5], b += +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "c":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + (+h[j]), b + (+h[j + 1]), g = c + (+h[j + 2]), f = b + (+h[j + 3]), c += +h[j + 4], b += +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "z":
-                    m.closePath();
-                    break;
-                case "s":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "S":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = +h[j], f = +h[j + 1], c = (+h[j + 2]), b = (+h[j + 3]));
-                        j += 4
-                    }
-                    break;
-                case "q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "Q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = +h[j], f = +h[j + 1], c = +h[j + 2], b = +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "t":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c += +h[j + 1], b += +h[j + 2]);
-                        j += 2
-                    }
-                    break;
-                case "T":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c = (+h[j + 1]), b = (+h[j + 2]));
-                        j += 2
-                    }
-                    break;
-                case "h":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b);
-                        j++
-                    }
-                    break;
-                case "H":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b);
-                        j++
-                    }
-                    break;
-                case "v":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b += +h[j]);
-                        j++
-                    }
-                    break;
-                case "V":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b = +h[j]);
-                        j++
-                    }
-                    break
-            }
-        }
-    },
-    clone: function() {
-        var a = this,
-            b = new Ext.draw.Path();
-        b.params = a.params.slice(0);
-        b.commands = a.commands.slice(0);
-        b.cursor = a.cursor ? a.cursor.slice(0) : null;
-        b.startX = a.startX;
-        b.startY = a.startY;
-        b.svgString = a.svgString;
-        return b
-    },
-    transform: function(j) {
-        if (j.isIdentity()) {
-            return
-        }
-        var a = j.getXX(),
-            f = j.getYX(),
-            m = j.getDX(),
-            l = j.getXY(),
-            e = j.getYY(),
-            k = j.getDY(),
-            b = this.params,
-            c = 0,
-            d = b.length,
-            h, g;
-        for (; c < d; c += 2) {
-            h = b[c];
-            g = b[c + 1];
-            b[c] = h * a + g * f + m;
-            b[c + 1] = h * l + g * e + k
-        }
-        this.dirt()
-    },
-    getDimension: function(f) {
-        if (!f) {
-            f = {}
-        }
-        if (!this.commands || !this.commands.length) {
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var d = 0,
-            c = 0,
-            b = this.commands,
-            g = this.params,
-            e = b.length,
-            a, h;
-        for (; d < e; d++) {
-            switch (b[d]) {
-                case "M":
-                case "L":
-                    a = g[c];
-                    h = g[c + 1];
-                    f.left = Math.min(a, f.left);
-                    f.top = Math.min(h, f.top);
-                    f.right = Math.max(a, f.right);
-                    f.bottom = Math.max(h, f.bottom);
-                    c += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, a, h, g[c], g[c + 1], g[c + 2], g[c + 3], a = g[c + 4], h = g[c + 5]);
-                    c += 6;
-                    break
-            }
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    getDimensionWithTransform: function(n, f) {
-        if (!this.commands || !this.commands.length) {
-            if (!f) {
-                f = {}
-            }
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var a = n.getXX(),
-            k = n.getYX(),
-            q = n.getDX(),
-            p = n.getXY(),
-            h = n.getYY(),
-            o = n.getDY(),
-            e = 0,
-            d = 0,
-            b = this.commands,
-            c = this.params,
-            g = b.length,
-            m, l;
-        for (; e < g; e++) {
-            switch (b[e]) {
-                case "M":
-                case "L":
-                    m = c[d] * a + c[d + 1] * k + q;
-                    l = c[d] * p + c[d + 1] * h + o;
-                    f.left = Math.min(m, f.left);
-                    f.top = Math.min(l, f.top);
-                    f.right = Math.max(m, f.right);
-                    f.bottom = Math.max(l, f.bottom);
-                    d += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, m, l, c[d] * a + c[d + 1] * k + q, c[d] * p + c[d + 1] * h + o, c[d + 2] * a + c[d + 3] * k + q, c[d + 2] * p + c[d + 3] * h + o, m = c[d + 4] * a + c[d + 5] * k + q, l = c[d + 4] * p + c[d + 5] * h + o);
-                    d += 6;
-                    break
-            }
-        }
-        if (!f) {
-            f = {}
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    expandDimension: function(i, d, p, k, g, j, e, c, o) {
-        var m = this,
-            f = i.left,
-            a = i.right,
-            q = i.top,
-            n = i.bottom,
-            h = m.dim || (m.dim = []);
-        m.curveDimension(d, k, j, c, h);
-        f = Math.min(f, h[0]);
-        a = Math.max(a, h[1]);
-        m.curveDimension(p, g, e, o, h);
-        q = Math.min(q, h[0]);
-        n = Math.max(n, h[1]);
-        i.left = f;
-        i.right = a;
-        i.top = q;
-        i.bottom = n
-    },
-    curveDimension: function(p, n, k, j, h) {
-        var i = 3 * (-p + 3 * (n - k) + j),
-            g = 6 * (p - 2 * n + k),
-            f = -3 * (p - n),
-            o, m, e = Math.min(p, j),
-            l = Math.max(p, j),
-            q;
-        if (i === 0) {
-            if (g === 0) {
-                h[0] = e;
-                h[1] = l;
-                return
-            } else {
-                o = -f / g;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-            }
-        } else {
-            q = g * g - 4 * i * f;
-            if (q >= 0) {
-                q = Math.sqrt(q);
-                o = (q - g) / 2 / i;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-                if (q > 0) {
-                    o -= q / i;
-                    if (0 < o && o < 1) {
-                        m = this.interpolate(p, n, k, j, o);
-                        e = Math.min(e, m);
-                        l = Math.max(l, m)
-                    }
-                }
-            }
-        }
-        h[0] = e;
-        h[1] = l
-    },
-    interpolate: function(f, e, j, i, g) {
-        if (g === 0) {
-            return f
-        }
-        if (g === 1) {
-            return i
-        }
-        var h = (1 - g) / g;
-        return g * g * g * (i + h * (3 * j + h * (3 * e + h * f)))
-    },
-    fromStripes: function(g) {
-        var e = this,
-            c = 0,
-            d = g.length,
-            b, a, f;
-        e.clear();
-        for (; c < d; c++) {
-            f = g[c];
-            e.params.push.apply(e.params, f);
-            e.commands.push("M");
-            for (b = 2, a = f.length; b < a; b += 6) {
-                e.commands.push("C")
-            }
-        }
-        if (!e.cursor) {
-            e.cursor = []
-        }
-        e.cursor[0] = e.params[e.params.length - 2];
-        e.cursor[1] = e.params[e.params.length - 1];
-        e.dirt()
-    },
-    toStripes: function(k) {
-        var o = k || [],
-            p, n, m, b, a, h, g, f, e, c = this.commands,
-            d = this.params,
-            l = c.length;
-        for (f = 0, e = 0; f < l; f++) {
-            switch (c[f]) {
-                case "M":
-                    p = [h = b = d[e++], g = a = d[e++]];
-                    o.push(p);
-                    break;
-                case "L":
-                    n = d[e++];
-                    m = d[e++];
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break;
-                case "C":
-                    p.push(d[e++], d[e++], d[e++], d[e++], b = d[e++], a = d[e++]);
-                    break;
-                case "Z":
-                    n = h;
-                    m = g;
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break
-            }
-        }
-        return o
-    },
-    updateSvgString: function() {
-        var b = [],
-            a = this.commands,
-            f = this.params,
-            e = a.length,
-            d = 0,
-            c = 0;
-        for (; d < e; d++) {
-            switch (a[d]) {
-                case "M":
-                    b.push("M" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "L":
-                    b.push("L" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "C":
-                    b.push("C" + f[c] + "," + f[c + 1] + " " + f[c + 2] + "," + f[c + 3] + " " + f[c + 4] + "," + f[c + 5]);
-                    c += 6;
-                    break;
-                case "Z":
-                    b.push("Z");
-                    break
-            }
-        }
-        this.svgString = b.join("")
-    },
-    toString: function() {
-        if (!this.svgString) {
-            this.updateSvgString()
-        }
-        return this.svgString
-    }
-});
-Ext.define("Ext.draw.overrides.Path", {
-    override: "Ext.draw.Path",
-    rayOrigin: {
-        x: -10000,
-        y: -10000
-    },
-    isPointInPath: function(o, n) {
-        var m = this,
-            c = m.commands,
-            q = Ext.draw.PathUtil,
-            p = m.rayOrigin,
-            f = m.params,
-            l = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            k = 0,
-            h, g;
-        for (h = 0, g = 0; h < l; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (q.linesIntersection(b, a, f[g], f[g + 1], p.x, p.y, o, n)) {
-                        k += 1
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    k += q.cubicLineIntersections(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], p.x, p.y, o, n).length;
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    break
-            }
-        }
-        return k % 2 === 1
-    },
-    isPointOnPath: function(n, m) {
-        var l = this,
-            c = l.commands,
-            o = Ext.draw.PathUtil,
-            f = l.params,
-            k = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            h, g;
-        for (h = 0, g = 0; h < k; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (o.pointOnLine(b, a, f[g], f[g + 1], n, m)) {
-                        return true
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    if (o.pointOnCubic(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], n, m)) {
-                        return true
-                    }
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    break
-            }
-        }
-        return false
-    },
-    getSegmentIntersections: function(t, d, s, c, r, b, o, a) {
-        var w = this,
-            g = arguments.length,
-            v = Ext.draw.PathUtil,
-            f = w.commands,
-            u = w.params,
-            k = f.length,
-            m = null,
-            l = null,
-            h = 0,
-            e = 0,
-            x = [],
-            q, n, p;
-        for (q = 0, n = 0; q < k; q++) {
-            switch (f[q]) {
-                case "M":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    m = h = u[n];
-                    l = e = u[n + 1];
-                    n += 2;
-                    break;
-                case "L":
-                    switch (g) {
-                        case 4:
-                            p = v.linesIntersection(h, e, u[n], u[n + 1], t, d, s, c);
-                            if (p) {
-                                x.push(p)
-                            }
-                            break;
-                        case 8:
-                            p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, h, e, u[n], u[n + 1]);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n];
-                    e = u[n + 1];
-                    n += 2;
-                    break;
-                case "C":
-                    switch (g) {
-                        case 4:
-                            p = v.cubicLineIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, d, s, c);
-                            x.push.apply(x, p);
-                            break;
-                        case 8:
-                            p = v.cubicsIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, s, r, o, d, c, b, a);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n + 4];
-                    e = u[n + 5];
-                    n += 6;
-                    break;
-                case "Z":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    break
-            }
-        }
-        return x
-    },
-    getIntersections: function(o) {
-        var m = this,
-            c = m.commands,
-            g = m.params,
-            l = c.length,
-            f = null,
-            e = null,
-            b = 0,
-            a = 0,
-            d = [],
-            k, h, n;
-        for (k = 0, h = 0; k < l; k++) {
-            switch (c[k]) {
-                case "M":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    f = b = g[h];
-                    e = a = g[h + 1];
-                    h += 2;
-                    break;
-                case "L":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1]);
-                    d.push.apply(d, n);
-                    b = g[h];
-                    a = g[h + 1];
-                    h += 2;
-                    break;
-                case "C":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1], g[h + 2], g[h + 3], g[h + 4], g[h + 5]);
-                    d.push.apply(d, n);
-                    b = g[h + 4];
-                    a = g[h + 5];
-                    h += 6;
-                    break;
-                case "Z":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    break
-            }
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.Path", {
-    extend: "Ext.draw.sprite.Sprite",
-    requires: ["Ext.draw.Draw", "Ext.draw.Path"],
-    alias: ["sprite.path", "Ext.draw.Sprite"],
-    type: "path",
-    isPath: true,
-    inheritableStatics: {
-        def: {
-            processors: {
-                path: function(b, a) {
-                    if (!(b instanceof Ext.draw.Path)) {
-                        b = new Ext.draw.Path(b)
-                    }
-                    return b
-                }
-            },
-            aliases: {
-                d: "path"
-            },
-            triggers: {
-                path: "bbox"
-            },
-            updaters: {
-                path: function(a) {
-                    var b = a.path;
-                    if (!b || b.bindAttr !== a) {
-                        b = new Ext.draw.Path();
-                        b.bindAttr = a;
-                        a.path = b
-                    }
-                    b.clear();
-                    this.updatePath(b, a);
-                    this.scheduleUpdater(a, "bbox", ["path"])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimension(a)
-        }
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimensionWithTransform(this.attr.matrix, a)
-        }
-    },
-    render: function(b, c) {
-        var d = this.attr.matrix,
-            a = this.attr;
-        if (!a.path || a.path.params.length === 0) {
-            return
-        }
-        d.toContext(c);
-        c.appendPath(a.path);
-        c.fillStroke(a)
-    },
-    updatePath: function(b, a) {}
-});
-Ext.define("Ext.draw.overrides.sprite.Path", {
-    override: "Ext.draw.sprite.Path",
-    requires: ["Ext.draw.Color"],
-    isPointInPath: function(c, g) {
-        var b = this.attr;
-        if (b.fillStyle === Ext.draw.Color.RGBA_NONE) {
-            return this.isPointOnPath(c, g)
-        }
-        var e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointInPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    isPointOnPath: function(c, g) {
-        var b = this.attr,
-            e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointOnPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    hitTest: function(i, l) {
-        var e = this,
-            c = e.attr,
-            k = c.path,
-            g = c.matrix,
-            h = i[0],
-            f = i[1],
-            d = e.callParent([i, l]),
-            j = null,
-            a, b;
-        if (!d) {
-            return j
-        }
-        l = l || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        if (!g.isIdentity()) {
-            a = k.params.slice(0);
-            k.transform(c.matrix)
-        }
-        if (l.fill && l.stroke) {
-            b = c.fillStyle !== Ext.draw.Color.NONE && c.fillStyle !== Ext.draw.Color.RGBA_NONE;
-            if (b) {
-                if (k.isPointInPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (k.isPointInPath(h, f) || k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            }
-        } else {
-            if (l.stroke && !l.fill) {
-                if (k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (l.fill && !l.stroke) {
-                    if (k.isPointInPath(h, f)) {
-                        j = {
-                            sprite: e
-                        }
-                    }
-                }
-            }
-        }
-        if (a) {
-            k.params = a
-        }
-        return j
-    },
-    getIntersections: function(j) {
-        if (!(j.isSprite && j.isPath)) {
-            return []
-        }
-        var e = this.attr,
-            d = j.attr,
-            i = e.path,
-            h = d.path,
-            g = e.matrix,
-            a = d.matrix,
-            c, f, b;
-        if (!g.isIdentity()) {
-            c = i.params.slice(0);
-            i.transform(e.matrix)
-        }
-        if (!a.isIdentity()) {
-            f = h.params.slice(0);
-            h.transform(d.matrix)
-        }
-        b = i.getIntersections(h);
-        if (c) {
-            i.params = c
-        }
-        if (f) {
-            h.params = f
-        }
-        return b
-    }
-});
-Ext.define("Ext.draw.sprite.Circle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.circle",
-    type: "circle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                r: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                r: 4
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                r: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            e = b.cy,
-            d = b.r;
-        c.x = a - d;
-        c.y = e - d;
-        c.width = d + d;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var g = this.attr,
-            f = g.cx,
-            e = g.cy,
-            a = g.r,
-            h = g.matrix,
-            j = h.getScaleX(),
-            i = h.getScaleY(),
-            c, b;
-        c = j * a;
-        b = i * a;
-        d.x = h.x(f, e) - c;
-        d.y = h.y(f, e) - b;
-        d.width = c + c;
-        d.height = b + b
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.Arc", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "sprite.arc",
-    type: "arc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Arrow", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.arrow",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.5,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c * 0.7, ",", e - c * 0.4, "l", [c * 0.6, 0, 0, -c * 0.4, c, c * 0.8, -c, c * 0.8, 0, -c * 0.4, -c * 0.6, 0], "z"))
-    }
-});
-Ext.define("Ext.draw.sprite.Composite", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.composite",
-    type: "composite",
-    isComposite: true,
-    config: {
-        sprites: []
-    },
-    constructor: function() {
-        this.sprites = [];
-        this.sprites.map = {};
-        this.callParent(arguments)
-    },
-    add: function(c) {
-        if (!c) {
-            return null
-        }
-        if (!c.isSprite) {
-            c = Ext.create("sprite." + c.type, c);
-            c.setParent(this);
-            c.setSurface(this.getSurface())
-        }
-        var d = this,
-            a = d.attr,
-            b = c.applyTransformations;
-        c.applyTransformations = function() {
-            if (c.attr.dirtyTransform) {
-                a.dirtyTransform = true;
-                a.bbox.plain.dirty = true;
-                a.bbox.transform.dirty = true
-            }
-            b.call(c)
-        };
-        d.sprites.push(c);
-        d.sprites.map[c.id] = c.getId();
-        a.bbox.plain.dirty = true;
-        a.bbox.transform.dirty = true;
-        return c
-    },
-    updateSurface: function(a) {
-        for (var b = 0, c = this.sprites.length; b < c; b++) {
-            this.sprites[b].setSurface(a)
-        }
-    },
-    addAll: function(b) {
-        if (b.isSprite || b.type) {
-            this.add(b)
-        } else {
-            if (Ext.isArray(b)) {
-                var a = 0;
-                while (a < b.length) {
-                    this.add(b[a++])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(g) {
-        var e = this,
-            b = Infinity,
-            h = -Infinity,
-            f = Infinity,
-            a = -Infinity,
-            j, k, c, d;
-        for (c = 0, d = e.sprites.length; c < d; c++) {
-            j = e.sprites[c];
-            j.applyTransformations();
-            k = j.getBBox();
-            if (b > k.x) {
-                b = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (f > k.y) {
-                f = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        g.x = b;
-        g.y = f;
-        g.width = h - b;
-        g.height = a - f
-    },
-    render: function(a, b, f) {
-        var d = this.attr.matrix,
-            c, e;
-        d.toContext(b);
-        for (c = 0, e = this.sprites.length; c < e; c++) {
-            a.renderSprite(this.sprites[c], f)
-        }
-    },
-    destroy: function() {
-        var c = this,
-            d = c.sprites,
-            b = d.length,
-            a;
-        c.callParent();
-        for (a = 0; a < b; a++) {
-            d[a].destroy()
-        }
-        d.length = 0
-    }
-});
-Ext.define("Ext.draw.sprite.Cross", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.cross",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.7,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c, ",", e, "l", [-c, -c, c, -c, c, c, c, -c, c, c, -c, c, c, c, -c, c, -c, -c, -c, c, -c, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Diamond", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.diamond",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.25,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString(["M", a, e - c, "l", c, c, -c, c, -c, -c, c, -c, "z"])
-    }
-});
-Ext.define("Ext.draw.sprite.Ellipse", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.ellipse",
-    type: "ellipse",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                rx: "number",
-                ry: "number",
-                axisRotation: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy",
-                radiusX: "rx",
-                radiusY: "ry"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                rx: 1,
-                ry: 1,
-                axisRotation: 0
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                rx: "path",
-                ry: "path",
-                axisRotation: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            f = b.cy,
-            e = b.rx,
-            d = b.ry;
-        c.x = a - e;
-        c.y = f - d;
-        c.width = e + e;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var i = this.attr,
-            f = i.cx,
-            e = i.cy,
-            c = i.rx,
-            b = i.ry,
-            l = b / c,
-            m = i.matrix.clone(),
-            a, q, k, j, p, o, n, g;
-        m.append(1, 0, 0, l, 0, e * (1 - l));
-        a = m.getXX();
-        k = m.getYX();
-        p = m.getDX();
-        q = m.getXY();
-        j = m.getYY();
-        o = m.getDY();
-        n = Math.sqrt(a * a + k * k) * c;
-        g = Math.sqrt(q * q + j * j) * c;
-        d.x = f * a + e * k + p - n;
-        d.y = f * q + e * j + o - g;
-        d.width = n + n;
-        d.height = g + g
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.EllipticalArc", {
-    extend: "Ext.draw.sprite.Ellipse",
-    alias: "sprite.ellipticalArc",
-    type: "ellipticalArc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Rect", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.rect",
-    type: "rect",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                radius: "number"
-            },
-            aliases: {},
-            triggers: {
-                x: "path",
-                y: "path",
-                width: "path",
-                height: "path",
-                radius: "path"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                radius: 0
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.x;
-        b.y = a.y;
-        b.width = a.width;
-        b.height = a.height
-    },
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, this.attr.radius, a)
-    },
-    updatePath: function(f, d) {
-        var c = d.x,
-            g = d.y,
-            e = d.width,
-            b = d.height,
-            a = Math.min(d.radius, Math.abs(d.height) * 0.5, Math.abs(d.width) * 0.5);
-        if (a === 0) {
-            f.rect(c, g, e, b)
-        } else {
-            f.moveTo(c + a, g);
-            f.arcTo(c + e, g, c + e, g + b, a);
-            f.arcTo(c + e, g + b, c, g + b, a);
-            f.arcTo(c, g + b, c, g, a);
-            f.arcTo(c, g, c + a, g, a)
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Image", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.image",
-    type: "image",
-    statics: {
-        imageLoaders: {}
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                src: "string"
-            },
-            defaults: {
-                src: "",
-                width: null,
-                height: null
-            }
-        }
-    },
-    render: function(c, o) {
-        var j = this,
-            h = j.attr,
-            n = h.matrix,
-            a = h.src,
-            l = h.x,
-            k = h.y,
-            b = h.width,
-            m = h.height,
-            g = Ext.draw.sprite.Image.imageLoaders[a],
-            f, d, e;
-        if (g && g.done) {
-            n.toContext(o);
-            d = g.image;
-            o.drawImage(d, l, k, b || (d.naturalWidth || d.width) / c.devicePixelRatio, m || (d.naturalHeight || d.height) / c.devicePixelRatio)
-        } else {
-            if (!g) {
-                f = new Image();
-                g = Ext.draw.sprite.Image.imageLoaders[a] = {
-                    image: f,
-                    done: false,
-                    pendingSprites: [j],
-                    pendingSurfaces: [c]
-                };
-                f.width = b;
-                f.height = m;
-                f.onload = function() {
-                    if (!g.done) {
-                        g.done = true;
-                        for (e = 0; e < g.pendingSprites.length; e++) {
-                            g.pendingSprites[e].setDirty(true)
-                        }
-                        for (e in g.pendingSurfaces) {
-                            g.pendingSurfaces[e].renderFrame()
-                        }
-                    }
-                };
-                f.src = a
-            } else {
-                Ext.Array.include(g.pendingSprites, j);
-                Ext.Array.include(g.pendingSurfaces, c)
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Instancing", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.instancing",
-    type: "instancing",
-    isInstancing: true,
-    config: {
-        template: null
-    },
-    instances: null,
-    applyTemplate: function(a) {
-        if (!a.isSprite) {
-            if (!a.xclass && !a.type) {
-                a.type = "circle"
-            }
-            a = Ext.create(a.xclass || "sprite." + a.type, a)
-        }
-        a.setParent(this);
-        return a
-    },
-    updateTemplate: function(a, b) {
-        if (b) {
-            delete b.ownAttr
-        }
-        a.setSurface(this.getSurface());
-        a.ownAttr = a.attr;
-        this.clearAll()
-    },
-    updateSurface: function(a) {
-        var b = this.getTemplate();
-        if (b) {
-            b.setSurface(a)
-        }
-    },
-    get: function(a) {
-        return this.instances[a]
-    },
-    getCount: function() {
-        return this.instances.length
-    },
-    clearAll: function() {
-        var a = this.getTemplate();
-        a.attr.children = this.instances = [];
-        this.position = 0
-    },
-    createInstance: function(d, f, c) {
-        var e = this.getTemplate(),
-            b = e.attr,
-            a = Ext.Object.chain(b);
-        e.topModifier.prepareAttributes(a);
-        e.attr = a;
-        e.setAttributes(d, f, c);
-        a.template = e;
-        this.instances.push(a);
-        e.attr = b;
-        this.position++;
-        return a
-    },
-    getBBox: function() {
-        return null
-    },
-    getBBoxFor: function(b, d) {
-        var c = this.getTemplate(),
-            a = c.attr,
-            e;
-        c.attr = this.instances[b];
-        e = c.getBBox(d);
-        c.attr = a;
-        return e
-    },
-    isVisible: function() {
-        var b = this.attr,
-            c = this.getParent(),
-            a;
-        a = c && c.isSurface && !b.hidden && b.globalAlpha;
-        return !!a
-    },
-    isInstanceVisible: function(c) {
-        var e = this,
-            d = e.getTemplate(),
-            b = d.attr,
-            f = e.instances,
-            a = false;
-        if (!Ext.isNumber(c) || c < 0 || c >= f.length || !e.isVisible()) {
-            return a
-        }
-        d.attr = f[c];
-        a = d.isVisible(point, options);
-        d.attr = b;
-        return a
-    },
-    render: function(b, l, d, h) {
-        var g = this,
-            j = g.getTemplate(),
-            k = g.attr.matrix,
-            c = j.attr,
-            a = g.instances,
-            e, f = g.position;
-        k.toContext(l);
-        j.preRender(b, l, d, h);
-        j.useAttributes(l, h);
-        for (e = 0; e < f; e++) {
-            if (a[e].dirtyZIndex) {
-                break
-            }
-        }
-        for (e = 0; e < f; e++) {
-            if (a[e].hidden) {
-                continue
-            }
-            l.save();
-            j.attr = a[e];
-            j.useAttributes(l, h);
-            j.render(b, l, d, h);
-            l.restore()
-        }
-        j.attr = c
-    },
-    setAttributesFor: function(c, e, f) {
-        var d = this.getTemplate(),
-            b = d.attr,
-            a = this.instances[c];
-        if (!a) {
-            return
-        }
-        d.attr = a;
-        if (f) {
-            e = Ext.apply({}, e)
-        } else {
-            e = d.self.def.normalize(e)
-        }
-        d.topModifier.pushDown(a, e);
-        d.attr = b
-    },
-    destroy: function() {
-        var b = this,
-            a = b.getTemplate();
-        b.instances = null;
-        if (a) {
-            a.destroy()
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.sprite.Instancing", {
-    override: "Ext.draw.sprite.Instancing",
-    hitTest: function(f, j) {
-        var e = this,
-            g = e.getTemplate(),
-            b = g.attr,
-            a = e.instances,
-            d = a.length,
-            c = 0,
-            h = null;
-        if (!e.isVisible()) {
-            return h
-        }
-        for (; c < d; c++) {
-            g.attr = a[c];
-            h = g.hitTest(f, j);
-            if (h) {
-                h.isInstance = true;
-                h.template = h.sprite;
-                h.sprite = this;
-                h.instance = a[c];
-                h.index = c;
-                return h
-            }
-        }
-        g.attr = b;
-        return h
-    }
-});
-Ext.define("Ext.draw.sprite.Line", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.line",
-    type: "line",
-    inheritableStatics: {
-        def: {
-            processors: {
-                fromX: "number",
-                fromY: "number",
-                toX: "number",
-                toY: "number"
-            },
-            defaults: {
-                fromX: 0,
-                fromY: 0,
-                toX: 1,
-                toY: 1,
-                strokeStyle: "black"
-            },
-            aliases: {
-                x1: "fromX",
-                y1: "fromY",
-                x2: "toX",
-                y2: "toY"
-            }
-        }
-    },
-    updateLineBBox: function(b, i, s, g, r, f) {
-        var o = this.attr,
-            q = o.matrix,
-            h = o.lineWidth / 2,
-            m, l, d, c, k, j, n;
-        if (i) {
-            n = q.transformPoint([s, g]);
-            s = n[0];
-            g = n[1];
-            n = q.transformPoint([r, f]);
-            r = n[0];
-            f = n[1]
-        }
-        m = Math.min(s, r);
-        d = Math.max(s, r);
-        l = Math.min(g, f);
-        c = Math.max(g, f);
-        var t = Math.atan2(d - m, c - l),
-            a = Math.sin(t),
-            e = Math.cos(t),
-            k = h * e,
-            j = h * a;
-        m -= k;
-        l -= j;
-        d += k;
-        c += j;
-        b.x = m;
-        b.y = l;
-        b.width = d - m;
-        b.height = c - l
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        this.updateLineBBox(b, false, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    updateTransformedBBox: function(b, c) {
-        var a = this.attr;
-        this.updateLineBBox(b, true, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    render: function(b, c) {
-        var a = this.attr,
-            d = this.attr.matrix;
-        d.toContext(c);
-        c.beginPath();
-        c.moveTo(a.fromX, a.fromY);
-        c.lineTo(a.toX, a.toY);
-        c.stroke()
-    }
-});
-Ext.define("Ext.draw.sprite.Plus", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.plus",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.3,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c / 2, ",", e - c / 2, "l", [0, -c, c, 0, 0, c, c, 0, 0, c, -c, 0, 0, c, -c, 0, 0, -c, -c, 0, 0, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Sector", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.sector",
-    type: "sector",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,bbox",
-                endAngle: "path,bbox",
-                startRho: "path,bbox",
-                endRho: "path,bbox",
-                margin: "path,bbox"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: 0,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                path: "M 0,0"
-            }
-        }
-    },
-    getMidAngle: function() {
-        return this.midAngle || 0
-    },
-    updatePath: function(j, h) {
-        var g = Math.min(h.startAngle, h.endAngle),
-            c = Math.max(h.startAngle, h.endAngle),
-            b = this.midAngle = (g + c) * 0.5,
-            d = h.margin,
-            f = h.centerX,
-            e = h.centerY,
-            i = Math.min(h.startRho, h.endRho),
-            a = Math.max(h.startRho, h.endRho);
-        if (d) {
-            f += d * Math.cos(b);
-            e += d * Math.sin(b)
-        }
-        j.moveTo(f + i * Math.cos(g), e + i * Math.sin(g));
-        j.lineTo(f + a * Math.cos(g), e + a * Math.sin(g));
-        j.arc(f, e, a, g, c, false);
-        j.lineTo(f + i * Math.cos(c), e + i * Math.sin(c));
-        j.arc(f, e, i, c, g, true)
-    }
-});
-Ext.define("Ext.draw.sprite.Square", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.square",
-    inheritableStatics: {
-        def: {
-            processors: {
-                size: "number"
-            },
-            defaults: {
-                size: 4
-            },
-            triggers: {
-                size: "size"
-            },
-            updaters: {
-                size: function(a) {
-                    var c = a.size,
-                        b = a.lineWidth / 2;
-                    this.setAttributes({
-                        x: a.x - c - b,
-                        y: a.y - c,
-                        height: 2 * c,
-                        width: 2 * c
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.TextMeasurer", {
-    singleton: true,
-    requires: ["Ext.util.TextMetrics"],
-    measureDiv: null,
-    measureCache: {},
-    precise: Ext.isIE8,
-    measureDivTpl: {
-        tag: "div",
-        style: {
-            overflow: "hidden",
-            position: "relative",
-            "float": "left",
-            width: 0,
-            height: 0
-        },
-        children: {
-            tag: "div",
-            style: {
-                display: "block",
-                position: "absolute",
-                x: -100000,
-                y: -100000,
-                padding: 0,
-                margin: 0,
-                "z-index": -100000,
-                "white-space": "nowrap"
-            }
-        }
-    },
-    actualMeasureText: function(g, b) {
-        var e = Ext.draw.TextMeasurer,
-            f = e.measureDiv,
-            a = 100000,
-            c;
-        if (!f) {
-            var d = Ext.Element.create({
-                style: {
-                    overflow: "hidden",
-                    position: "relative",
-                    "float": "left",
-                    width: 0,
-                    height: 0
-                }
-            });
-            e.measureDiv = f = Ext.Element.create({
-                style: {
-                    position: "absolute",
-                    x: a,
-                    y: a,
-                    "z-index": -a,
-                    "white-space": "nowrap",
-                    display: "block",
-                    padding: 0,
-                    margin: 0
-                }
-            });
-            Ext.getBody().appendChild(d);
-            d.appendChild(f)
-        }
-        if (b) {
-            f.setStyle({
-                font: b,
-                lineHeight: "normal"
-            })
-        }
-        f.setText("(" + g + ")");
-        c = f.getSize();
-        f.setText("()");
-        c.width -= f.getSize().width;
-        return c
-    },
-    measureTextSingleLine: function(h, d) {
-        if (this.precise) {
-            return this.preciseMeasureTextSingleLine(h, d)
-        }
-        h = h.toString();
-        var a = this.measureCache,
-            g = h.split(""),
-            c = 0,
-            j = 0,
-            l, b, e, f, k;
-        if (!a[d]) {
-            a[d] = {}
-        }
-        a = a[d];
-        if (a[h]) {
-            return a[h]
-        }
-        for (e = 0, f = g.length; e < f; e++) {
-            b = g[e];
-            if (!(l = a[b])) {
-                k = this.actualMeasureText(b, d);
-                l = a[b] = k
-            }
-            c += l.width;
-            j = Math.max(j, l.height)
-        }
-        return a[h] = {
-            width: c,
-            height: j
-        }
-    },
-    preciseMeasureTextSingleLine: function(c, a) {
-        c = c.toString();
-        var b = this.measureDiv || (this.measureDiv = Ext.getBody().createChild(this.measureDivTpl).down("div"));
-        b.setStyle({
-            font: a || ""
-        });
-        return Ext.util.TextMetrics.measure(b, c)
-    },
-    measureText: function(e, b) {
-        var h = e.split("\n"),
-            d = h.length,
-            f = 0,
-            a = 0,
-            j, c, g;
-        if (d === 1) {
-            return this.measureTextSingleLine(e, b)
-        }
-        g = [];
-        for (c = 0; c < d; c++) {
-            j = this.measureTextSingleLine(h[c], b);
-            g.push(j);
-            f += j.height;
-            a = Math.max(a, j.width)
-        }
-        return {
-            width: a,
-            height: f,
-            sizes: g
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Text", function() {
-    var d = {
-        "xx-small": true,
-        "x-small": true,
-        small: true,
-        medium: true,
-        large: true,
-        "x-large": true,
-        "xx-large": true
-    };
-    var b = {
-        normal: true,
-        bold: true,
-        bolder: true,
-        lighter: true,
-        100: true,
-        200: true,
-        300: true,
-        400: true,
-        500: true,
-        600: true,
-        700: true,
-        800: true,
-        900: true
-    };
-    var a = {
-        start: "start",
-        left: "start",
-        center: "center",
-        middle: "center",
-        end: "end",
-        right: "end"
-    };
-    var c = {
-        top: "top",
-        hanging: "hanging",
-        middle: "middle",
-        center: "middle",
-        alphabetic: "alphabetic",
-        ideographic: "ideographic",
-        bottom: "bottom"
-    };
-    return {
-        extend: "Ext.draw.sprite.Sprite",
-        requires: ["Ext.draw.TextMeasurer", "Ext.draw.Color"],
-        alias: "sprite.text",
-        type: "text",
-        lineBreakRe: /\r?\n/g,
-        inheritableStatics: {
-            def: {
-                animationProcessors: {
-                    text: "text"
-                },
-                processors: {
-                    x: "number",
-                    y: "number",
-                    text: "string",
-                    fontSize: function(e) {
-                        if (Ext.isNumber(+e)) {
-                            return e + "px"
-                        } else {
-                            if (e.match(Ext.dom.Element.unitRe)) {
-                                return e
-                            } else {
-                                if (e in d) {
-                                    return e
-                                }
-                            }
-                        }
-                    },
-                    fontStyle: "enums(,italic,oblique)",
-                    fontVariant: "enums(,small-caps)",
-                    fontWeight: function(e) {
-                        if (e in b) {
-                            return String(e)
-                        } else {
-                            return ""
-                        }
-                    },
-                    fontFamily: "string",
-                    textAlign: function(e) {
-                        return a[e] || "center"
-                    },
-                    textBaseline: function(e) {
-                        return c[e] || "alphabetic"
-                    },
-                    font: "string"
-                },
-                aliases: {
-                    "font-size": "fontSize",
-                    "font-family": "fontFamily",
-                    "font-weight": "fontWeight",
-                    "font-variant": "fontVariant",
-                    "text-anchor": "textAlign"
-                },
-                defaults: {
-                    fontStyle: "",
-                    fontVariant: "",
-                    fontWeight: "",
-                    fontSize: "10px",
-                    fontFamily: "sans-serif",
-                    font: "10px sans-serif",
-                    textBaseline: "alphabetic",
-                    textAlign: "start",
-                    strokeStyle: "rgba(0, 0, 0, 0)",
-                    fillStyle: "#000",
-                    x: 0,
-                    y: 0,
-                    text: ""
-                },
-                triggers: {
-                    fontStyle: "fontX,bbox",
-                    fontVariant: "fontX,bbox",
-                    fontWeight: "fontX,bbox",
-                    fontSize: "fontX,bbox",
-                    fontFamily: "fontX,bbox",
-                    font: "font,bbox,canvas",
-                    textBaseline: "bbox",
-                    textAlign: "bbox",
-                    x: "bbox",
-                    y: "bbox",
-                    text: "bbox"
-                },
-                updaters: {
-                    fontX: "makeFontShorthand",
-                    font: "parseFontShorthand"
-                }
-            }
-        },
-        constructor: function(e) {
-            if (e && e.font) {
-                e = Ext.clone(e);
-                for (var f in e) {
-                    if (f !== "font" && f.indexOf("font") === 0) {
-                        delete e[f]
-                    }
-                }
-            }
-            Ext.draw.sprite.Sprite.prototype.constructor.call(this, e)
-        },
-        fontValuesMap: {
-            italic: "fontStyle",
-            oblique: "fontStyle",
-            "small-caps": "fontVariant",
-            bold: "fontWeight",
-            bolder: "fontWeight",
-            lighter: "fontWeight",
-            "100": "fontWeight",
-            "200": "fontWeight",
-            "300": "fontWeight",
-            "400": "fontWeight",
-            "500": "fontWeight",
-            "600": "fontWeight",
-            "700": "fontWeight",
-            "800": "fontWeight",
-            "900": "fontWeight",
-            "xx-small": "fontSize",
-            "x-small": "fontSize",
-            small: "fontSize",
-            medium: "fontSize",
-            large: "fontSize",
-            "x-large": "fontSize",
-            "xx-large": "fontSize"
-        },
-        makeFontShorthand: function(e) {
-            var f = [];
-            if (e.fontStyle) {
-                f.push(e.fontStyle)
-            }
-            if (e.fontVariant) {
-                f.push(e.fontVariant)
-            }
-            if (e.fontWeight) {
-                f.push(e.fontWeight)
-            }
-            if (e.fontSize) {
-                f.push(e.fontSize)
-            }
-            if (e.fontFamily) {
-                f.push(e.fontFamily)
-            }
-            this.setAttributes({
-                font: f.join(" ")
-            }, true)
-        },
-        parseFontShorthand: function(j) {
-            var m = j.font,
-                k = m.length,
-                l = {},
-                n = this.fontValuesMap,
-                e = 0,
-                i, g, f, h;
-            while (e < k && i !== -1) {
-                i = m.indexOf(" ", e);
-                if (i < 0) {
-                    f = m.substr(e)
-                } else {
-                    if (i > e) {
-                        f = m.substr(e, i - e)
-                    } else {
-                        continue
-                    }
-                }
-                g = f.indexOf("/");
-                if (g > 0) {
-                    f = f.substr(0, g)
-                } else {
-                    if (g === 0) {
-                        continue
-                    }
-                }
-                if (f !== "normal" && f !== "inherit") {
-                    h = n[f];
-                    if (h) {
-                        l[h] = f
-                    } else {
-                        if (f.match(Ext.dom.Element.unitRe)) {
-                            l.fontSize = f
-                        } else {
-                            l.fontFamily = m.substr(e);
-                            break
-                        }
-                    }
-                }
-                e = i + 1
-            }
-            if (!l.fontStyle) {
-                l.fontStyle = ""
-            }
-            if (!l.fontVariant) {
-                l.fontVariant = ""
-            }
-            if (!l.fontWeight) {
-                l.fontWeight = ""
-            }
-            this.setAttributes(l, true)
-        },
-        fontProperties: {
-            fontStyle: true,
-            fontVariant: true,
-            fontWeight: true,
-            fontSize: true,
-            fontFamily: true
-        },
-        setAttributes: function(g, i, e) {
-            var f, h;
-            if (g && g.font) {
-                h = {};
-                for (f in g) {
-                    if (!(f in this.fontProperties)) {
-                        h[f] = g[f]
-                    }
-                }
-                g = h
-            }
-            this.callParent([g, i, e])
-        },
-        getBBox: function(g) {
-            var h = this,
-                f = h.attr.bbox.plain,
-                e = h.getSurface();
-            if (f.dirty) {
-                h.updatePlainBBox(f);
-                f.dirty = false
-            }
-            if (e.getInherited().rtl && e.getFlipRtlText()) {
-                h.updatePlainBBox(f, true)
-            }
-            return h.callParent([g])
-        },
-        rtlAlignments: {
-            start: "end",
-            center: "center",
-            end: "start"
-        },
-        updatePlainBBox: function(k, B) {
-            var C = this,
-                w = C.attr,
-                o = w.x,
-                n = w.y,
-                q = [],
-                t = w.font,
-                r = w.text,
-                s = w.textBaseline,
-                l = w.textAlign,
-                u = (B && C.oldSize) ? C.oldSize : (C.oldSize = Ext.draw.TextMeasurer.measureText(r, t)),
-                z = C.getSurface(),
-                p = z.getInherited().rtl,
-                v = p && z.getFlipRtlText(),
-                h = z.getRect(),
-                f = u.sizes,
-                g = u.height,
-                j = u.width,
-                m = f ? f.length : 0,
-                e, A = 0;
-            switch (s) {
-                case "hanging":
-                case "top":
-                    break;
-                case "ideographic":
-                case "bottom":
-                    n -= g;
-                    break;
-                case "alphabetic":
-                    n -= g * 0.8;
-                    break;
-                case "middle":
-                    n -= g * 0.5;
-                    break
-            }
-            if (v) {
-                o = h[2] - h[0] - o;
-                l = C.rtlAlignments[l]
-            }
-            switch (l) {
-                case "start":
-                    if (p) {
-                        for (; A < m; A++) {
-                            e = f[A].width;
-                            q.push(-(j - e))
-                        }
-                    }
-                    break;
-                case "end":
-                    o -= j;
-                    if (p) {
-                        break
-                    }
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push(j - e)
-                    }
-                    break;
-                case "center":
-                    o -= j * 0.5;
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push((p ? -1 : 1) * (j - e) * 0.5)
-                    }
-                    break
-            }
-            w.textAlignOffsets = q;
-            k.x = o;
-            k.y = n;
-            k.width = j;
-            k.height = g
-        },
-        setText: function(e) {
-            this.setAttributes({
-                text: e
-            }, true)
-        },
-        render: function(e, q, k) {
-            var h = this,
-                g = h.attr,
-                p = Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),
-                o = h.getBBox(true),
-                s = g.textAlignOffsets,
-                m = Ext.draw.Color.RGBA_NONE,
-                l, j, f, r, n;
-            if (g.text.length === 0) {
-                return
-            }
-            r = g.text.split(h.lineBreakRe);
-            n = o.height / r.length;
-            l = g.bbox.plain.x;
-            j = g.bbox.plain.y + n * 0.78;
-            p.toContext(q);
-            if (e.getInherited().rtl) {
-                l += g.bbox.plain.width
-            }
-            for (f = 0; f < r.length; f++) {
-                if (q.fillStyle !== m) {
-                    q.fillText(r[f], l + (s[f] || 0), j + n * f)
-                }
-                if (q.strokeStyle !== m) {
-                    q.strokeText(r[f], l + (s[f] || 0), j + n * f)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Tick", {
-    extend: "Ext.draw.sprite.Line",
-    alias: "sprite.tick",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "tick",
-                y: "tick",
-                size: "tick"
-            },
-            updaters: {
-                tick: function(b) {
-                    var d = b.size * 1.5,
-                        c = b.lineWidth / 2,
-                        a = b.x,
-                        e = b.y;
-                    this.setAttributes({
-                        fromX: a - c,
-                        fromY: e - d,
-                        toX: a - c,
-                        toY: e + d
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Triangle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.triangle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 2.2,
-            a = b.x,
-            e = b.y;
-        d.fromSvgString("M".concat(a, ",", e, "m0-", c * 0.58, "l", c * 0.5, ",", c * 0.87, "-", c, ",0z"))
-    }
-});
-Ext.define("Ext.draw.gradient.Linear", {
-    extend: "Ext.draw.gradient.Gradient",
-    requires: ["Ext.draw.Color"],
-    type: "linear",
-    config: {
-        degrees: 0,
-        radians: 0
-    },
-    applyRadians: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    applyDegrees: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    updateRadians: function(a) {
-        this.setDegrees(Ext.draw.Draw.degrees(a))
-    },
-    updateDegrees: function(a) {
-        this.setRadians(Ext.draw.Draw.rad(a))
-    },
-    generateGradient: function(q, o) {
-        var c = this.getRadians(),
-            p = Math.cos(c),
-            j = Math.sin(c),
-            m = o.width,
-            f = o.height,
-            d = o.x + m * 0.5,
-            b = o.y + f * 0.5,
-            n = this.getStops(),
-            g = n.length,
-            k, a, e;
-        if (Ext.isNumber(d + b) && f > 0 && m > 0) {
-            a = (Math.sqrt(f * f + m * m) * Math.abs(Math.cos(c - Math.atan(f / m)))) / 2;
-            k = q.createLinearGradient(d + p * a, b + j * a, d - p * a, b - j * a);
-            for (e = 0; e < g; e++) {
-                k.addColorStop(n[e].offset, n[e].color)
-            }
-            return k
-        }
-        return Ext.draw.Color.NONE
-    }
-});
-Ext.define("Ext.draw.gradient.Radial", {
-    extend: "Ext.draw.gradient.Gradient",
-    type: "radial",
-    config: {
-        start: {
-            x: 0,
-            y: 0,
-            r: 0
-        },
-        end: {
-            x: 0,
-            y: 0,
-            r: 1
-        }
-    },
-    applyStart: function(a, b) {
-        if (!b) {
-            return a
-        }
-        var c = {
-            x: b.x,
-            y: b.y,
-            r: b.r
-        };
-        if ("x" in a) {
-            c.x = a.x
-        } else {
-            if ("centerX" in a) {
-                c.x = a.centerX
-            }
-        }
-        if ("y" in a) {
-            c.y = a.y
-        } else {
-            if ("centerY" in a) {
-                c.y = a.centerY
-            }
-        }
-        if ("r" in a) {
-            c.r = a.r
-        } else {
-            if ("radius" in a) {
-                c.r = a.radius
-            }
-        }
-        return c
-    },
-    applyEnd: function(b, a) {
-        if (!a) {
-            return b
-        }
-        var c = {
-            x: a.x,
-            y: a.y,
-            r: a.r
-        };
-        if ("x" in b) {
-            c.x = b.x
-        } else {
-            if ("centerX" in b) {
-                c.x = b.centerX
-            }
-        }
-        if ("y" in b) {
-            c.y = b.y
-        } else {
-            if ("centerY" in b) {
-                c.y = b.centerY
-            }
-        }
-        if ("r" in b) {
-            c.r = b.r
-        } else {
-            if ("radius" in b) {
-                c.r = b.radius
-            }
-        }
-        return c
-    },
-    generateGradient: function(n, m) {
-        var a = this.getStart(),
-            b = this.getEnd(),
-            k = m.width * 0.5,
-            d = m.height * 0.5,
-            j = m.x + k,
-            f = m.y + d,
-            g = n.createRadialGradient(j + a.x * k, f + a.y * d, a.r * Math.max(k, d), j + b.x * k, f + b.y * d, b.r * Math.max(k, d)),
-            l = this.getStops(),
-            e = l.length,
-            c;
-        for (c = 0; c < e; c++) {
-            g.addColorStop(l[c].offset, l[c].color)
-        }
-        return g
-    }
-});
-Ext.define("Ext.draw.Surface", {
-    extend: "Ext.draw.SurfaceBase",
-    xtype: "surface",
-    requires: ["Ext.draw.sprite.*", "Ext.draw.gradient.*", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.Matrix", "Ext.draw.Draw"],
-    uses: ["Ext.draw.engine.Canvas"],
-    devicePixelRatio: window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI,
-    deprecated: {
-        "5.1.0": {
-            statics: {
-                methods: {
-                    stableSort: function(a) {
-                        return Ext.Array.sort(a, function(d, c) {
-                            return d.attr.zIndex - c.attr.zIndex
-                        })
-                    }
-                }
-            }
-        }
-    },
-    config: {
-        cls: Ext.baseCSSPrefix + "surface",
-        rect: null,
-        background: null,
-        items: [],
-        dirty: false,
-        flipRtlText: false
-    },
-    isSurface: true,
-    isPendingRenderFrame: false,
-    dirtyPredecessorCount: 0,
-    constructor: function(a) {
-        var b = this;
-        b.predecessors = [];
-        b.successors = [];
-        b.map = {};
-        b.callParent([a]);
-        b.matrix = new Ext.draw.Matrix();
-        b.inverseMatrix = b.matrix.inverse()
-    },
-    roundPixel: function(a) {
-        return Math.round(this.devicePixelRatio * a) / this.devicePixelRatio
-    },
-    waitFor: function(a) {
-        var b = this,
-            c = b.predecessors;
-        if (!Ext.Array.contains(c, a)) {
-            c.push(a);
-            a.successors.push(b);
-            if (a.getDirty()) {
-                b.dirtyPredecessorCount++
-            }
-        }
-    },
-    updateDirty: function(d) {
-        var c = this.successors,
-            e = c.length,
-            b = 0,
-            a;
-        for (; b < e; b++) {
-            a = c[b];
-            if (d) {
-                a.dirtyPredecessorCount++;
-                a.setDirty(true)
-            } else {
-                a.dirtyPredecessorCount--;
-                if (a.dirtyPredecessorCount === 0 && a.isPendingRenderFrame) {
-                    a.renderFrame()
-                }
-            }
-        }
-    },
-    applyBackground: function(a, b) {
-        this.setDirty(true);
-        if (Ext.isString(a)) {
-            a = {
-                fillStyle: a
-            }
-        }
-        return Ext.factory(a, Ext.draw.sprite.Rect, b)
-    },
-    applyRect: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return
-        }
-        if (Ext.isArray(a)) {
-            return [a[0], a[1], a[2], a[3]]
-        } else {
-            if (Ext.isObject(a)) {
-                return [a.x || a.left, a.y || a.top, a.width || (a.right - a.left), a.height || (a.bottom - a.top)]
-            }
-        }
-    },
-    updateRect: function(i) {
-        var h = this,
-            c = i[0],
-            f = i[1],
-            g = c + i[2],
-            a = f + i[3],
-            e = h.getBackground(),
-            d = h.element;
-        d.setLocalXY(Math.floor(c), Math.floor(f));
-        d.setSize(Math.ceil(g - Math.floor(c)), Math.ceil(a - Math.floor(f)));
-        if (e) {
-            e.setAttributes({
-                x: 0,
-                y: 0,
-                width: Math.ceil(g - Math.floor(c)),
-                height: Math.ceil(a - Math.floor(f))
-            })
-        }
-        h.setDirty(true)
-    },
-    resetTransform: function() {
-        this.matrix.set(1, 0, 0, 1, 0, 0);
-        this.inverseMatrix.set(1, 0, 0, 1, 0, 0);
-        this.setDirty(true)
-    },
-    get: function(a) {
-        return this.map[a] || this.getItems()[a]
-    },
-    add: function() {
-        var g = this,
-            e = Array.prototype.slice.call(arguments),
-            j = Ext.isArray(e[0]),
-            a = g.map,
-            c = [],
-            f, k, h, b, d;
-        f = Ext.Array.clean(j ? e[0] : e);
-        if (!f.length) {
-            return c
-        }
-        for (b = 0, d = f.length; b < d; b++) {
-            k = f[b];
-            h = null;
-            if (k.isSprite && !a[k.getId()]) {
-                h = k
-            } else {
-                if (!a[k.id]) {
-                    h = this.createItem(k)
-                }
-            }
-            if (h) {
-                a[h.getId()] = h;
-                c.push(h);
-                h.setParent(g);
-                h.setSurface(g);
-                g.onAdd(h)
-            }
-        }
-        f = g.getItems();
-        if (f) {
-            f.push.apply(f, c)
-        }
-        g.dirtyZIndex = true;
-        g.setDirty(true);
-        if (!j && c.length === 1) {
-            return c[0]
-        } else {
-            return c
-        }
-    },
-    onAdd: Ext.emptyFn,
-    remove: function(a, c) {
-        var b = this,
-            e, d;
-        if (a) {
-            if (a.charAt) {
-                a = b.map[a]
-            }
-            if (!a || !a.isSprite) {
-                return null
-            }
-            if (a.isDestroyed || a.isDestroying) {
-                return a
-            }
-            e = a.getId();
-            d = b.map[e];
-            delete b.map[e];
-            if (c) {
-                a.destroy()
-            }
-            if (!d) {
-                return a
-            }
-            a.setParent(null);
-            a.setSurface(null);
-            Ext.Array.remove(b.getItems(), a);
-            b.dirtyZIndex = true;
-            b.setDirty(true)
-        }
-        return a || null
-    },
-    removeAll: function(d) {
-        var a = this.getItems(),
-            b = a.length - 1,
-            c;
-        if (d) {
-            for (; b >= 0; b--) {
-                a[b].destroy()
-            }
-        } else {
-            for (; b >= 0; b--) {
-                c = a[b];
-                c.setParent(null);
-                c.setSurface(null)
-            }
-        }
-        a.length = 0;
-        this.map = {};
-        this.dirtyZIndex = true
-    },
-    applyItems: function(a) {
-        if (this.getItems()) {
-            this.removeAll(true)
-        }
-        return Ext.Array.from(this.add(a))
-    },
-    createItem: function(a) {
-        return Ext.create(a.xclass || "sprite." + a.type, a)
-    },
-    getBBox: function(f, b) {
-        var f = Ext.Array.from(f),
-            c = Infinity,
-            h = -Infinity,
-            g = Infinity,
-            a = -Infinity,
-            j, k, d, e;
-        for (d = 0, e = f.length; d < e; d++) {
-            j = f[d];
-            k = j.getBBox(b);
-            if (c > k.x) {
-                c = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (g > k.y) {
-                g = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        return {
-            x: c,
-            y: g,
-            width: h - c,
-            height: a - g
-        }
-    },
-    emptyRect: [0, 0, 0, 0],
-    getEventXY: function(d) {
-        var g = this,
-            f = g.getInherited().rtl,
-            c = d.getXY(),
-            a = g.getOwnerBody(),
-            i = a.getXY(),
-            h = g.getRect() || g.emptyRect,
-            j = [],
-            b;
-        if (f) {
-            b = a.getWidth();
-            j[0] = i[0] - c[0] - h[0] + b
-        } else {
-            j[0] = c[0] - i[0] - h[0]
-        }
-        j[1] = c[1] - i[1] - h[1];
-        return j
-    },
-    clear: Ext.emptyFn,
-    orderByZIndex: function() {
-        var d = this,
-            a = d.getItems(),
-            e = false,
-            b, c;
-        if (d.getDirty()) {
-            for (b = 0, c = a.length; b < c; b++) {
-                if (a[b].attr.dirtyZIndex) {
-                    e = true;
-                    break
-                }
-            }
-            if (e) {
-                Ext.Array.sort(a, function(g, f) {
-                    return g.attr.zIndex - f.attr.zIndex
-                });
-                this.setDirty(true)
-            }
-            for (b = 0, c = a.length; b < c; b++) {
-                a[b].attr.dirtyZIndex = false
-            }
-        }
-    },
-    repaint: function() {
-        var a = this;
-        a.repaint = Ext.emptyFn;
-        Ext.defer(function() {
-            delete a.repaint;
-            a.element.repaint()
-        }, 1)
-    },
-    renderFrame: function() {
-        var g = this;
-        if (!g.element) {
-            return
-        }
-        if (g.dirtyPredecessorCount > 0) {
-            g.isPendingRenderFrame = true;
-            return
-        }
-        var f = g.getRect(),
-            c = g.getBackground(),
-            a = g.getItems(),
-            e, b, d;
-        if (!f) {
-            return
-        }
-        g.orderByZIndex();
-        if (g.getDirty()) {
-            g.clear();
-            g.clearTransform();
-            if (c) {
-                g.renderSprite(c)
-            }
-            for (b = 0, d = a.length; b < d; b++) {
-                e = a[b];
-                if (g.renderSprite(e) === false) {
-                    return
-                }
-                e.attr.textPositionCount = g.textPosition
-            }
-            g.setDirty(false)
-        }
-    },
-    renderSprite: Ext.emptyFn,
-    clearTransform: Ext.emptyFn,
-    destroy: function() {
-        var a = this;
-        a.removeAll(true);
-        a.predecessors = null;
-        a.successors = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.Surface", {
-    override: "Ext.draw.Surface",
-    hitTest: function(b, c) {
-        var f = this,
-            g = f.getItems(),
-            e, d, a;
-        c = c || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        for (e = g.length - 1; e >= 0; e--) {
-            d = g[e];
-            if (d.hitTest) {
-                a = d.hitTest(b, c);
-                if (a) {
-                    return a
-                }
-            }
-        }
-        return null
-    },
-    hitTestEvent: function(b, a) {
-        var c = this.getEventXY(b);
-        return this.hitTest(c, a)
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext", {
-    requires: ["Ext.draw.Color"],
-    toSave: ["strokeOpacity", "strokeStyle", "fillOpacity", "fillStyle", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "lineDash", "lineDashOffset", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "globalCompositeOperation", "position", "fillGradient", "strokeGradient"],
-    strokeOpacity: 1,
-    strokeStyle: "none",
-    fillOpacity: 1,
-    fillStyle: "none",
-    lineDash: [],
-    lineDashOffset: 0,
-    globalAlpha: 1,
-    lineWidth: 1,
-    lineCap: "butt",
-    lineJoin: "miter",
-    miterLimit: 10,
-    shadowOffsetX: 0,
-    shadowOffsetY: 0,
-    shadowBlur: 0,
-    shadowColor: "none",
-    globalCompositeOperation: "src",
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    constructor: function(a) {
-        this.surface = a;
-        this.state = [];
-        this.matrix = new Ext.draw.Matrix();
-        this.path = null;
-        this.clear()
-    },
-    clear: function() {
-        this.group = this.surface.mainGroup;
-        this.position = 0;
-        this.path = null
-    },
-    getElement: function(a) {
-        return this.surface.getSvgElement(this.group, a, this.position++)
-    },
-    removeElement: function(d) {
-        var d = Ext.fly(d),
-            h, g, b, f, a, e, c;
-        if (!d) {
-            return
-        }
-        if (d.dom.tagName === "g") {
-            a = d.dom.gradients;
-            for (c in a) {
-                a[c].destroy()
-            }
-        } else {
-            h = d.getAttribute("fill");
-            g = d.getAttribute("stroke");
-            b = h && h.match(this.urlStringRe);
-            f = g && g.match(this.urlStringRe);
-            if (b && b[1]) {
-                e = Ext.fly(b[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-            if (f && f[1]) {
-                e = Ext.fly(f[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-        }
-        d.destroy()
-    },
-    save: function() {
-        var c = this.toSave,
-            e = {},
-            d = this.getElement("g"),
-            b, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            if (b in this) {
-                e[b] = this[b]
-            }
-        }
-        this.position = 0;
-        e.matrix = this.matrix.clone();
-        this.state.push(e);
-        this.group = d;
-        return d
-    },
-    restore: function() {
-        var d = this.toSave,
-            e = this.state.pop(),
-            c = this.group.dom.childNodes,
-            b, a;
-        while (c.length > this.position) {
-            this.removeElement(c[c.length - 1])
-        }
-        for (a = 0; a < d.length; a++) {
-            b = d[a];
-            if (b in e) {
-                this[b] = e[b]
-            } else {
-                delete this[b]
-            }
-        }
-        this.setTransform.apply(this, e.matrix.elements);
-        this.group = this.group.getParent()
-    },
-    transform: function(f, b, e, g, d, c) {
-        if (this.path) {
-            var a = Ext.draw.Matrix.fly([f, b, e, g, d, c]).inverse();
-            this.path.transform(a)
-        }
-        this.matrix.append(f, b, e, g, d, c)
-    },
-    setTransform: function(e, a, d, f, c, b) {
-        if (this.path) {
-            this.path.transform(this.matrix)
-        }
-        this.matrix.reset();
-        this.transform(e, a, d, f, c, b)
-    },
-    scale: function(a, b) {
-        this.transform(a, 0, 0, b, 0, 0)
-    },
-    rotate: function(d) {
-        var c = Math.cos(d),
-            a = Math.sin(d),
-            b = -Math.sin(d),
-            e = Math.cos(d);
-        this.transform(c, a, b, e, 0, 0)
-    },
-    translate: function(a, b) {
-        this.transform(1, 0, 0, 1, a, b)
-    },
-    setGradientBBox: function(a) {
-        this.bbox = a
-    },
-    beginPath: function() {
-        this.path = new Ext.draw.Path()
-    },
-    moveTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.moveTo(a, b);
-        this.path.element = null
-    },
-    lineTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.lineTo(a, b);
-        this.path.element = null
-    },
-    rect: function(b, d, c, a) {
-        this.moveTo(b, d);
-        this.lineTo(b + c, d);
-        this.lineTo(b + c, d + a);
-        this.lineTo(b, d + a);
-        this.closePath()
-    },
-    strokeRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.stroke()
-    },
-    fillRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.fill()
-    },
-    closePath: function() {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.closePath();
-        this.path.element = null
-    },
-    arcSvg: function(d, a, f, g, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcSvg(d, a, f, g, c, b, e);
-        this.path.element = null
-    },
-    arc: function(b, f, a, d, c, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arc(b, f, a, d, c, e);
-        this.path.element = null
-    },
-    ellipse: function(a, h, g, f, d, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.ellipse(a, h, g, f, d, c, b, e);
-        this.path.element = null
-    },
-    arcTo: function(b, e, a, d, g, f, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcTo(b, e, a, d, g, f, c);
-        this.path.element = null
-    },
-    bezierCurveTo: function(d, f, b, e, a, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.bezierCurveTo(d, f, b, e, a, c);
-        this.path.element = null
-    },
-    strokeText: function(d, a, e) {
-        d = String(d);
-        if (this.strokeStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                stroke: this.strokeStyle,
-                fill: "none",
-                opacity: this.globalAlpha,
-                "stroke-opacity": this.strokeOpacity,
-                style: "font: " + this.font,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(b, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    fillText: function(d, a, e) {
-        d = String(d);
-        if (this.fillStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                fill: this.fillStyle,
-                opacity: this.globalAlpha,
-                "fill-opacity": this.fillOpacity,
-                style: "font: " + this.font
-            });
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    drawImage: function(c, k, i, l, e, p, n, a, g) {
-        var f = this,
-            d = f.getElement("image"),
-            j = k,
-            h = i,
-            b = typeof l === "undefined" ? c.width : l,
-            m = typeof e === "undefined" ? c.height : e,
-            o = null;
-        if (typeof g !== "undefined") {
-            o = k + " " + i + " " + l + " " + e;
-            j = p;
-            h = n;
-            b = a;
-            m = g
-        }
-        d.dom.setAttributeNS("http://www.w3.org/1999/xlink", "href", c.src);
-        f.surface.setElementAttributes(d, {
-            viewBox: o,
-            x: j,
-            y: h,
-            width: b,
-            height: m,
-            opacity: f.globalAlpha,
-            transform: f.matrix.toSvg()
-        })
-    },
-    fill: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.fillStyle) {
-            var c, a = this.fillGradient,
-                d = this.bbox,
-                b = this.path.element;
-            if (!b) {
-                c = this.path.toString();
-                b = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(b, {
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(b, {
-                fill: a && d ? a.generateGradient(this, d) : this.fillStyle,
-                "fill-opacity": this.fillOpacity * this.globalAlpha
-            })
-        }
-    },
-    stroke: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.strokeStyle) {
-            var c, b = this.strokeGradient,
-                d = this.bbox,
-                a = this.path.element;
-            if (!a || !this.path.svgString) {
-                c = this.path.toString();
-                if (!c) {
-                    return
-                }
-                a = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(a, {
-                    fill: "none",
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(a, {
-                stroke: b && d ? b.generateGradient(this, d) : this.strokeStyle,
-                "stroke-linecap": this.lineCap,
-                "stroke-linejoin": this.lineJoin,
-                "stroke-width": this.lineWidth,
-                "stroke-opacity": this.strokeOpacity * this.globalAlpha,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(a, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-        }
-    },
-    fillStroke: function(a, e) {
-        var b = this,
-            d = b.fillStyle,
-            g = b.strokeStyle,
-            c = b.fillOpacity,
-            f = b.strokeOpacity;
-        if (e === undefined) {
-            e = a.transformFillStroke
-        }
-        if (!e) {
-            a.inverseMatrix.toContext(b)
-        }
-        if (d && c !== 0) {
-            b.fill()
-        }
-        if (g && f !== 0) {
-            b.stroke()
-        }
-    },
-    appendPath: function(a) {
-        this.path = a.clone()
-    },
-    setLineDash: function(a) {
-        this.lineDash = a
-    },
-    getLineDash: function() {
-        return this.lineDash
-    },
-    createLinearGradient: function(d, g, b, e) {
-        var f = this,
-            c = f.surface.getNextDef("linearGradient"),
-            a = f.group.dom.gradients || (f.group.dom.gradients = {}),
-            h;
-        f.surface.setElementAttributes(c, {
-            x1: d,
-            y1: g,
-            x2: b,
-            y2: e,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(f, f.surface, c);
-        a[c.dom.id] = h;
-        return h
-    },
-    createRadialGradient: function(b, j, d, a, i, c) {
-        var g = this,
-            e = g.surface.getNextDef("radialGradient"),
-            f = g.group.dom.gradients || (g.group.dom.gradients = {}),
-            h;
-        g.surface.setElementAttributes(e, {
-            fx: b,
-            fy: j,
-            cx: a,
-            cy: i,
-            r: c,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(g, g.surface, e, d / c);
-        f[e.dom.id] = h;
-        return h
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext.Gradient", {
-    statics: {
-        map: {}
-    },
-    constructor: function(c, a, d, b) {
-        var f = this.statics().map,
-            e;
-        e = f[d.dom.id];
-        if (e) {
-            e.element = null
-        }
-        f[d.dom.id] = this;
-        this.ctx = c;
-        this.surface = a;
-        this.element = d;
-        this.position = 0;
-        this.compression = b || 0
-    },
-    addColorStop: function(d, b) {
-        var c = this.surface.getSvgElement(this.element, "stop", this.position++),
-            a = this.compression;
-        this.surface.setElementAttributes(c, {
-            offset: (((1 - a) * d + a) * 100).toFixed(2) + "%",
-            "stop-color": b,
-            "stop-opacity": Ext.draw.Color.fly(b).a.toFixed(15)
-        })
-    },
-    toString: function() {
-        var a = this.element.dom.childNodes;
-        while (a.length > this.position) {
-            Ext.fly(a[a.length - 1]).destroy()
-        }
-        return "url(#" + this.element.getId() + ")"
-    },
-    destroy: function() {
-        var b = this.statics().map,
-            a = this.element;
-        if (a && a.dom) {
-            delete b[a.dom.id];
-            a.destroy()
-        }
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.engine.Svg", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.SvgContext"],
-    statics: {
-        BBoxTextCache: {}
-    },
-    config: {
-        highPrecision: false
-    },
-    getElementConfig: function() {
-        return {
-            reference: "element",
-            style: {
-                position: "absolute"
-            },
-            children: [{
-                reference: "innerElement",
-                style: {
-                    width: "100%",
-                    height: "100%",
-                    position: "relative"
-                },
-                children: [{
-                    tag: "svg",
-                    reference: "svgElement",
-                    namespace: "http://www.w3.org/2000/svg",
-                    width: "100%",
-                    height: "100%",
-                    version: 1.1
-                }]
-            }]
-        }
-    },
-    constructor: function(a) {
-        var b = this;
-        b.callParent([a]);
-        b.mainGroup = b.createSvgNode("g");
-        b.defElement = b.createSvgNode("defs");
-        b.svgElement.appendChild(b.mainGroup);
-        b.svgElement.appendChild(b.defElement);
-        b.ctx = new Ext.draw.engine.SvgContext(b)
-    },
-    createSvgNode: function(a) {
-        var b = document.createElementNS("http://www.w3.org/2000/svg", a);
-        return Ext.get(b)
-    },
-    getSvgElement: function(d, b, a) {
-        var c;
-        if (d.dom.childNodes.length > a) {
-            c = d.dom.childNodes[a];
-            if (c.tagName === b) {
-                return Ext.get(c)
-            } else {
-                Ext.destroy(c)
-            }
-        }
-        c = Ext.get(this.createSvgNode(b));
-        if (a === 0) {
-            d.insertFirst(c)
-        } else {
-            c.insertAfter(Ext.fly(d.dom.childNodes[a - 1]))
-        }
-        c.cache = {};
-        return c
-    },
-    setElementAttributes: function(d, b) {
-        var f = d.dom,
-            a = d.cache,
-            c, e;
-        for (c in b) {
-            e = b[c];
-            if (a[c] !== e) {
-                a[c] = e;
-                f.setAttribute(c, e)
-            }
-        }
-    },
-    getNextDef: function(a) {
-        return this.getSvgElement(this.defElement, a, this.defPosition++)
-    },
-    clearTransform: function() {
-        var a = this;
-        a.mainGroup.set({
-            transform: a.matrix.toSvg()
-        })
-    },
-    clear: function() {
-        this.ctx.clear();
-        this.defPosition = 0
-    },
-    renderSprite: function(b) {
-        var d = this,
-            c = d.getRect(),
-            a = d.ctx;
-        if (b.attr.hidden || b.attr.globalAlpha === 0) {
-            a.save();
-            a.restore();
-            return
-        }
-        b.element = a.save();
-        b.preRender(this);
-        b.useAttributes(a, c);
-        if (false === b.render(this, a, [0, 0, c[2], c[3]])) {
-            return false
-        }
-        b.setDirty(false);
-        a.restore()
-    },
-    flatten: function(e, b) {
-        var c = '<?xml version="1.0" standalone="yes"?>',
-            f = Ext.getClassName(this),
-            a, g, d;
-        c += '<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="' + e.width + '" height="' + e.height + '">';
-        for (d = 0; d < b.length; d++) {
-            a = b[d];
-            if (Ext.getClassName(a) !== f) {
-                continue
-            }
-            g = a.getRect();
-            c += '<g transform="translate(' + g[0] + "," + g[1] + ')">';
-            c += this.serializeNode(a.svgElement.dom);
-            c += "</g>"
-        }
-        c += "</svg>";
-        return {
-            data: "data:image/svg+xml;utf8," + encodeURIComponent(c),
-            type: "svg"
-        }
-    },
-    serializeNode: function(d) {
-        var b = "",
-            c, f, a, e;
-        if (d.nodeType === document.TEXT_NODE) {
-            return d.nodeValue
-        }
-        b += "<" + d.nodeName;
-        if (d.attributes.length) {
-            for (c = 0, f = d.attributes.length; c < f; c++) {
-                a = d.attributes[c];
-                b += " " + a.name + '="' + a.value + '"'
-            }
-        }
-        b += ">";
-        if (d.childNodes && d.childNodes.length) {
-            for (c = 0, f = d.childNodes.length; c < f; c++) {
-                e = d.childNodes[c];
-                b += this.serializeNode(e)
-            }
-        }
-        b += "</" + d.nodeName + ">";
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.ctx.destroy();
-        a.mainGroup.destroy();
-        delete a.mainGroup;
-        delete a.ctx;
-        a.callParent()
-    },
-    remove: function(a, b) {
-        if (a && a.element) {
-            if (this.ctx) {
-                this.ctx.removeElement(a.element)
-            } else {
-                a.element.destroy()
-            }
-            a.element = null
-        }
-        this.callParent(arguments)
-    }
-});
-Ext.draw || (Ext.draw = {});
-Ext.draw.engine || (Ext.draw.engine = {});
-Ext.draw.engine.excanvas = true;
-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) {
-            Ext.onReady(function() {
-                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.lineDash = j.lineDash;
-            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.lineDash = [];
-            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(an, j) {
-            var ah, Z, aj, ar, al, ak, ao, av;
-            var ai = an.runtimeStyle.width;
-            var am = an.runtimeStyle.height;
-            an.runtimeStyle.width = "auto";
-            an.runtimeStyle.height = "auto";
-            var ag = an.width;
-            var aq = an.height;
-            an.runtimeStyle.width = ai;
-            an.runtimeStyle.height = am;
-            if (arguments.length == 3) {
-                ah = arguments[1];
-                Z = arguments[2];
-                al = ak = 0;
-                ao = aj = ag;
-                av = ar = aq
-            } else {
-                if (arguments.length == 5) {
-                    ah = arguments[1];
-                    Z = arguments[2];
-                    aj = arguments[3];
-                    ar = arguments[4];
-                    al = ak = 0;
-                    ao = ag;
-                    av = aq
-                } else {
-                    if (arguments.length == 9) {
-                        al = arguments[1];
-                        ak = arguments[2];
-                        ao = arguments[3];
-                        av = arguments[4];
-                        ah = arguments[5];
-                        Z = arguments[6];
-                        aj = arguments[7];
-                        ar = arguments[8]
-                    } else {
-                        throw Error("Invalid number of arguments")
-                    }
-                }
-            }
-            var au = V(this, ah, Z);
-            var at = [];
-            var i = 10;
-            var p = 10;
-            var ap = this.m_;
-            at.push(" <g_vml_:group", ' coordsize="', d * i, ",", d * p, '"', ' coordorigin="0,0"', ' style="width:', n(i * ap[0][0]), "px;height:", n(p * ap[1][1]), "px;position:absolute;", "top:", n(au.y / d), "px;left:", n(au.x / d), "px; rotation:", n(Math.atan(ap[0][1] / ap[1][1]) * 180 / Math.PI), ";");
-            at.push('" >', '<g_vml_:image src="', an.src, '"', ' style="width:', d * aj, "px;", " height:", d * ar, 'px"', ' cropleft="', al / ag, '"', ' croptop="', ak / aq, '"', ' cropright="', (ag - al - ao) / ag, '"', ' cropbottom="', (aq - ak - av) / aq, '"', " />", "</g_vml_:group>");
-            this.element_.insertAdjacentHTML("BeforeEnd", at.join(""))
-        };
-        q.setLineDash = function(i) {
-            if (i.length === 1) {
-                i = i.slice();
-                i[1] = i[0]
-            }
-            this.lineDash = i
-        };
-        q.getLineDash = function() {
-            return this.lineDash
-        };
-        q.stroke = function(ak) {
-            var ai = [];
-            var m = 10;
-            var al = 10;
-            ai.push("<g_vml_:shape", ' filled="', !!ak, '"', ' style="position:absolute;width:', m, "px;height:", al, 'px;left:0px;top:0px;"', ' coordorigin="0,0"', ' coordsize="', d * m, ",", d * al, '"', ' stroked="', !ak, '"', ' path="');
-            var Z = {
-                x: null,
-                y: null
-            };
-            var aj = {
-                x: null,
-                y: null
-            };
-            for (var ag = 0; ag < this.currentPath_.length; ag++) {
-                var j = this.currentPath_[ag];
-                var ah;
-                switch (j.type) {
-                    case "moveTo":
-                        ah = j;
-                        ai.push(" m ", n(j.x), ",", n(j.y));
-                        break;
-                    case "lineTo":
-                        ai.push(" l ", n(j.x), ",", n(j.y));
-                        break;
-                    case "close":
-                        ai.push(" x ");
-                        j = null;
-                        break;
-                    case "bezierCurveTo":
-                        ai.push(" c ", n(j.cp1x), ",", n(j.cp1y), ",", n(j.cp2x), ",", n(j.cp2y), ",", n(j.x), ",", n(j.y));
-                        break;
-                    case "at":
-                    case "wa":
-                        ai.push(" ", j.type, " ", n(j.x - this.arcScaleX_ * j.radius), ",", n(j.y - this.arcScaleY_ * j.radius), " ", n(j.x + this.arcScaleX_ * j.radius), ",", n(j.y + this.arcScaleY_ * j.radius), " ", n(j.xStart), ",", n(j.yStart), " ", n(j.xEnd), ",", n(j.yEnd));
-                        break
-                }
-                if (j) {
-                    if (Z.x == null || j.x < Z.x) {
-                        Z.x = j.x
-                    }
-                    if (aj.x == null || j.x > aj.x) {
-                        aj.x = j.x
-                    }
-                    if (Z.y == null || j.y < Z.y) {
-                        Z.y = j.y
-                    }
-                    if (aj.y == null || j.y > aj.y) {
-                        aj.y = j.y
-                    }
-                }
-            }
-            ai.push(' ">');
-            if (!ak) {
-                w(this, ai)
-            } else {
-                G(this, ai, Z, aj)
-            }
-            ai.push("</g_vml_:shape>");
-            this.element_.insertAdjacentHTML("beforeEnd", ai.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, '"', ' dashstyle="', m.lineDash.join(" "), '"', ' 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 / 3;
-                    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;left:0px;top:0px;">');
-            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
-    })()
-}
-Ext.define("Ext.draw.engine.Canvas", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.excanvas", "Ext.draw.Animator", "Ext.draw.Color"],
-    config: {
-        highPrecision: false
-    },
-    statics: {
-        contextOverrides: {
-            setGradientBBox: function(a) {
-                this.bbox = a
-            },
-            fill: function() {
-                var c = this.fillStyle,
-                    a = this.fillGradient,
-                    b = this.fillOpacity,
-                    d = this.globalAlpha,
-                    e = this.bbox;
-                if (c !== Ext.draw.Color.RGBA_NONE && b !== 0) {
-                    if (a && e) {
-                        this.fillStyle = a.generateGradient(this, e)
-                    }
-                    if (b !== 1) {
-                        this.globalAlpha = d * b
-                    }
-                    this.$fill();
-                    if (b !== 1) {
-                        this.globalAlpha = d
-                    }
-                    if (a && e) {
-                        this.fillStyle = c
-                    }
-                }
-            },
-            stroke: function() {
-                var e = this.strokeStyle,
-                    c = this.strokeGradient,
-                    a = this.strokeOpacity,
-                    b = this.globalAlpha,
-                    d = this.bbox;
-                if (e !== Ext.draw.Color.RGBA_NONE && a !== 0) {
-                    if (c && d) {
-                        this.strokeStyle = c.generateGradient(this, d)
-                    }
-                    if (a !== 1) {
-                        this.globalAlpha = b * a
-                    }
-                    this.$stroke();
-                    if (a !== 1) {
-                        this.globalAlpha = b
-                    }
-                    if (c && d) {
-                        this.strokeStyle = e
-                    }
-                }
-            },
-            fillStroke: function(d, e) {
-                var j = this,
-                    i = this.fillStyle,
-                    h = this.fillOpacity,
-                    f = this.strokeStyle,
-                    c = this.strokeOpacity,
-                    b = j.shadowColor,
-                    a = j.shadowBlur,
-                    g = Ext.draw.Color.RGBA_NONE;
-                if (e === undefined) {
-                    e = d.transformFillStroke
-                }
-                if (!e) {
-                    d.inverseMatrix.toContext(j)
-                }
-                if (i !== g && h !== 0) {
-                    j.fill();
-                    j.shadowColor = g;
-                    j.shadowBlur = 0
-                }
-                if (f !== g && c !== 0) {
-                    j.stroke()
-                }
-                j.shadowColor = b;
-                j.shadowBlur = a
-            },
-            setLineDash: function(a) {
-                if (this.$setLineDash) {
-                    this.$setLineDash(a)
-                }
-            },
-            getLineDash: function() {
-                if (this.$getLineDash) {
-                    return this.$getLineDash()
-                }
-            },
-            ellipse: function(g, e, c, a, j, b, f, d) {
-                var i = Math.cos(j),
-                    h = Math.sin(j);
-                this.transform(i * c, h * c, -h * a, i * a, g, e);
-                this.arc(0, 0, 1, b, f, d);
-                this.transform(i / c, -h / a, h / c, i / a, -(i * g + h * e) / c, (h * g - i * e) / a)
-            },
-            appendPath: function(f) {
-                var e = this,
-                    c = 0,
-                    b = 0,
-                    a = f.commands,
-                    g = f.params,
-                    d = a.length;
-                e.beginPath();
-                for (; c < d; c++) {
-                    switch (a[c]) {
-                        case "M":
-                            e.moveTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "L":
-                            e.lineTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "C":
-                            e.bezierCurveTo(g[b], g[b + 1], g[b + 2], g[b + 3], g[b + 4], g[b + 5]);
-                            b += 6;
-                            break;
-                        case "Z":
-                            e.closePath();
-                            break
-                    }
-                }
-            },
-            save: function() {
-                var c = this.toSave,
-                    d = c.length,
-                    e = d && {},
-                    b = 0,
-                    a;
-                for (; b < d; b++) {
-                    a = c[b];
-                    if (a in this) {
-                        e[a] = this[a]
-                    }
-                }
-                this.state.push(e);
-                this.$save()
-            },
-            restore: function() {
-                var b = this.state.pop(),
-                    a;
-                if (b) {
-                    for (a in b) {
-                        this[a] = b[a]
-                    }
-                }
-                this.$restore()
-            }
-        }
-    },
-    splitThreshold: 3000,
-    toSave: ["fillGradient", "strokeGradient"],
-    element: {
-        reference: "element",
-        style: {
-            position: "absolute"
-        },
-        children: [{
-            reference: "innerElement",
-            style: {
-                width: "100%",
-                height: "100%",
-                position: "relative"
-            }
-        }]
-    },
-    createCanvas: function() {
-        var c = Ext.Element.create({
-            tag: "canvas",
-            cls: Ext.baseCSSPrefix + "surface-canvas"
-        });
-        window.G_vmlCanvasManager && G_vmlCanvasManager.initElement(c.dom);
-        var d = Ext.draw.engine.Canvas.contextOverrides,
-            a = c.dom.getContext("2d"),
-            b;
-        if (a.ellipse) {
-            delete d.ellipse
-        }
-        a.state = [];
-        a.toSave = this.toSave;
-        for (b in d) {
-            a["$" + b] = a[b]
-        }
-        Ext.apply(a, d);
-        if (this.getHighPrecision()) {
-            this.enablePrecisionCompensation(a)
-        } else {
-            this.disablePrecisionCompensation(a)
-        }
-        this.innerElement.appendChild(c);
-        this.canvases.push(c);
-        this.contexts.push(a)
-    },
-    updateHighPrecision: function(d) {
-        var e = this.contexts,
-            c = e.length,
-            b, a;
-        for (b = 0; b < c; b++) {
-            a = e[b];
-            if (d) {
-                this.enablePrecisionCompensation(a)
-            } else {
-                this.disablePrecisionCompensation(a)
-            }
-        }
-    },
-    precisionNames: ["rect", "fillRect", "strokeRect", "clearRect", "moveTo", "lineTo", "arc", "arcTo", "save", "restore", "updatePrecisionCompensate", "setTransform", "transform", "scale", "translate", "rotate", "quadraticCurveTo", "bezierCurveTo", "createLinearGradient", "createRadialGradient", "fillText", "strokeText", "drawImage"],
-    disablePrecisionCompensation: function(b) {
-        var a = Ext.draw.engine.Canvas.contextOverrides,
-            f = this.precisionNames,
-            e = f.length,
-            d, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            if (!(c in a)) {
-                delete b[c]
-            }
-        }
-        this.setDirty(true)
-    },
-    enablePrecisionCompensation: function(j) {
-        var c = this,
-            a = 1,
-            g = 1,
-            l = 0,
-            k = 0,
-            i = new Ext.draw.Matrix(),
-            b = [],
-            e = {},
-            d = Ext.draw.engine.Canvas.contextOverrides,
-            h = j.constructor.prototype;
-        var f = {
-            toSave: c.toSave,
-            rect: function(m, p, n, o) {
-                return h.rect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            fillRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.fillRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            strokeRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.strokeRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            clearRect: function(m, p, n, o) {
-                return h.clearRect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            moveTo: function(m, n) {
-                return h.moveTo.call(this, m * a + l, n * g + k)
-            },
-            lineTo: function(m, n) {
-                return h.lineTo.call(this, m * a + l, n * g + k)
-            },
-            arc: function(n, r, m, p, o, q) {
-                this.updatePrecisionCompensateRect();
-                h.arc.call(this, n * a + l, r * a + k, m * a, p, o, q);
-                this.updatePrecisionCompensate()
-            },
-            arcTo: function(o, q, n, p, m) {
-                this.updatePrecisionCompensateRect();
-                h.arcTo.call(this, o * a + l, q * g + k, n * a + l, p * g + k, m * a);
-                this.updatePrecisionCompensate()
-            },
-            save: function() {
-                b.push(i);
-                i = i.clone();
-                d.save.call(this);
-                h.save.call(this)
-            },
-            restore: function() {
-                i = b.pop();
-                d.restore.call(this);
-                h.restore.call(this);
-                this.updatePrecisionCompensate()
-            },
-            updatePrecisionCompensate: function() {
-                i.precisionCompensate(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            updatePrecisionCompensateRect: function() {
-                i.precisionCompensateRect(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            setTransform: function(q, o, n, m, r, p) {
-                i.set(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            transform: function(q, o, n, m, r, p) {
-                i.append(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            scale: function(n, m) {
-                this.transform(n, 0, 0, m, 0, 0)
-            },
-            translate: function(n, m) {
-                this.transform(1, 0, 0, 1, n, m)
-            },
-            rotate: function(o) {
-                var n = Math.cos(o),
-                    m = Math.sin(o);
-                this.transform(n, m, -m, n, 0, 0)
-            },
-            quadraticCurveTo: function(n, p, m, o) {
-                h.quadraticCurveTo.call(this, n * a + l, p * g + k, m * a + l, o * g + k)
-            },
-            bezierCurveTo: function(r, p, o, n, m, q) {
-                h.bezierCurveTo.call(this, r * a + l, p * g + k, o * a + l, n * g + k, m * a + l, q * g + k)
-            },
-            createLinearGradient: function(n, p, m, o) {
-                this.updatePrecisionCompensateRect();
-                var q = h.createLinearGradient.call(this, n * a + l, p * g + k, m * a + l, o * g + k);
-                this.updatePrecisionCompensate();
-                return q
-            },
-            createRadialGradient: function(p, r, o, n, q, m) {
-                this.updatePrecisionCompensateRect();
-                var s = h.createLinearGradient.call(this, p * a + l, r * a + k, o * a, n * a + l, q * a + k, m * a);
-                this.updatePrecisionCompensate();
-                return s
-            },
-            fillText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.fillText.call(this, o, m, p)
-                } else {
-                    h.fillText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            strokeText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.strokeText.call(this, o, m, p)
-                } else {
-                    h.strokeText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            fill: function() {
-                var m = this.fillGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.fillStyle = m.generateGradient(this, n)
-                }
-                h.fill.call(this);
-                this.updatePrecisionCompensate()
-            },
-            stroke: function() {
-                var m = this.strokeGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.strokeStyle = m.generateGradient(this, n)
-                }
-                h.stroke.call(this);
-                this.updatePrecisionCompensate()
-            },
-            drawImage: function(u, s, r, q, p, o, n, m, t) {
-                switch (arguments.length) {
-                    case 3:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k);
-                    case 5:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k, q * a, p * g);
-                    case 9:
-                        return h.drawImage.call(this, u, s, r, q, p, o * a + l, n * g * k, m * a, t * g)
-                }
-            }
-        };
-        Ext.apply(j, f);
-        this.setDirty(true)
-    },
-    updateRect: function(a) {
-        this.callParent([a]);
-        var C = this,
-            p = Math.floor(a[0]),
-            e = Math.floor(a[1]),
-            g = Math.ceil(a[0] + a[2]),
-            B = Math.ceil(a[1] + a[3]),
-            u = C.devicePixelRatio,
-            D = C.canvases,
-            d = g - p,
-            y = B - e,
-            n = Math.round(C.splitThreshold / u),
-            c = C.xSplits = Math.ceil(d / n),
-            f = C.ySplits = Math.ceil(y / n),
-            v, s, q, A, z, x, o, m;
-        for (s = 0, z = 0; s < f; s++, z += n) {
-            for (v = 0, A = 0; v < c; v++, A += n) {
-                q = s * c + v;
-                if (q >= D.length) {
-                    C.createCanvas()
-                }
-                x = D[q].dom;
-                x.style.left = A + "px";
-                x.style.top = z + "px";
-                m = Math.min(n, y - z);
-                if (m * u !== x.height) {
-                    x.height = m * u;
-                    x.style.height = m + "px"
-                }
-                o = Math.min(n, d - A);
-                if (o * u !== x.width) {
-                    x.width = o * u;
-                    x.style.width = o + "px"
-                }
-                C.applyDefaults(C.contexts[q])
-            }
-        }
-        for (q += 1; q < D.length; q++) {
-            D[q].destroy()
-        }
-        C.activeCanvases = c * f;
-        D.length = C.activeCanvases;
-        C.clear()
-    },
-    clearTransform: function() {
-        var f = this,
-            a = f.xSplits,
-            g = f.ySplits,
-            d = f.contexts,
-            h = f.splitThreshold,
-            l = f.devicePixelRatio,
-            e, c, b, m;
-        for (e = 0; e < a; e++) {
-            for (c = 0; c < g; c++) {
-                b = c * a + e;
-                m = d[b];
-                m.translate(-h * e, -h * c);
-                m.scale(l, l);
-                f.matrix.toContext(m)
-            }
-        }
-    },
-    renderSprite: function(q) {
-        var C = this,
-            b = C.getRect(),
-            e = C.matrix,
-            g = q.getParent(),
-            v = Ext.draw.Matrix.fly([1, 0, 0, 1, 0, 0]),
-            p = C.splitThreshold / C.devicePixelRatio,
-            c = C.xSplits,
-            m = C.ySplits,
-            A, z, s, a, r, o, d = 0,
-            B, n = 0,
-            f, l = b[2],
-            y = b[3],
-            x, u, t;
-        while (g && (g !== C)) {
-            v.prependMatrix(g.matrix || g.attr && g.attr.matrix);
-            g = g.getParent()
-        }
-        v.prependMatrix(e);
-        a = q.getBBox();
-        if (a) {
-            a = v.transformBBox(a)
-        }
-        q.preRender(C);
-        if (q.attr.hidden || q.attr.globalAlpha === 0) {
-            q.setDirty(false);
-            return
-        }
-        for (u = 0, z = 0; u < m; u++, z += p) {
-            for (x = 0, A = 0; x < c; x++, A += p) {
-                t = u * c + x;
-                s = C.contexts[t];
-                r = Math.min(p, l - A);
-                o = Math.min(p, y - z);
-                d = A;
-                B = d + r;
-                n = z;
-                f = n + o;
-                if (a) {
-                    if (a.x > B || a.x + a.width < d || a.y > f || a.y + a.height < n) {
-                        continue
-                    }
-                }
-                s.save();
-                q.useAttributes(s, b);
-                if (false === q.render(C, s, [d, n, r, o], b)) {
-                    return false
-                }
-                s.restore()
-            }
-        }
-        q.setDirty(false)
-    },
-    flatten: function(n, a) {
-        var k = document.createElement("canvas"),
-            f = Ext.getClassName(this),
-            g = this.devicePixelRatio,
-            l = k.getContext("2d"),
-            b, c, h, e, d, m;
-        k.width = Math.ceil(n.width * g);
-        k.height = Math.ceil(n.height * g);
-        for (e = 0; e < a.length; e++) {
-            b = a[e];
-            if (Ext.getClassName(b) !== f) {
-                continue
-            }
-            h = b.getRect();
-            for (d = 0; d < b.canvases.length; d++) {
-                c = b.canvases[d];
-                m = c.getOffsetsTo(c.getParent());
-                l.drawImage(c.dom, (h[0] + m[0]) * g, (h[1] + m[1]) * g)
-            }
-        }
-        return {
-            data: k.toDataURL(),
-            type: "png"
-        }
-    },
-    applyDefaults: function(a) {
-        var b = Ext.draw.Color.RGBA_NONE;
-        a.strokeStyle = b;
-        a.fillStyle = b;
-        a.textAlign = "start";
-        a.textBaseline = "alphabetic";
-        a.miterLimit = 1
-    },
-    clear: function() {
-        var d = this,
-            e = d.activeCanvases,
-            c, b, a;
-        for (c = 0; c < e; c++) {
-            b = d.canvases[c].dom;
-            a = d.contexts[c];
-            a.setTransform(1, 0, 0, 1, 0, 0);
-            a.clearRect(0, 0, b.width, b.height)
-        }
-        d.setDirty(true)
-    },
-    destroy: function() {
-        var c = this,
-            a, b = c.canvases.length;
-        for (a = 0; a < b; a++) {
-            c.contexts[a] = null;
-            c.canvases[a].destroy();
-            c.canvases[a] = null
-        }
-        delete c.contexts;
-        delete c.canvases;
-        c.callParent()
-    },
-    privates: {
-        initElement: function() {
-            var a = this;
-            a.callParent();
-            a.canvases = [];
-            a.contexts = [];
-            a.activeCanvases = (a.xSplits = 0) * (a.ySplits = 0)
-        }
-    }
-}, function() {
-    var c = this,
-        b = c.prototype,
-        a = 10000000000;
-    if (Ext.os.is.Android4 && Ext.browser.is.Chrome) {
-        a = 3000
-    } else {
-        if (Ext.is.iOS) {
-            a = 2200
-        }
-    }
-    b.splitThreshold = a
-});
-Ext.define("Ext.draw.Container", {
-    extend: "Ext.draw.ContainerBase",
-    alternateClassName: "Ext.draw.Component",
-    xtype: "draw",
-    defaultType: "surface",
-    isDrawContainer: true,
-    requires: ["Ext.draw.Surface", "Ext.draw.engine.Svg", "Ext.draw.engine.Canvas", "Ext.draw.gradient.GradientDefinition"],
-    engine: "Ext.draw.engine.Canvas",
-    config: {
-        cls: Ext.baseCSSPrefix + "draw-container",
-        resizeHandler: null,
-        sprites: null,
-        gradients: []
-    },
-    defaultDownloadServerUrl: "http://svg.sencha.io",
-    supportedFormats: ["png", "pdf", "jpeg", "gif"],
-    supportedOptions: {
-        version: Ext.isNumber,
-        data: Ext.isString,
-        format: function(a) {
-            return Ext.Array.indexOf(this.supportedFormats, a) >= 0
-        },
-        filename: Ext.isString,
-        width: Ext.isNumber,
-        height: Ext.isNumber,
-        scale: Ext.isNumber,
-        pdf: Ext.isObject,
-        jpeg: Ext.isObject
-    },
-    initAnimator: function() {
-        this.frameCallbackId = Ext.draw.Animator.addFrameCallback("renderFrame", this)
-    },
-    applyGradients: function(b) {
-        var a = [],
-            c, f, d, e;
-        if (!Ext.isArray(b)) {
-            return a
-        }
-        for (c = 0, f = b.length; c < f; c++) {
-            d = b[c];
-            if (!Ext.isObject(d)) {
-                continue
-            }
-            if (typeof d.type !== "string") {
-                d.type = "linear"
-            }
-            if (d.angle) {
-                d.degrees = d.angle;
-                delete d.angle
-            }
-            if (Ext.isObject(d.stops)) {
-                d.stops = (function(i) {
-                    var g = [],
-                        h;
-                    for (e in i) {
-                        h = i[e];
-                        h.offset = e / 100;
-                        g.push(h)
-                    }
-                    return g
-                })(d.stops)
-            }
-            a.push(d)
-        }
-        Ext.draw.gradient.GradientDefinition.add(a);
-        return a
-    },
-    applySprites: function(f) {
-        if (!f) {
-            return
-        }
-        f = Ext.Array.from(f);
-        var e = f.length,
-            b = [],
-            d, a, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            a = c.surface;
-            if (!(a && a.isSurface)) {
-                if (Ext.isString(a)) {
-                    a = this.getSurface(a)
-                } else {
-                    a = this.getSurface("main")
-                }
-            }
-            c = a.add(c);
-            b.push(c)
-        }
-        return b
-    },
-    onBodyResize: function() {
-        var b = this.element,
-            a;
-        if (!b) {
-            return
-        }
-        a = b.getSize();
-        if (a.width && a.height) {
-            this.setBodySize(a)
-        }
-    },
-    setBodySize: function(c) {
-        var d = this,
-            b = d.getResizeHandler() || d.defaultResizeHandler,
-            a;
-        d.fireEvent("bodyresize", d, c);
-        a = b.call(d, c);
-        if (a !== false) {
-            d.renderFrame()
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.getItems().each(function(b) {
-            b.setRect([0, 0, a.width, a.height])
-        })
-    },
-    getSurface: function(d) {
-        d = this.getId() + "-" + (d || "main");
-        var c = this,
-            b = c.getItems(),
-            a = b.get(d);
-        if (!a) {
-            a = c.add({
-                xclass: c.engine,
-                id: d
-            });
-            c.onBodyResize()
-        }
-        return a
-    },
-    renderFrame: function() {
-        var e = this,
-            a = e.getItems(),
-            b, d, c;
-        for (b = 0, d = a.length; b < d; b++) {
-            c = a.items[b];
-            if (c.isSurface) {
-                c.renderFrame()
-            }
-        }
-    },
-    getImage: function(k) {
-        var l = this.innerElement.getSize(),
-            a = Array.prototype.slice.call(this.items.items),
-            d, g, c = this.surfaceZIndexes,
-            f, e, b, h;
-        for (e = 1; e < a.length; e++) {
-            b = a[e];
-            h = c[b.type];
-            f = e - 1;
-            while (f >= 0 && c[a[f].type] > h) {
-                a[f + 1] = a[f];
-                f--
-            }
-            a[f + 1] = b
-        }
-        d = a[0].flatten(l, a);
-        if (k === "image") {
-            g = new Image();
-            g.src = d.data;
-            d.data = g;
-            return d
-        }
-        if (k === "stream") {
-            d.data = d.data.replace(/^data:image\/[^;]+/, "data:application/octet-stream");
-            return d
-        }
-        return d
-    },
-    download: function(d) {
-        var e = this,
-            a = [],
-            b, c, f;
-        d = Ext.apply({
-            version: 2,
-            data: e.getImage().data
-        }, d);
-        for (c in d) {
-            if (d.hasOwnProperty(c)) {
-                f = d[c];
-                if (c in e.supportedOptions) {
-                    if (e.supportedOptions[c].call(e, f)) {
-                        a.push({
-                            tag: "input",
-                            type: "hidden",
-                            name: c,
-                            value: Ext.String.htmlEncode(Ext.isObject(f) ? Ext.JSON.encode(f) : f)
-                        })
-                    }
-                }
-            }
-        }
-        b = Ext.dom.Helper.markup({
-            tag: "html",
-            children: [{
-                tag: "head"
-            }, {
-                tag: "body",
-                children: [{
-                    tag: "form",
-                    method: "POST",
-                    action: d.url || e.defaultDownloadServerUrl,
-                    children: a
-                }, {
-                    tag: "script",
-                    type: "text/javascript",
-                    children: 'document.getElementsByTagName("form")[0].submit();'
-                }]
-            }]
-        });
-        window.open("", "ImageDownload_" + Date.now()).document.write(b)
-    },
-    destroy: function() {
-        var a = this.frameCallbackId;
-        if (a) {
-            Ext.draw.Animator.removeFrameCallback(a)
-        }
-        this.callParent()
-    }
-}, function() {
-    if (location.search.match("svg")) {
-        Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-    } else {
-        if ((Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) || (Ext.browser.is.AndroidStock4 && (Ext.os.version.getMinor() === 1 || Ext.os.version.getMinor() === 2 || Ext.os.version.getMinor() === 3))) {
-            Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Base", {
-    mixins: {
-        factoryable: "Ext.mixin.Factoryable"
-    },
-    requires: ["Ext.draw.Color"],
-    factoryConfig: {
-        type: "chart.theme"
-    },
-    isTheme: true,
-    config: {
-        baseColor: null,
-        colors: undefined,
-        gradients: null,
-        chart: {
-            defaults: {
-                background: "#23272a"
-            }
-        },
-        axis: {
-            defaults: {
-                label: {
-                    x: 0,
-                    y: 0,
-                    textBaseline: "middle",
-                    textAlign: "center",
-                    fontSize: "default",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fillStyle: "black",
-                    color: "white"
-                },
-                title: {
-                    fillStyle: "black",
-                    fontSize: "default*1.23",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    color: "white"
-                },
-                style: {
-                    strokeStyle: "black"
-                },
-                grid: {
-                    strokeStyle: "rgba(44, 47, 51, 1)"
-                }
-            },
-            top: {
-                style: {
-                    textPadding: 5
-                }
-            },
-            bottom: {
-                style: {
-                    textPadding: 5
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "black",
-                    strokeStyle: "none",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fontSize: "default*1.077",
-                    textBaseline: "middle",
-                    textAlign: "center"
-                },
-                labelOverflowPadding: 5
-            }
-        },
-        sprites: {
-            text: {
-                fontSize: "default",
-                fontWeight: "default",
-                fontFamily: "default",
-                fillStyle: "black",
-                color: "white"
-            }
-        },
-        seriesThemes: undefined,
-        markerThemes: {
-            type: ["circle", "cross", "plus", "square", "triangle", "diamond"]
-        },
-        useGradients: false,
-        background: null
-    },
-    colorDefaults: ["#94ae0a", "#115fa6", "#a61120", "#ff8809", "#ffd13e", "#a61187", "#24ad9a", "#7c7474", "#a66111"],
-    constructor: function(a) {
-        this.initConfig(a);
-        this.resolveDefaults()
-    },
-    defaultRegEx: /^default([+\-/\*]\d+(?:\.\d+)?)?$/,
-    defaultOperators: {
-        "*": function(b, a) {
-            return b * a
-        },
-        "+": function(b, a) {
-            return b + a
-        },
-        "-": function(b, a) {
-            return b - a
-        }
-    },
-    resolveDefaults: function() {
-        var a = this;
-        Ext.onReady(function() {
-            var f = Ext.clone(a.getSprites()),
-                e = Ext.clone(a.getAxis()),
-                d = Ext.clone(a.getSeries()),
-                g, c, b;
-            if (!a.superclass.defaults) {
-                g = Ext.getBody().createChild({
-                    tag: "div",
-                    cls: "x-component"
-                });
-                a.superclass.defaults = {
-                    fontFamily: g.getStyle("fontFamily"),
-                    fontWeight: g.getStyle("fontWeight"),
-                    fontSize: parseFloat(g.getStyle("fontSize")),
-                    fontVariant: g.getStyle("fontVariant"),
-                    fontStyle: g.getStyle("fontStyle")
-                };
-                g.destroy()
-            }
-            a.replaceDefaults(f.text);
-            a.setSprites(f);
-            for (c in e) {
-                b = e[c];
-                a.replaceDefaults(b.label);
-                a.replaceDefaults(b.title)
-            }
-            a.setAxis(e);
-            for (c in d) {
-                b = d[c];
-                a.replaceDefaults(b.label)
-            }
-            a.setSeries(d)
-        })
-    },
-    replaceDefaults: function(h) {
-        var e = this,
-            g = e.superclass.defaults,
-            a = e.defaultRegEx,
-            d, f, c, b;
-        if (Ext.isObject(h)) {
-            for (d in g) {
-                c = a.exec(h[d]);
-                if (c) {
-                    f = g[d];
-                    c = c[1];
-                    if (c) {
-                        b = e.defaultOperators[c.charAt(0)];
-                        f = Math.round(b(f, parseFloat(c.substr(1))))
-                    }
-                    h[d] = f
-                }
-            }
-        }
-    },
-    applyBaseColor: function(c) {
-        var a, b;
-        if (c) {
-            a = c.isColor ? c : Ext.draw.Color.fromString(c);
-            b = a.getHSL()[2];
-            if (b < 0.15) {
-                a = a.createLighter(0.3)
-            } else {
-                if (b < 0.3) {
-                    a = a.createLighter(0.15)
-                } else {
-                    if (b > 0.85) {
-                        a = a.createDarker(0.3)
-                    } else {
-                        if (b > 0.7) {
-                            a = a.createDarker(0.15)
-                        }
-                    }
-                }
-            }
-            this.setColors([a.createDarker(0.3).toString(), a.createDarker(0.15).toString(), a.toString(), a.createLighter(0.12).toString(), a.createLighter(0.24).toString(), a.createLighter(0.31).toString()])
-        }
-        return c
-    },
-    applyColors: function(a) {
-        return a || this.colorDefaults
-    },
-    updateUseGradients: function(a) {
-        if (a) {
-            this.updateGradients({
-                type: "linear",
-                degrees: 90
-            })
-        }
-    },
-    updateBackground: function(a) {
-        if (a) {
-            var b = this.getChart();
-            b.defaults.background = a;
-            this.setChart(b)
-        }
-    },
-    updateGradients: function(a) {
-        var c = this.getColors(),
-            e = [],
-            h, b, d, f, g;
-        if (Ext.isObject(a)) {
-            for (f = 0, g = c && c.length || 0; f < g; f++) {
-                b = Ext.draw.Color.fromString(c[f]);
-                if (b) {
-                    d = b.createLighter(0.15).toString();
-                    h = Ext.apply(Ext.Object.chain(a), {
-                        stops: [{
-                            offset: 1,
-                            color: b.toString()
-                        }, {
-                            offset: 0,
-                            color: d.toString()
-                        }]
-                    });
-                    e.push(h)
-                }
-            }
-            this.setColors(e)
-        }
-    },
-    applySeriesThemes: function(a) {
-        this.getBaseColor();
-        this.getUseGradients();
-        this.getGradients();
-        var b = this.getColors();
-        if (!a) {
-            a = {
-                fillStyle: Ext.Array.clone(b),
-                strokeStyle: Ext.Array.map(b, function(d) {
-                    var c = Ext.draw.Color.fromString(d.stops ? d.stops[0].color : d);
-                    return c.createDarker(0.15).toString()
-                })
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.theme.Default", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default", "chart.theme.Base"]
-});
-Ext.define("Ext.chart.Markers", {
-    extend: "Ext.draw.sprite.Instancing",
-    isMarkers: true,
-    defaultCategory: "default",
-    constructor: function() {
-        this.callParent(arguments);
-        this.categories = {};
-        this.revisions = {}
-    },
-    destroy: function() {
-        this.categories = null;
-        this.revisions = null;
-        this.callParent()
-    },
-    getMarkerFor: function(b, a) {
-        if (b in this.categories) {
-            var c = this.categories[b];
-            if (a in c) {
-                return this.get(c[a])
-            }
-        }
-    },
-    clear: function(a) {
-        a = a || this.defaultCategory;
-        if (!(a in this.revisions)) {
-            this.revisions[a] = 1
-        } else {
-            this.revisions[a]++
-        }
-    },
-    putMarkerFor: function(e, b, c, h, f) {
-        e = e || this.defaultCategory;
-        var d = this,
-            g = d.categories[e] || (d.categories[e] = {}),
-            a;
-        if (c in g) {
-            d.setAttributesFor(g[c], b, h)
-        } else {
-            g[c] = d.getCount();
-            d.createInstance(b, h)
-        }
-        a = d.get(g[c]);
-        if (a) {
-            a.category = e;
-            if (!f) {
-                a.revision = d.revisions[e] || (d.revisions[e] = 1)
-            }
-        }
-    },
-    getMarkerBBoxFor: function(c, a, b) {
-        if (c in this.categories) {
-            var d = this.categories[c];
-            if (a in d) {
-                return this.getBBoxFor(d[a], b)
-            }
-        }
-    },
-    getBBox: function() {
-        return null
-    },
-    render: function(a, l, b) {
-        var f = this,
-            k = f.revisions,
-            j = f.attr.matrix,
-            h = f.getTemplate(),
-            d = h.attr,
-            g, c, e;
-        j.toContext(l);
-        h.preRender(a, l, b);
-        h.useAttributes(l, b);
-        for (c = 0, e = f.instances.length; c < e; c++) {
-            g = f.get(c);
-            if (g.hidden || g.revision !== k[g.category]) {
-                continue
-            }
-            l.save();
-            h.attr = g;
-            h.useAttributes(l, b);
-            h.render(a, l, b);
-            l.restore()
-        }
-        h.attr = d
-    }
-});
-Ext.define("Ext.chart.label.Callout", {
-    extend: "Ext.draw.modifier.Modifier",
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("calloutOriginal")) {
-            a.calloutOriginal = Ext.Object.chain(a);
-            a.calloutOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.calloutOriginal)
-        }
-    },
-    setAttrs: function(e, h) {
-        var d = e.callout,
-            i = e.calloutOriginal,
-            l = e.bbox.plain,
-            c = (l.width || 0) + e.labelOverflowPadding,
-            m = (l.height || 0) + e.labelOverflowPadding,
-            p, o;
-        if ("callout" in h) {
-            d = h.callout
-        }
-        if ("callout" in h || "calloutPlaceX" in h || "calloutPlaceY" in h || "x" in h || "y" in h) {
-            var n = "rotationRads" in h ? i.rotationRads = h.rotationRads : i.rotationRads,
-                g = "x" in h ? (i.x = h.x) : i.x,
-                f = "y" in h ? (i.y = h.y) : i.y,
-                b = "calloutPlaceX" in h ? h.calloutPlaceX : e.calloutPlaceX,
-                a = "calloutPlaceY" in h ? h.calloutPlaceY : e.calloutPlaceY,
-                k = "calloutVertical" in h ? h.calloutVertical : e.calloutVertical,
-                j;
-            n %= Math.PI * 2;
-            if (Math.cos(n) < 0) {
-                n = (n + Math.PI) % (Math.PI * 2)
-            }
-            if (n > Math.PI) {
-                n -= Math.PI * 2
-            }
-            if (k) {
-                n = n * (1 - d) - Math.PI / 2 * d;
-                j = c;
-                c = m;
-                m = j
-            } else {
-                n = n * (1 - d)
-            }
-            h.rotationRads = n;
-            h.x = g * (1 - d) + b * d;
-            h.y = f * (1 - d) + a * d;
-            p = b - g;
-            o = a - f;
-            if (Math.abs(o * c) > Math.abs(p * m)) {
-                if (o > 0) {
-                    h.calloutEndX = h.x - (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y - (m / 2) * d
-                } else {
-                    h.calloutEndX = h.x + (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y + (m / 2) * d
-                }
-            } else {
-                if (p > 0) {
-                    h.calloutEndX = h.x - c / 2;
-                    h.calloutEndY = h.y - (c / 2) * (o / p) * d
-                } else {
-                    h.calloutEndX = h.x + c / 2;
-                    h.calloutEndY = h.y + (c / 2) * (o / p) * d
-                }
-            }
-            if (h.calloutStartX && h.calloutStartY) {
-                h.calloutHasLine = (p > 0 && h.calloutStartX < h.calloutEndX) || (p <= 0 && h.calloutStartX > h.calloutEndX) || (o > 0 && h.calloutStartY < h.calloutEndY) || (o <= 0 && h.calloutStartY > h.calloutEndY)
-            } else {
-                h.calloutHasLine = true
-            }
-        }
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.calloutOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    }
-});
-Ext.define("Ext.chart.label.Label", {
-    extend: "Ext.draw.sprite.Text",
-    requires: ["Ext.chart.label.Callout"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                callout: "limited01",
-                calloutHasLine: "bool",
-                calloutPlaceX: "number",
-                calloutPlaceY: "number",
-                calloutStartX: "number",
-                calloutStartY: "number",
-                calloutEndX: "number",
-                calloutEndY: "number",
-                calloutColor: "color",
-                calloutWidth: "number",
-                calloutVertical: "bool",
-                labelOverflowPadding: "number",
-                display: "enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",
-                orientation: "enums(horizontal,vertical)",
-                renderer: "default"
-            },
-            defaults: {
-                callout: 0,
-                calloutHasLine: true,
-                calloutPlaceX: 0,
-                calloutPlaceY: 0,
-                calloutStartX: 0,
-                calloutStartY: 0,
-                calloutEndX: 0,
-                calloutEndY: 0,
-                calloutWidth: 1,
-                calloutVertical: false,
-                calloutColor: "black",
-                labelOverflowPadding: 5,
-                display: "none",
-                orientation: "",
-                renderer: null
-            },
-            triggers: {
-                callout: "transform",
-                calloutPlaceX: "transform",
-                calloutPlaceY: "transform",
-                labelOverflowPadding: "transform",
-                calloutRotation: "transform",
-                display: "hidden"
-            },
-            updaters: {
-                hidden: function(a) {
-                    a.hidden = a.display === "none"
-                }
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                callout: 200
-            }
-        },
-        field: null,
-        calloutLine: true
-    },
-    applyCalloutLine: function(a) {
-        if (a) {
-            return Ext.apply({}, a)
-        }
-    },
-    prepareModifiers: function() {
-        this.callParent(arguments);
-        this.calloutModifier = new Ext.chart.label.Callout({
-            sprite: this
-        });
-        this.fx.setNext(this.calloutModifier);
-        this.calloutModifier.setNext(this.topModifier)
-    },
-    render: function(b, c) {
-        var e = this,
-            a = e.attr,
-            d = a.calloutColor;
-        c.save();
-        c.globalAlpha *= a.callout;
-        if (c.globalAlpha > 0 && a.calloutHasLine) {
-            if (d && d.isGradient) {
-                d = d.getStops()[0].color
-            }
-            c.strokeStyle = d;
-            c.fillStyle = d;
-            c.lineWidth = a.calloutWidth;
-            c.beginPath();
-            c.moveTo(e.attr.calloutStartX, e.attr.calloutStartY);
-            c.lineTo(e.attr.calloutEndX, e.attr.calloutEndY);
-            c.stroke();
-            c.beginPath();
-            c.arc(e.attr.calloutStartX, e.attr.calloutStartY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill();
-            c.beginPath();
-            c.arc(e.attr.calloutEndX, e.attr.calloutEndY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill()
-        }
-        c.restore();
-        Ext.draw.sprite.Text.prototype.render.apply(e, arguments)
-    }
-});
-Ext.define("Ext.chart.series.Series", {
-    requires: ["Ext.chart.Markers", "Ext.chart.label.Label", "Ext.tip.ToolTip"],
-    mixins: ["Ext.mixin.Observable", "Ext.mixin.Bindable"],
-    isSeries: true,
-    defaultBindProperty: "store",
-    type: null,
-    seriesType: "sprite",
-    identifiablePrefix: "ext-line-",
-    observableType: "series",
-    darkerStrokeRatio: 0.15,
-    config: {
-        chart: null,
-        title: null,
-        renderer: null,
-        showInLegend: true,
-        triggerAfterDraw: false,
-        style: {},
-        subStyle: {},
-        themeStyle: {},
-        colors: null,
-        useDarkerStrokeColor: true,
-        store: null,
-        label: {},
-        labelOverflowPadding: null,
-        showMarkers: true,
-        marker: null,
-        markerSubStyle: null,
-        itemInstancing: null,
-        background: null,
-        highlightItem: null,
-        surface: null,
-        overlaySurface: null,
-        hidden: false,
-        highlight: false,
-        highlightCfg: {
-            merge: function(a) {
-                return a
-            },
-            $value: {
-                fillStyle: "yellow",
-                strokeStyle: "red"
-            }
-        },
-        animation: null,
-        tooltip: null
-    },
-    directions: [],
-    sprites: null,
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 0
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        var a = this.getChart();
-        if (a && a.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    updateTitle: function(a) {
-        var j = this,
-            g = j.getChart();
-        if (!g || g.isInitializing) {
-            return
-        }
-        a = Ext.Array.from(a);
-        var c = g.getSeries(),
-            b = Ext.Array.indexOf(c, j),
-            e = g.getLegendStore(),
-            h = j.getYField(),
-            d, l, k, f;
-        if (e.getCount() && b !== -1) {
-            f = h ? Math.min(a.length, h.length) : a.length;
-            for (d = 0; d < f; d++) {
-                k = a[d];
-                l = e.getAt(b + d);
-                if (k && l) {
-                    l.set("name", k)
-                }
-            }
-        }
-    },
-    applyHighlight: function(a, b) {
-        if (Ext.isObject(a)) {
-            a = Ext.merge({}, this.config.highlightCfg, a)
-        } else {
-            if (a === true) {
-                a = this.config.highlightCfg
-            }
-        }
-        return Ext.apply(b || {}, a)
-    },
-    updateHighlight: function(a) {
-        this.getStyle();
-        if (!Ext.Object.isEmpty(a)) {
-            this.addItemHighlight()
-        }
-    },
-    updateHighlightCfg: function(a) {
-        if (!Ext.Object.equals(a, this.defaultConfig.highlightCfg)) {
-            this.addItemHighlight()
-        }
-    },
-    applyItemInstancing: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    setAttributesForItem: function(c, d) {
-        var b = c && c.sprite,
-            a;
-        if (b) {
-            if (b.itemsMarker && c.category === "items") {
-                b.putMarker(c.category, d, c.index, false, true)
-            }
-            if (b.isMarkerHolder && c.category === "markers") {
-                b.putMarker(c.category, d, c.index, false, true)
-            } else {
-                if (b.isInstancing) {
-                    b.setAttributesFor(c.index, d)
-                } else {
-                    if (Ext.isArray(b)) {
-                        for (a = 0; a < b.length; a++) {
-                            b[a].setAttributes(d)
-                        }
-                    } else {
-                        b.setAttributes(d)
-                    }
-                }
-            }
-        }
-    },
-    getBBoxForItem: function(a) {
-        if (a && a.sprite) {
-            if (a.sprite.itemsMarker && a.category === "items") {
-                return a.sprite.getMarkerBBox(a.category, a.index)
-            } else {
-                if (a.sprite instanceof Ext.draw.sprite.Instancing) {
-                    return a.sprite.getBBoxFor(a.index)
-                } else {
-                    return a.sprite.getBBox()
-                }
-            }
-        }
-        return null
-    },
-    applyHighlightItem: function(d, a) {
-        if (d === a) {
-            return
-        }
-        if (Ext.isObject(d) && Ext.isObject(a)) {
-            var c = d.sprite === a.sprite,
-                b = d.index === a.index;
-            if (c && b) {
-                return
-            }
-        }
-        return d
-    },
-    updateHighlightItem: function(b, a) {
-        this.setAttributesForItem(a, {
-            highlighted: false
-        });
-        this.setAttributesForItem(b, {
-            highlighted: true
-        })
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if (a.tips) {
-            a = Ext.apply({
-                tooltip: a.tips
-            }, a)
-        }
-        if (a.highlightCfg) {
-            a = Ext.apply({
-                highlight: a.highlightCfg
-            }, a)
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.sprites = [];
-        b.dataRange = [];
-        b.mixins.observable.constructor.call(b, a);
-        b.initBindable()
-    },
-    lookupViewModel: function(a) {
-        var b = this.getChart();
-        return b ? b.lookupViewModel(a) : null
-    },
-    applyTooltip: function(c, b) {
-        var a = Ext.apply({
-            xtype: "tooltip",
-            renderer: Ext.emptyFn,
-            constrainPosition: true,
-            shrinkWrapDock: true,
-            autoHide: true,
-            offsetX: 10,
-            offsetY: 10
-        }, c);
-        return Ext.create(a)
-    },
-    updateTooltip: function() {
-        this.addItemHighlight()
-    },
-    addItemHighlight: function() {
-        var d = this.getChart();
-        if (!d) {
-            return
-        }
-        var e = d.getInteractions(),
-            c, a, b;
-        for (c = 0; c < e.length; c++) {
-            a = e[c];
-            if (a.isItemHighlight || a.isItemEdit) {
-                b = true;
-                break
-            }
-        }
-        if (!b) {
-            e.push("itemhighlight");
-            d.setInteractions(e)
-        }
-    },
-    showTooltip: function(l, m) {
-        var d = this,
-            n = d.getTooltip(),
-            j, a, i, f, h, k, g, e, b, c;
-        if (!n) {
-            return
-        }
-        clearTimeout(d.tooltipTimeout);
-        b = n.config;
-        if (n.trackMouse) {
-            m[0] += b.offsetX;
-            m[1] += b.offsetY
-        } else {
-            j = l.sprite;
-            a = j.getSurface();
-            i = Ext.get(a.getId());
-            if (i) {
-                k = l.series.getBBoxForItem(l);
-                g = k.x + k.width / 2;
-                e = k.y + k.height / 2;
-                h = a.matrix.transformPoint([g, e]);
-                f = i.getXY();
-                c = a.getInherited().rtl;
-                g = c ? f[0] + i.getWidth() - h[0] : f[0] + h[0];
-                e = f[1] + h[1];
-                m = [g, e]
-            }
-        }
-        Ext.callback(n.renderer, n.scope, [n, l.record, l], 0, d);
-        n.show(m)
-    },
-    hideTooltip: function(b) {
-        var a = this,
-            c = a.getTooltip();
-        if (!c) {
-            return
-        }
-        clearTimeout(a.tooltipTimeout);
-        a.tooltipTimeout = Ext.defer(function() {
-            c.hide()
-        }, 1)
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    getStore: function() {
-        return this._store || this.getChart() && this.getChart().getStore()
-    },
-    updateStore: function(b, a) {
-        var h = this,
-            g = h.getChart(),
-            c = g && g.getStore(),
-            f, j, e, d;
-        a = a || c;
-        if (a && a !== b) {
-            a.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            })
-        }
-        if (b) {
-            b.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            });
-            f = h.getSprites();
-            for (d = 0, e = f.length; d < e; d++) {
-                j = f[d];
-                if (j.setStore) {
-                    j.setStore(b)
-                }
-            }
-            h.onDataChanged()
-        }
-        h.fireEvent("storechange", h, b, a)
-    },
-    onStoreChange: function(b, a, c) {
-        if (!this._store) {
-            this.updateStore(a, c)
-        }
-    },
-    coordinate: function(o, m, e) {
-        var l = this,
-            p = l.getStore(),
-            h = l.getHidden(),
-            k = p.getData().items,
-            b = l["get" + o + "Axis"](),
-            f = {
-                min: Infinity,
-                max: -Infinity
-            },
-            q = l["fieldCategory" + o] || [o],
-            g = l.getFields(q),
-            d, n, c, a = {},
-            j = l.getSprites();
-        if (j.length > 0) {
-            if (!Ext.isBoolean(h) || !h) {
-                for (d = 0; d < q.length; d++) {
-                    n = g[d];
-                    c = l.coordinateData(k, n, b);
-                    l.getRangeOfData(c, f);
-                    a["data" + q[d]] = c
-                }
-            }
-            l.dataRange[m] = f.min;
-            l.dataRange[m + e] = f.max;
-            a["dataMin" + o] = f.min;
-            a["dataMax" + o] = f.max;
-            if (b) {
-                b.range = null;
-                a["range" + o] = b.getRange()
-            }
-            for (d = 0; d < j.length; d++) {
-                j[d].setAttributes(a)
-            }
-        }
-    },
-    coordinateData: function(b, h, d) {
-        var g = [],
-            f = b.length,
-            e = d && d.getLayout(),
-            c, a;
-        for (c = 0; c < f; c++) {
-            a = b[c].data[h];
-            if (!Ext.isEmpty(a, true)) {
-                if (e) {
-                    g[c] = e.getCoordFor(a, h, c, b)
-                } else {
-                    g[c] = +a
-                }
-            } else {
-                g[c] = a
-            }
-        }
-        return g
-    },
-    getRangeOfData: function(g, b) {
-        var e = g.length,
-            d = b.min,
-            a = b.max,
-            c, f;
-        for (c = 0; c < e; c++) {
-            f = g[c];
-            if (f < d) {
-                d = f
-            }
-            if (f > a) {
-                a = f
-            }
-        }
-        b.min = d;
-        b.max = a
-    },
-    updateLabelData: function() {
-        var h = this,
-            l = h.getStore(),
-            g = l.getData().items,
-            f = h.getSprites(),
-            a = h.getLabel().getTemplate(),
-            n = Ext.Array.from(a.getField()),
-            c, b, e, d, m, k;
-        if (!f.length || !n.length) {
-            return
-        }
-        for (c = 0; c < f.length; c++) {
-            d = [];
-            m = f[c];
-            k = m.getField();
-            if (Ext.Array.indexOf(n, k) < 0) {
-                k = n[c]
-            }
-            for (b = 0, e = g.length; b < e; b++) {
-                d.push(g[b].get(k))
-            }
-            m.setAttributes({
-                labels: d
-            })
-        }
-    },
-    processData: function() {
-        if (!this.getStore()) {
-            return
-        }
-        var d = this,
-            f = this.directions,
-            a, c = f.length,
-            e, b;
-        for (a = 0; a < c; a++) {
-            e = f[a];
-            b = d["get" + e + "Axis"]();
-            if (b) {
-                b.processData(d);
-                continue
-            }
-            if (d["coordinate" + e]) {
-                d["coordinate" + e]()
-            }
-        }
-        d.updateLabelData()
-    },
-    applyBackground: function(a) {
-        if (this.getChart()) {
-            this.getSurface().setBackground(a);
-            return this.getSurface().getBackground()
-        } else {
-            return a
-        }
-    },
-    updateChart: function(d, a) {
-        var c = this,
-            b = c._store;
-        if (a) {
-            a.un("axeschange", "onAxesChange", c);
-            c.clearSprites();
-            c.setSurface(null);
-            c.setOverlaySurface(null);
-            a.unregister(c);
-            c.onChartDetached(a);
-            if (!b) {
-                c.updateStore(null)
-            }
-        }
-        if (d) {
-            c.setSurface(d.getSurface("series"));
-            c.setOverlaySurface(d.getSurface("overlay"));
-            d.on("axeschange", "onAxesChange", c);
-            if (d.getAxes()) {
-                c.onAxesChange(d)
-            }
-            c.onChartAttached(d);
-            d.register(c);
-            if (!b) {
-                c.updateStore(d.getStore())
-            }
-        }
-    },
-    onAxesChange: function(h) {
-        var k = this,
-            g = h.getAxes(),
-            c, a = {},
-            b = {},
-            e = false,
-            j = this.directions,
-            l, d, f;
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            b[l] = k.getFields(k["fieldCategory" + l])
-        }
-        for (d = 0, f = g.length; d < f; d++) {
-            c = g[d];
-            if (!a[c.getDirection()]) {
-                a[c.getDirection()] = [c]
-            } else {
-                a[c.getDirection()].push(c)
-            }
-        }
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            if (k["get" + l + "Axis"]()) {
-                continue
-            }
-            if (a[l]) {
-                c = k.findMatchingAxis(a[l], b[l]);
-                if (c) {
-                    k["set" + l + "Axis"](c);
-                    if (c.getNeedHighPrecision()) {
-                        e = true
-                    }
-                }
-            }
-        }
-        this.getSurface().setHighPrecision(e)
-    },
-    findMatchingAxis: function(f, e) {
-        var d, c, b, a;
-        for (b = 0; b < f.length; b++) {
-            d = f[b];
-            c = d.getFields();
-            if (!c.length) {
-                return d
-            } else {
-                if (e) {
-                    for (a = 0; a < e.length; a++) {
-                        if (Ext.Array.indexOf(c, e[a]) >= 0) {
-                            return d
-                        }
-                    }
-                }
-            }
-        }
-    },
-    onChartDetached: function(a) {
-        var b = this;
-        b.fireEvent("chartdetached", a, b);
-        a.un("storechange", "onStoreChange", b)
-    },
-    onChartAttached: function(a) {
-        var b = this;
-        b.setBackground(b.getBackground());
-        b.fireEvent("chartattached", a, b);
-        a.on("storechange", "onStoreChange", b);
-        b.processData()
-    },
-    updateOverlaySurface: function(a) {
-        var b = this;
-        if (a) {
-            if (b.getLabel()) {
-                b.getOverlaySurface().add(b.getLabel())
-            }
-        }
-    },
-    applyLabel: function(a, b) {
-        if (!b) {
-            b = new Ext.chart.Markers({
-                zIndex: 10
-            });
-            b.setTemplate(new Ext.chart.label.Label(a))
-        } else {
-            b.getTemplate().setAttributes(a)
-        }
-        return b
-    },
-    createItemInstancingSprite: function(c, b) {
-        var e = this,
-            f = new Ext.chart.Markers(),
-            a, d;
-        f.setAttributes({
-            zIndex: Number.MAX_VALUE
-        });
-        a = Ext.apply({}, b);
-        if (e.getHighlight()) {
-            a.highlight = e.getHighlight();
-            a.modifiers = ["highlight"]
-        }
-        f.setTemplate(a);
-        d = f.getTemplate();
-        d.setAttributes(e.getStyle());
-        d.fx.on("animationstart", "onSpriteAnimationStart", this);
-        d.fx.on("animationend", "onSpriteAnimationEnd", this);
-        c.bindMarker("items", f);
-        e.getSurface().add(f);
-        return f
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer()
-        }
-    },
-    updateRenderer: function(c) {
-        var b = this,
-            a = b.getChart(),
-            d;
-        if (a && a.isInitializing) {
-            return
-        }
-        d = b.getSprites();
-        if (d.length) {
-            d[0].setAttributes({
-                renderer: c || null
-            });
-            if (a && !a.isInitializing) {
-                a.redraw()
-            }
-        }
-    },
-    updateShowMarkers: function(a) {
-        var d = this.getSprites(),
-            b = d && d[0],
-            c = b && b.getMarker("markers");
-        if (c) {
-            c.getTemplate().setAttributes({
-                hidden: !a
-            })
-        }
-    },
-    createSprite: function() {
-        var f = this,
-            a = f.getSurface(),
-            e = f.getItemInstancing(),
-            d = a.add(f.getDefaultSpriteConfig()),
-            b = f.getMarker(),
-            g, c;
-        d.setAttributes(f.getStyle());
-        d.setSeries(f);
-        if (e) {
-            d.itemsMarker = f.createItemInstancingSprite(d, e)
-        }
-        if (d.bindMarker) {
-            if (b) {
-                g = new Ext.chart.Markers();
-                c = Ext.Object.merge({}, b);
-                if (f.getHighlight()) {
-                    c.highlight = f.getHighlight();
-                    c.modifiers = ["highlight"]
-                }
-                g.setTemplate(c);
-                g.getTemplate().fx.setCustomDurations({
-                    translationX: 0,
-                    translationY: 0
-                });
-                d.dataMarker = g;
-                d.bindMarker("markers", g);
-                f.getOverlaySurface().add(g)
-            }
-            if (f.getLabel().getTemplate().getField()) {
-                d.bindMarker("labels", f.getLabel())
-            }
-        }
-        if (d.setStore) {
-            d.setStore(f.getStore())
-        }
-        d.fx.on("animationstart", "onSpriteAnimationStart", f);
-        d.fx.on("animationend", "onSpriteAnimationEnd", f);
-        f.sprites.push(d);
-        return d
-    },
-    getSprites: Ext.emptyFn,
-    onDataChanged: function() {
-        var d = this,
-            c = d.getChart(),
-            b = c && c.getStore(),
-            a = d.getStore();
-        if (a !== b) {
-            d.processData()
-        }
-    },
-    isXType: function(a) {
-        return a === "series"
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    applyThemeStyle: function(e, a) {
-        var b = this,
-            d, c;
-        d = e && e.subStyle && e.subStyle.fillStyle;
-        c = d && e.subStyle.strokeStyle;
-        if (d && !c) {
-            e.subStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        d = e && e.markerSubStyle && e.markerSubStyle.fillStyle;
-        c = d && e.markerSubStyle.strokeStyle;
-        if (d && !c) {
-            e.markerSubStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        return Ext.apply(a || {}, e)
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        return Ext.apply({}, c, b)
-    },
-    applySubStyle: function(b, c) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            b = a.def.batchedNormalize(b, true)
-        }
-        return Ext.merge({}, c, b)
-    },
-    applyMarker: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.normalize(Ext.isObject(c) ? c : {}, true);
-            c.type = d
-        }
-        return Ext.merge(a || {}, c)
-    },
-    applyMarkerSubStyle: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.batchedNormalize(c, true)
-        }
-        return Ext.merge(a || {}, c)
-    },
-    updateHidden: function(b) {
-        var a = this;
-        a.getColors();
-        a.getSubStyle();
-        a.setSubStyle({
-            hidden: b
-        });
-        a.processData();
-        a.doUpdateStyles();
-        if (!Ext.isArray(b)) {
-            a.updateLegendStore(b)
-        }
-    },
-    updateLegendStore: function(f, b) {
-        var e = this,
-            d = e.getChart(),
-            c = d.getLegendStore(),
-            g = e.getId(),
-            a;
-        if (c) {
-            if (arguments.length > 1) {
-                a = c.findBy(function(h) {
-                    return h.get("series") === g && h.get("index") === b
-                });
-                if (a !== -1) {
-                    a = c.getAt(a)
-                }
-            } else {
-                a = c.findRecord("series", g)
-            }
-            if (a && a.get("disabled") !== f) {
-                a.set("disabled", f)
-            }
-        }
-    },
-    setHiddenByIndex: function(a, c) {
-        var b = this;
-        if (Ext.isArray(b.getHidden())) {
-            b.getHidden()[a] = c;
-            b.updateHidden(b.getHidden());
-            b.updateLegendStore(c, a)
-        } else {
-            b.setHidden(c)
-        }
-    },
-    getStrokeColorsFromFillColors: function(a) {
-        var c = this,
-            e = c.getUseDarkerStrokeColor(),
-            b = (Ext.isNumber(e) ? e : c.darkerStrokeRatio),
-            d;
-        if (e) {
-            d = Ext.Array.map(a, function(f) {
-                f = Ext.isString(f) ? f : f.stops[0].color;
-                f = Ext.draw.Color.fromString(f);
-                return f.createDarker(b).toString()
-            })
-        } else {
-            d = Ext.Array.clone(a)
-        }
-        return d
-    },
-    updateThemeColors: function(b) {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = Ext.Array.clone(b),
-            f = c.getStrokeColorsFromFillColors(b),
-            e = {
-                fillStyle: a,
-                strokeStyle: f
-            };
-        d.subStyle = Ext.apply(d.subStyle || {}, e);
-        d.markerSubStyle = Ext.apply(d.markerSubStyle || {}, e);
-        c.doUpdateStyles()
-    },
-    themeOnlyIfConfigured: {},
-    updateTheme: function(d) {
-        var h = this,
-            a = d.getSeries(),
-            n = h.getInitialConfig(),
-            c = h.defaultConfig,
-            f = h.getConfigurator().configs,
-            j = a.defaults,
-            k = a[h.type],
-            g = h.themeOnlyIfConfigured,
-            l, i, o, b, m, e;
-        a = Ext.merge({}, j, k);
-        for (l in a) {
-            i = a[l];
-            e = f[l];
-            if (i !== null && i !== undefined && e) {
-                m = n[l];
-                o = Ext.isObject(i);
-                b = m === c[l];
-                if (o) {
-                    if (b && g[l]) {
-                        continue
-                    }
-                    i = Ext.merge({}, i, m)
-                }
-                if (b || o) {
-                    h[e.names.set](i)
-                }
-            }
-        }
-    },
-    updateChartColors: function(a) {
-        var b = this;
-        if (!b.getColors()) {
-            b.updateThemeColors(a)
-        }
-    },
-    updateColors: function(a) {
-        this.updateThemeColors(a)
-    },
-    updateStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateSubStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateThemeStyle: function() {
-        this.doUpdateStyles()
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.sprites,
-            d = g.getItemInstancing(),
-            c = 0,
-            f = h && h.length,
-            a = g.getConfig("showMarkers", true),
-            b = g.getMarker(),
-            e;
-        for (; c < f; c++) {
-            e = g.getStyleByIndex(c);
-            if (d) {
-                h[c].itemsMarker.getTemplate().setAttributes(e)
-            }
-            h[c].setAttributes(e);
-            if (b && h[c].dataMarker) {
-                h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))
-            }
-        }
-    },
-    getStyleWithTheme: function() {
-        var b = this,
-            c = b.getThemeStyle(),
-            d = (c && c.style) || {},
-            a = Ext.applyIf(Ext.apply({}, b.getStyle()), d);
-        return a
-    },
-    getSubStyleWithTheme: function() {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = (d && d.subStyle) || {},
-            b = Ext.applyIf(Ext.apply({}, c.getSubStyle()), a);
-        return b
-    },
-    getStyleByIndex: function(b) {
-        var e = this,
-            h = e.getThemeStyle(),
-            d, g, c, f, a = {};
-        d = e.getStyle();
-        g = (h && h.style) || {};
-        c = e.styleDataForIndex(e.getSubStyle(), b);
-        f = e.styleDataForIndex((h && h.subStyle), b);
-        Ext.apply(a, g);
-        Ext.apply(a, f);
-        Ext.apply(a, d);
-        Ext.apply(a, c);
-        return a
-    },
-    getMarkerStyleByIndex: function(d) {
-        var g = this,
-            c = g.getThemeStyle(),
-            a, e, k, j, b, l, h, f, m = {};
-        a = g.getStyle();
-        e = (c && c.style) || {};
-        k = g.styleDataForIndex(g.getSubStyle(), d);
-        if (k.hasOwnProperty("hidden")) {
-            k.hidden = k.hidden || !this.getConfig("showMarkers", true)
-        }
-        j = g.styleDataForIndex((c && c.subStyle), d);
-        b = g.getMarker();
-        l = (c && c.marker) || {};
-        h = g.getMarkerSubStyle();
-        f = g.styleDataForIndex((c && c.markerSubStyle), d);
-        Ext.apply(m, e);
-        Ext.apply(m, j);
-        Ext.apply(m, l);
-        Ext.apply(m, f);
-        Ext.apply(m, a);
-        Ext.apply(m, k);
-        Ext.apply(m, b);
-        Ext.apply(m, h);
-        return m
-    },
-    styleDataForIndex: function(d, c) {
-        var e, b, a = {};
-        if (d) {
-            for (b in d) {
-                e = d[b];
-                if (Ext.isArray(e)) {
-                    a[b] = e[c % e.length]
-                } else {
-                    a[b] = e
-                }
-            }
-        }
-        return a
-    },
-    getItemForPoint: Ext.emptyFn,
-    getItemByIndex: function(a, e) {
-        var d = this,
-            f = d.getSprites(),
-            b = f && f[0],
-            c;
-        if (!b) {
-            return
-        }
-        if (e === undefined && b.isMarkerHolder) {
-            e = d.getItemInstancing() ? "items" : "markers"
-        } else {
-            if (!e || e === "" || e === "sprites") {
-                b = f[a]
-            }
-        }
-        if (b) {
-            c = {
-                series: d,
-                category: e,
-                index: a,
-                record: d.getStore().getData().items[a],
-                field: d.getYField(),
-                sprite: b
-            };
-            return c
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.fireEvent("animationstart", this, a)
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.fireEvent("animationend", this, a)
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    provideLegendInfo: function(a) {
-        a.push({
-            name: this.getTitle() || this.getId(),
-            mark: "black",
-            disabled: this.getHidden(),
-            series: this.getId(),
-            index: 0
-        })
-    },
-    clearSprites: function() {
-        var d = this.sprites,
-            b, a, c;
-        for (a = 0, c = d.length; a < c; a++) {
-            b = d[a];
-            if (b && b.isSprite) {
-                b.destroy()
-            }
-        }
-        this.sprites = []
-    },
-    destroy: function() {
-        var b = this,
-            a = b._store,
-            c = b.getConfig("tooltip", true);
-        if (a && a.getAutoDestroy()) {
-            Ext.destroy(a)
-        }
-        b.setChart(null);
-        b.clearListeners();
-        if (c) {
-            Ext.destroy(c);
-            clearTimeout(b.tooltipTimeout)
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Abstract", {
-    xtype: "interaction",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        gestures: {
-            tap: "onGesture"
-        },
-        chart: null,
-        enabled: true
-    },
-    throttleGap: 0,
-    stopAnimationBeforeSync: false,
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.call(b, a)
-    },
-    initialize: Ext.emptyFn,
-    updateChart: function(c, a) {
-        var b = this;
-        if (a === c) {
-            return
-        }
-        if (a) {
-            a.unregister(b);
-            b.removeChartListener(a)
-        }
-        if (c) {
-            c.register(b);
-            b.addChartListener()
-        }
-    },
-    updateEnabled: function(a) {
-        var c = this,
-            b = c.getChart();
-        if (b) {
-            if (a) {
-                c.addChartListener()
-            } else {
-                c.removeChartListener(b)
-            }
-        }
-    },
-    onGesture: Ext.emptyFn,
-    getItemForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemForPoint(c[0], c[1])
-    },
-    getItemsForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemsForPoint(c[0], c[1])
-    },
-    addChartListener: function() {
-        var c = this,
-            b = c.getChart(),
-            e = c.getGestures(),
-            a;
-        if (!c.getEnabled()) {
-            return
-        }
-
-        function d(f, g) {
-            b.addElementListener(f, c.listeners[f] = function(j) {
-                var i = c.getLocks(),
-                    h;
-                if (c.getEnabled() && (!(f in i) || i[f] === c)) {
-                    h = (Ext.isFunction(g) ? g : c[g]).apply(this, arguments);
-                    if (h === false && j && j.stopPropagation) {
-                        j.stopPropagation()
-                    }
-                    return h
-                }
-            }, c)
-        }
-        c.listeners = c.listeners || {};
-        for (a in e) {
-            d(a, e[a])
-        }
-    },
-    removeChartListener: function(c) {
-        var d = this,
-            e = d.getGestures(),
-            b;
-
-        function a(f) {
-            var g = d.listeners[f];
-            if (g) {
-                c.removeElementListener(f, g);
-                delete d.listeners[f]
-            }
-        }
-        if (d.listeners) {
-            for (b in e) {
-                a(b)
-            }
-        }
-    },
-    lockEvents: function() {
-        var d = this,
-            c = d.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            c[a[b]] = d
-        }
-    },
-    unlockEvents: function() {
-        var c = this.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            delete c[a[b]]
-        }
-    },
-    getLocks: function() {
-        var a = this.getChart();
-        return a.lockedEvents || (a.lockedEvents = {})
-    },
-    isMultiTouch: function() {
-        if (Ext.browser.is.IE10) {
-            return true
-        }
-        return !Ext.os.is.Desktop
-    },
-    initializeDefaults: Ext.emptyFn,
-    doSync: function() {
-        var b = this,
-            a = b.getChart();
-        if (b.syncTimer) {
-            clearTimeout(b.syncTimer);
-            b.syncTimer = null
-        }
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount++
-        }
-        a.redraw();
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount--
-        }
-        b.syncThrottle = Date.now() + b.throttleGap
-    },
-    sync: function() {
-        var a = this;
-        if (a.throttleGap && Ext.frameStartTime < a.syncThrottle) {
-            if (a.syncTimer) {
-                return
-            }
-            a.syncTimer = Ext.defer(function() {
-                a.doSync()
-            }, a.throttleGap)
-        } else {
-            a.doSync()
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    isXType: function(a) {
-        return a === "interaction"
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        delete a.listeners;
-        a.callParent()
-    }
-}, function() {
-    if (Ext.os.is.Android4) {
-        this.prototype.throttleGap = 40
-    }
-});
-Ext.define("Ext.chart.MarkerHolder", {
-    extend: "Ext.Mixin",
-    mixinConfig: {
-        id: "markerHolder",
-        after: {
-            constructor: "constructor",
-            preRender: "preRender"
-        },
-        before: {
-            destroy: "destroy"
-        }
-    },
-    isMarkerHolder: true,
-    surfaceMatrix: null,
-    inverseSurfaceMatrix: null,
-    deprecated: {
-        6: {
-            methods: {
-                getBoundMarker: {
-                    message: "Please use the 'getMarker' method instead.",
-                    fn: function(b) {
-                        var a = this.boundMarkers[b];
-                        return a ? [a] : a
-                    }
-                }
-            }
-        }
-    },
-    constructor: function() {
-        this.boundMarkers = {};
-        this.cleanRedraw = false
-    },
-    bindMarker: function(b, a) {
-        var c = this,
-            d = c.boundMarkers;
-        if (a && a.isMarkers) {
-            c.releaseMarker(b);
-            d[b] = a;
-            a.on("destroy", c.onMarkerDestroy, c)
-        }
-    },
-    onMarkerDestroy: function(a) {
-        this.releaseMarker(a)
-    },
-    releaseMarker: function(a) {
-        var c = this.boundMarkers,
-            b;
-        if (a && a.isMarkers) {
-            for (b in c) {
-                if (c[b] === a) {
-                    delete c[b];
-                    break
-                }
-            }
-        } else {
-            b = a;
-            a = c[b];
-            delete c[b]
-        }
-        return a || null
-    },
-    getMarker: function(a) {
-        return this.boundMarkers[a] || null
-    },
-    preRender: function() {
-        var f = this,
-            g = f.getId(),
-            d = f.boundMarkers,
-            e = f.getParent(),
-            c, a, b;
-        if (f.surfaceMatrix) {
-            b = f.surfaceMatrix.set(1, 0, 0, 1, 0, 0)
-        } else {
-            b = f.surfaceMatrix = new Ext.draw.Matrix()
-        }
-        f.cleanRedraw = !f.attr.dirty;
-        if (!f.cleanRedraw) {
-            for (c in d) {
-                a = d[c];
-                if (a) {
-                    a.clear(g)
-                }
-            }
-        }
-        while (e && e.attr && e.attr.matrix) {
-            b.prependMatrix(e.attr.matrix);
-            e = e.getParent()
-        }
-        b.prependMatrix(e.matrix);
-        f.surfaceMatrix = b;
-        f.inverseSurfaceMatrix = b.inverse(f.inverseSurfaceMatrix)
-    },
-    putMarker: function(d, a, c, g, e) {
-        var b = this.boundMarkers[d],
-            f = this.getId();
-        if (b) {
-            b.putMarkerFor(f, a, c, g, e)
-        }
-    },
-    getMarkerBBox: function(c, b, d) {
-        var a = this.boundMarkers[c],
-            e = this.getId();
-        if (a) {
-            return a.getMarkerBBoxFor(e, b, d)
-        }
-    },
-    destroy: function() {
-        var c = this.boundMarkers,
-            b, a;
-        for (b in c) {
-            a = c[b];
-            a.destroy()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.axis",
-    type: "axis",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    requires: ["Ext.draw.sprite.Text"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                grid: "bool",
-                axisLine: "bool",
-                minorTicks: "bool",
-                minorTickSize: "number",
-                majorTicks: "bool",
-                majorTickSize: "number",
-                length: "number",
-                startGap: "number",
-                endGap: "number",
-                dataMin: "number",
-                dataMax: "number",
-                visibleMin: "number",
-                visibleMax: "number",
-                position: "enums(left,right,top,bottom,angular,radial,gauge)",
-                minStepSize: "number",
-                estStepSize: "number",
-                titleOffset: "number",
-                textPadding: "number",
-                min: "number",
-                max: "number",
-                centerX: "number",
-                centerY: "number",
-                radius: "number",
-                totalAngle: "number",
-                baseRotation: "number",
-                data: "default",
-                enlargeEstStepSizeByText: "bool"
-            },
-            defaults: {
-                grid: false,
-                axisLine: true,
-                minorTicks: false,
-                minorTickSize: 3,
-                majorTicks: true,
-                majorTickSize: 5,
-                length: 0,
-                startGap: 0,
-                endGap: 0,
-                visibleMin: 0,
-                visibleMax: 1,
-                dataMin: 0,
-                dataMax: 1,
-                position: "",
-                minStepSize: 0,
-                estStepSize: 20,
-                min: 0,
-                max: 1,
-                centerX: 0,
-                centerY: 0,
-                radius: 1,
-                baseRotation: 0,
-                data: null,
-                titleOffset: 0,
-                textPadding: 0,
-                scalingCenterY: 0,
-                scalingCenterX: 0,
-                strokeStyle: "black",
-                enlargeEstStepSizeByText: false
-            },
-            triggers: {
-                minorTickSize: "bbox",
-                majorTickSize: "bbox",
-                position: "bbox,layout",
-                axisLine: "bbox,layout",
-                min: "layout",
-                max: "layout",
-                length: "layout",
-                minStepSize: "layout",
-                estStepSize: "layout",
-                data: "layout",
-                dataMin: "layout",
-                dataMax: "layout",
-                visibleMin: "layout",
-                visibleMax: "layout",
-                enlargeEstStepSizeByText: "layout"
-            },
-            updaters: {
-                layout: "layoutUpdater"
-            }
-        }
-    },
-    config: {
-        label: null,
-        layout: null,
-        segmenter: null,
-        renderer: null,
-        layoutContext: null,
-        axis: null
-    },
-    thickness: 0,
-    stepSize: 0,
-    getBBox: function() {
-        return null
-    },
-    defaultRenderer: function(a) {
-        return this.segmenter.renderer(a, this)
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            c = e.position,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (c === "left" || c === "right") {
-            e.translationX = 0;
-            e.translationY = i * e.length / (i - b);
-            e.scalingX = 1;
-            e.scalingY = -e.length / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (c === "top" || c === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * e.length / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    iterate: function(e, j) {
-        var c, g, a, b, h, d, k = Ext.Array.some,
-            m = Math.abs,
-            f;
-        if (e.getLabel) {
-            if (e.min < e.from) {
-                j.call(this, e.min, e.getLabel(e.min), -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                j.call(this, e.get(c), e.getLabel(c), c, e)
-            }
-            if (e.max > e.to) {
-                j.call(this, e.max, e.getLabel(e.max), e.steps + 1, e)
-            }
-        } else {
-            b = this.getAxis();
-            h = b.floatingAxes;
-            d = [];
-            f = (e.to - e.from) / (e.steps + 1);
-            if (b.getFloating()) {
-                for (a in h) {
-                    d.push(h[a])
-                }
-            }
-
-            function l(i) {
-                return !d.length || k(d, function(n) {
-                    return m(n - i) > f
-                })
-            }
-            if (e.min < e.from && l(e.min)) {
-                j.call(this, e.min, e.min, -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                g = e.get(c);
-                if (l(g)) {
-                    j.call(this, g, g, c, e)
-                }
-            }
-            if (e.max > e.to && l(e.max)) {
-                j.call(this, e.max, e.max, e.steps + 1, e)
-            }
-        }
-    },
-    renderTicks: function(l, m, s, p) {
-        var v = this,
-            k = v.attr,
-            u = k.position,
-            n = k.matrix,
-            e = 0.5 * k.lineWidth,
-            f = n.getXX(),
-            i = n.getDX(),
-            j = n.getYY(),
-            h = n.getDY(),
-            o = s.majorTicks,
-            d = k.majorTickSize,
-            a = s.minorTicks,
-            r = k.minorTickSize;
-        if (o) {
-            switch (u) {
-                case "right":
-                    function q(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(0, x);
-                            m.lineTo(w, x)
-                        }
-                    }
-                    v.iterate(o, q(d));
-                    a && v.iterate(a, q(r));
-                    break;
-                case "left":
-                    function t(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(p[2] - w, x);
-                            m.lineTo(p[2], x)
-                        }
-                    }
-                    v.iterate(o, t(d));
-                    a && v.iterate(a, t(r));
-                    break;
-                case "bottom":
-                    function c(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, 0);
-                            m.lineTo(x, w)
-                        }
-                    }
-                    v.iterate(o, c(d));
-                    a && v.iterate(a, c(r));
-                    break;
-                case "top":
-                    function b(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, p[3]);
-                            m.lineTo(x, p[3] - w)
-                        }
-                    }
-                    v.iterate(o, b(d));
-                    a && v.iterate(a, b(r));
-                    break;
-                case "angular":
-                    v.iterate(o, function(w, y, x) {
-                        w = w / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break;
-                case "gauge":
-                    var g = v.getGaugeAngles();
-                    v.iterate(o, function(w, y, x) {
-                        w = (w - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + g.start;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break
-            }
-        }
-    },
-    renderLabels: function(E, q, D, K) {
-        var o = this,
-            k = o.attr,
-            i = 0.5 * k.lineWidth,
-            u = k.position,
-            y = k.matrix,
-            A = k.textPadding,
-            x = y.getXX(),
-            d = y.getDX(),
-            g = y.getYY(),
-            c = y.getDY(),
-            n = 0,
-            I = D.majorTicks,
-            G = Math.max(k.majorTickSize, k.minorTickSize) + k.lineWidth,
-            f = Ext.draw.Draw.isBBoxIntersect,
-            F = o.getLabel(),
-            J, s, r = null,
-            w = 0,
-            b = 0,
-            m = D.segmenter,
-            B = o.getRenderer(),
-            t = o.getAxis(),
-            z = t.getTitle(),
-            a = z && z.attr.text !== "" && z.getBBox(),
-            l, h = null,
-            p, C, v, e, H;
-        if (I && F && !F.attr.hidden) {
-            J = F.attr.font;
-            if (q.font !== J) {
-                q.font = J
-            }
-            F.setAttributes({
-                translationX: 0,
-                translationY: 0
-            }, true);
-            F.applyTransformations();
-            l = F.attr.inverseMatrix.elements.slice(0);
-            switch (u) {
-                case "left":
-                    e = a ? a.x + a.width : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(e + d) - i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - G + d) - i;
-                            break;
-                        default:
-                            H = E.roundPixel(e + (K[2] - e - G) / 2 + d) - i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "right":
-                    e = a ? K[2] - a.x : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(G + d) + i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - e + d) + i;
-                            break;
-                        default:
-                            H = E.roundPixel(G + (K[2] - G - e) / 2 + d) + i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "top":
-                    e = a ? a.y + a.height : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(e + (K[3] - e - G) / 2) - i
-                    }, true);
-                    break;
-                case "bottom":
-                    e = a ? K[3] - a.y : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(G + (K[3] - G - e) / 2) + i
-                    }, true);
-                    break;
-                case "radial":
-                    F.setAttributes({
-                        translationX: k.centerX
-                    }, true);
-                    break;
-                case "angular":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break;
-                case "gauge":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break
-            }
-            if (u === "left" || u === "right") {
-                o.iterate(I, function(L, N, M) {
-                    if (N === undefined) {
-                        return
-                    }
-                    if (B) {
-                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                    } else {
-                        v = m.renderer(N, D, r)
-                    }
-                    r = N;
-                    F.setAttributes({
-                        text: String(v),
-                        translationY: E.roundPixel(L * g + c)
-                    }, true);
-                    F.applyTransformations();
-                    n = Math.max(n, F.getBBox().width + G);
-                    if (n <= o.thickness) {
-                        C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                        p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                        if (h && !f(p, h, A)) {
-                            return
-                        }
-                        E.renderSprite(F);
-                        h = p;
-                        w += p.height;
-                        b++
-                    }
-                })
-            } else {
-                if (u === "top" || u === "bottom") {
-                    o.iterate(I, function(L, N, M) {
-                        if (N === undefined) {
-                            return
-                        }
-                        if (B) {
-                            v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                        } else {
-                            v = m.renderer(N, D, r)
-                        }
-                        r = N;
-                        F.setAttributes({
-                            text: String(v),
-                            translationX: E.roundPixel(L * x + d)
-                        }, true);
-                        F.applyTransformations();
-                        n = Math.max(n, F.getBBox().height + G);
-                        if (n <= o.thickness) {
-                            C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                            p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                            if (h && !f(p, h, A)) {
-                                return
-                            }
-                            E.renderSprite(F);
-                            h = p;
-                            w += p.width;
-                            b++
-                        }
-                    })
-                } else {
-                    if (u === "radial") {
-                        o.iterate(I, function(L, N, M) {
-                            if (N === undefined) {
-                                return
-                            }
-                            if (B) {
-                                v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                            } else {
-                                v = m.renderer(N, D, r)
-                            }
-                            r = N;
-                            if (typeof v !== "undefined") {
-                                F.setAttributes({
-                                    text: String(v),
-                                    translationX: k.centerX - E.roundPixel(L) / k.max * k.length * Math.cos(k.baseRotation + Math.PI / 2),
-                                    translationY: k.centerY - E.roundPixel(L) / k.max * k.length * Math.sin(k.baseRotation + Math.PI / 2)
-                                }, true);
-                                F.applyTransformations();
-                                p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                if (h && !f(p, h)) {
-                                    return
-                                }
-                                E.renderSprite(F);
-                                h = p;
-                                w += p.width;
-                                b++
-                            }
-                        })
-                    } else {
-                        if (u === "angular") {
-                            s = k.majorTickSize + k.lineWidth * 0.5 + (parseInt(F.attr.fontSize, 10) || 10) / 2;
-                            o.iterate(I, function(L, N, M) {
-                                if (N === undefined) {
-                                    return
-                                }
-                                if (B) {
-                                    v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                } else {
-                                    v = m.renderer(N, D, r)
-                                }
-                                r = N;
-                                n = Math.max(n, Math.max(k.majorTickSize, k.minorTickSize) + (k.lineCap !== "butt" ? k.lineWidth * 0.5 : 0));
-                                if (typeof v !== "undefined") {
-                                    var O = L / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                                    F.setAttributes({
-                                        text: String(v),
-                                        translationX: k.centerX + (k.length + s) * Math.cos(O),
-                                        translationY: k.centerY + (k.length + s) * Math.sin(O)
-                                    }, true);
-                                    F.applyTransformations();
-                                    p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                    if (h && !f(p, h)) {
-                                        return
-                                    }
-                                    E.renderSprite(F);
-                                    h = p;
-                                    w += p.width;
-                                    b++
-                                }
-                            })
-                        } else {
-                            if (u === "gauge") {
-                                var j = o.getGaugeAngles();
-                                o.iterate(I, function(L, N, M) {
-                                    if (N === undefined) {
-                                        return
-                                    }
-                                    if (B) {
-                                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                    } else {
-                                        v = m.renderer(N, D, r)
-                                    }
-                                    r = N;
-                                    if (typeof v !== "undefined") {
-                                        var O = (L - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + j.start;
-                                        F.setAttributes({
-                                            text: String(v),
-                                            translationX: k.centerX + (k.length + 10) * Math.cos(O),
-                                            translationY: k.centerY + (k.length + 10) * Math.sin(O)
-                                        }, true);
-                                        F.applyTransformations();
-                                        p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                        if (h && !f(p, h)) {
-                                            return
-                                        }
-                                        E.renderSprite(F);
-                                        h = p;
-                                        w += p.width;
-                                        b++
-                                    }
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-            if (k.enlargeEstStepSizeByText && b) {
-                w /= b;
-                w += G;
-                w *= 2;
-                if (k.estStepSize < w) {
-                    k.estStepSize = w
-                }
-            }
-            if (Math.abs(o.thickness - (n)) > 1) {
-                o.thickness = n;
-                k.bbox.plain.dirty = true;
-                k.bbox.transform.dirty = true;
-                o.doThicknessChanged();
-                return false
-            }
-        }
-    },
-    renderAxisLine: function(a, i, e, c) {
-        var h = this,
-            g = h.attr,
-            b = g.lineWidth * 0.5,
-            j = g.position,
-            d, f;
-        if (g.axisLine && g.length) {
-            switch (j) {
-                case "left":
-                    d = a.roundPixel(c[2]) - b;
-                    i.moveTo(d, -g.endGap);
-                    i.lineTo(d, g.length + g.startGap + 1);
-                    break;
-                case "right":
-                    i.moveTo(b, -g.endGap);
-                    i.lineTo(b, g.length + g.startGap + 1);
-                    break;
-                case "bottom":
-                    i.moveTo(-g.startGap, b);
-                    i.lineTo(g.length + g.endGap, b);
-                    break;
-                case "top":
-                    d = a.roundPixel(c[3]) - b;
-                    i.moveTo(-g.startGap, d);
-                    i.lineTo(g.length + g.endGap, d);
-                    break;
-                case "angular":
-                    i.moveTo(g.centerX + g.length, g.centerY);
-                    i.arc(g.centerX, g.centerY, g.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    f = h.getGaugeAngles();
-                    i.moveTo(g.centerX + Math.cos(f.start) * g.length, g.centerY + Math.sin(f.start) * g.length);
-                    i.arc(g.centerX, g.centerY, g.length, f.start, f.end, true);
-                    break
-            }
-        }
-    },
-    getGaugeAngles: function() {
-        var a = this,
-            c = a.attr.totalAngle,
-            b;
-        if (c <= Math.PI) {
-            b = (Math.PI - c) * 0.5
-        } else {
-            b = -(Math.PI * 2 - c) * 0.5
-        }
-        b = Math.PI * 2 - b;
-        return {
-            start: b,
-            end: b - c
-        }
-    },
-    renderGridLines: function(m, n, s, r) {
-        var t = this,
-            b = t.getAxis(),
-            l = t.attr,
-            p = l.matrix,
-            d = l.startGap,
-            a = l.endGap,
-            c = p.getXX(),
-            k = p.getYY(),
-            h = p.getDX(),
-            g = p.getDY(),
-            u = l.position,
-            f = b.getGridAlignment(),
-            q = s.majorTicks,
-            e, o, i;
-        if (l.grid) {
-            if (q) {
-                if (u === "left" || u === "right") {
-                    i = l.min * k + g + a + d;
-                    t.iterate(q, function(j, w, v) {
-                        e = j * k + g + a;
-                        t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                            y: e,
-                            height: i - e
-                        }, o = v, true);
-                        i = e
-                    });
-                    o++;
-                    e = 0;
-                    t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                        y: e,
-                        height: i - e
-                    }, o, true)
-                } else {
-                    if (u === "top" || u === "bottom") {
-                        i = l.min * c + h + d;
-                        if (d) {
-                            t.putMarker(f + "-even", {
-                                x: 0,
-                                width: i
-                            }, -1, true)
-                        }
-                        t.iterate(q, function(j, w, v) {
-                            e = j * c + h + d;
-                            t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                x: e,
-                                width: i - e
-                            }, o = v, true);
-                            i = e
-                        });
-                        o++;
-                        e = l.length + l.startGap + l.endGap;
-                        t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                            x: e,
-                            width: i - e
-                        }, o, true)
-                    } else {
-                        if (u === "radial") {
-                            t.iterate(q, function(j, w, v) {
-                                if (!j) {
-                                    return
-                                }
-                                e = j / l.max * l.length;
-                                t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                    scalingX: e,
-                                    scalingY: e
-                                }, v, true);
-                                i = e
-                            })
-                        } else {
-                            if (u === "angular") {
-                                t.iterate(q, function(j, w, v) {
-                                    if (!l.length) {
-                                        return
-                                    }
-                                    e = j / (l.max + 1) * Math.PI * 2 + l.baseRotation;
-                                    t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                        rotationRads: e,
-                                        rotationCenterX: 0,
-                                        rotationCenterY: 0,
-                                        scalingX: l.length,
-                                        scalingY: l.length
-                                    }, v, true);
-                                    i = e
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    renderLimits: function(o) {
-        var t = this,
-            a = t.getAxis(),
-            h = a.getChart(),
-            p = h.getInnerPadding(),
-            d = Ext.Array.from(a.getLimits());
-        if (!d.length) {
-            return
-        }
-        var r = a.limits.surface.getRect(),
-            m = t.attr,
-            n = m.matrix,
-            u = m.position,
-            k = Ext.Object.chain,
-            v = a.limits.titles,
-            c, j, b, s, l, q, f, g, e;
-        v.instances = [];
-        v.position = 0;
-        if (u === "left" || u === "right") {
-            for (q = 0, f = d.length; q < f; q++) {
-                s = k(d[q]);
-                !s.line && (s.line = {});
-                l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                l = l * n.getYY() + n.getDY();
-                s.line.y = l + p.top;
-                s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                t.putMarker("horizontal-limit-lines", s.line, q, true);
-                if (s.line.title) {
-                    v.createInstance(s.line.title);
-                    c = v.getBBoxFor(v.position - 1);
-                    j = s.line.title.position || (u === "left" ? "start" : "end");
-                    switch (j) {
-                        case "start":
-                            g = 10;
-                            break;
-                        case "end":
-                            g = r[2] - 10;
-                            break;
-                        case "middle":
-                            g = r[2] / 2;
-                            break
-                    }
-                    v.setAttributesFor(v.position - 1, {
-                        x: g,
-                        y: s.line.y - c.height / 2,
-                        textAlign: j,
-                        fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                    })
-                }
-            }
-        } else {
-            if (u === "top" || u === "bottom") {
-                for (q = 0, f = d.length; q < f; q++) {
-                    s = k(d[q]);
-                    !s.line && (s.line = {});
-                    l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                    l = l * n.getXX() + n.getDX();
-                    s.line.x = l + p.left;
-                    s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                    t.putMarker("vertical-limit-lines", s.line, q, true);
-                    if (s.line.title) {
-                        v.createInstance(s.line.title);
-                        c = v.getBBoxFor(v.position - 1);
-                        j = s.line.title.position || (u === "top" ? "end" : "start");
-                        switch (j) {
-                            case "start":
-                                e = r[3] - c.width / 2 - 10;
-                                break;
-                            case "end":
-                                e = c.width / 2 + 10;
-                                break;
-                            case "middle":
-                                e = r[3] / 2;
-                                break
-                        }
-                        v.setAttributesFor(v.position - 1, {
-                            x: s.line.x + c.height / 2,
-                            y: e,
-                            fillStyle: s.line.title.fillStyle || s.line.strokeStyle,
-                            rotationRads: Math.PI / 2
-                        })
-                    }
-                }
-            } else {
-                if (u === "radial") {
-                    for (q = 0, f = d.length; q < f; q++) {
-                        s = k(d[q]);
-                        !s.line && (s.line = {});
-                        l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                        if (l > m.max) {
-                            continue
-                        }
-                        l = l / m.max * m.length;
-                        s.line.cx = m.centerX;
-                        s.line.cy = m.centerY;
-                        s.line.scalingX = l;
-                        s.line.scalingY = l;
-                        s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                        t.putMarker("circular-limit-lines", s.line, q, true);
-                        if (s.line.title) {
-                            v.createInstance(s.line.title);
-                            c = v.getBBoxFor(v.position - 1);
-                            v.setAttributesFor(v.position - 1, {
-                                x: m.centerX,
-                                y: m.centerY - l - c.height / 2,
-                                fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                            })
-                        }
-                    }
-                } else {
-                    if (u === "angular") {
-                        for (q = 0, f = d.length; q < f; q++) {
-                            s = k(d[q]);
-                            !s.line && (s.line = {});
-                            l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                            l = l / (m.max + 1) * Math.PI * 2 + m.baseRotation;
-                            s.line.translationX = m.centerX;
-                            s.line.translationY = m.centerY;
-                            s.line.rotationRads = l;
-                            s.line.rotationCenterX = 0;
-                            s.line.rotationCenterY = 0;
-                            s.line.scalingX = m.length;
-                            s.line.scalingY = m.length;
-                            s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                            t.putMarker("radial-limit-lines", s.line, q, true);
-                            if (s.line.title) {
-                                v.createInstance(s.line.title);
-                                c = v.getBBoxFor(v.position - 1);
-                                b = ((l > -0.5 * Math.PI && l < 0.5 * Math.PI) || (l > 1.5 * Math.PI && l < 2 * Math.PI)) ? 1 : -1;
-                                v.setAttributesFor(v.position - 1, {
-                                    x: m.centerX + 0.5 * m.length * Math.cos(l) + b * c.height / 2 * Math.sin(l),
-                                    y: m.centerY + 0.5 * m.length * Math.sin(l) - b * c.height / 2 * Math.cos(l),
-                                    rotationRads: b === 1 ? l : l - Math.PI,
-                                    fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                                })
-                            }
-                        }
-                    } else {
-                        if (u === "gauge") {}
-                    }
-                }
-            }
-        }
-    },
-    doThicknessChanged: function() {
-        var a = this.getAxis();
-        if (a) {
-            a.onThicknessChanged()
-        }
-    },
-    render: function(a, c, d) {
-        var e = this,
-            b = e.getLayoutContext();
-        if (b) {
-            if (false === e.renderLabels(a, c, b, d)) {
-                return false
-            }
-            c.beginPath();
-            e.renderTicks(a, c, b, d);
-            e.renderAxisLine(a, c, b, d);
-            e.renderGridLines(a, c, b, d);
-            e.renderLimits(d);
-            c.stroke()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Segmenter", {
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    renderer: function(b, a) {
-        return String(b)
-    },
-    from: function(a) {
-        return a
-    },
-    diff: Ext.emptyFn,
-    align: Ext.emptyFn,
-    add: Ext.emptyFn,
-    preferredStep: Ext.emptyFn
-});
-Ext.define("Ext.chart.axis.segmenter.Names", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.names",
-    renderer: function(b, a) {
-        return b
-    },
-    diff: function(b, a, c) {
-        return Math.floor(a - b)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c)
-    },
-    add: function(c, b, a) {
-        return c + b
-    },
-    preferredStep: function(c, a, b, d) {
-        return {
-            unit: 1,
-            step: 1
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Numeric", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.numeric",
-    isNumeric: true,
-    renderer: function(b, a) {
-        return b.toFixed(Math.max(0, a.majorTicks.unit.fixes))
-    },
-    diff: function(b, a, c) {
-        return Math.floor((a - b) / c.scale)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c / (a.scale * b)) * a.scale * b
-    },
-    add: function(c, b, a) {
-        return c + b * a.scale
-    },
-    preferredStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        b /= d;
-        if (b < 2) {
-            b = 2
-        } else {
-            if (b < 5) {
-                b = 5
-            } else {
-                if (b < 10) {
-                    b = 10;
-                    a++
-                }
-            }
-        }
-        return {
-            unit: {
-                fixes: -a,
-                scale: d
-            },
-            step: b
-        }
-    },
-    exactStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        return {
-            unit: {
-                fixes: -a + (b % d === 0 ? 0 : 1),
-                scale: 1
-            },
-            step: b
-        }
-    },
-    adjustByMajorUnit: function(e, g, c) {
-        var d = c[0],
-            b = c[1],
-            a = e * g,
-            f = d % a;
-        if (f !== 0) {
-            c[0] = d - f + (d < 0 ? -a : 0)
-        }
-        f = b % a;
-        if (f !== 0) {
-            c[1] = b - f + (b > 0 ? a : 0)
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Time", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.time",
-    config: {
-        step: null
-    },
-    renderer: function(c, b) {
-        var a = Ext.Date;
-        switch (b.majorTicks.unit) {
-            case "y":
-                return a.format(c, "Y");
-            case "mo":
-                return a.format(c, "Y-m");
-            case "d":
-                return a.format(c, "Y-m-d")
-        }
-        return a.format(c, "Y-m-d\nH:i:s")
-    },
-    from: function(a) {
-        return new Date(a)
-    },
-    diff: function(b, a, c) {
-        if (isFinite(b)) {
-            b = new Date(b)
-        }
-        if (isFinite(a)) {
-            a = new Date(a)
-        }
-        return Ext.Date.diff(b, a, c)
-    },
-    align: function(a, c, b) {
-        if (b === "d" && c >= 7) {
-            a = Ext.Date.align(a, "d", c);
-            a.setDate(a.getDate() - a.getDay() + 1);
-            return a
-        } else {
-            return Ext.Date.align(a, b, c)
-        }
-    },
-    add: function(c, b, a) {
-        return Ext.Date.add(new Date(c), a, b)
-    },
-    stepUnits: [
-        [Ext.Date.YEAR, 1, 2, 5, 10, 20, 50, 100, 200, 500],
-        [Ext.Date.MONTH, 1, 3, 6],
-        [Ext.Date.DAY, 1, 7, 14],
-        [Ext.Date.HOUR, 1, 6, 12],
-        [Ext.Date.MINUTE, 1, 5, 15, 30],
-        [Ext.Date.SECOND, 1, 5, 15, 30],
-        [Ext.Date.MILLI, 1, 2, 5, 10, 20, 50, 100, 200, 500]
-    ],
-    preferredStep: function(b, e) {
-        if (this.getStep()) {
-            return this.getStep()
-        }
-        var f = new Date(+b),
-            g = new Date(+b + Math.ceil(e)),
-            d = this.stepUnits,
-            l, k, h, c, a;
-        for (c = 0; c < d.length; c++) {
-            k = d[c][0];
-            h = this.diff(f, g, k);
-            if (h > 0) {
-                for (a = 1; a < d[c].length; a++) {
-                    if (h <= d[c][a]) {
-                        l = {
-                            unit: k,
-                            step: d[c][a]
-                        };
-                        break
-                    }
-                }
-                if (!l) {
-                    c--;
-                    l = {
-                        unit: d[c][0],
-                        step: 1
-                    }
-                }
-                break
-            }
-        }
-        if (!l) {
-            l = {
-                unit: Ext.Date.DAY,
-                step: 1
-            }
-        }
-        return l
-    }
-});
-Ext.define("Ext.chart.axis.layout.Layout", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    processData: function(b) {
-        var e = this,
-            c = e.getAxis(),
-            f = c.getDirection(),
-            g = c.boundSeries,
-            a, d;
-        if (b) {
-            b["coordinate" + f]()
-        } else {
-            for (a = 0, d = g.length; a < d; a++) {
-                g[a]["coordinate" + f]()
-            }
-        }
-    },
-    calculateMajorTicks: function(a) {
-        var f = this,
-            e = a.attr,
-            d = e.max - e.min,
-            i = d / Math.max(1, e.length) * (e.visibleMax - e.visibleMin),
-            h = e.min + d * e.visibleMin,
-            b = e.min + d * e.visibleMax,
-            g = e.estStepSize * i,
-            c = f.snapEnds(a, e.min, e.max, g);
-        if (c) {
-            f.trimByRange(a, c, h, b);
-            a.majorTicks = c
-        }
-    },
-    calculateMinorTicks: function(a) {
-        if (this.snapMinorEnds) {
-            a.minorTicks = this.snapMinorEnds(a)
-        }
-    },
-    calculateLayout: function(b) {
-        var c = this,
-            a = b.attr;
-        if (a.length === 0) {
-            return null
-        }
-        if (a.majorTicks) {
-            c.calculateMajorTicks(b);
-            if (a.minorTicks) {
-                c.calculateMinorTicks(b)
-            }
-        }
-    },
-    snapEnds: Ext.emptyFn,
-    trimByRange: function(b, f, i, a) {
-        var g = b.segmenter,
-            j = f.unit,
-            h = g.diff(f.from, i, j),
-            d = g.diff(f.from, a, j),
-            c = Math.max(0, Math.ceil(h / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = g.add(f.from, e * f.step, j)
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < i) {
-            f.from = g.add(f.from, c * f.step, j);
-            while (f.from < i) {
-                c++;
-                f.from = g.add(f.from, f.step, j)
-            }
-        }
-        if (f.min < i) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    }
-});
-Ext.define("Ext.chart.axis.layout.Discrete", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.discrete",
-    isDiscrete: true,
-    processData: function() {
-        var f = this,
-            d = f.getAxis(),
-            c = d.boundSeries,
-            g = d.getDirection(),
-            b, e, a;
-        f.labels = [];
-        f.labelMap = {};
-        for (b = 0, e = c.length; b < e; b++) {
-            a = c[b];
-            if (a["get" + g + "Axis"]() === d) {
-                a["coordinate" + g]()
-            }
-        }
-        d.getSprites()[0].setAttributes({
-            data: f.labels
-        });
-        f.fireEvent("datachange", f.labels)
-    },
-    calculateLayout: function(a) {
-        a.data = this.labels;
-        this.callParent([a])
-    },
-    calculateMajorTicks: function(a) {
-        var g = this,
-            f = a.attr,
-            d = a.data,
-            e = f.max - f.min,
-            j = e / Math.max(1, f.length) * (f.visibleMax - f.visibleMin),
-            i = f.min + e * f.visibleMin,
-            b = f.min + e * f.visibleMax,
-            h = f.estStepSize * j;
-        var c = g.snapEnds(a, Math.max(0, f.min), Math.min(f.max, d.length - 1), h);
-        if (c) {
-            g.trimByRange(a, c, i, b);
-            a.majorTicks = c
-        }
-    },
-    snapEnds: function(e, d, a, b) {
-        b = Math.ceil(b);
-        var c = Math.floor((a - d) / b),
-            f = e.data;
-        return {
-            min: d,
-            max: a,
-            from: d,
-            to: c * b + d,
-            step: b,
-            steps: c,
-            unit: 1,
-            getLabel: function(g) {
-                return f[this.from + this.step * g]
-            },
-            get: function(g) {
-                return this.from + this.step * g
-            }
-        }
-    },
-    trimByRange: function(b, f, h, a) {
-        var i = f.unit,
-            g = Math.ceil((h - f.from) / i) * i,
-            d = Math.floor((a - f.from) / i) * i,
-            c = Math.max(0, Math.ceil(g / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = e
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < h && f.step > 0) {
-            f.from = f.from + c * f.step * i;
-            while (f.from < h) {
-                c++;
-                f.from += f.step * i
-            }
-        }
-        if (f.min < h) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    },
-    getCoordFor: function(c, d, a, b) {
-        this.labels.push(c);
-        return this.labels.length - 1
-    }
-});
-Ext.define("Ext.chart.axis.layout.CombineDuplicate", {
-    extend: "Ext.chart.axis.layout.Discrete",
-    alias: "axisLayout.combineDuplicate",
-    getCoordFor: function(d, e, b, c) {
-        if (!(d in this.labelMap)) {
-            var a = this.labelMap[d] = this.labels.length;
-            this.labels.push(d);
-            return a
-        }
-        return this.labelMap[d]
-    }
-});
-Ext.define("Ext.chart.axis.layout.Continuous", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.continuous",
-    isContinuous: true,
-    config: {
-        adjustMinimumByMajorUnit: false,
-        adjustMaximumByMajorUnit: false
-    },
-    getCoordFor: function(c, d, a, b) {
-        return +c
-    },
-    snapEnds: function(a, d, i, h) {
-        var f = a.segmenter,
-            c = this.getAxis(),
-            l = c.getMajorTickSteps(),
-            e = l && f.exactStep ? f.exactStep(d, (i - d) / l) : f.preferredStep(d, h),
-            k = e.unit,
-            b = e.step,
-            j = f.align(d, b, k),
-            g = (l || f.diff(d, i, k)) + 1;
-        return {
-            min: f.from(d),
-            max: f.from(i),
-            from: j,
-            to: f.add(j, g * b, k),
-            step: b,
-            steps: g,
-            unit: k,
-            get: function(m) {
-                return f.add(this.from, this.step * m, k)
-            }
-        }
-    },
-    snapMinorEnds: function(a) {
-        var e = a.majorTicks,
-            m = this.getAxis().getMinorTickSteps(),
-            f = a.segmenter,
-            d = e.min,
-            i = e.max,
-            k = e.from,
-            l = e.unit,
-            b = e.step / m,
-            n = b * l.scale,
-            j = k - d,
-            c = Math.floor(j / n),
-            h = c + Math.floor((i - e.to) / n) + 1,
-            g = e.steps * m + h;
-        return {
-            min: d,
-            max: i,
-            from: d + j % n,
-            to: f.add(k, g * b, l),
-            step: b,
-            steps: g,
-            unit: l,
-            get: function(o) {
-                return (o % m + c + 1 !== 0) ? f.add(this.from, this.step * o, l) : null
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis", {
-    xtype: "axis",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.chart.axis.sprite.Axis", "Ext.chart.axis.segmenter.*", "Ext.chart.axis.layout.*"],
-    isAxis: true,
-    config: {
-        position: "bottom",
-        fields: [],
-        label: undefined,
-        grid: false,
-        limits: null,
-        renderer: null,
-        chart: null,
-        style: null,
-        margin: 0,
-        titleMargin: 4,
-        background: null,
-        minimum: NaN,
-        maximum: NaN,
-        reconcileRange: false,
-        minZoom: 1,
-        maxZoom: 10000,
-        layout: "continuous",
-        segmenter: "numeric",
-        hidden: false,
-        majorTickSteps: 0,
-        minorTickSteps: 0,
-        adjustByMajorUnit: true,
-        title: null,
-        increment: 0.5,
-        length: 0,
-        center: null,
-        radius: null,
-        totalAngle: Math.PI,
-        rotation: null,
-        labelInSpan: null,
-        visibleRange: [0, 1],
-        needHighPrecision: false,
-        linkedTo: null,
-        floating: null
-    },
-    titleOffset: 0,
-    spriteAnimationCount: 0,
-    prevMin: 0,
-    prevMax: 1,
-    boundSeries: [],
-    sprites: null,
-    surface: null,
-    range: null,
-    xValues: [],
-    yValues: [],
-    masterAxis: null,
-    applyRotation: function(b) {
-        var a = Math.PI * 2;
-        return (b % a + Math.PI) % a - Math.PI
-    },
-    updateRotation: function(b) {
-        var c = this.getSprites(),
-            a = this.getPosition();
-        if (!this.getHidden() && a === "angular" && c[0]) {
-            c[0].setAttributes({
-                baseRotation: b
-            })
-        }
-    },
-    applyTitle: function(c, b) {
-        var a;
-        if (Ext.isString(c)) {
-            c = {
-                text: c
-            }
-        }
-        if (!b) {
-            b = Ext.create("sprite.text", c);
-            if ((a = this.getSurface())) {
-                a.add(b)
-            }
-        } else {
-            b.setAttributes(c)
-        }
-        return b
-    },
-    applyFloating: function(b, a) {
-        if (b === null) {
-            b = {
-                value: null,
-                alongAxis: null
-            }
-        } else {
-            if (Ext.isNumber(b)) {
-                b = {
-                    value: b,
-                    alongAxis: null
-                }
-            }
-        }
-        if (Ext.isObject(b)) {
-            if (a && a.alongAxis) {
-                delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]
-            }
-            return b
-        }
-        return a
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        b.sprites = [];
-        b.labels = [];
-        b.floatingAxes = {};
-        a = a || {};
-        if (a.position === "angular") {
-            a.style = a.style || {};
-            a.style.estStepSize = 1
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.apply(b, arguments)
-    },
-    getAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "vertical";
-            case "top":
-            case "bottom":
-                return "horizontal";
-            case "radial":
-                return "radial";
-            case "angular":
-                return "angular"
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal";
-            case "top":
-            case "bottom":
-                return "vertical";
-            case "radial":
-                return "circular";
-            case "angular":
-                return "radial"
-        }
-    },
-    getSurface: function() {
-        var e = this,
-            d = e.getChart();
-        if (d && !e.surface) {
-            var b = e.surface = d.getSurface(e.getId(), "axis"),
-                c = e.gridSurface = d.getSurface("main"),
-                a = e.getSprites()[0],
-                f = e.getGridAlignment();
-            c.waitFor(b);
-            e.getGrid();
-            if (e.getLimits() && f) {
-                f = f.replace("3d", "");
-                e.limits = {
-                    surface: d.getSurface("overlay"),
-                    lines: new Ext.chart.Markers(),
-                    titles: new Ext.draw.sprite.Instancing()
-                };
-                e.limits.lines.setTemplate({
-                    xclass: "grid." + f
-                });
-                e.limits.lines.getTemplate().setAttributes({
-                    strokeStyle: "black"
-                }, true);
-                e.limits.surface.add(e.limits.lines);
-                a.bindMarker(f + "-limit-lines", e.limits.lines);
-                e.limitTitleTpl = new Ext.draw.sprite.Text();
-                e.limits.titles.setTemplate(e.limitTitleTpl);
-                e.limits.surface.add(e.limits.titles);
-                d.on("redraw", e.renderLimits, e)
-            }
-        }
-        return e.surface
-    },
-    applyGrid: function(a) {
-        if (a === true) {
-            return {}
-        }
-        return a
-    },
-    updateGrid: function(b) {
-        var e = this,
-            d = e.getChart();
-        if (!d) {
-            e.on({
-                chartattached: Ext.bind(e.updateGrid, e, [b]),
-                single: true
-            });
-            return
-        }
-        var c = e.gridSurface,
-            a = e.getSprites()[0],
-            f = e.getGridAlignment(),
-            g;
-        if (b) {
-            g = e.gridSpriteEven;
-            if (!g) {
-                g = e.gridSpriteEven = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-even", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.even)) {
-                    g.getTemplate().setAttributes(b.even)
-                }
-            }
-            g = e.gridSpriteOdd;
-            if (!g) {
-                g = e.gridSpriteOdd = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-odd", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.odd)) {
-                    g.getTemplate().setAttributes(b.odd)
-                }
-            }
-        }
-    },
-    renderLimits: function() {
-        this.getSprites()[0].renderLimits()
-    },
-    getCoordFor: function(c, d, a, b) {
-        return this.getLayout().getCoordFor(c, d, a, b)
-    },
-    applyPosition: function(a) {
-        return a.toLowerCase()
-    },
-    applyLength: function(b, a) {
-        return b > 0 ? b : a
-    },
-    applyLabel: function(b, a) {
-        if (!a) {
-            a = new Ext.draw.sprite.Text({})
-        }
-        if (this.limitTitleTpl) {
-            this.limitTitleTpl.setAttributes(b)
-        }
-        a.setAttributes(b);
-        return a
-    },
-    applyLayout: function(b, a) {
-        b = Ext.factory(b, null, a, "axisLayout");
-        b.setAxis(this);
-        return b
-    },
-    applySegmenter: function(a, b) {
-        a = Ext.factory(a, null, b, "segmenter");
-        a.setAxis(this);
-        return a
-    },
-    updateMinimum: function() {
-        this.range = null
-    },
-    updateMaximum: function() {
-        this.range = null
-    },
-    hideLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: true
-        })
-    },
-    showLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: false
-        })
-    },
-    renderFrame: function() {
-        this.getSurface().renderFrame()
-    },
-    updateChart: function(d, b) {
-        var c = this,
-            a;
-        if (b) {
-            b.unregister(c);
-            b.un("serieschange", c.onSeriesChange, c);
-            b.un("redraw", c.renderLimits, c);
-            c.linkAxis();
-            c.fireEvent("chartdetached", b, c)
-        }
-        if (d) {
-            d.on("serieschange", c.onSeriesChange, c);
-            c.surface = null;
-            a = c.getSurface();
-            c.getLabel().setSurface(a);
-            a.add(c.getSprites());
-            a.add(c.getTitle());
-            d.register(c);
-            c.fireEvent("chartattached", d, c)
-        }
-    },
-    applyBackground: function(a) {
-        var b = Ext.ClassManager.getByAlias("sprite.rect");
-        return b.def.normalize(a)
-    },
-    processData: function() {
-        this.getLayout().processData();
-        this.range = null
-    },
-    getDirection: function() {
-        return this.getChart().getDirectionForAxis(this.getPosition())
-    },
-    isSide: function() {
-        var a = this.getPosition();
-        return a === "left" || a === "right"
-    },
-    applyFields: function(a) {
-        return Ext.Array.from(a)
-    },
-    applyVisibleRange: function(a, c) {
-        this.getChart();
-        if (a[0] > a[1]) {
-            var b = a[0];
-            a[0] = a[1];
-            a[0] = b
-        }
-        if (a[1] === a[0]) {
-            a[1] += 1 / this.getMaxZoom()
-        }
-        if (a[1] > a[0] + 1) {
-            a[0] = 0;
-            a[1] = 1
-        } else {
-            if (a[0] < 0) {
-                a[1] -= a[0];
-                a[0] = 0
-            } else {
-                if (a[1] > 1) {
-                    a[0] -= a[1] - 1;
-                    a[1] = 1
-                }
-            }
-        }
-        if (c && a[0] === c[0] && a[1] === c[1]) {
-            return undefined
-        }
-        return a
-    },
-    updateVisibleRange: function(a) {
-        this.fireEvent("visiblerangechange", this, a)
-    },
-    onSeriesChange: function(e) {
-        var f = this,
-            b = e.getSeries(),
-            j = "get" + f.getDirection() + "Axis",
-            g = [],
-            c, d = b.length,
-            a, h;
-        for (c = 0; c < d; c++) {
-            if (this === b[c][j]()) {
-                g.push(b[c])
-            }
-        }
-        f.boundSeries = g;
-        a = f.getLinkedTo();
-        h = !Ext.isEmpty(a) && e.getAxis(a);
-        if (h) {
-            f.linkAxis(h)
-        } else {
-            f.getLayout().processData()
-        }
-    },
-    linkAxis: function(a) {
-        var c = this;
-
-        function b(f, d, e) {
-            e.getLayout()[f]("datachange", "onDataChange", d);
-            e[f]("rangechange", "onMasterAxisRangeChange", d)
-        }
-        if (c.masterAxis) {
-            b("un", c, c.masterAxis);
-            c.masterAxis = null
-        }
-        if (a) {
-            if (a.type !== this.type) {
-                Ext.Error.raise("Linked axes must be of the same type.")
-            }
-            b("on", c, a);
-            c.onDataChange(a.getLayout().labels);
-            c.onMasterAxisRangeChange(a, a.range);
-            c.setStyle(Ext.apply({}, c.config.style, a.config.style));
-            c.setTitle(Ext.apply({}, c.config.title, a.config.title));
-            c.setLabel(Ext.apply({}, c.config.label, a.config.label));
-            c.masterAxis = a
-        }
-    },
-    onDataChange: function(a) {
-        this.getLayout().labels = a
-    },
-    onMasterAxisRangeChange: function(b, a) {
-        this.range = a
-    },
-    applyRange: function(a) {
-        if (!a) {
-            return this.dataRange.slice(0)
-        } else {
-            return [a[0] === null ? this.dataRange[0] : a[0], a[1] === null ? this.dataRange[1] : a[1]]
-        }
-    },
-    getRange: function() {
-        var m = this;
-        if (m.range) {
-            return m.range
-        } else {
-            if (m.masterAxis) {
-                return m.masterAxis.range
-            }
-        }
-        if (Ext.isNumber(m.getMinimum() + m.getMaximum())) {
-            return m.range = [m.getMinimum(), m.getMaximum()]
-        }
-        var d = Infinity,
-            n = -Infinity,
-            o = m.boundSeries,
-            h = m.getLayout(),
-            l = m.getSegmenter(),
-            p = m.getVisibleRange(),
-            b = "get" + m.getDirection() + "Range",
-            a, j, g, f, e, k;
-        for (e = 0, k = o.length; e < k; e++) {
-            f = o[e];
-            var c = f[b]();
-            if (c) {
-                if (c[0] < d) {
-                    d = c[0]
-                }
-                if (c[1] > n) {
-                    n = c[1]
-                }
-            }
-        }
-        if (!isFinite(n)) {
-            n = m.prevMax
-        }
-        if (!isFinite(d)) {
-            d = m.prevMin
-        }
-        if (m.getLabelInSpan() || d === n) {
-            n += m.getIncrement();
-            d -= m.getIncrement()
-        }
-        if (Ext.isNumber(m.getMinimum())) {
-            d = m.getMinimum()
-        } else {
-            m.prevMin = d
-        }
-        if (Ext.isNumber(m.getMaximum())) {
-            n = m.getMaximum()
-        } else {
-            m.prevMax = n
-        }
-        m.range = [Ext.Number.correctFloat(d), Ext.Number.correctFloat(n)];
-        if (m.getReconcileRange()) {
-            m.reconcileRange()
-        }
-        if (m.getAdjustByMajorUnit() && l.adjustByMajorUnit && !m.getMajorTickSteps()) {
-            j = Ext.Object.chain(m.getSprites()[0].attr);
-            j.min = m.range[0];
-            j.max = m.range[1];
-            j.visibleMin = p[0];
-            j.visibleMax = p[1];
-            a = {
-                attr: j,
-                segmenter: l
-            };
-            h.calculateLayout(a);
-            g = a.majorTicks;
-            if (g) {
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range);
-                j.min = m.range[0];
-                j.max = m.range[1];
-                delete a.majorTicks;
-                h.calculateLayout(a);
-                g = a.majorTicks;
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range)
-            } else {
-                if (!m.hasClearRangePending) {
-                    m.hasClearRangePending = true;
-                    m.getChart().on("layout", "clearRange", m)
-                }
-            }
-        }
-        if (!Ext.Array.equals(m.range, m.oldRange || [])) {
-            m.fireEvent("rangechange", m, m.range);
-            m.oldRange = m.range
-        }
-        return m.range
-    },
-    clearRange: function() {
-        delete this.hasClearRangePending;
-        this.range = null
-    },
-    reconcileRange: function() {
-        var e = this,
-            g = e.getChart().getAxes(),
-            f = e.getDirection(),
-            b, d, c, a;
-        if (!g) {
-            return
-        }
-        for (b = 0, d = g.length; b < d; b++) {
-            c = g[b];
-            a = c.getRange();
-            if (c === e || c.getDirection() !== f || !a || !c.getReconcileRange()) {
-                continue
-            }
-            if (a[0] < e.range[0]) {
-                e.range[0] = a[0]
-            }
-            if (a[1] > e.range[1]) {
-                e.range[1] = a[1]
-            }
-        }
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.getByAlias("sprite." + this.seriesType);
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        b = Ext.apply(b || {}, c);
-        return b
-    },
-    themeOnlyIfConfigured: {
-        grid: true
-    },
-    updateTheme: function(d) {
-        var i = this,
-            k = d.getAxis(),
-            e = i.getPosition(),
-            o = i.getInitialConfig(),
-            c = i.defaultConfig,
-            g = i.getConfigurator().configs,
-            a = k.defaults,
-            n = k[e],
-            h = i.themeOnlyIfConfigured,
-            l, j, p, b, m, f;
-        k = Ext.merge({}, a, n);
-        for (l in k) {
-            j = k[l];
-            f = g[l];
-            if (j !== null && j !== undefined && f) {
-                m = o[l];
-                p = Ext.isObject(j);
-                b = m === c[l];
-                if (p) {
-                    if (b && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (b || p) {
-                    i[f.names.set](j)
-                }
-            }
-        }
-    },
-    updateCenter: function(b) {
-        var e = this.getSprites(),
-            a = e[0],
-            d = b[0],
-            c = b[1];
-        if (a) {
-            a.setAttributes({
-                centerX: d,
-                centerY: c
-            })
-        }
-        if (this.gridSpriteEven) {
-            this.gridSpriteEven.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-        if (this.gridSpriteOdd) {
-            this.gridSpriteOdd.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-    },
-    getSprites: function() {
-        if (!this.getChart()) {
-            return
-        }
-        var i = this,
-            e = i.getRange(),
-            f = i.getPosition(),
-            g = i.getChart(),
-            c = g.getAnimation(),
-            d, a, b = i.getLength(),
-            h = i.superclass;
-        if (c === false) {
-            c = {
-                duration: 0
-            }
-        }
-        if (e) {
-            a = Ext.applyIf({
-                position: f,
-                axis: i,
-                min: e[0],
-                max: e[1],
-                length: b,
-                grid: i.getGrid(),
-                hidden: i.getHidden(),
-                titleOffset: i.titleOffset,
-                layout: i.getLayout(),
-                segmenter: i.getSegmenter(),
-                totalAngle: i.getTotalAngle(),
-                label: i.getLabel()
-            }, i.getStyle());
-            if (!i.sprites.length) {
-                while (!h.xtype) {
-                    h = h.superclass
-                }
-                d = Ext.create("sprite." + h.xtype, a);
-                d.fx.setCustomDurations({
-                    baseRotation: 0
-                });
-                d.fx.on("animationstart", "onAnimationStart", i);
-                d.fx.on("animationend", "onAnimationEnd", i);
-                d.setLayout(i.getLayout());
-                d.setSegmenter(i.getSegmenter());
-                d.setLabel(i.getLabel());
-                i.sprites.push(d);
-                i.updateTitleSprite()
-            } else {
-                d = i.sprites[0];
-                d.setAnimation(c);
-                d.setAttributes(a)
-            }
-            if (i.getRenderer()) {
-                d.setRenderer(i.getRenderer())
-            }
-        }
-        return i.sprites
-    },
-    updateTitleSprite: function() {
-        var f = this,
-            b = f.getLength();
-        if (!f.sprites[0] || !Ext.isNumber(b)) {
-            return
-        }
-        var h = this.sprites[0].thickness,
-            a = f.getSurface(),
-            g = f.getTitle(),
-            e = f.getPosition(),
-            c = f.getMargin(),
-            i = f.getTitleMargin(),
-            d = a.roundPixel(b / 2);
-        if (g) {
-            switch (e) {
-                case "top":
-                    g.setAttributes({
-                        x: d,
-                        y: c + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "bottom":
-                    g.setAttributes({
-                        x: d,
-                        y: h + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "left":
-                    g.setAttributes({
-                        x: c + i / 2,
-                        y: d,
-                        textBaseline: "top",
-                        textAlign: "center",
-                        rotationCenterX: c + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: -Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break;
-                case "right":
-                    g.setAttributes({
-                        x: h - c + i / 2,
-                        y: d,
-                        textBaseline: "bottom",
-                        textAlign: "center",
-                        rotationCenterX: h + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        this.getChart().onThicknessChanged()
-    },
-    getThickness: function() {
-        if (this.getHidden()) {
-            return 0
-        }
-        return (this.sprites[0] && this.sprites[0].thickness || 1) + this.titleOffset + this.getMargin()
-    },
-    onAnimationStart: function() {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart", this)
-        }
-    },
-    onAnimationEnd: function() {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend", this)
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    getAncestorIds: function() {
-        return [this.getChart().getId()]
-    },
-    isXType: function(a) {
-        return a === "axis"
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        a.surface.destroy();
-        a.surface = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.chart.LegendBase", {
-    extend: "Ext.view.View",
-    config: {
-        tpl: ['<div class="', Ext.baseCSSPrefix, 'legend-container">', '<tpl for=".">', '<div class="', Ext.baseCSSPrefix, 'legend-item">', "<span ", 'class="', Ext.baseCSSPrefix, "legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ", 'style="background:{mark};">', "</span>{name}", "</div>", "</tpl>", "</div>"],
-        nodeContainerSelector: "div." + Ext.baseCSSPrefix + "legend-container",
-        itemSelector: "div." + Ext.baseCSSPrefix + "legend-item",
-        docked: "bottom"
-    },
-    setDocked: function(d) {
-        var c = this,
-            a = c.ownerCt,
-            b;
-        c.docked = d;
-        switch (d) {
-            case "top":
-            case "bottom":
-                c.addCls(Ext.baseCSSPrefix + "horizontal");
-                b = "hbox";
-                break;
-            case "left":
-            case "right":
-                c.removeCls(Ext.baseCSSPrefix + "horizontal");
-                b = "vbox";
-                break
-        }
-        if (a) {
-            a.setDocked(d)
-        }
-    },
-    setStore: function(a) {
-        this.bindStore(a)
-    },
-    clearViewEl: function() {
-        this.callParent(arguments);
-        Ext.removeNode(this.getNodeContainer())
-    },
-    onItemClick: function(a, c, b, d) {
-        this.callParent(arguments);
-        this.toggleItem(b)
-    }
-});
-Ext.define("Ext.chart.Legend", {
-    xtype: "legend",
-    extend: "Ext.chart.LegendBase",
-    config: {
-        baseCls: Ext.baseCSSPrefix + "legend",
-        padding: 5,
-        rect: null,
-        disableSelection: true,
-        toggleable: true
-    },
-    toggleItem: function(c) {
-        if (!this.getToggleable()) {
-            return
-        }
-        var b = this.getStore(),
-            h = 0,
-            e, g = true,
-            d, f, a;
-        if (b) {
-            f = b.getCount();
-            for (d = 0; d < f; d++) {
-                a = b.getAt(d);
-                if (a.get("disabled")) {
-                    h++
-                }
-            }
-            g = f - h > 1;
-            a = b.getAt(c);
-            if (a) {
-                e = a.get("disabled");
-                if (e || g) {
-                    a.set("disabled", !e)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.AbstractChart", {
-    extend: "Ext.draw.Container",
-    requires: ["Ext.chart.theme.Default", "Ext.chart.series.Series", "Ext.chart.interactions.Abstract", "Ext.chart.axis.Axis", "Ext.data.StoreManager", "Ext.chart.Legend", "Ext.data.Store"],
-    isChart: true,
-    defaultBindProperty: "store",
-    config: {
-        store: "ext-empty-store",
-        theme: "default",
-        style: null,
-        animation: !Ext.isIE8,
-        series: [],
-        axes: [],
-        legend: null,
-        colors: null,
-        insetPadding: {
-            top: 10,
-            left: 10,
-            right: 10,
-            bottom: 10
-        },
-        background: null,
-        interactions: [],
-        mainRect: null,
-        resizeHandler: null,
-        highlightItem: null
-    },
-    animationSuspendCount: 0,
-    chartLayoutSuspendCount: 0,
-    axisThicknessSuspendCount: 0,
-    isThicknessChanged: false,
-    surfaceZIndexes: {
-        background: 0,
-        main: 1,
-        grid: 2,
-        series: 3,
-        axis: 4,
-        chart: 5,
-        overlay: 6,
-        events: 7
-    },
-    constructor: function(a) {
-        var b = this;
-        b.itemListeners = {};
-        b.surfaceMap = {};
-        b.chartComponents = {};
-        b.isInitializing = true;
-        b.suspendChartLayout();
-        b.animationSuspendCount++;
-        b.callParent(arguments);
-        delete b.isInitializing;
-        b.getSurface("main");
-        b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);
-        b.getSurface("overlay").waitFor(b.getSurface("series"));
-        b.animationSuspendCount--;
-        b.resumeChartLayout()
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        if (this.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    applyInsetPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    suspendAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            e = c.length,
-            b = -1,
-            a;
-        d.animationSuspendCount++;
-        if (d.animationSuspendCount === 1) {
-            while (++b < e) {
-                a = c[b];
-                a.setAnimation(a.getAnimation())
-            }
-        }
-    },
-    resumeAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            f = c.length,
-            b = -1,
-            a, e;
-        d.animationSuspendCount--;
-        if (d.animationSuspendCount === 0) {
-            while (++b < f) {
-                a = c[b];
-                e = a.getAnimation();
-                a.setAnimation(e.duration && e || d.getAnimation())
-            }
-        }
-    },
-    suspendChartLayout: function() {
-        this.chartLayoutSuspendCount++;
-        if (this.chartLayoutSuspendCount === 1) {
-            if (this.scheduledLayoutId) {
-                this.layoutInSuspension = true;
-                this.cancelChartLayout()
-            } else {
-                this.layoutInSuspension = false
-            }
-        }
-    },
-    resumeChartLayout: function() {
-        this.chartLayoutSuspendCount--;
-        if (this.chartLayoutSuspendCount === 0) {
-            if (this.layoutInSuspension) {
-                this.scheduleLayout()
-            }
-        }
-    },
-    cancelChartLayout: function() {
-        if (this.scheduledLayoutId) {
-            Ext.draw.Animator.cancel(this.scheduledLayoutId);
-            this.scheduledLayoutId = null
-        }
-    },
-    scheduleLayout: function() {
-        var a = this;
-        if (a.allowSchedule() && !a.scheduledLayoutId) {
-            a.scheduledLayoutId = Ext.draw.Animator.schedule("doScheduleLayout", a)
-        }
-    },
-    allowSchedule: function() {
-        return true
-    },
-    doScheduleLayout: function() {
-        if (this.chartLayoutSuspendCount) {
-            this.layoutInSuspension = true
-        } else {
-            this.performLayout()
-        }
-    },
-    suspendThicknessChanged: function() {
-        this.axisThicknessSuspendCount++
-    },
-    resumeThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount > 0) {
-            this.axisThicknessSuspendCount--;
-            if (this.axisThicknessSuspendCount === 0 && this.isThicknessChanged) {
-                this.onThicknessChanged()
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount === 0) {
-            this.isThicknessChanged = false;
-            this.performLayout()
-        } else {
-            this.isThicknessChanged = true
-        }
-    },
-    applySprites: function(b) {
-        var a = this.getSurface("chart");
-        b = Ext.Array.from(b);
-        a.removeAll(true);
-        a.add(b);
-        return b
-    },
-    initItems: function() {
-        var a = this.items,
-            b, d, c;
-        if (a && !a.isMixedCollection) {
-            this.items = [];
-            a = Ext.Array.from(a);
-            for (b = 0, d = a.length; b < d; b++) {
-                c = a[b];
-                if (c.type) {
-                    Ext.raise("To add custom sprites to the chart use the 'sprites' config.")
-                } else {
-                    this.items.push(c)
-                }
-            }
-        }
-        this.callParent()
-    },
-    applyBackground: function(c, e) {
-        var b = this.getSurface("background"),
-            d, a, f;
-        if (c) {
-            if (e) {
-                d = e.attr.width;
-                a = e.attr.height;
-                f = e.type === (c.type || "rect")
-            }
-            if (c.isSprite) {
-                e = c
-            } else {
-                if (c.type === "image" && Ext.isString(c.src)) {
-                    if (f) {
-                        e.setAttributes({
-                            src: c.src
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add(c)
-                    }
-                } else {
-                    if (f) {
-                        e.setAttributes({
-                            fillStyle: c
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add({
-                            type: "rect",
-                            fillStyle: c,
-                            fx: {
-                                customDurations: {
-                                    x: 0,
-                                    y: 0,
-                                    width: 0,
-                                    height: 0
-                                }
-                            }
-                        })
-                    }
-                }
-            }
-        }
-        if (d && a) {
-            e.setAttributes({
-                width: d,
-                height: a
-            })
-        }
-        e.setAnimation(this.getAnimation());
-        return e
-    },
-    getLegendStore: function() {
-        return this.legendStore
-    },
-    refreshLegendStore: function() {
-        if (this.getLegendStore()) {
-            var d, e, c = this.getSeries(),
-                b, a = [];
-            if (c) {
-                for (d = 0, e = c.length; d < e; d++) {
-                    b = c[d];
-                    if (b.getShowInLegend()) {
-                        b.provideLegendInfo(a)
-                    }
-                }
-            }
-            this.getLegendStore().setData(a)
-        }
-    },
-    resetLegendStore: function() {
-        var c = this.getLegendStore(),
-            e, d, a, b;
-        if (c) {
-            e = this.getLegendStore().getData().items;
-            for (d = 0, a = e.length; d < a; d++) {
-                b = e[d];
-                b.beginEdit();
-                b.set("disabled", false);
-                b.commit()
-            }
-        }
-    },
-    onUpdateLegendStore: function(b, a) {
-        var d = this.getSeries(),
-            c;
-        if (a && d) {
-            c = d.map[a.get("series")];
-            if (c) {
-                c.setHiddenByIndex(a.get("index"), a.get("disabled"));
-                this.redraw()
-            }
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.scheduleLayout();
-        return false
-    },
-    applyMainRect: function(a, b) {
-        if (!b) {
-            return a
-        }
-        this.getSeries();
-        this.getAxes();
-        if (a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return b
-        } else {
-            return a
-        }
-    },
-    register: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        b[c] = a
-    },
-    unregister: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        delete b[c]
-    },
-    get: function(a) {
-        return this.chartComponents[a]
-    },
-    getAxis: function(a) {
-        if (a instanceof Ext.chart.axis.Axis) {
-            return a
-        } else {
-            if (Ext.isNumber(a)) {
-                return this.getAxes()[a]
-            } else {
-                if (Ext.isString(a)) {
-                    return this.get(a)
-                }
-            }
-        }
-    },
-    getSurface: function(b, c) {
-        b = b || "main";
-        c = c || b;
-        var d = this,
-            a = this.callParent([b]),
-            f = d.surfaceZIndexes,
-            e = d.surfaceMap;
-        if (c in f) {
-            a.element.setStyle("zIndex", f[c])
-        }
-        if (!e[c]) {
-            e[c] = []
-        }
-        if (Ext.Array.indexOf(e[c], a) < 0) {
-            a.type = c;
-            e[c].push(a);
-            a.on("destroy", d.forgetSurface, d)
-        }
-        return a
-    },
-    forgetSurface: function(a) {
-        var d = this.surfaceMap;
-        if (!d || this.isDestroying) {
-            return
-        }
-        var c = d[a.type],
-            b = c ? Ext.Array.indexOf(c, a) : -1;
-        if (b >= 0) {
-            c.splice(b, 1)
-        }
-    },
-    applyAxes: function(b, k) {
-        var l = this,
-            g = {
-                left: "right",
-                right: "left"
-            },
-            m = [],
-            c, d, e, a, f, h, j;
-        l.animationSuspendCount++;
-        l.getStore();
-        if (!k) {
-            k = [];
-            k.map = {}
-        }
-        j = k.map;
-        m.map = {};
-        b = Ext.Array.from(b, true);
-        for (f = 0, h = b.length; f < h; f++) {
-            c = b[f];
-            if (!c) {
-                continue
-            }
-            if (c instanceof Ext.chart.axis.Axis) {
-                d = j[c.getId()];
-                c.setChart(l)
-            } else {
-                c = Ext.Object.chain(c);
-                e = c.linkedTo;
-                a = c.id;
-                if (Ext.isNumber(e)) {
-                    c = Ext.merge({}, b[e], c)
-                } else {
-                    if (Ext.isString(e)) {
-                        Ext.Array.each(b, function(i) {
-                            if (i.id === c.linkedTo) {
-                                c = Ext.merge({}, i, c);
-                                return false
-                            }
-                        })
-                    }
-                }
-                c.id = a;
-                c.chart = l;
-                if (l.getInherited().rtl) {
-                    c.position = g[c.position] || c.position
-                }
-                a = c.getId && c.getId() || c.id;
-                c = Ext.factory(c, null, d = j[a], "axis")
-            }
-            if (c) {
-                m.push(c);
-                m.map[c.getId()] = c;
-                if (!d) {
-                    c.on("animationstart", "onAnimationStart", l);
-                    c.on("animationend", "onAnimationEnd", l)
-                }
-            }
-        }
-        for (f in j) {
-            if (!m.map[f]) {
-                j[f].destroy()
-            }
-        }
-        l.animationSuspendCount--;
-        return m
-    },
-    updateAxes: function() {
-        if (!this.isDestroying) {
-            this.scheduleLayout()
-        }
-    },
-    circularCopyArray: function(e, f, d) {
-        var c = [],
-            b, a = e && e.length;
-        if (a) {
-            for (b = 0; b < d; b++) {
-                c.push(e[(f + b) % a])
-            }
-        }
-        return c
-    },
-    circularCopyObject: function(f, g, d) {
-        var c = this,
-            b, e, a = {};
-        if (d) {
-            for (b in f) {
-                if (f.hasOwnProperty(b)) {
-                    e = f[b];
-                    if (Ext.isArray(e)) {
-                        a[b] = c.circularCopyArray(e, g, d)
-                    } else {
-                        a[b] = e
-                    }
-                }
-            }
-        }
-        return a
-    },
-    getColors: function() {
-        var b = this,
-            a = b.config.colors,
-            c = b.getTheme();
-        if (Ext.isArray(a) && a.length > 0) {
-            a = b.applyColors(a)
-        }
-        return a || (c && c.getColors())
-    },
-    applyColors: function(a) {
-        a = Ext.Array.map(a, function(b) {
-            if (Ext.isString(b)) {
-                return b
-            } else {
-                return b.toString()
-            }
-        });
-        return a
-    },
-    updateColors: function(c) {
-        var k = this,
-            e = k.getTheme(),
-            a = c || (e && e.getColors()),
-            l = 0,
-            f = k.getSeries(),
-            d = f && f.length,
-            g, j, b, h;
-        if (a.length) {
-            for (g = 0; g < d; g++) {
-                j = f[g];
-                h = j.themeColorCount();
-                b = k.circularCopyArray(a, l, h);
-                l += h;
-                j.updateChartColors(b)
-            }
-        }
-        k.refreshLegendStore()
-    },
-    applyTheme: function(a) {
-        if (a && a.isTheme) {
-            return a
-        }
-        return Ext.Factory.chartTheme(a)
-    },
-    updateTheme: function(g) {
-        var e = this,
-            f = e.getAxes(),
-            d = e.getSeries(),
-            a = e.getColors(),
-            c, b;
-        e.updateChartTheme(g);
-        for (b = 0; b < f.length; b++) {
-            f[b].updateTheme(g)
-        }
-        for (b = 0; b < d.length; b++) {
-            c = d[b];
-            c.updateTheme(g)
-        }
-        e.updateSpriteTheme(g);
-        e.updateColors(a);
-        e.redraw()
-    },
-    themeOnlyIfConfigured: {},
-    updateChartTheme: function(c) {
-        var i = this,
-            k = c.getChart(),
-            n = i.getInitialConfig(),
-            b = i.defaultConfig,
-            e = i.getConfigurator().configs,
-            f = k.defaults,
-            g = k[i.xtype],
-            h = i.themeOnlyIfConfigured,
-            l, j, o, a, m, d;
-        k = Ext.merge({}, f, g);
-        for (l in k) {
-            j = k[l];
-            d = e[l];
-            if (j !== null && j !== undefined && d) {
-                m = n[l];
-                o = Ext.isObject(j);
-                a = m === b[l];
-                if (o) {
-                    if (a && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (a || o) {
-                    i[d.names.set](j)
-                }
-            }
-        }
-    },
-    updateSpriteTheme: function(c) {
-        this.getSprites();
-        var j = this,
-            e = j.getSurface("chart"),
-            h = e.getItems(),
-            m = c.getSprites(),
-            k, a, l, f, d, b, g;
-        for (b = 0, g = h.length; b < g; b++) {
-            k = h[b];
-            a = m[k.type];
-            if (a) {
-                f = {};
-                d = k.type === "text";
-                for (l in a) {
-                    if (!(l in k.config)) {
-                        if (!(d && l.indexOf("font") === 0 && k.config.font)) {
-                            f[l] = a[l]
-                        }
-                    }
-                }
-                k.setAttributes(f)
-            }
-        }
-    },
-    addSeries: function(b) {
-        var a = this.getSeries();
-        Ext.Array.push(a, b);
-        this.setSeries(a)
-    },
-    removeSeries: function(d) {
-        d = Ext.Array.from(d);
-        var b = this.getSeries(),
-            f = [],
-            a = d.length,
-            g = {},
-            c, e;
-        for (c = 0; c < a; c++) {
-            e = d[c];
-            if (typeof e !== "string") {
-                e = e.getId()
-            }
-            g[e] = true
-        }
-        for (c = 0, a = b.length; c < a; c++) {
-            if (!g[b[c].getId()]) {
-                f.push(b[c])
-            }
-        }
-        this.setSeries(f)
-    },
-    applySeries: function(e, d) {
-        var g = this,
-            j = [],
-            h, a, c, f, b;
-        g.animationSuspendCount++;
-        g.getAxes();
-        if (d) {
-            h = d.map
-        } else {
-            d = [];
-            h = d.map = {}
-        }
-        j.map = {};
-        e = Ext.Array.from(e, true);
-        for (c = 0, f = e.length; c < f; c++) {
-            b = e[c];
-            if (!b) {
-                continue
-            }
-            a = h[b.getId && b.getId() || b.id];
-            if (b instanceof Ext.chart.series.Series) {
-                if (a && a !== b) {
-                    a.destroy()
-                }
-                b.setChart(g)
-            } else {
-                if (Ext.isObject(b)) {
-                    if (a) {
-                        a.setConfig(b);
-                        b = a
-                    } else {
-                        if (Ext.isString(b)) {
-                            b = {
-                                type: b
-                            }
-                        }
-                        b.chart = g;
-                        b = Ext.create(b.xclass || ("series." + b.type), b);
-                        b.on("animationstart", "onAnimationStart", g);
-                        b.on("animationend", "onAnimationEnd", g)
-                    }
-                }
-            }
-            j.push(b);
-            j.map[b.getId()] = b
-        }
-        for (c in h) {
-            if (!j.map[h[c].getId()]) {
-                h[c].destroy()
-            }
-        }
-        g.animationSuspendCount--;
-        return j
-    },
-    applyLegend: function(b, a) {
-        return Ext.factory(b, Ext.chart.Legend, a)
-    },
-    updateLegend: function(b, a) {
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            this.getItems();
-            this.legendStore = new Ext.data.Store({
-                autoDestroy: true,
-                fields: ["id", "name", "mark", "disabled", "series", "index"]
-            });
-            b.setStore(this.legendStore);
-            this.refreshLegendStore();
-            this.legendStore.on("update", "onUpdateLegendStore", this)
-        }
-    },
-    updateSeries: function(b, a) {
-        var c = this;
-        if (c.isDestroying) {
-            return
-        }
-        c.animationSuspendCount++;
-        c.fireEvent("serieschange", c, b, a);
-        c.refreshLegendStore();
-        if (!Ext.isEmpty(b)) {
-            c.updateTheme(c.getTheme())
-        }
-        c.scheduleLayout();
-        c.animationSuspendCount--
-    },
-    applyInteractions: function(h, d) {
-        if (!d) {
-            d = [];
-            d.map = {}
-        }
-        var g = this,
-            a = [],
-            c = d.map,
-            e, f, b;
-        a.map = {};
-        h = Ext.Array.from(h, true);
-        for (e = 0, f = h.length; e < f; e++) {
-            b = h[e];
-            if (!b) {
-                continue
-            }
-            b = Ext.factory(b, null, c[b.getId && b.getId() || b.id], "interaction");
-            if (b) {
-                b.setChart(g);
-                a.push(b);
-                a.map[b.getId()] = b
-            }
-        }
-        for (e in c) {
-            if (!a.map[e]) {
-                c[e].destroy()
-            }
-        }
-        return a
-    },
-    getInteraction: function(e) {
-        var f = this.getInteractions(),
-            a = f && f.length,
-            c = null,
-            b, d;
-        if (a) {
-            for (d = 0; d < a; ++d) {
-                b = f[d];
-                if (b.type === e) {
-                    c = b;
-                    break
-                }
-            }
-        }
-        return c
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    updateStore: function(a, c) {
-        var b = this;
-        if (c) {
-            c.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            });
-            if (c.autoDestroy) {
-                c.destroy()
-            }
-        }
-        if (a) {
-            a.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            })
-        }
-        b.fireEvent("storechange", b, a, c);
-        b.onDataChanged()
-    },
-    redraw: function() {
-        this.fireEvent("redraw", this)
-    },
-    performLayout: function() {
-        var d = this,
-            b = d.getChartSize(true),
-            c = [0, 0, b.width, b.height],
-            a = d.getBackground();
-        d.hasFirstLayout = true;
-        d.fireEvent("layout", d);
-        d.cancelChartLayout();
-        d.getSurface("background").setRect(c);
-        d.getSurface("chart").setRect(c);
-        a.setAttributes({
-            width: b.width,
-            height: b.height
-        })
-    },
-    getChartSize: function(b) {
-        var a = this;
-        if (b) {
-            a.chartSize = null
-        }
-        return a.chartSize || (a.chartSize = a.innerElement.getSize())
-    },
-    getEventXY: function(a) {
-        return this.getSurface().getEventXY(a)
-    },
-    getItemForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            e = f.getMainRect(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            c, j;
-        if (!(e && h >= 0 && h <= e[2] && g >= 0 && g <= e[3])) {
-            return null
-        }
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                return j
-            }
-        }
-        return null
-    },
-    getItemsForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            e = [],
-            c, j;
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                e.push(j)
-            }
-        }
-        return e
-    },
-    onAnimationStart: function() {
-        this.fireEvent("animationstart", this)
-    },
-    onAnimationEnd: function() {
-        this.fireEvent("animationend", this)
-    },
-    onDataChanged: function() {
-        var d = this;
-        if (d.isInitializing) {
-            return
-        }
-        var c = d.getMainRect(),
-            a = d.getStore(),
-            b = d.getSeries(),
-            e = d.getAxes();
-        if (!a || !e || !b) {
-            return
-        }
-        if (!c) {
-            d.on({
-                redraw: d.onDataChanged,
-                scope: d,
-                single: true
-            });
-            return
-        }
-        d.processData();
-        d.redraw()
-    },
-    recordCount: 0,
-    processData: function() {
-        var g = this,
-            e = g.getStore().getCount(),
-            c = g.getSeries(),
-            f = c.length,
-            d = false,
-            b = 0,
-            a;
-        for (; b < f; b++) {
-            a = c[b];
-            a.processData();
-            if (!d && a.isStoreDependantColorCount) {
-                d = true
-            }
-        }
-        if (d && e > g.recordCount) {
-            g.updateColors(g.getColors());
-            g.recordCount = e
-        }
-    },
-    bindStore: function(a) {
-        this.setStore(a)
-    },
-    applyHighlightItem: function(f, a) {
-        if (f === a) {
-            return
-        }
-        if (Ext.isObject(f) && Ext.isObject(a)) {
-            var e = f,
-                d = a,
-                c = e.sprite && (e.sprite[0] || e.sprite),
-                b = d.sprite && (d.sprite[0] || d.sprite);
-            if (c === b && e.index === d.index) {
-                return
-            }
-        }
-        return f
-    },
-    updateHighlightItem: function(b, a) {
-        if (a) {
-            a.series.setAttributesForItem(a, {
-                highlighted: false
-            })
-        }
-        if (b) {
-            b.series.setAttributesForItem(b, {
-                highlighted: true
-            });
-            this.fireEvent("itemhighlight", this, b, a)
-        }
-        this.fireEvent("itemhighlightchange", this, b, a)
-    },
-    destroyChart: function() {
-        var f = this,
-            d = f.getLegend(),
-            g = f.getAxes(),
-            c = f.getSeries(),
-            h = f.getInteractions(),
-            b = [],
-            a, e;
-        f.surfaceMap = null;
-        for (a = 0, e = h.length; a < e; a++) {
-            h[a].destroy()
-        }
-        for (a = 0, e = g.length; a < e; a++) {
-            g[a].destroy()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            c[a].destroy()
-        }
-        f.setInteractions(b);
-        f.setAxes(b);
-        f.setSeries(b);
-        if (d) {
-            d.destroy();
-            f.setLegend(null)
-        }
-        f.legendStore = null;
-        f.setStore(null);
-        f.cancelChartLayout()
-    },
-    getRefItems: function(b) {
-        var g = this,
-            e = g.getSeries(),
-            h = g.getAxes(),
-            a = g.getInteractions(),
-            c = [],
-            d, f;
-        for (d = 0, f = e.length; d < f; d++) {
-            c.push(e[d]);
-            if (e[d].getRefItems) {
-                c.push.apply(c, e[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = h.length; d < f; d++) {
-            c.push(h[d]);
-            if (h[d].getRefItems) {
-                c.push.apply(c, h[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = a.length; d < f; d++) {
-            c.push(a[d]);
-            if (a[d].getRefItems) {
-                c.push.apply(c, a[d].getRefItems(b))
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.overrides.AbstractChart", {
-    override: "Ext.chart.AbstractChart",
-    updateLegend: function(b, a) {
-        var c;
-        this.callParent([b, a]);
-        if (b) {
-            c = b.docked;
-            this.addDocked({
-                dock: c,
-                xtype: "panel",
-                shrinkWrap: true,
-                scrollable: true,
-                layout: {
-                    type: c === "top" || c === "bottom" ? "hbox" : "vbox",
-                    pack: "center"
-                },
-                items: b,
-                cls: Ext.baseCSSPrefix + "legend-panel"
-            })
-        }
-    },
-    performLayout: function() {
-        if (this.isVisible(true)) {
-            return this.callParent()
-        }
-        this.cancelChartLayout();
-        return false
-    },
-    afterComponentLayout: function(c, a, b, d) {
-        this.callParent([c, a, b, d]);
-        this.scheduleLayout()
-    },
-    allowSchedule: function() {
-        return this.rendered
-    },
-    onDestroy: function() {
-        this.destroyChart();
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.horizontal",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(b, c, e) {
-        var a = this.attr,
-            f = b.roundPixel(a.y),
-            d = c.lineWidth * 0.5;
-        c.beginPath();
-        c.rect(e[0] - b.matrix.getDX(), f + d, +e[2], a.height);
-        c.fill();
-        c.beginPath();
-        c.moveTo(e[0] - b.matrix.getDX(), f + d);
-        c.lineTo(e[0] + e[2] - b.matrix.getDX(), f + d);
-        c.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.vertical",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    }
-});
-Ext.define("Ext.chart.CartesianChart", {
-    extend: "Ext.chart.AbstractChart",
-    alternateClassName: "Ext.chart.Chart",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid"],
-    xtype: ["cartesian", "chart"],
-    isCartesian: true,
-    config: {
-        flipXY: false,
-        innerRect: [0, 0, 1, 1],
-        innerPadding: {
-            top: 0,
-            left: 0,
-            right: 0,
-            bottom: 0
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    getDirectionForAxis: function(a) {
-        var b = this.getFlipXY();
-        if (a === "left" || a === "right") {
-            if (b) {
-                return "X"
-            } else {
-                return "Y"
-            }
-        } else {
-            if (b) {
-                return "Y"
-            } else {
-                return "X"
-            }
-        }
-    },
-    performLayout: function() {
-        var A = this;
-        A.animationSuspendCount++;
-        if (A.callParent() === false) {
-            --A.animationSuspendCount;
-            return
-        }
-        A.suspendThicknessChanged();
-        var d = A.getSurface("chart").getRect(),
-            o = d[2],
-            n = d[3],
-            z = A.getAxes(),
-            b, q = A.getSeries(),
-            h, l, a, f = A.getInsetPadding(),
-            v = A.getInnerPadding(),
-            r, c, e = Ext.apply({}, f),
-            u, p, s, k, m, y, t, x, g, j = A.getInherited().rtl,
-            w = A.getFlipXY();
-        if (o <= 0 || n <= 0) {
-            return
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            m = b.getFloating();
-            y = m ? m.value : null;
-            a = b.getThickness();
-            switch (b.getPosition()) {
-                case "top":
-                    l.setRect([0, e.top + 1, o, a]);
-                    break;
-                case "bottom":
-                    l.setRect([0, n - (e.bottom + a), o, a]);
-                    break;
-                case "left":
-                    l.setRect([e.left, 0, a, n]);
-                    break;
-                case "right":
-                    l.setRect([o - (e.right + a), 0, a, n]);
-                    break
-            }
-            if (y === null) {
-                e[b.getPosition()] += a
-            }
-        }
-        o -= e.left + e.right;
-        n -= e.top + e.bottom;
-        u = [e.left, e.top, o, n];
-        e.left += v.left;
-        e.top += v.top;
-        e.right += v.right;
-        e.bottom += v.bottom;
-        p = o - v.left - v.right;
-        s = n - v.top - v.bottom;
-        A.setInnerRect([e.left, e.top, p, s]);
-        if (p <= 0 || s <= 0) {
-            return
-        }
-        A.setMainRect(u);
-        A.getSurface().setRect(u);
-        for (x = 0, g = A.surfaceMap.grid && A.surfaceMap.grid.length; x < g; x++) {
-            c = A.surfaceMap.grid[x];
-            c.setRect(u);
-            c.matrix.set(1, 0, 0, 1, v.left, v.top);
-            c.matrix.inverse(c.inverseMatrix)
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            t = l.matrix;
-            k = t.elements;
-            switch (b.getPosition()) {
-                case "top":
-                case "bottom":
-                    k[4] = e.left;
-                    b.setLength(p);
-                    break;
-                case "left":
-                case "right":
-                    k[5] = e.top;
-                    b.setLength(s);
-                    break
-            }
-            b.updateTitleSprite();
-            t.inverse(l.inverseMatrix)
-        }
-        for (x = 0, g = q.length; x < g; x++) {
-            h = q[x];
-            r = h.getSurface();
-            r.setRect(u);
-            if (w) {
-                if (j) {
-                    r.matrix.set(0, -1, -1, 0, v.left + p, v.top + s)
-                } else {
-                    r.matrix.set(0, -1, 1, 0, v.left, v.top + s)
-                }
-            } else {
-                r.matrix.set(1, 0, 0, -1, v.left, v.top + s)
-            }
-            r.matrix.inverse(r.inverseMatrix);
-            h.getOverlaySurface().setRect(u)
-        }
-        A.redraw();
-        A.animationSuspendCount--;
-        A.resumeThicknessChanged()
-    },
-    refloatAxes: function() {
-        var h = this,
-            g = h.getAxes(),
-            o = (g && g.length) || 0,
-            c, d, n, f, l, b, k, r = h.getChartSize(),
-            q = h.getInsetPadding(),
-            p = h.getInnerPadding(),
-            a = r.width - q.left - q.right,
-            m = r.height - q.top - q.bottom,
-            j, e;
-        for (e = 0; e < o; e++) {
-            c = g[e];
-            f = c.getFloating();
-            l = f ? f.value : null;
-            if (l === null) {
-                delete c.floatingAtCoord;
-                continue
-            }
-            d = c.getSurface();
-            n = d.getRect();
-            if (!n) {
-                continue
-            }
-            n = n.slice();
-            b = h.getAxis(f.alongAxis);
-            if (b) {
-                j = b.getAlignment() === "horizontal";
-                if (Ext.isString(l)) {
-                    l = b.getCoordFor(l)
-                }
-                b.floatingAxes[c.getId()] = l;
-                k = b.getSprites()[0].attr.matrix;
-                if (j) {
-                    l = l * k.getXX() + k.getDX();
-                    c.floatingAtCoord = l + p.left + p.right
-                } else {
-                    l = l * k.getYY() + k.getDY();
-                    c.floatingAtCoord = l + p.top + p.bottom
-                }
-            } else {
-                j = c.getAlignment() === "horizontal";
-                if (j) {
-                    c.floatingAtCoord = l + p.top + p.bottom
-                } else {
-                    c.floatingAtCoord = l + p.left + p.right
-                }
-                l = d.roundPixel(0.01 * l * (j ? m : a))
-            }
-            switch (c.getPosition()) {
-                case "top":
-                    n[1] = q.top + p.top + l - n[3] + 1;
-                    break;
-                case "bottom":
-                    n[1] = q.top + p.top + (b ? l : m - l);
-                    break;
-                case "left":
-                    n[0] = q.left + p.left + l - n[2];
-                    break;
-                case "right":
-                    n[0] = q.left + p.left + (b ? l : a - l) - 1;
-                    break
-            }
-            d.setRect(n)
-        }
-    },
-    redraw: function() {
-        var C = this,
-            r = C.getSeries(),
-            z = C.getAxes(),
-            b = C.getMainRect(),
-            p, t, w = C.getInnerPadding(),
-            f, l, s, e, q, A, v, g, d, c, a, k, n, y = C.getFlipXY(),
-            x = 1000,
-            m, u, h, o, B;
-        if (!b) {
-            return
-        }
-        p = b[2] - w.left - w.right;
-        t = b[3] - w.top - w.bottom;
-        for (A = 0; A < r.length; A++) {
-            h = r[A];
-            if ((c = h.getXAxis())) {
-                n = c.getVisibleRange();
-                l = c.getRange();
-                l = [l[0] + (l[1] - l[0]) * n[0], l[0] + (l[1] - l[0]) * n[1]]
-            } else {
-                l = h.getXRange()
-            }
-            if ((a = h.getYAxis())) {
-                n = a.getVisibleRange();
-                s = a.getRange();
-                s = [s[0] + (s[1] - s[0]) * n[0], s[0] + (s[1] - s[0]) * n[1]]
-            } else {
-                s = h.getYRange()
-            }
-            q = {
-                visibleMinX: l[0],
-                visibleMaxX: l[1],
-                visibleMinY: s[0],
-                visibleMaxY: s[1],
-                innerWidth: p,
-                innerHeight: t,
-                flipXY: y
-            };
-            f = h.getSprites();
-            for (v = 0, g = f.length; v < g; v++) {
-                o = f[v];
-                m = o.attr.zIndex;
-                if (m < x) {
-                    m += (A + 1) * 100 + x;
-                    o.attr.zIndex = m;
-                    B = o.getMarker("items");
-                    if (B) {
-                        u = B.attr.zIndex;
-                        if (u === Number.MAX_VALUE) {
-                            B.attr.zIndex = m
-                        } else {
-                            if (u < x) {
-                                B.attr.zIndex = m + u
-                            }
-                        }
-                    }
-                }
-                o.setAttributes(q, true)
-            }
-        }
-        for (A = 0; A < z.length; A++) {
-            d = z[A];
-            e = d.isSide();
-            f = d.getSprites();
-            k = d.getRange();
-            n = d.getVisibleRange();
-            q = {
-                dataMin: k[0],
-                dataMax: k[1],
-                visibleMin: n[0],
-                visibleMax: n[1]
-            };
-            if (e) {
-                q.length = t;
-                q.startGap = w.bottom;
-                q.endGap = w.top
-            } else {
-                q.length = p;
-                q.startGap = w.left;
-                q.endGap = w.right
-            }
-            for (v = 0, g = f.length; v < g; v++) {
-                f[v].setAttributes(q, true)
-            }
-        }
-        C.renderFrame();
-        C.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.grid.CircularGrid", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "grid.circular",
-    inheritableStatics: {
-        def: {
-            defaults: {
-                r: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.grid.RadialGrid", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "grid.radial",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startRadius: "number",
-                endRadius: "number"
-            },
-            defaults: {
-                startRadius: 0,
-                endRadius: 1,
-                scalingCenterX: 0,
-                scalingCenterY: 0,
-                strokeStyle: "#DDD"
-            },
-            triggers: {
-                startRadius: "path,bbox",
-                endRadius: "path,bbox"
-            }
-        }
-    },
-    render: function() {
-        this.callParent(arguments)
-    },
-    updatePath: function(d, a) {
-        var b = a.startRadius,
-            c = a.endRadius;
-        d.moveTo(b, 0);
-        d.lineTo(c, 0)
-    }
-});
-Ext.define("Ext.chart.PolarChart", {
-    extend: "Ext.chart.AbstractChart",
-    requires: ["Ext.chart.grid.CircularGrid", "Ext.chart.grid.RadialGrid"],
-    xtype: "polar",
-    isPolar: true,
-    config: {
-        center: [0, 0],
-        radius: 0,
-        innerPadding: 0
-    },
-    getDirectionForAxis: function(a) {
-        return a === "radial" ? "Y" : "X"
-    },
-    applyCenter: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1]) {
-            return
-        }
-        return [+a[0], +a[1]]
-    },
-    updateCenter: function(a) {
-        var g = this,
-            h = g.getAxes(),
-            d = g.getSeries(),
-            c, f, e, b;
-        for (c = 0, f = h.length; c < f; c++) {
-            e = h[c];
-            e.setCenter(a)
-        }
-        for (c = 0, f = d.length; c < f; c++) {
-            b = d[c];
-            b.setCenter(a)
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        return Ext.isNumber(b) ? b : a
-    },
-    doSetSurfaceRect: function(b, c) {
-        var a = this.getMainRect();
-        b.setRect(c);
-        b.matrix.set(1, 0, 0, 1, a[0] - c[0], a[1] - c[1]);
-        b.inverseMatrix.set(1, 0, 0, 1, c[0] - a[0], c[1] - a[1])
-    },
-    applyAxes: function(f, h) {
-        var e = this,
-            g = Ext.Array.from(e.config.series)[0],
-            b, d, c, a;
-        if (g.type === "radar" && f && f.length) {
-            for (b = 0, d = f.length; b < d; b++) {
-                c = f[b];
-                if (c.position === "angular") {
-                    a = true;
-                    break
-                }
-            }
-            if (!a) {
-                f.push({
-                    type: "category",
-                    position: "angular",
-                    fields: g.xField || g.angleField,
-                    style: {
-                        estStepSize: 1
-                    },
-                    grid: true
-                })
-            }
-        }
-        return this.callParent(arguments)
-    },
-    performLayout: function() {
-        var F = this,
-            g = true;
-        try {
-            F.animationSuspendCount++;
-            if (this.callParent() === false) {
-                g = false;
-                return
-            }
-            F.suspendThicknessChanged();
-            var h = F.getSurface("chart").getRect(),
-                v = F.getInsetPadding(),
-                G = F.getInnerPadding(),
-                l = Ext.apply({}, v),
-                d, s = h[2] - v.left - v.right,
-                r = h[3] - v.top - v.bottom,
-                x = [v.left, v.top, s, r],
-                u = F.getSeries(),
-                p, t = s - G * 2,
-                w = r - G * 2,
-                D = [t * 0.5 + G, w * 0.5 + G],
-                j = Math.min(t, w) * 0.5,
-                A = F.getAxes(),
-                f, a, k, m = [],
-                o = [],
-                E = j - G,
-                z, n, b, q, y, c, C;
-            F.setMainRect(x);
-            F.doSetSurfaceRect(F.getSurface(), x);
-            for (z = 0, n = F.surfaceMap.grid && F.surfaceMap.grid.length; z < n; z++) {
-                F.doSetSurfaceRect(F.surfaceMap.grid[z], h)
-            }
-            for (z = 0, n = A.length; z < n; z++) {
-                f = A[z];
-                switch (f.getPosition()) {
-                    case "angular":
-                        m.push(f);
-                        break;
-                    case "radial":
-                        o.push(f);
-                        break
-                }
-            }
-            for (z = 0, n = m.length; z < n; z++) {
-                f = m[z];
-                q = f.getFloating();
-                y = q ? q.value : null;
-                F.doSetSurfaceRect(f.getSurface(), h);
-                a = f.getThickness();
-                for (d in l) {
-                    l[d] += a
-                }
-                s = h[2] - l.left - l.right;
-                r = h[3] - l.top - l.bottom;
-                b = Math.min(s, r) * 0.5;
-                if (z === 0) {
-                    E = b - G
-                }
-                f.setMinimum(0);
-                f.setLength(b);
-                f.getSprites();
-                k = f.sprites[0].attr.lineWidth * 0.5;
-                for (d in l) {
-                    l[d] += k
-                }
-            }
-            for (z = 0, n = o.length; z < n; z++) {
-                f = o[z];
-                F.doSetSurfaceRect(f.getSurface(), h);
-                f.setMinimum(0);
-                f.setLength(E);
-                f.getSprites()
-            }
-            for (z = 0, n = u.length; z < n; z++) {
-                p = u[z];
-                if (p.type === "gauge" && !c) {
-                    c = p
-                } else {
-                    p.setRadius(E)
-                }
-                F.doSetSurfaceRect(p.getSurface(), x)
-            }
-            F.doSetSurfaceRect(F.getSurface("overlay"), h);
-            if (c) {
-                c.setRect(x);
-                C = c.getRadius() - G;
-                F.setRadius(C);
-                F.setCenter(c.getCenter());
-                c.setRadius(C);
-                if (A.length && A[0].getPosition() === "gauge") {
-                    f = A[0];
-                    F.doSetSurfaceRect(f.getSurface(), h);
-                    f.setTotalAngle(c.getTotalAngle());
-                    f.setLength(C)
-                }
-            } else {
-                F.setRadius(j);
-                F.setCenter(D)
-            }
-            F.redraw()
-        } catch (B) {
-            throw B
-        } finally {
-            F.animationSuspendCount--;
-            if (g) {
-                F.resumeThicknessChanged()
-            }
-        }
-    },
-    refloatAxes: function() {
-        var j = this,
-            g = j.getAxes(),
-            h = j.getMainRect(),
-            f, k, b, d, a, c, e;
-        if (!h) {
-            return
-        }
-        e = 0.5 * Math.min(h[2], h[3]);
-        for (d = 0, a = g.length; d < a; d++) {
-            c = g[d];
-            f = c.getFloating();
-            k = f ? f.value : null;
-            if (k !== null) {
-                b = j.getAxis(f.alongAxis);
-                if (c.getPosition() === "angular") {
-                    if (b) {
-                        k = b.getLength() * k / b.getRange()[1]
-                    } else {
-                        k = 0.01 * k * e
-                    }
-                    c.sprites[0].setAttributes({
-                        length: k
-                    }, true)
-                } else {
-                    if (b) {
-                        if (Ext.isString(k)) {
-                            k = b.getCoordFor(k)
-                        }
-                        k = k / (b.getRange()[1] + 1) * Math.PI * 2 - Math.PI * 1.5 + c.getRotation()
-                    } else {
-                        k = Ext.draw.Draw.rad(k)
-                    }
-                    c.sprites[0].setAttributes({
-                        baseRotation: k
-                    }, true)
-                }
-            }
-        }
-    },
-    redraw: function() {
-        var f = this,
-            g = f.getAxes(),
-            d, c = f.getSeries(),
-            b, a, e;
-        for (a = 0, e = g.length; a < e; a++) {
-            d = g[a];
-            d.getSprites()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        f.renderFrame();
-        f.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.SpaceFillingChart", {
-    extend: "Ext.chart.AbstractChart",
-    xtype: "spacefilling",
-    config: {},
-    performLayout: function() {
-        var j = this;
-        try {
-            j.animationSuspendCount++;
-            if (j.callParent() === false) {
-                return
-            }
-            var k = j.getSurface("chart").getRect(),
-                l = j.getInsetPadding(),
-                a = k[2] - l.left - l.right,
-                m = k[3] - l.top - l.bottom,
-                h = [l.left, l.top, a, m],
-                b = j.getSeries(),
-                d, c, g;
-            j.getSurface().setRect(h);
-            j.setMainRect(h);
-            for (c = 0, g = b.length; c < g; c++) {
-                d = b[c];
-                d.getSurface().setRect(h);
-                if (d.setRect) {
-                    d.setRect(h)
-                }
-                d.getOverlaySurface().setRect(k)
-            }
-            j.redraw()
-        } catch (f) {
-            throw f
-        } finally {
-            j.animationSuspendCount--
-        }
-    },
-    redraw: function() {
-        var e = this,
-            c = e.getSeries(),
-            b, a, d;
-        for (a = 0, d = c.length; a < d; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        e.renderFrame();
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis3D", {
-    extend: "Ext.chart.axis.sprite.Axis",
-    alias: "sprite.axis3d",
-    type: "axis3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            },
-            triggers: {
-                depth: "layout"
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                depth: 0
-            }
-        }
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            c = d.isDiscrete ? 0 : e.depth,
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (e.position === "left" || e.position === "right") {
-            e.translationX = 0;
-            e.translationY = i * (e.length - c) / (i - b) + c;
-            e.scalingX = 1;
-            e.scalingY = (-e.length + c) / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (e.position === "top" || e.position === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * (e.length - c) / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    renderAxisLine: function(a, j, f, c) {
-        var i = this,
-            h = i.attr,
-            b = h.lineWidth * 0.5,
-            f = i.getLayout(),
-            d = f.isDiscrete ? 0 : h.depth,
-            k = h.position,
-            e, g;
-        if (h.axisLine && h.length) {
-            switch (k) {
-                case "left":
-                    e = a.roundPixel(c[2]) - b;
-                    j.moveTo(e, -h.endGap + d);
-                    j.lineTo(e, h.length + h.startGap);
-                    break;
-                case "right":
-                    j.moveTo(b, -h.endGap);
-                    j.lineTo(b, h.length + h.startGap);
-                    break;
-                case "bottom":
-                    j.moveTo(-h.startGap, b);
-                    j.lineTo(h.length - d + h.endGap, b);
-                    break;
-                case "top":
-                    e = a.roundPixel(c[3]) - b;
-                    j.moveTo(-h.startGap, e);
-                    j.lineTo(h.length + h.endGap, e);
-                    break;
-                case "angular":
-                    j.moveTo(h.centerX + h.length, h.centerY);
-                    j.arc(h.centerX, h.centerY, h.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    g = i.getGaugeAngles();
-                    j.moveTo(h.centerX + Math.cos(g.start) * h.length, h.centerY + Math.sin(g.start) * h.length);
-                    j.arc(h.centerX, h.centerY, h.length, g.start, g.end, true);
-                    break
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis3D", {
-    extend: "Ext.chart.axis.Axis",
-    xtype: "axis3d",
-    requires: ["Ext.chart.axis.sprite.Axis3D"],
-    config: {
-        depth: 0
-    },
-    onSeriesChange: function(e) {
-        var g = this,
-            b = "depthchange",
-            f = "onSeriesDepthChange",
-            d, c;
-
-        function a(h) {
-            var i = g.boundSeries;
-            for (d = 0; d < i.length; d++) {
-                c = i[d];
-                c[h](b, f, g)
-            }
-        }
-        a("un");
-        g.callParent(arguments);
-        a("on")
-    },
-    onSeriesDepthChange: function(b, f) {
-        var d = this,
-            g = f,
-            e = d.boundSeries,
-            a, c;
-        if (f > d.getDepth()) {
-            g = f
-        } else {
-            for (a = 0; a < e.length; a++) {
-                c = e[a];
-                if (c !== b && c.getDepth) {
-                    f = c.getDepth();
-                    if (f > g) {
-                        g = f
-                    }
-                }
-            }
-        }
-        d.setDepth(g)
-    },
-    updateDepth: function(d) {
-        var b = this,
-            c = b.getSprites(),
-            a = {
-                depth: d
-            };
-        if (c && c.length) {
-            c[0].setAttributes(a)
-        }
-        if (b.gridSpriteEven && b.gridSpriteOdd) {
-            b.gridSpriteEven.getTemplate().setAttributes(a);
-            b.gridSpriteOdd.getTemplate().setAttributes(a)
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal3d";
-            case "top":
-            case "bottom":
-                return "vertical3d"
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Category", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis",
-    alias: "axis.category",
-    type: "category",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Category3D", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis3D",
-    alias: "axis.category3d",
-    type: "category3d",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric", {
-    extend: "Ext.chart.axis.Axis",
-    type: "numeric",
-    alias: ["axis.numeric", "axis.radial"],
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric3D", {
-    extend: "Ext.chart.axis.Axis3D",
-    alias: ["axis.numeric3d"],
-    type: "numeric3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Time", {
-    extend: "Ext.chart.axis.Numeric",
-    alias: "axis.time",
-    type: "time",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.axis.Time3D", {
-    extend: "Ext.chart.axis.Numeric3D",
-    alias: "axis.time3d",
-    type: "time3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid3D", {
-    extend: "Ext.chart.grid.HorizontalGrid",
-    alias: "grid.horizontal3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render: function(a, k, d) {
-        var f = this.attr,
-            i = a.roundPixel(f.x),
-            h = a.roundPixel(f.y),
-            l = a.matrix.getDX(),
-            c = k.lineWidth * 0.5,
-            j = f.height,
-            e = f.depth,
-            b, g;
-        if (h <= d[1]) {
-            return
-        }
-        b = d[0] + e - l;
-        g = h + c - e;
-        k.beginPath();
-        k.rect(b, g, d[2], j);
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + d[2], g);
-        k.stroke();
-        b = d[0] + i - l;
-        g = h + c;
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.lineTo(b + e, g - e + j);
-        k.lineTo(b, g + j);
-        k.closePath();
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid3D", {
-    extend: "Ext.chart.grid.VerticalGrid",
-    alias: "grid.vertical3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render_: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    },
-    render: function(b, j, e) {
-        var g = this.attr,
-            i = b.roundPixel(g.x),
-            k = b.matrix.getDY(),
-            d = j.lineWidth * 0.5,
-            a = g.width,
-            f = g.depth,
-            c, h;
-        if (i >= e[2]) {
-            return
-        }
-        c = i - d + f;
-        h = e[1] - f - k;
-        j.beginPath();
-        j.rect(c, h, a, e[3]);
-        j.fill();
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c, h + e[3]);
-        j.stroke();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.lineTo(c + f + a, h - f);
-        j.lineTo(c + a, h);
-        j.closePath();
-        j.fill();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.stroke()
-    }
-});
-Ext.define("Ext.chart.interactions.CrossZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "crosszoom",
-    alias: "interaction.crosszoom",
-    isCrossZoom: true,
-    config: {
-        axes: true,
-        gestures: {
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd",
-            dblclick: "onDoubleTap"
-        },
-        undoButton: {}
-    },
-    stopAnimationBeforeSync: false,
-    zoomAnimationInProgress: false,
-    constructor: function() {
-        this.callParent(arguments);
-        this.zoomHistory = []
-    },
-    applyAxes: function(b) {
-        var a = {};
-        if (b === true) {
-            return {
-                top: {},
-                right: {},
-                bottom: {},
-                left: {}
-            }
-        } else {
-            if (Ext.isArray(b)) {
-                a = {};
-                Ext.each(b, function(c) {
-                    a[c] = {}
-                })
-            } else {
-                if (Ext.isObject(b)) {
-                    Ext.iterate(b, function(c, d) {
-                        if (d === true) {
-                            a[c] = {}
-                        } else {
-                            if (d !== false) {
-                                a[c] = d
-                            }
-                        }
-                    })
-                }
-            }
-        }
-        return a
-    },
-    applyUndoButton: function(b, a) {
-        var c = this;
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            return Ext.create("Ext.Button", Ext.apply({
-                cls: [],
-                text: "Undo Zoom",
-                disabled: true,
-                handler: function() {
-                    c.undoZoom()
-                }
-            }, b))
-        }
-    },
-    getSurface: function() {
-        return this.getChart() && this.getChart().getSurface("main")
-    },
-    setSeriesOpacity: function(b) {
-        var a = this.getChart() && this.getChart().getSurface("series");
-        if (a) {
-            a.element.setStyle("opacity", b)
-        }
-    },
-    onGestureStart: function(h) {
-        var j = this,
-            i = j.getChart(),
-            d = j.getSurface(),
-            l = i.getInnerRect(),
-            c = i.getInnerPadding(),
-            g = c.left,
-            b = g + l[2],
-            f = c.top,
-            a = f + l[3],
-            n = i.getEventXY(h),
-            m = n[0],
-            k = n[1];
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (m > g && m < b && k > f && k < a) {
-            j.gestureEvent = "drag";
-            j.lockEvents(j.gestureEvent);
-            j.startX = m;
-            j.startY = k;
-            j.selectionRect = d.add({
-                type: "rect",
-                globalAlpha: 0.5,
-                fillStyle: "rgba(80,80,140,0.5)",
-                strokeStyle: "rgba(80,80,140,1)",
-                lineWidth: 2,
-                x: m,
-                y: k,
-                width: 0,
-                height: 0,
-                zIndex: 10000
-            });
-            j.setSeriesOpacity(0.8);
-            return false
-        }
-    },
-    onGesture: function(h) {
-        var j = this;
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (j.getLocks()[j.gestureEvent] === j) {
-            var i = j.getChart(),
-                d = j.getSurface(),
-                l = i.getInnerRect(),
-                c = i.getInnerPadding(),
-                g = c.left,
-                b = g + l[2],
-                f = c.top,
-                a = f + l[3],
-                n = i.getEventXY(h),
-                m = n[0],
-                k = n[1];
-            if (m < g) {
-                m = g
-            } else {
-                if (m > b) {
-                    m = b
-                }
-            }
-            if (k < f) {
-                k = f
-            } else {
-                if (k > a) {
-                    k = a
-                }
-            }
-            j.selectionRect.setAttributes({
-                width: m - j.startX,
-                height: k - j.startY
-            });
-            if (Math.abs(j.startX - m) < 11 || Math.abs(j.startY - k) < 11) {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 0.5
-                })
-            } else {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 1
-                })
-            }
-            d.renderFrame();
-            return false
-        }
-    },
-    onGestureEnd: function(i) {
-        var l = this;
-        if (l.zoomAnimationInProgress) {
-            return
-        }
-        if (l.getLocks()[l.gestureEvent] === l) {
-            var k = l.getChart(),
-                d = l.getSurface(),
-                n = k.getInnerRect(),
-                c = k.getInnerPadding(),
-                g = c.left,
-                b = g + n[2],
-                f = c.top,
-                a = f + n[3],
-                h = n[2],
-                j = n[3],
-                p = k.getEventXY(i),
-                o = p[0],
-                m = p[1];
-            if (o < g) {
-                o = g
-            } else {
-                if (o > b) {
-                    o = b
-                }
-            }
-            if (m < f) {
-                m = f
-            } else {
-                if (m > a) {
-                    m = a
-                }
-            }
-            if (Math.abs(l.startX - o) < 11 || Math.abs(l.startY - m) < 11) {
-                d.remove(l.selectionRect)
-            } else {
-                l.zoomBy([Math.min(l.startX, o) / h, 1 - Math.max(l.startY, m) / j, Math.max(l.startX, o) / h, 1 - Math.min(l.startY, m) / j]);
-                l.selectionRect.setAttributes({
-                    x: Math.min(l.startX, o),
-                    y: Math.min(l.startY, m),
-                    width: Math.abs(l.startX - o),
-                    height: Math.abs(l.startY - m)
-                });
-                l.selectionRect.setAnimation(k.getAnimation() || {
-                    duration: 0
-                });
-                l.selectionRect.setAttributes({
-                    globalAlpha: 0,
-                    x: 0,
-                    y: 0,
-                    width: h,
-                    height: j
-                });
-                l.zoomAnimationInProgress = true;
-                k.suspendThicknessChanged();
-                l.selectionRect.fx.on("animationend", function() {
-                    k.resumeThicknessChanged();
-                    d.remove(l.selectionRect);
-                    l.selectionRect = null;
-                    l.zoomAnimationInProgress = false
-                })
-            }
-            d.renderFrame();
-            l.sync();
-            l.unlockEvents(l.gestureEvent);
-            l.setSeriesOpacity(1);
-            if (!l.zoomAnimationInProgress) {
-                d.remove(l.selectionRect);
-                l.selectionRect = null
-            }
-        }
-    },
-    zoomBy: function(o) {
-        var n = this,
-            a = n.getAxes(),
-            k = n.getChart(),
-            j = k.getAxes(),
-            l = k.getInherited().rtl,
-            f, d = {},
-            c, b;
-        if (l) {
-            o = o.slice();
-            c = 1 - o[0];
-            b = 1 - o[2];
-            o[0] = Math.min(c, b);
-            o[2] = Math.max(c, b)
-        }
-        for (var h = 0; h < j.length; h++) {
-            var g = j[h];
-            f = a[g.getPosition()];
-            if (f && f.allowZoom !== false) {
-                var e = g.isSide(),
-                    m = g.getVisibleRange();
-                d[g.getId()] = m.slice(0);
-                if (!e) {
-                    g.setVisibleRange([(m[1] - m[0]) * o[0] + m[0], (m[1] - m[0]) * o[2] + m[0]])
-                } else {
-                    g.setVisibleRange([(m[1] - m[0]) * o[1] + m[0], (m[1] - m[0]) * o[3] + m[0]])
-                }
-            }
-        }
-        n.zoomHistory.push(d);
-        n.getUndoButton().setDisabled(false)
-    },
-    undoZoom: function() {
-        var c = this.zoomHistory.pop(),
-            d = this.getChart().getAxes();
-        if (c) {
-            for (var a = 0; a < d.length; a++) {
-                var b = d[a];
-                if (c[b.getId()]) {
-                    b.setVisibleRange(c[b.getId()])
-                }
-            }
-        }
-        this.getUndoButton().setDisabled(this.zoomHistory.length === 0);
-        this.sync()
-    },
-    onDoubleTap: function(a) {
-        this.undoZoom()
-    },
-    destroy: function() {
-        this.setUndoButton(null);
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.interactions.Crosshair", {
-    extend: "Ext.chart.interactions.Abstract",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid", "Ext.chart.CartesianChart", "Ext.chart.axis.layout.Discrete"],
-    type: "crosshair",
-    alias: "interaction.crosshair",
-    config: {
-        axes: {
-            top: {
-                label: {},
-                rect: {}
-            },
-            right: {
-                label: {},
-                rect: {}
-            },
-            bottom: {
-                label: {},
-                rect: {}
-            },
-            left: {
-                label: {},
-                rect: {}
-            }
-        },
-        lines: {
-            horizontal: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            },
-            vertical: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            }
-        },
-        gesture: "drag"
-    },
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyLines: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    updateChart: function(a) {
-        if (a && !a.isCartesian) {
-            Ext.raise("Crosshair interaction can only be used on cartesian charts.")
-        }
-        this.callParent(arguments)
-    },
-    getGestures: function() {
-        var a = this,
-            b = {};
-        b[a.getGesture()] = "onGesture";
-        b[a.getGesture() + "start"] = "onGestureStart";
-        b[a.getGesture() + "end"] = "onGestureEnd";
-        return b
-    },
-    onGestureStart: function(N) {
-        var m = this,
-            O = m.getChart(),
-            B = O.getTheme().getAxis(),
-            A, F = O.getSurface("overlay"),
-            s = O.getInnerRect(),
-            n = s[2],
-            M = s[3],
-            r = O.getEventXY(N),
-            D = r[0],
-            C = r[1],
-            E = O.getAxes(),
-            u = m.getAxes(),
-            h = m.getLines(),
-            q, v, b, d, k, z, G, L, J, o, I, w, l, f, p, j, t, a, g, H, c, K;
-        if (D > 0 && D < n && C > 0 && C < M) {
-            m.lockEvents(m.getGesture());
-            H = Ext.apply({
-                xclass: "Ext.chart.grid.HorizontalGrid",
-                x: 0,
-                y: C,
-                width: n
-            }, h.horizontal);
-            c = Ext.apply({
-                xclass: "Ext.chart.grid.VerticalGrid",
-                x: D,
-                y: 0,
-                height: M
-            }, h.vertical);
-            m.axesLabels = m.axesLabels || {};
-            for (K = 0; K < E.length; K++) {
-                q = E[K];
-                v = q.getSurface();
-                b = v.getRect();
-                w = q.getSprites()[0];
-                d = b[2];
-                k = b[3];
-                z = q.getPosition();
-                G = q.getAlignment();
-                t = q.getTitle();
-                a = t && t.attr.text !== "" && t.getBBox();
-                l = w.attr;
-                f = w.thickness;
-                p = l.axisLine ? l.lineWidth : 0;
-                j = p / 2;
-                I = Math.max(l.majorTickSize, l.minorTickSize) + p;
-                L = m.axesLabels[z] = v.add({
-                    type: "composite"
-                });
-                L.labelRect = L.add(Ext.apply({
-                    type: "rect",
-                    fillStyle: "white",
-                    x: z === "right" ? p : 0,
-                    y: z === "bottom" ? p : 0,
-                    width: d - p - (G === "vertical" && a ? a.width : 0),
-                    height: k - p - (G === "horizontal" && a ? a.height : 0),
-                    translationX: z === "left" && a ? a.width : 0,
-                    translationY: z === "top" && a ? a.height : 0
-                }, u.rect || u[z].rect));
-                if (G === "vertical" && !c.strokeStyle) {
-                    c.strokeStyle = l.strokeStyle
-                }
-                if (G === "horizontal" && !H.strokeStyle) {
-                    H.strokeStyle = l.strokeStyle
-                }
-                A = Ext.merge({}, B.defaults, B[z]);
-                J = Ext.apply({}, q.config.label, A.label);
-                o = u.label || u[z].label;
-                L.labelText = L.add(Ext.apply(J, o, {
-                    type: "text",
-                    x: (function() {
-                        switch (z) {
-                            case "left":
-                                g = a ? a.x + a.width : 0;
-                                return g + (d - g - I) / 2 - j;
-                            case "right":
-                                g = a ? d - a.x : 0;
-                                return I + (d - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })(),
-                    y: (function() {
-                        switch (z) {
-                            case "top":
-                                g = a ? a.y + a.height : 0;
-                                return g + (k - g - I) / 2 - j;
-                            case "bottom":
-                                g = a ? k - a.y : 0;
-                                return I + (k - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })()
-                }))
-            }
-            m.horizontalLine = F.add(H);
-            m.verticalLine = F.add(c);
-            return false
-        }
-    },
-    onGesture: function(G) {
-        var K = this;
-        if (K.getLocks()[K.getGesture()] !== K) {
-            return
-        }
-        var u = K.getChart(),
-            z = u.getSurface("overlay"),
-            a = Ext.Array.slice(u.getInnerRect()),
-            r = u.getInnerPadding(),
-            t = r.left,
-            q = r.top,
-            E = a[2],
-            f = a[3],
-            d = u.getEventXY(G),
-            k = d[0],
-            j = d[1],
-            D = u.getAxes(),
-            c, h, m, p, J, w, I, H, s, b, C, g, v, n, l, A, F, o, B;
-        if (k < 0) {
-            k = 0
-        } else {
-            if (k > E) {
-                k = E
-            }
-        }
-        if (j < 0) {
-            j = 0
-        } else {
-            if (j > f) {
-                j = f
-            }
-        }
-        k += t;
-        j += q;
-        for (B = 0; B < D.length; B++) {
-            c = D[B];
-            h = c.getPosition();
-            m = c.getAlignment();
-            p = c.getSurface();
-            J = c.getSprites()[0];
-            w = J.attr.matrix;
-            C = J.attr.textPadding * 2;
-            s = K.axesLabels[h];
-            I = J.getLayoutContext();
-            H = c.getSegmenter();
-            if (s) {
-                if (m === "vertical") {
-                    v = w.getYY();
-                    l = w.getDY();
-                    F = (j - l - q) / v;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        j = Math.round(F) * v + l + q;
-                        F = H.from(Math.round(F));
-                        F = J.attr.data[F]
-                    } else {
-                        F = H.from(F)
-                    }
-                    o = H.renderer(F, I);
-                    s.setAttributes({
-                        translationY: j - q
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        height: b.height + C,
-                        y: -(b.height + C) / 2
-                    });
-                    p.renderFrame()
-                } else {
-                    g = w.getXX();
-                    n = w.getDX();
-                    A = (k - n - t) / g;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        k = Math.round(A) * g + n + t;
-                        A = H.from(Math.round(A));
-                        A = J.attr.data[A]
-                    } else {
-                        A = H.from(A)
-                    }
-                    o = H.renderer(A, I);
-                    s.setAttributes({
-                        translationX: k - t
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        width: b.width + C,
-                        x: -(b.width + C) / 2
-                    });
-                    p.renderFrame()
-                }
-            }
-        }
-        K.horizontalLine.setAttributes({
-            y: j,
-            strokeStyle: J.attr.strokeStyle
-        });
-        K.verticalLine.setAttributes({
-            x: k,
-            strokeStyle: J.attr.strokeStyle
-        });
-        z.renderFrame();
-        return false
-    },
-    onGestureEnd: function(h) {
-        var l = this,
-            k = l.getChart(),
-            a = k.getSurface("overlay"),
-            j = k.getAxes(),
-            c, g, d, b, f;
-        a.remove(l.verticalLine);
-        a.remove(l.horizontalLine);
-        for (f = 0; f < j.length; f++) {
-            c = j[f];
-            g = c.getPosition();
-            d = c.getSurface();
-            b = l.axesLabels[g];
-            if (b) {
-                delete l.axesLabels[g];
-                d.remove(b)
-            }
-            d.renderFrame()
-        }
-        a.renderFrame();
-        l.unlockEvents(l.getGesture())
-    }
-});
-Ext.define("Ext.chart.interactions.ItemHighlight", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "itemhighlight",
-    alias: "interaction.itemhighlight",
-    isItemHighlight: true,
-    config: {
-        gestures: {
-            tap: "onTapGesture",
-            mousemove: "onMouseMoveGesture",
-            mousedown: "onMouseDownGesture",
-            mouseup: "onMouseUpGesture",
-            mouseleave: "onMouseUpGesture"
-        },
-        sticky: false
-    },
-    stickyHighlightItem: null,
-    onMouseMoveGesture: function(g) {
-        var d = this,
-            h = d.tipItem,
-            a = g.pointerType === "mouse",
-            c, f, b;
-        if (d.getSticky()) {
-            return true
-        }
-        if (d.isDragging) {
-            if (h && a) {
-                h.series.hideTooltip(h);
-                d.tipItem = null
-            }
-        } else {
-            if (!d.stickyHighlightItem) {
-                c = d.getItemForEvent(g);
-                b = d.getChart();
-                if (c !== b.getHighlightItem()) {
-                    d.highlight(c);
-                    d.sync()
-                }
-                if (a) {
-                    if (h && (!c || h.field !== c.field || h.record !== c.record)) {
-                        h.series.hideTooltip(h);
-                        d.tipItem = h = null
-                    }
-                    if (c && (f = c.series.getTooltip())) {
-                        if (f.trackMouse || !h) {
-                            c.series.showTooltip(c, g.getXY())
-                        }
-                        d.tipItem = c
-                    }
-                }
-                return false
-            }
-        }
-    },
-    highlight: function(a) {
-        this.getChart().setHighlightItem(a)
-    },
-    showTooltip: function(b, a) {
-        a.series.showTooltip(a, b.getXY());
-        this.tipItem = a
-    },
-    onMouseDownGesture: function() {
-        this.isDragging = true
-    },
-    onMouseUpGesture: function() {
-        this.isDragging = false
-    },
-    onTapGesture: function(c) {
-        var b = this;
-        if (c.pointerType === "mouse" && !b.getSticky()) {
-            return
-        }
-        var a = b.getItemForEvent(c);
-        if (b.stickyHighlightItem && a && (b.stickyHighlightItem.index === a.index)) {
-            a = null
-        }
-        b.stickyHighlightItem = a;
-        b.highlight(a)
-    }
-});
-Ext.define("Ext.chart.interactions.ItemEdit", {
-    extend: "Ext.chart.interactions.ItemHighlight",
-    requires: ["Ext.tip.ToolTip"],
-    type: "itemedit",
-    alias: "interaction.itemedit",
-    isItemEdit: true,
-    config: {
-        style: null,
-        renderer: null,
-        tooltip: true,
-        gestures: {
-            dragstart: "onDragStart",
-            drag: "onDrag",
-            dragend: "onDragEnd"
-        },
-        cursors: {
-            ewResize: "ew-resize",
-            nsResize: "ns-resize",
-            move: "move"
-        }
-    },
-    item: null,
-    applyTooltip: function(b) {
-        if (b) {
-            var a = Ext.apply({}, b, {
-                renderer: this.defaultTooltipRenderer,
-                constrainPosition: true,
-                shrinkWrapDock: true,
-                autoHide: true,
-                offsetX: 10,
-                offsetY: 10
-            });
-            b = new Ext.tip.ToolTip(a)
-        }
-        return b
-    },
-    defaultTooltipRenderer: function(b, a, f, d) {
-        var c = [];
-        if (f.xField) {
-            c.push(f.xField + ": " + f.xValue)
-        }
-        if (f.yField) {
-            c.push(f.yField + ": " + f.yValue)
-        }
-        b.setHtml(c.join("<br>"))
-    },
-    onDragStart: function(d) {
-        var c = this,
-            a = c.getChart(),
-            b = a.getHighlightItem();
-        if (b) {
-            a.fireEvent("beginitemedit", a, c, c.item = b);
-            return false
-        }
-    },
-    onDrag: function(f) {
-        var d = this,
-            b = d.getChart(),
-            c = b.getHighlightItem(),
-            a = c && c.sprite.type;
-        if (c) {
-            switch (a) {
-                case "barSeries":
-                    return d.onDragBar(f);
-                    break;
-                case "scatterSeries":
-                    return d.onDragScatter(f);
-                    break
-            }
-        }
-    },
-    highlight: function(f) {
-        var e = this,
-            d = e.getChart(),
-            a = d.getFlipXY(),
-            g = e.getCursors(),
-            c = f && f.sprite.type,
-            b = d.el.dom.style;
-        e.callParent([f]);
-        if (f) {
-            switch (c) {
-                case "barSeries":
-                    if (a) {
-                        b.cursor = g.ewResize
-                    } else {
-                        b.cursor = g.nsResize
-                    }
-                    break;
-                case "scatterSeries":
-                    b.cursor = g.move;
-                    break
-            }
-        } else {
-            d.el.dom.style.cursor = "default"
-        }
-    },
-    onDragBar: function(i) {
-        var m = this,
-            k = m.getChart(),
-            l = k.getInherited().rtl,
-            f = k.isCartesian && k.getFlipXY(),
-            q = k.getHighlightItem(),
-            g = q.sprite.getMarker("items"),
-            p = g.getMarkerFor(q.sprite.getId(), q.index),
-            b = q.sprite.getSurface(),
-            c = b.getRect(),
-            r = b.getEventXY(i),
-            o = q.sprite.attr.matrix,
-            j = m.getRenderer(),
-            a, n, d, h;
-        if (f) {
-            h = l ? c[2] - r[0] : r[0]
-        } else {
-            h = c[3] - r[1]
-        }
-        a = {
-            x: p.x,
-            y: h,
-            width: p.width,
-            height: p.height + (p.y - h),
-            radius: p.radius,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(a, m.getStyle());
-        if (Ext.isArray(q.series.getYField())) {
-            h = h - p.y - p.height
-        }
-        m.target = {
-            index: q.index,
-            yField: q.field,
-            yValue: (h - o.getDY()) / o.getYY()
-        };
-        d = [k, {
-            target: m.target,
-            style: a,
-            item: q
-        }];
-        n = Ext.callback(j, null, d, 0, k);
-        if (n) {
-            Ext.apply(a, n)
-        }
-        q.sprite.putMarker("items", a, "itemedit");
-        m.showTooltip(i, m.target, q);
-        b.renderFrame()
-    },
-    onDragScatter: function(n) {
-        var t = this,
-            g = t.getChart(),
-            d = g.getInherited().rtl,
-            l = g.isCartesian && g.getFlipXY(),
-            o = g.getHighlightItem(),
-            b = o.sprite.getMarker("items"),
-            p = b.getMarkerFor(o.sprite.getId(), o.index),
-            j = o.sprite.getSurface(),
-            h = j.getRect(),
-            a = j.getEventXY(n),
-            k = o.sprite.attr.matrix,
-            c = o.series.getXAxis(),
-            f = c && c.getLayout().isContinuous,
-            i = t.getRenderer(),
-            m, u, q, s, r;
-        if (l) {
-            r = d ? h[2] - a[0] : a[0]
-        } else {
-            r = h[3] - a[1]
-        }
-        if (f) {
-            if (l) {
-                s = h[3] - a[1]
-            } else {
-                s = a[0]
-            }
-        } else {
-            s = p.translationX
-        }
-        m = {
-            translationX: s,
-            translationY: r,
-            scalingX: p.scalingX,
-            scalingY: p.scalingY,
-            r: p.r,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(m, t.getStyle());
-        t.target = {
-            index: o.index,
-            yField: o.field,
-            yValue: (r - k.getDY()) / k.getYY()
-        };
-        if (f) {
-            Ext.apply(t.target, {
-                xField: o.series.getXField(),
-                xValue: (s - k.getDX()) / k.getXX()
-            })
-        }
-        q = [g, {
-            target: t.target,
-            style: m,
-            item: o
-        }];
-        u = Ext.callback(i, null, q, 0, g);
-        if (u) {
-            Ext.apply(m, u)
-        }
-        o.sprite.putMarker("items", m, "itemedit");
-        t.showTooltip(n, t.target, o);
-        j.renderFrame()
-    },
-    showTooltip: function(g, f, c) {
-        var d = this.getTooltip(),
-            a, b;
-        if (d && Ext.toolkit !== "modern") {
-            a = d.config;
-            b = this.getChart();
-            Ext.callback(a.renderer, null, [d, c, f, g], 0, b);
-            d.show([g.x + a.offsetX, g.y + a.offsetY])
-        }
-    },
-    hideTooltip: function() {
-        var a = this.getTooltip();
-        if (a && Ext.toolkit !== "modern") {
-            a.hide()
-        }
-    },
-    onDragEnd: function(g) {
-        var d = this,
-            f = d.target,
-            c = d.getChart(),
-            b = c.getStore(),
-            a;
-        if (f) {
-            a = b.getAt(f.index);
-            if (f.yField) {
-                a.set(f.yField, f.yValue, {
-                    convert: false
-                })
-            }
-            if (f.xField) {
-                a.set(f.xField, f.xValue, {
-                    convert: false
-                })
-            }
-            if (f.yField || f.xField) {
-                d.getChart().onDataChanged()
-            }
-            d.target = null
-        }
-        d.hideTooltip();
-        if (d.item) {
-            c.fireEvent("enditemedit", c, d, d.item, f)
-        }
-        d.highlight(d.item = null)
-    },
-    destroy: function() {
-        var a = this.getConfig("tooltip", true);
-        Ext.destroy(a);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.PanZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "panzoom",
-    alias: "interaction.panzoom",
-    requires: ["Ext.draw.Animator"],
-    config: {
-        axes: {
-            top: {},
-            right: {},
-            bottom: {},
-            left: {}
-        },
-        minZoom: null,
-        maxZoom: null,
-        showOverflowArrows: true,
-        panGesture: "drag",
-        zoomGesture: "pinch",
-        zoomOnPanGesture: false,
-        modeToggleButton: {
-            xtype: "segmentedbutton",
-            width: 200,
-            defaults: {
-                ui: "default-toolbar"
-            },
-            cls: Ext.baseCSSPrefix + "panzoom-toggle",
-            items: [{
-                text: "Pan"
-            }, {
-                text: "Zoom"
-            }]
-        },
-        hideLabelInGesture: false
-    },
-    stopAnimationBeforeSync: true,
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyZoomOnPanGesture: function(a) {
-        this.getChart();
-        if (this.isMultiTouch()) {
-            return false
-        }
-        return a
-    },
-    updateZoomOnPanGesture: function(b) {
-        var a = this.getModeToggleButton();
-        if (!this.isMultiTouch()) {
-            a.show();
-            a.setValue(b ? 1 : 0)
-        } else {
-            a.hide()
-        }
-    },
-    toggleMode: function() {
-        var a = this;
-        if (!a.isMultiTouch()) {
-            a.setZoomOnPanGesture(!a.getZoomOnPanGesture())
-        }
-    },
-    applyModeToggleButton: function(c, b) {
-        var d = this,
-            a = Ext.factory(c, "Ext.button.Segmented", b);
-        if (!a && b) {
-            b.destroy()
-        }
-        if (a && !b) {
-            a.addListener("toggle", function(e) {
-                d.setZoomOnPanGesture(e.getValue() === 1)
-            })
-        }
-        return a
-    },
-    getGestures: function() {
-        var c = this,
-            e = {},
-            d = c.getPanGesture(),
-            b = c.getZoomGesture(),
-            a = Ext.supports.Touch;
-        e[b] = "onZoomGestureMove";
-        e[b + "start"] = "onZoomGestureStart";
-        e[b + "end"] = "onZoomGestureEnd";
-        e[d] = "onPanGestureMove";
-        e[d + "start"] = "onPanGestureStart";
-        e[d + "end"] = "onPanGestureEnd";
-        e.doubletap = "onDoubleTap";
-        return e
-    },
-    onDoubleTap: function(h) {
-        var f = this,
-            c = f.getChart(),
-            g = c.getAxes(),
-            b, a, d;
-        for (a = 0, d = g.length; a < d; a++) {
-            b = g[a];
-            b.setVisibleRange([0, 1])
-        }
-        c.redraw()
-    },
-    onPanGestureStart: function(d) {
-        if (!d || !d.touches || d.touches.length < 2) {
-            var b = this,
-                a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            b.startX = d.getX() - c[0] - a[0];
-            b.startY = d.getY() - c[1] - a[1];
-            b.oldVisibleRanges = null;
-            b.hideLabels();
-            b.getChart().suspendThicknessChanged();
-            b.lockEvents(b.getPanGesture());
-            return false
-        }
-    },
-    onPanGestureMove: function(d) {
-        var b = this;
-        if (b.getLocks()[b.getPanGesture()] === b) {
-            var a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            if (b.getZoomOnPanGesture()) {
-                b.transformAxesBy(b.getZoomableAxes(d), 0, 0, (d.getX() - c[0] - a[0]) / b.startX, b.startY / (d.getY() - c[1] - a[1]))
-            } else {
-                b.transformAxesBy(b.getPannableAxes(d), d.getX() - c[0] - a[0] - b.startX, d.getY() - c[1] - a[1] - b.startY, 1, 1)
-            }
-            b.sync();
-            return false
-        }
-    },
-    onPanGestureEnd: function(b) {
-        var a = this,
-            c = a.getPanGesture();
-        if (a.getLocks()[c] === a) {
-            a.getChart().resumeThicknessChanged();
-            a.showLabels();
-            a.sync();
-            a.unlockEvents(c);
-            return false
-        }
-    },
-    onZoomGestureStart: function(b) {
-        if (b.touches && b.touches.length === 2) {
-            var c = this,
-                i = c.getChart().element.getXY(),
-                f = c.getChart().getInnerRect(),
-                h = i[0] + f[0],
-                d = i[1] + f[1],
-                j = [b.touches[0].point.x - h, b.touches[0].point.y - d, b.touches[1].point.x - h, b.touches[1].point.y - d],
-                g = Math.max(44, Math.abs(j[2] - j[0])),
-                a = Math.max(44, Math.abs(j[3] - j[1]));
-            c.getChart().suspendThicknessChanged();
-            c.lastZoomDistances = [g, a];
-            c.lastPoints = j;
-            c.oldVisibleRanges = null;
-            c.hideLabels();
-            c.lockEvents(c.getZoomGesture());
-            return false
-        }
-    },
-    onZoomGestureMove: function(d) {
-        var f = this;
-        if (f.getLocks()[f.getZoomGesture()] === f) {
-            var i = f.getChart().getInnerRect(),
-                n = f.getChart().element.getXY(),
-                k = n[0] + i[0],
-                h = n[1] + i[1],
-                o = Math.abs,
-                c = f.lastPoints,
-                m = [d.touches[0].point.x - k, d.touches[0].point.y - h, d.touches[1].point.x - k, d.touches[1].point.y - h],
-                g = Math.max(44, o(m[2] - m[0])),
-                b = Math.max(44, o(m[3] - m[1])),
-                a = this.lastZoomDistances || [g, b],
-                l = g / a[0],
-                j = b / a[1];
-            f.transformAxesBy(f.getZoomableAxes(d), i[2] * (l - 1) / 2 + m[2] - c[2] * l, i[3] * (j - 1) / 2 + m[3] - c[3] * j, l, j);
-            f.sync();
-            return false
-        }
-    },
-    onZoomGestureEnd: function(c) {
-        var b = this,
-            a = b.getZoomGesture();
-        if (b.getLocks()[a] === b) {
-            b.getChart().resumeThicknessChanged();
-            b.showLabels();
-            b.sync();
-            b.unlockEvents(a);
-            return false
-        }
-    },
-    hideLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.hideLabels()
-            })
-        }
-    },
-    showLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.showLabels()
-            })
-        }
-    },
-    isEventOnAxis: function(c, a) {
-        var b = a.getSurface().getRect();
-        return b[0] <= c.getX() && c.getX() <= b[0] + b[2] && b[1] <= c.getY() && c.getY() <= b[1] + b[3]
-    },
-    getPannableAxes: function(d) {
-        var h = this,
-            a = h.getAxes(),
-            f = h.getChart().getAxes(),
-            c, g = f.length,
-            k = [],
-            j = false,
-            b;
-        if (d) {
-            for (c = 0; c < g; c++) {
-                if (this.isEventOnAxis(d, f[c])) {
-                    j = true;
-                    break
-                }
-            }
-        }
-        for (c = 0; c < g; c++) {
-            b = a[f[c].getPosition()];
-            if (b && b.allowPan !== false && (!j || this.isEventOnAxis(d, f[c]))) {
-                k.push(f[c])
-            }
-        }
-        return k
-    },
-    getZoomableAxes: function(f) {
-        var j = this,
-            a = j.getAxes(),
-            g = j.getChart().getAxes(),
-            l = [],
-            d, h = g.length,
-            c, k = false,
-            b;
-        if (f) {
-            for (d = 0; d < h; d++) {
-                if (this.isEventOnAxis(f, g[d])) {
-                    k = true;
-                    break
-                }
-            }
-        }
-        for (d = 0; d < h; d++) {
-            c = g[d];
-            b = a[c.getPosition()];
-            if (b && b.allowZoom !== false && (!k || this.isEventOnAxis(f, c))) {
-                l.push(c)
-            }
-        }
-        return l
-    },
-    eachInteractiveAxes: function(c) {
-        var d = this,
-            b = d.getAxes(),
-            e = d.getChart().getAxes();
-        for (var a = 0; a < e.length; a++) {
-            if (b[e[a].getPosition()]) {
-                if (false === c.call(this, e[a])) {
-                    return
-                }
-            }
-        }
-    },
-    transformAxesBy: function(d, j, g, h, e) {
-        var f = this.getChart().getInnerRect(),
-            a = this.getAxes(),
-            k, b = this.oldVisibleRanges,
-            l = false;
-        if (!b) {
-            this.oldVisibleRanges = b = {};
-            this.eachInteractiveAxes(function(i) {
-                b[i.getId()] = i.getVisibleRange()
-            })
-        }
-        if (!f) {
-            return
-        }
-        for (var c = 0; c < d.length; c++) {
-            k = a[d[c].getPosition()];
-            l = this.transformAxisBy(d[c], b[d[c].getId()], j, g, h, e, this.minZoom || k.minZoom, this.maxZoom || k.maxZoom) || l
-        }
-        return l
-    },
-    transformAxisBy: function(c, o, r, q, k, i, h, m) {
-        var s = this,
-            b = o[1] - o[0],
-            l = c.getVisibleRange(),
-            g = h || s.getMinZoom() || c.config.minZoom,
-            j = m || s.getMaxZoom() || c.config.maxZoom,
-            a = s.getChart().getInnerRect(),
-            f, p;
-        if (!a) {
-            return
-        }
-        var d = c.isSide(),
-            e = d ? a[3] : a[2],
-            n = d ? -q : r;
-        b /= d ? i : k;
-        if (b < 0) {
-            b = -b
-        }
-        if (b * g > 1) {
-            b = 1
-        }
-        if (b * j < 1) {
-            b = 1 / j
-        }
-        f = o[0];
-        p = o[1];
-        l = l[1] - l[0];
-        if (b === l && l === 1) {
-            return
-        }
-        c.setVisibleRange([(o[0] + o[1] - b) * 0.5 - n / e * b, (o[0] + o[1] + b) * 0.5 - n / e * b]);
-        return (Math.abs(f - c.getVisibleRange()[0]) > 1e-10 || Math.abs(p - c.getVisibleRange()[1]) > 1e-10)
-    },
-    destroy: function() {
-        this.setModeToggleButton(null);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Rotate", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "rotate",
-    alias: "interaction.rotate",
-    config: {
-        gesture: "rotate",
-        gestures: {
-            rotate: "onRotate",
-            rotateend: "onRotate",
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd"
-        },
-        rotation: 0
-    },
-    oldRotations: null,
-    getAngle: function(f) {
-        var c = this,
-            b = c.getChart(),
-            d = b.getEventXY(f),
-            a = b.getCenter();
-        return Math.atan2(d[1] - a[1], d[0] - a[0])
-    },
-    getRadius: function(a) {
-        return this.getChart().getRadius()
-    },
-    getEventRadius: function(h) {
-        var f = this,
-            d = f.getChart(),
-            g = d.getEventXY(h),
-            a = d.getCenter(),
-            c = g[0] - a[0],
-            b = g[1] - a[1];
-        return Math.sqrt(c * c + b * b)
-    },
-    onGestureStart: function(d) {
-        var c = this,
-            b = c.getRadius(d),
-            a = c.getEventRadius(d);
-        if (b >= a) {
-            c.lockEvents("drag");
-            c.angle = c.getAngle(d);
-            c.oldRotations = {};
-            return false
-        }
-    },
-    onGesture: function(b) {
-        var a = this,
-            c = a.getAngle(b) - a.angle;
-        if (a.getLocks().drag === a) {
-            a.doRotateTo(c, true);
-            return false
-        }
-    },
-    doRotateTo: function(d, a, b) {
-        var n = this,
-            l = n.getChart(),
-            k = l.getAxes(),
-            f = l.getSeries(),
-            m = n.oldRotations,
-            c, j, g, e, h;
-        if (!b) {
-            l.suspendAnimation()
-        }
-        for (e = 0, h = k.length; e < h; e++) {
-            c = k[e];
-            g = m[c.getId()] || (m[c.getId()] = c.getRotation());
-            c.setRotation(d + (a ? g : 0))
-        }
-        for (e = 0, h = f.length; e < h; e++) {
-            j = f[e];
-            g = m[j.getId()] || (m[j.getId()] = j.getRotation());
-            j.setRotation(d + (a ? g : 0))
-        }
-        n.setRotation(d + (a ? g : 0));
-        n.fireEvent("rotate", n, n.getRotation());
-        n.sync();
-        if (!b) {
-            l.resumeAnimation()
-        }
-    },
-    rotateTo: function(c, b, a) {
-        this.doRotateTo(c, b, a);
-        this.oldRotations = {}
-    },
-    onGestureEnd: function(b) {
-        var a = this;
-        if (a.getLocks().drag === a) {
-            a.onGesture(b);
-            a.unlockEvents("drag");
-            a.fireEvent("rotationEnd", a, a.getRotation());
-            return false
-        }
-    },
-    onRotate: function(a) {}
-});
-Ext.define("Ext.chart.interactions.RotatePie3D", {
-    extend: "Ext.chart.interactions.Rotate",
-    type: "rotatePie3d",
-    alias: "interaction.rotatePie3d",
-    getAngle: function(g) {
-        var a = this.getChart(),
-            f = a.getInherited().rtl,
-            d = f ? -1 : 1,
-            h = g.getXY(),
-            c = a.element.getXY(),
-            b = a.getMainRect();
-        return d * Math.atan2(h[1] - c[1] - b[3] * 0.5, h[0] - c[0] - b[2] * 0.5)
-    },
-    getRadius: function(j) {
-        var f = this.getChart(),
-            a = f.getRadius(),
-            d = f.getSeries(),
-            h = d.length,
-            c = 0,
-            b, g;
-        for (; c < h; c++) {
-            b = d[c];
-            if (b.isPie3D) {
-                g = b.getRadius();
-                if (g > a) {
-                    a = g
-                }
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.plugin.ItemEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.chartitemevents",
-    moveEvents: false,
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    itemMouseMoveEvents: {
-        itemmousemove: true,
-        itemmouseover: true,
-        itemmouseout: true
-    },
-    init: function(b) {
-        var a = "handleEvent";
-        this.chart = b;
-        b.addElementListener({
-            click: a,
-            dblclick: a,
-            mousedown: a,
-            mousemove: a,
-            mouseup: a,
-            mouseover: a,
-            mouseout: a,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasItemMouseMoveListeners: function() {
-        var b = this.chart.hasListeners,
-            a;
-        for (a in this.itemMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    handleEvent: function(g) {
-        var d = this,
-            a = d.chart,
-            h = g.type in d.mouseMoveEvents,
-            c = d.lastItem,
-            f, b;
-        if (h && !d.hasItemMouseMoveListeners() && !d.moveEvents) {
-            return
-        }
-        f = a.getEventXY(g);
-        b = a.getItemForPoint(f[0], f[1]);
-        if (h && !Ext.Object.equals(b, c)) {
-            if (c) {
-                a.fireEvent("itemmouseout", a, c, g);
-                c.series.fireEvent("itemmouseout", c.series, c, g)
-            }
-            if (b) {
-                a.fireEvent("itemmouseover", a, b, g);
-                b.series.fireEvent("itemmouseover", b.series, b, g)
-            }
-        }
-        if (b) {
-            a.fireEvent("item" + g.type, a, b, g);
-            b.series.fireEvent("item" + g.type, b.series, b, g)
-        }
-        d.lastItem = b
-    }
-});
-Ext.define("Ext.chart.series.Cartesian", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        xField: null,
-        yField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    updateXAxis: function(a) {
-        a.processData(this)
-    },
-    updateYAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    getItemForPoint: function(a, g) {
-        if (this.getSprites()) {
-            var f = this,
-                d = f.getSprites()[0],
-                b = f.getStore(),
-                e, c;
-            if (f.getHidden()) {
-                return null
-            }
-            if (d) {
-                c = d.getIndexNearPoint(a, g);
-                if (c !== -1) {
-                    e = {
-                        series: f,
-                        category: f.getItemInstancing() ? "items" : "markers",
-                        index: c,
-                        record: b.getData().items[c],
-                        field: f.getYField(),
-                        sprite: d
-                    };
-                    return e
-                }
-            }
-        }
-    },
-    createSprite: function() {
-        var c = this,
-            a = c.callParent(),
-            b = c.getChart(),
-            d = c.getXAxis();
-        a.setAttributes({
-            flipXY: b.getFlipXY(),
-            xAxis: d
-        });
-        if (a.setAggregator && d && d.getAggregator) {
-            if (d.getAggregator) {
-                a.setAggregator({
-                    strategy: d.getAggregator()
-                })
-            } else {
-                a.setAggregator({})
-            }
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = this.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.getItemInstancing(),
-            f = d.sprites,
-            a;
-        if (!c) {
-            return []
-        }
-        if (!f.length) {
-            a = d.createSprite()
-        } else {
-            a = f[0]
-        }
-        if (e) {
-            if (b) {
-                a.itemsMarker.getTemplate().setAnimation(e)
-            }
-            a.setAnimation(e)
-        }
-        return f
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    }
-});
-Ext.define("Ext.chart.series.StackedCartesian", {
-    extend: "Ext.chart.series.Cartesian",
-    config: {
-        stacked: true,
-        splitStacks: true,
-        fullStack: false,
-        fullStackTotal: 100,
-        hidden: []
-    },
-    spriteAnimationCount: 0,
-    themeColorCount: function() {
-        var b = this,
-            a = b.getYField();
-        return Ext.isArray(a) ? a.length : 1
-    },
-    updateStacked: function() {
-        this.processData()
-    },
-    updateSplitStacks: function() {
-        this.processData()
-    },
-    coordinateY: function() {
-        return this.coordinateStacked("Y", 1, 2)
-    },
-    coordinateStacked: function(D, e, m) {
-        var F = this,
-            f = F.getStore(),
-            r = f.getData().items,
-            B = r.length,
-            c = F["get" + D + "Axis"](),
-            x = F.getHidden(),
-            a = F.getSplitStacks(),
-            z = F.getFullStack(),
-            l = F.getFullStackTotal(),
-            p = {
-                min: 0,
-                max: 0
-            },
-            n = F["fieldCategory" + D],
-            C = [],
-            o = [],
-            E = [],
-            h, A = F.getStacked(),
-            g = F.getSprites(),
-            q = [],
-            w, v, u, s, H, y, b, d, G, t;
-        if (!g.length) {
-            return
-        }
-        for (w = 0; w < n.length; w++) {
-            d = n[w];
-            s = F.getFields([d]);
-            H = s.length;
-            for (v = 0; v < B; v++) {
-                C[v] = 0;
-                o[v] = 0;
-                E[v] = 0
-            }
-            for (v = 0; v < H; v++) {
-                if (!x[v]) {
-                    q[v] = F.coordinateData(r, s[v], c)
-                }
-            }
-            if (A && z) {
-                y = [];
-                if (a) {
-                    b = []
-                }
-                for (v = 0; v < B; v++) {
-                    y[v] = 0;
-                    if (a) {
-                        b[v] = 0
-                    }
-                    for (u = 0; u < H; u++) {
-                        G = q[u];
-                        if (!G) {
-                            continue
-                        }
-                        G = G[v];
-                        if (G >= 0 || !a) {
-                            y[v] += G
-                        } else {
-                            if (G < 0) {
-                                b[v] += G
-                            }
-                        }
-                    }
-                }
-            }
-            for (v = 0; v < H; v++) {
-                t = {};
-                if (x[v]) {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = C;
-                    g[v].setAttributes(t);
-                    continue
-                }
-                G = q[v];
-                if (A) {
-                    h = [];
-                    for (u = 0; u < B; u++) {
-                        if (!G[u]) {
-                            G[u] = 0
-                        }
-                        if (G[u] >= 0 || !a) {
-                            if (z && y[u]) {
-                                G[u] *= l / y[u]
-                            }
-                            C[u] = o[u];
-                            o[u] += G[u];
-                            h[u] = o[u]
-                        } else {
-                            if (z && b[u]) {
-                                G[u] *= l / b[u]
-                            }
-                            C[u] = E[u];
-                            E[u] += G[u];
-                            h[u] = E[u]
-                        }
-                    }
-                    t["dataStart" + d] = C;
-                    t["data" + d] = h;
-                    F.getRangeOfData(C, p);
-                    F.getRangeOfData(h, p)
-                } else {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = G;
-                    F.getRangeOfData(G, p)
-                }
-                g[v].setAttributes(t)
-            }
-        }
-        F.dataRange[e] = p.min;
-        F.dataRange[e + m] = p.max;
-        t = {};
-        t["dataMin" + D] = p.min;
-        t["dataMax" + D] = p.max;
-        for (w = 0; w < g.length; w++) {
-            g[w].setAttributes(t)
-        }
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    updateLabelOverflowPadding: function(a) {
-        this.getLabel().setAttributes({
-            labelOverflowPadding: a
-        })
-    },
-    getSprites: function() {
-        var k = this,
-            j = k.getChart(),
-            c = k.getAnimation() || j && j.getAnimation(),
-            f = k.getFields(k.fieldCategoryY),
-            b = k.getItemInstancing(),
-            h = k.sprites,
-            l, e = k.getHidden(),
-            g = false,
-            d, a = f.length;
-        if (!j) {
-            return []
-        }
-        for (d = 0; d < a; d++) {
-            l = h[d];
-            if (!l) {
-                l = k.createSprite();
-                l.setAttributes({
-                    zIndex: -d
-                });
-                l.setField(f[d]);
-                g = true;
-                e.push(false);
-                if (b) {
-                    l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))
-                } else {
-                    l.setAttributes(k.getStyleByIndex(d))
-                }
-            }
-            if (c) {
-                if (b) {
-                    l.itemsMarker.getTemplate().setAnimation(c)
-                }
-                l.setAnimation(c)
-            }
-        }
-        if (g) {
-            k.updateHidden(e)
-        }
-        return h
-    },
-    getItemForPoint: function(k, j) {
-        if (this.getSprites()) {
-            var h = this,
-                b, g, m, a = h.getItemInstancing(),
-                f = h.getSprites(),
-                l = h.getStore(),
-                c = h.getHidden(),
-                n, d, e;
-            for (b = 0, g = f.length; b < g; b++) {
-                if (!c[b]) {
-                    m = f[b];
-                    d = m.getIndexNearPoint(k, j);
-                    if (d !== -1) {
-                        e = h.getYField();
-                        n = {
-                            series: h,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: l.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: m
-                        };
-                        return n
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(e) {
-        var g = this,
-            f = g.getSprites(),
-            h = g.getTitle(),
-            j = g.getYField(),
-            d = g.getHidden(),
-            k = f.length === 1,
-            b, l, c, a;
-        for (c = 0; c < f.length; c++) {
-            b = g.getStyleByIndex(c);
-            l = b.fillStyle;
-            if (h) {
-                if (Ext.isArray(h)) {
-                    a = h[c]
-                } else {
-                    if (k) {
-                        a = h
-                    }
-                }
-            } else {
-                if (Ext.isArray(j)) {
-                    a = j[c]
-                } else {
-                    a = g.getId()
-                }
-            }
-            e.push({
-                name: a,
-                mark: (Ext.isObject(l) ? l.stops && l.stops[0].color : l) || b.strokeStyle || "black",
-                disabled: d[c],
-                series: g.getId(),
-                index: c
-            })
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart")
-        }
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend")
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Series", {
-    extend: "Ext.draw.sprite.Sprite",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataMinX: "number",
-                dataMaxX: "number",
-                dataMinY: "number",
-                dataMaxY: "number",
-                rangeX: "data",
-                rangeY: "data",
-                dataX: "data",
-                dataY: "data"
-            },
-            defaults: {
-                dataMinX: 0,
-                dataMaxX: 1,
-                dataMinY: 0,
-                dataMaxY: 1,
-                rangeX: null,
-                rangeY: null,
-                dataX: null,
-                dataY: null
-            },
-            triggers: {
-                dataX: "bbox",
-                dataY: "bbox",
-                dataMinX: "bbox",
-                dataMaxX: "bbox",
-                dataMinY: "bbox",
-                dataMaxY: "bbox"
-            }
-        }
-    },
-    config: {
-        store: null,
-        series: null,
-        field: null
-    }
-});
-Ext.define("Ext.chart.series.sprite.Cartesian", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                labels: "default",
-                labelOverflowPadding: "number",
-                selectionTolerance: "number",
-                flipXY: "bool",
-                renderer: "default",
-                visibleMinX: "number",
-                visibleMinY: "number",
-                visibleMaxX: "number",
-                visibleMaxY: "number",
-                innerWidth: "number",
-                innerHeight: "number"
-            },
-            defaults: {
-                labels: null,
-                labelOverflowPadding: 10,
-                selectionTolerance: 20,
-                flipXY: false,
-                renderer: null,
-                transformFillStroke: false,
-                visibleMinX: 0,
-                visibleMinY: 0,
-                visibleMaxX: 1,
-                visibleMaxY: 1,
-                innerWidth: 1,
-                innerHeight: 1
-            },
-            triggers: {
-                dataX: "dataX,bbox",
-                dataY: "dataY,bbox",
-                visibleMinX: "panzoom",
-                visibleMinY: "panzoom",
-                visibleMaxX: "panzoom",
-                visibleMaxY: "panzoom",
-                innerWidth: "panzoom",
-                innerHeight: "panzoom"
-            },
-            updaters: {
-                dataX: function(a) {
-                    this.processDataX();
-                    this.scheduleUpdater(a, "dataY", ["dataY"])
-                },
-                dataY: function() {
-                    this.processDataY()
-                },
-                panzoom: function(c) {
-                    var e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        g = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = this.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * g / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = g / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    this.applyTransformations(true)
-                }
-            }
-        }
-    },
-    processDataY: Ext.emptyFn,
-    processDataX: Ext.emptyFn,
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.dataMinX;
-        b.y = a.dataMinY;
-        b.width = a.dataMaxX - a.dataMinX;
-        b.height = a.dataMaxY - a.dataMinY
-    },
-    binarySearch: function(d) {
-        var b = this.attr.dataX,
-            f = 0,
-            a = b.length;
-        if (d <= b[0]) {
-            return f
-        }
-        if (d >= b[a - 1]) {
-            return a - 1
-        }
-        while (f + 1 < a) {
-            var c = (f + a) >> 1,
-                e = b[c];
-            if (e === d) {
-                return c
-            } else {
-                if (e < d) {
-                    f = c
-                } else {
-                    a = c
-                }
-            }
-        }
-        return f
-    },
-    render: function(b, c, g) {
-        var f = this,
-            a = f.attr,
-            e = a.inverseMatrix.clone();
-        e.appendMatrix(b.inverseMatrix);
-        if (a.dataX === null || a.dataX === undefined) {
-            return
-        }
-        if (a.dataY === null || a.dataY === undefined) {
-            return
-        }
-        if (e.getXX() * e.getYX() || e.getXY() * e.getYY()) {
-            console.log("Cartesian Series sprite does not support rotation/sheering");
-            return
-        }
-        var d = e.transformList([
-            [g[0] - 1, g[3] + 1],
-            [g[0] + g[2] + 1, -1]
-        ]);
-        d = d[0].concat(d[1]);
-        f.renderClipped(b, c, d, g)
-    },
-    renderClipped: Ext.emptyFn,
-    getIndexNearPoint: function(f, e) {
-        var w = this,
-            q = w.attr.matrix,
-            h = w.attr.dataX,
-            g = w.attr.dataY,
-            k = w.attr.selectionTolerance,
-            t, r, c = -1,
-            j = q.clone().prependMatrix(w.surfaceMatrix).inverse(),
-            u = j.transformPoint([f, e]),
-            b = j.transformPoint([f - k, e - k]),
-            n = j.transformPoint([f + k, e + k]),
-            a = Math.min(b[0], n[0]),
-            s = Math.max(b[0], n[0]),
-            l = Math.min(b[1], n[1]),
-            d = Math.max(b[1], n[1]),
-            m, v, o, p;
-        for (o = 0, p = h.length; o < p; o++) {
-            m = h[o];
-            v = g[o];
-            if (m > a && m < s && v > l && v < d) {
-                if (c === -1 || (Math.abs(m - u[0]) < t) && (Math.abs(v - u[1]) < r)) {
-                    t = Math.abs(m - u[0]);
-                    r = Math.abs(v - u[1]);
-                    c = o
-                }
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.series.sprite.StackedCartesian", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                groupCount: "number",
-                groupOffset: "number",
-                dataStartY: "data"
-            },
-            defaults: {
-                selectionTolerance: 20,
-                groupCount: 1,
-                groupOffset: 0,
-                dataStartY: null
-            },
-            triggers: {
-                dataStartY: "dataY,bbox"
-            }
-        }
-    },
-    getIndexNearPoint: function(e, d) {
-        var o = this,
-            q = o.attr.matrix,
-            h = o.attr.dataX,
-            f = o.attr.dataY,
-            u = o.attr.dataStartY,
-            l = o.attr.selectionTolerance,
-            s = 0.5,
-            r = Infinity,
-            b = -1,
-            k = q.clone().prependMatrix(this.surfaceMatrix).inverse(),
-            t = k.transformPoint([e, d]),
-            a = k.transformPoint([e - l, d - l]),
-            n = k.transformPoint([e + l, d + l]),
-            m = Math.min(a[1], n[1]),
-            c = Math.max(a[1], n[1]),
-            j, g;
-        for (var p = 0; p < h.length; p++) {
-            if (Math.min(u[p], f[p]) <= c && m <= Math.max(u[p], f[p])) {
-                j = Math.abs(h[p] - t[0]);
-                g = Math.max(-Math.min(f[p] - t[1], t[1] - u[p]), 0);
-                if (j < s && g <= r) {
-                    s = j;
-                    r = g;
-                    b = p
-                }
-            }
-        }
-        return b
-    }
-});
-Ext.define("Ext.chart.series.sprite.Area", {
-    alias: "sprite.areaSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                step: "bool"
-            },
-            defaults: {
-                step: false
-            }
-        }
-    },
-    renderClipped: function(q, s, A) {
-        var B = this,
-            p = B.attr,
-            l = p.dataX,
-            j = p.dataY,
-            C = p.dataStartY,
-            t = p.matrix,
-            h, g, v, f, d, z, w, e = t.elements[0],
-            m = t.elements[4],
-            o = t.elements[3],
-            k = t.elements[5],
-            c = B.surfaceMatrix,
-            n = {},
-            r = Math.min(A[0], A[2]),
-            u = Math.max(A[0], A[2]),
-            b = Math.max(0, this.binarySearch(r)),
-            a = Math.min(l.length - 1, this.binarySearch(u) + 1);
-        s.beginPath();
-        z = l[b] * e + m;
-        w = j[b] * o + k;
-        s.moveTo(z, w);
-        if (p.step) {
-            d = w;
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g)
-            }
-        }
-        if (C) {
-            if (p.step) {
-                f = l[a] * e + m;
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(f, g);
-                    s.lineTo(f = h, g)
-                }
-            } else {
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(h, g)
-                }
-            }
-        } else {
-            s.lineTo(l[a] * e + m, g);
-            s.lineTo(l[a] * e + m, k);
-            s.lineTo(z, k);
-            s.lineTo(z, j[v] * o + k)
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.fill();
-        if (p.transformFillStroke) {
-            p.inverseMatrix.toContext(s)
-        }
-        s.beginPath();
-        s.moveTo(z, w);
-        if (p.step) {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.stroke()
-    }
-});
-Ext.define("Ext.chart.series.Area", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.area",
-    type: "area",
-    seriesType: "areaSeries",
-    requires: ["Ext.chart.series.sprite.Area"],
-    config: {
-        splitStacks: false
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar", {
-    alias: "sprite.barSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                minBarWidth: "number",
-                maxBarWidth: "number",
-                minGapWidth: "number",
-                radius: "number",
-                inGroupGapWidth: "number"
-            },
-            defaults: {
-                minBarWidth: 2,
-                maxBarWidth: 100,
-                minGapWidth: 5,
-                inGroupGapWidth: 3,
-                radius: 0
-            }
-        }
-    },
-    drawLabel: function(k, i, s, h, o) {
-        var q = this,
-            n = q.attr,
-            f = q.getMarker("labels"),
-            d = f.getTemplate(),
-            l = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            j = n.labelOverflowPadding,
-            b = d.attr.display,
-            m = d.attr.orientation,
-            g, e, a, r, t, p;
-        l.x = c.x(i, h);
-        l.y = c.y(i, h);
-        if (!n.flipXY) {
-            l.rotationRads = -Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        l.calloutVertical = !n.flipXY;
-        switch (m) {
-            case "horizontal":
-                l.rotationRads = 0;
-                l.calloutVertical = false;
-                break;
-            case "vertical":
-                l.rotationRads = -Math.PI * 0.5;
-                l.calloutVertical = true;
-                break
-        }
-        l.text = k;
-        if (d.attr.renderer) {
-            p = [k, f, l, {
-                store: q.getStore()
-            }, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                l.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        l.text = r.text
-                    }
-                    t = true
-                }
-            }
-        }
-        a = q.getMarkerBBox("labels", o, true);
-        if (!a) {
-            q.putMarker("labels", l, o);
-            a = q.getMarkerBBox("labels", o, true)
-        }
-        e = (a.width / 2 + j);
-        if (s > h) {
-            e = -e
-        }
-        if ((m === "horizontal" && n.flipXY) || (m === "vertical" && !n.flipXY) || !m) {
-            g = (b === "insideStart") ? s + e : h - e
-        } else {
-            g = (b === "insideStart") ? s + j * 2 : h - j * 2
-        }
-        l.x = c.x(i, g);
-        l.y = c.y(i, g);
-        g = (b === "insideStart") ? s - e : h + e;
-        l.calloutPlaceX = c.x(i, g);
-        l.calloutPlaceY = c.y(i, g);
-        g = (b === "insideStart") ? s : h;
-        l.calloutStartX = c.x(i, g);
-        l.calloutStartY = c.y(i, g);
-        if (s > h) {
-            e = -e
-        }
-        if (Math.abs(h - s) <= e * 2 || b === "outside") {
-            l.callout = 1
-        } else {
-            l.callout = 0
-        }
-        if (t) {
-            Ext.apply(l, r)
-        }
-        q.putMarker("labels", l, o)
-    },
-    drawBar: function(l, b, d, c, h, k, a, e) {
-        var g = this,
-            j = {},
-            f = g.attr.renderer,
-            i;
-        j.x = c;
-        j.y = h;
-        j.width = k - c;
-        j.height = a - h;
-        j.radius = g.attr.radius;
-        if (f) {
-            i = Ext.callback(f, null, [g, j, {
-                store: g.getStore()
-            }, e], 0, g.getSeries());
-            Ext.apply(j, i)
-        }
-        g.putMarker("items", j, e, !f)
-    },
-    renderClipped: function(G, u, F, C) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var q = this,
-            o = q.attr,
-            w = o.dataX,
-            v = o.dataY,
-            H = o.labels,
-            n = o.dataStartY,
-            m = o.groupCount,
-            E = o.groupOffset - (m - 1) * 0.5,
-            z = o.inGroupGapWidth,
-            t = u.lineWidth,
-            D = o.matrix,
-            B = D.elements[0],
-            j = D.elements[3],
-            e = D.elements[4],
-            d = G.roundPixel(D.elements[5]) - 1,
-            J = (B < 0 ? -1 : 1) * B - o.minGapWidth,
-            k = (Math.min(J, o.maxBarWidth) - z * (m - 1)) / m,
-            A = G.roundPixel(Math.max(o.minBarWidth, k)),
-            c = q.surfaceMatrix,
-            g, I, b, h, K, a, l = 0.5 * o.lineWidth,
-            L = Math.min(F[0], F[2]),
-            x = Math.max(F[0], F[2]),
-            y = Math.max(0, Math.floor(L)),
-            p = Math.min(w.length - 1, Math.ceil(x)),
-            f = H && q.getMarker("labels"),
-            s, r;
-        for (K = y; K <= p; K++) {
-            s = n ? n[K] : 0;
-            r = v[K];
-            a = w[K] * B + e + E * (A + z);
-            g = G.roundPixel(a - A / 2) + l;
-            h = G.roundPixel(r * j + d + t);
-            I = G.roundPixel(a + A / 2) - l;
-            b = G.roundPixel(s * j + d + t);
-            q.drawBar(u, G, F, g, h - l, I, b - l, K);
-            if (f && H[K] != null) {
-                q.drawLabel(H[K], a, b, h, K)
-            }
-            q.putMarker("markers", {
-                translationX: c.x(a, h),
-                translationY: c.y(a, h)
-            }, K, true)
-        }
-    },
-    getIndexNearPoint: function(l, k) {
-        var m = this,
-            g = m.attr,
-            h = g.dataX,
-            a = m.getSurface(),
-            b = a.getRect() || [0, 0, 0, 0],
-            j = b[3],
-            e, d, c, n, f = -1;
-        if (g.flipXY) {
-            e = j - k;
-            if (a.getInherited().rtl) {
-                d = b[2] - l
-            } else {
-                d = l
-            }
-        } else {
-            e = l;
-            d = j - k
-        }
-        for (c = 0; c < h.length; c++) {
-            n = m.getMarkerBBox("items", c);
-            if (Ext.draw.Draw.isPointInBBox(e, d, n)) {
-                f = c;
-                break
-            }
-        }
-        return f
-    }
-});
-Ext.define("Ext.chart.series.Bar", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.bar",
-    type: "bar",
-    seriesType: "barSeries",
-    requires: ["Ext.chart.series.sprite.Bar", "Ext.draw.sprite.Rect"],
-    config: {
-        itemInstancing: {
-            type: "rect",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    radius: 0
-                }
-            }
-        }
-    },
-    getItemForPoint: function(a, f) {
-        if (this.getSprites()) {
-            var d = this,
-                c = d.getChart(),
-                e = c.getInnerPadding(),
-                b = c.getInherited().rtl;
-            arguments[0] = a + (b ? e.right : -e.left);
-            arguments[1] = f + e.bottom;
-            return d.callParent(arguments)
-        }
-    },
-    updateXAxis: function(a) {
-        a.setLabelInSpan(true);
-        this.callParent(arguments)
-    },
-    updateHidden: function(a) {
-        this.callParent(arguments);
-        this.updateStacked()
-    },
-    updateStacked: function(c) {
-        var e = this,
-            g = e.getSprites(),
-            d = g.length,
-            f = [],
-            a = {},
-            b;
-        for (b = 0; b < d; b++) {
-            if (!g[b].attr.hidden) {
-                f.push(g[b])
-            }
-        }
-        d = f.length;
-        if (e.getStacked()) {
-            a.groupCount = 1;
-            a.groupOffset = 0;
-            for (b = 0; b < d; b++) {
-                f[b].setAttributes(a)
-            }
-        } else {
-            a.groupCount = f.length;
-            for (b = 0; b < d; b++) {
-                a.groupOffset = b;
-                f[b].setAttributes(a)
-            }
-        }
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar3D", {
-    extend: "Ext.chart.series.sprite.Bar",
-    alias: "sprite.bar3dSeries",
-    requires: ["Ext.draw.gradient.Linear"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                depthWidthRatio: "number",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            defaults: {
-                depthWidthRatio: 1 / 3,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                transformFillStroke: true
-            },
-            triggers: {
-                groupCount: "panzoom"
-            },
-            updaters: {
-                panzoom: function(c) {
-                    var g = this,
-                        e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        h = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = g.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * (h - g.depth) / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = (h - g.depth) / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    g.applyTransformations(true)
-                }
-            }
-        }
-    },
-    config: {
-        showStroke: false
-    },
-    depth: 0,
-    drawBar: function(p, b, d, c, l, o, a, h) {
-        var k = this,
-            i = k.attr,
-            n = {},
-            j = i.renderer,
-            m, g, f, e;
-        n.x = (c + o) * 0.5;
-        n.y = l;
-        n.width = (o - c) * 0.75;
-        n.height = a - l;
-        n.depth = g = n.width * i.depthWidthRatio;
-        n.orientation = i.flipXY ? "horizontal" : "vertical";
-        n.saturationFactor = i.saturationFactor;
-        n.brightnessFactor = i.brightnessFactor;
-        n.colorSpread = i.colorSpread;
-        if (g !== k.depth) {
-            k.depth = g;
-            f = k.getSeries();
-            f.fireEvent("depthchange", f, g)
-        }
-        if (j) {
-            e = [k, n, {
-                store: k.getStore()
-            }, h];
-            m = Ext.callback(j, null, e, 0, k.getSeries());
-            Ext.apply(n, m)
-        }
-        k.putMarker("items", n, h, !j)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Box", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.box",
-    type: "box",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                depth: "number",
-                orientation: "enums(vertical,horizontal)",
-                showStroke: "bool",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            triggers: {
-                x: "bbox",
-                y: "bbox",
-                width: "bbox",
-                height: "bbox",
-                depth: "bbox",
-                orientation: "bbox"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                depth: 8,
-                orientation: "vertical",
-                showStroke: false,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                lineJoin: "bevel"
-            }
-        }
-    },
-    constructor: function(a) {
-        this.callParent([a]);
-        this.topGradient = new Ext.draw.gradient.Linear({});
-        this.rightGradient = new Ext.draw.gradient.Linear({});
-        this.frontGradient = new Ext.draw.gradient.Linear({})
-    },
-    updatePlainBBox: function(d) {
-        var c = this.attr,
-            b = c.x,
-            g = c.y,
-            e = c.width,
-            a = c.height,
-            f = c.depth;
-        d.x = b - e * 0.5;
-        d.width = e + f;
-        if (a > 0) {
-            d.y = g;
-            d.height = a + f
-        } else {
-            d.y = g + f;
-            d.height = a - f
-        }
-    },
-    render: function(l, m) {
-        var u = this,
-            k = u.attr,
-            r = k.x,
-            j = k.y,
-            f = j + k.height,
-            i = j < f,
-            e = k.width * 0.5,
-            v = k.depth,
-            d = k.orientation === "horizontal",
-            g = k.globalAlpha < 1,
-            c = k.fillStyle,
-            n = Ext.draw.Color.create(c.isGradient ? c.getStops()[0].color : c),
-            h = k.saturationFactor,
-            o = k.brightnessFactor,
-            t = k.colorSpread,
-            b = n.getHSV(),
-            a = {},
-            s, q, p;
-        if (!k.showStroke) {
-            m.strokeStyle = Ext.draw.Color.RGBA_NONE
-        }
-        if (i) {
-            p = j;
-            j = f;
-            f = p
-        }
-        u.topGradient.setDegrees(d ? 0 : 80);
-        u.topGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.11) * o, 0, 1))
-        }]);
-        u.rightGradient.setDegrees(d ? 45 : 90);
-        u.rightGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.14) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.4) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.32) * o, 0, 1))
-        }]);
-        if (d) {
-            u.frontGradient.setDegrees(0)
-        } else {
-            u.frontGradient.setRadians(Math.atan2(j - f, e * 2))
-        }
-        u.frontGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 - t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.23) * o, 0, 1))
-        }]);
-        if (g || i) {
-            m.beginPath();
-            m.moveTo(r - e, f);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r + e + v, f + v);
-            m.lineTo(r + e, f);
-            m.closePath();
-            a.x = r - e;
-            a.y = j;
-            a.width = e + v;
-            a.height = v;
-            m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        if (g) {
-            m.beginPath();
-            m.moveTo(r - e, j);
-            m.lineTo(r - e + v, j + v);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r - e, f);
-            m.closePath();
-            a.x = r + e;
-            a.y = f;
-            a.width = v;
-            a.height = j + v - f;
-            m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, q);
-        m.lineTo(r - e + v, j + v);
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e, q);
-        m.closePath();
-        a.x = r - e;
-        a.y = j;
-        a.width = e + v;
-        a.height = v;
-        m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        m.beginPath();
-        m.moveTo(s, l.roundPixel(j));
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e + v, f + v);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r + e;
-        a.y = f;
-        a.width = v;
-        a.height = j + v - f;
-        m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, f);
-        m.lineTo(r - e, q);
-        m.lineTo(s, q);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r - e;
-        a.y = f;
-        a.width = e * 2;
-        a.height = j - f;
-        m.fillStyle = u.frontGradient.generateGradient(m, a);
-        m.fillStroke(k)
-    }
-});
-Ext.define("Ext.chart.series.Bar3D", {
-    extend: "Ext.chart.series.Bar",
-    requires: ["Ext.chart.series.sprite.Bar3D", "Ext.chart.series.sprite.Box"],
-    alias: "series.bar3d",
-    type: "bar3d",
-    seriesType: "bar3dSeries",
-    config: {
-        itemInstancing: {
-            type: "box",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    depth: 0
-                }
-            }
-        },
-        highlightCfg: {
-            opacity: 0.8
-        }
-    },
-    getSprites: function() {
-        var c = this.callParent(arguments),
-            b, d, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            d = b.attr.zIndex;
-            if (d < 0) {
-                b.setAttributes({
-                    zIndex: -d
-                })
-            }
-            if (b.setSeries) {
-                b.setSeries(this)
-            }
-        }
-        return c
-    },
-    getDepth: function() {
-        var a = this.getSprites()[0];
-        return a ? (a.depth || 0) : 0
-    },
-    getItemForPoint: function(m, k) {
-        if (this.getSprites()) {
-            var j = this,
-                b, o, a = j.getItemInstancing(),
-                h = j.getSprites(),
-                n = j.getStore(),
-                c = j.getHidden(),
-                g = j.getChart(),
-                l = g.getInnerPadding(),
-                f = g.getInherited().rtl,
-                p, d, e;
-            m = m + (f ? l.right : -l.left);
-            k = k + l.bottom;
-            for (b = h.length - 1; b >= 0; b--) {
-                if (!c[b]) {
-                    o = h[b];
-                    d = o.getIndexNearPoint(m, k);
-                    if (d !== -1) {
-                        e = j.getYField();
-                        p = {
-                            series: j,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: n.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: o
-                        };
-                        return p
-                    }
-                }
-            }
-            return null
-        }
-    }
-});
-Ext.define("Ext.draw.LimitedCache", {
-    config: {
-        limit: 40,
-        feeder: function() {
-            return 0
-        },
-        scope: null
-    },
-    cache: null,
-    constructor: function(a) {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0;
-        this.initConfig(a)
-    },
-    get: function(e) {
-        var c = this.cache,
-            b = this.getLimit(),
-            a = this.getFeeder(),
-            d = this.getScope() || this;
-        if (c[e]) {
-            return c[e].value
-        }
-        if (c.list[c.tail]) {
-            delete c[c.list[c.tail].cacheId]
-        }
-        c[e] = c.list[c.tail] = {
-            value: a.apply(d, Array.prototype.slice.call(arguments, 1)),
-            cacheId: e
-        };
-        c.tail++;
-        if (c.tail === b) {
-            c.tail = 0
-        }
-        return c[e].value
-    },
-    clear: function() {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0
-    }
-});
-Ext.define("Ext.draw.SegmentTree", {
-    config: {
-        strategy: "double"
-    },
-    time: function(m, l, n, c, E, d, e) {
-        var f = 0,
-            o, A, s = new Date(n[m.startIdx[0]]),
-            x = new Date(n[m.endIdx[l - 1]]),
-            D = Ext.Date,
-            u = [
-                [D.MILLI, 1, "ms1", null],
-                [D.MILLI, 2, "ms2", "ms1"],
-                [D.MILLI, 5, "ms5", "ms1"],
-                [D.MILLI, 10, "ms10", "ms5"],
-                [D.MILLI, 50, "ms50", "ms10"],
-                [D.MILLI, 100, "ms100", "ms50"],
-                [D.MILLI, 500, "ms500", "ms100"],
-                [D.SECOND, 1, "s1", "ms500"],
-                [D.SECOND, 10, "s10", "s1"],
-                [D.SECOND, 30, "s30", "s10"],
-                [D.MINUTE, 1, "mi1", "s10"],
-                [D.MINUTE, 5, "mi5", "mi1"],
-                [D.MINUTE, 10, "mi10", "mi5"],
-                [D.MINUTE, 30, "mi30", "mi10"],
-                [D.HOUR, 1, "h1", "mi30"],
-                [D.HOUR, 6, "h6", "h1"],
-                [D.HOUR, 12, "h12", "h6"],
-                [D.DAY, 1, "d1", "h12"],
-                [D.DAY, 7, "d7", "d1"],
-                [D.MONTH, 1, "mo1", "d1"],
-                [D.MONTH, 3, "mo3", "mo1"],
-                [D.MONTH, 6, "mo6", "mo3"],
-                [D.YEAR, 1, "y1", "mo3"],
-                [D.YEAR, 5, "y5", "y1"],
-                [D.YEAR, 10, "y10", "y5"],
-                [D.YEAR, 100, "y100", "y10"]
-            ],
-            z, b, k = f,
-            F = l,
-            j = false,
-            r = m.startIdx,
-            h = m.endIdx,
-            w = m.minIdx,
-            C = m.maxIdx,
-            a = m.open,
-            y = m.close,
-            g = m.minX,
-            q = m.minY,
-            p = m.maxX,
-            B = m.maxY,
-            v, t;
-        for (z = 0; l > f + 1 && z < u.length; z++) {
-            s = new Date(n[r[0]]);
-            b = u[z];
-            s = D.align(s, b[0], b[1]);
-            if (D.diff(s, x, b[0]) > n.length * 2 * b[1]) {
-                continue
-            }
-            if (b[3] && m.map["time_" + b[3]]) {
-                o = m.map["time_" + b[3]][0];
-                A = m.map["time_" + b[3]][1]
-            } else {
-                o = k;
-                A = F
-            }
-            f = l;
-            t = s;
-            j = true;
-            r[l] = r[o];
-            h[l] = h[o];
-            w[l] = w[o];
-            C[l] = C[o];
-            a[l] = a[o];
-            y[l] = y[o];
-            g[l] = g[o];
-            q[l] = q[o];
-            p[l] = p[o];
-            B[l] = B[o];
-            t = Ext.Date.add(t, b[0], b[1]);
-            for (v = o + 1; v < A; v++) {
-                if (n[h[v]] < +t) {
-                    h[l] = h[v];
-                    y[l] = y[v];
-                    if (B[v] > B[l]) {
-                        B[l] = B[v];
-                        p[l] = p[v];
-                        C[l] = C[v]
-                    }
-                    if (q[v] < q[l]) {
-                        q[l] = q[v];
-                        g[l] = g[v];
-                        w[l] = w[v]
-                    }
-                } else {
-                    l++;
-                    r[l] = r[v];
-                    h[l] = h[v];
-                    w[l] = w[v];
-                    C[l] = C[v];
-                    a[l] = a[v];
-                    y[l] = y[v];
-                    g[l] = g[v];
-                    q[l] = q[v];
-                    p[l] = p[v];
-                    B[l] = B[v];
-                    t = Ext.Date.add(t, b[0], b[1])
-                }
-            }
-            if (l > f) {
-                m.map["time_" + b[2]] = [f, l]
-            }
-        }
-    },
-    "double": function(h, u, j, a, t, b, c) {
-        var e = 0,
-            k, f = 1,
-            n, d, v, g, s, l, m, r, q, p, o;
-        while (u > e + 1) {
-            k = e;
-            e = u;
-            f += f;
-            for (n = k; n < e; n += 2) {
-                if (n === e - 1) {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n];
-                    g = h.minIdx[n];
-                    s = h.maxIdx[n];
-                    l = h.open[n];
-                    m = h.close[n];
-                    r = h.minX[n];
-                    q = h.minY[n];
-                    p = h.maxX[n];
-                    o = h.maxY[n]
-                } else {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n + 1];
-                    l = h.open[n];
-                    m = h.close[n];
-                    if (h.minY[n] <= h.minY[n + 1]) {
-                        g = h.minIdx[n];
-                        r = h.minX[n];
-                        q = h.minY[n]
-                    } else {
-                        g = h.minIdx[n + 1];
-                        r = h.minX[n + 1];
-                        q = h.minY[n + 1]
-                    }
-                    if (h.maxY[n] >= h.maxY[n + 1]) {
-                        s = h.maxIdx[n];
-                        p = h.maxX[n];
-                        o = h.maxY[n]
-                    } else {
-                        s = h.maxIdx[n + 1];
-                        p = h.maxX[n + 1];
-                        o = h.maxY[n + 1]
-                    }
-                }
-                h.startIdx[u] = d;
-                h.endIdx[u] = v;
-                h.minIdx[u] = g;
-                h.maxIdx[u] = s;
-                h.open[u] = l;
-                h.close[u] = m;
-                h.minX[u] = r;
-                h.minY[u] = q;
-                h.maxX[u] = p;
-                h.maxY[u] = o;
-                u++
-            }
-            h.map["double_" + f] = [e, u]
-        }
-    },
-    none: Ext.emptyFn,
-    aggregateData: function(h, a, r, c, d) {
-        var b = h.length,
-            e = [],
-            s = [],
-            f = [],
-            q = [],
-            j = [],
-            p = [],
-            n = [],
-            o = [],
-            m = [],
-            k = [],
-            g = {
-                startIdx: e,
-                endIdx: s,
-                minIdx: f,
-                maxIdx: q,
-                open: j,
-                minX: p,
-                minY: n,
-                maxX: o,
-                maxY: m,
-                close: k
-            },
-            l;
-        for (l = 0; l < b; l++) {
-            e[l] = l;
-            s[l] = l;
-            f[l] = l;
-            q[l] = l;
-            j[l] = a[l];
-            p[l] = h[l];
-            n[l] = c[l];
-            o[l] = h[l];
-            m[l] = r[l];
-            k[l] = d[l]
-        }
-        g.map = {
-            original: [0, b]
-        };
-        if (b) {
-            this[this.getStrategy()](g, b, h, a, r, c, d)
-        }
-        return g
-    },
-    binarySearchMin: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.startIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.startIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.startIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return g
-    },
-    binarySearchMax: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.endIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.endIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.endIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return a
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    setData: function(d, a, b, c, e) {
-        if (!b) {
-            e = c = b = a
-        }
-        this.dataX = d;
-        this.dataOpen = a;
-        this.dataHigh = b;
-        this.dataLow = c;
-        this.dataClose = e;
-        if (d.length === b.length && d.length === c.length) {
-            this.cache = this.aggregateData(d, a, b, c, e)
-        }
-    },
-    getAggregation: function(d, k, i) {
-        if (!this.cache) {
-            return null
-        }
-        var c = Infinity,
-            g = this.dataX[this.dataX.length - 1] - this.dataX[0],
-            l = this.cache.map,
-            m = l.original,
-            a, e, j, b, f, h;
-        for (a in l) {
-            e = l[a];
-            j = e[1] - e[0] - 1;
-            b = g / j;
-            if (i <= b && b < c) {
-                m = e;
-                c = b
-            }
-        }
-        f = Math.max(this.binarySearchMin(this.cache, m[0], m[1], d), m[0]);
-        h = Math.min(this.binarySearchMax(this.cache, m[0], m[1], k) + 1, m[1]);
-        return {
-            data: this.cache,
-            start: f,
-            end: h
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Aggregative", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    requires: ["Ext.draw.LimitedCache", "Ext.draw.SegmentTree"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataHigh: "data",
-                dataLow: "data",
-                dataClose: "data"
-            },
-            aliases: {
-                dataOpen: "dataY"
-            },
-            defaults: {
-                dataHigh: null,
-                dataLow: null,
-                dataClose: null
-            }
-        }
-    },
-    config: {
-        aggregator: {}
-    },
-    applyAggregator: function(b, a) {
-        return Ext.factory(b, Ext.draw.SegmentTree, a)
-    },
-    constructor: function() {
-        this.callParent(arguments)
-    },
-    processDataY: function() {
-        var d = this,
-            b = d.attr,
-            e = b.dataHigh,
-            a = b.dataLow,
-            f = b.dataClose,
-            c = b.dataY;
-        d.callParent(arguments);
-        if (b.dataX && c && c.length > 0) {
-            if (e) {
-                d.getAggregator().setData(b.dataX, b.dataY, e, a, f)
-            } else {
-                d.getAggregator().setData(b.dataX, b.dataY)
-            }
-        }
-    },
-    getGapWidth: function() {
-        return 1
-    },
-    renderClipped: function(b, c, g, f) {
-        var e = this,
-            d = Math.min(g[0], g[2]),
-            a = Math.max(g[0], g[2]),
-            h = e.getAggregator() && e.getAggregator().getAggregation(d, a, (a - d) / f[2] * e.getGapWidth());
-        if (h) {
-            e.dataStart = h.data.startIdx[h.start];
-            e.dataEnd = h.data.endIdx[h.end - 1];
-            e.renderAggregates(h.data, h.start, h.end, b, c, g, f)
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.CandleStick", {
-    alias: "sprite.candlestickSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                raiseStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                dropStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                barWidth: "number",
-                padding: "number",
-                ohlcType: "enums(candlestick,ohlc)"
-            },
-            defaults: {
-                raiseStyle: {
-                    strokeStyle: "green",
-                    fillStyle: "green"
-                },
-                dropStyle: {
-                    strokeStyle: "red",
-                    fillStyle: "red"
-                },
-                planar: false,
-                barWidth: 15,
-                padding: 3,
-                lineJoin: "miter",
-                miterLimit: 5,
-                ohlcType: "candlestick"
-            },
-            triggers: {
-                raiseStyle: "raiseStyle",
-                dropStyle: "dropStyle"
-            },
-            updaters: {
-                raiseStyle: function() {
-                    this.raiseTemplate && this.raiseTemplate.setAttributes(this.attr.raiseStyle)
-                },
-                dropStyle: function() {
-                    this.dropTemplate && this.dropTemplate.setAttributes(this.attr.dropStyle)
-                }
-            }
-        }
-    },
-    candlestick: function(i, c, a, e, h, f, b) {
-        var d = Math.min(c, h),
-            g = Math.max(c, h);
-        i.moveTo(f, e);
-        i.lineTo(f, g);
-        i.moveTo(f + b, g);
-        i.lineTo(f + b, d);
-        i.lineTo(f - b, d);
-        i.lineTo(f - b, g);
-        i.closePath();
-        i.moveTo(f, a);
-        i.lineTo(f, d)
-    },
-    ohlc: function(b, d, e, a, f, c, g) {
-        b.moveTo(c, e);
-        b.lineTo(c, a);
-        b.moveTo(c, d);
-        b.lineTo(c - g, d);
-        b.moveTo(c, f);
-        b.lineTo(c + g, f)
-    },
-    constructor: function() {
-        this.callParent(arguments);
-        this.raiseTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        });
-        this.dropTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        })
-    },
-    getGapWidth: function() {
-        var a = this.attr,
-            b = a.barWidth,
-            c = a.padding;
-        return b + c
-    },
-    renderAggregates: function(d, c, b, t, u, z) {
-        var D = this,
-            s = this.attr,
-            j = s.dataX,
-            v = s.matrix,
-            e = v.getXX(),
-            r = v.getYY(),
-            l = v.getDX(),
-            h = v.getDY(),
-            o = s.barWidth / e,
-            C, k = s.ohlcType,
-            f = Math.round(o * 0.5 * e),
-            a = d.open,
-            y = d.close,
-            B = d.maxY,
-            p = d.minY,
-            q = d.startIdx,
-            m, g, E, n, A, x, w = s.lineWidth * t.devicePixelRatio / 2;
-        w -= Math.floor(w);
-        u.save();
-        C = this.raiseTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] <= y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore();
-        u.save();
-        C = this.dropTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] > y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore()
-    }
-});
-Ext.define("Ext.chart.series.CandleStick", {
-    extend: "Ext.chart.series.Cartesian",
-    requires: ["Ext.chart.series.sprite.CandleStick"],
-    alias: "series.candlestick",
-    type: "candlestick",
-    seriesType: "candlestickSeries",
-    config: {
-        openField: null,
-        highField: null,
-        lowField: null,
-        closeField: null
-    },
-    fieldCategoryY: ["Open", "High", "Low", "Close"],
-    themeColorCount: function() {
-        return 2
-    }
-});
-Ext.define("Ext.chart.series.Polar", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        rotation: 0,
-        radius: null,
-        center: [0, 0],
-        offsetX: 0,
-        offsetY: 0,
-        showInLegend: true,
-        xField: null,
-        yField: null,
-        angleField: null,
-        radiusField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    deprecatedConfigs: {
-        field: "angleField",
-        lengthField: "radiusField"
-    },
-    constructor: function(b) {
-        var c = this,
-            a = c.getConfigurator(),
-            e = a.configs,
-            d;
-        if (b) {
-            for (d in c.deprecatedConfigs) {
-                if (d in b && !(b in e)) {
-                    Ext.raise("'" + d + "' config has been deprecated. Please use the '" + c.deprecatedConfigs[d] + "' config instead.")
-                }
-            }
-        }
-        c.callParent([b])
-    },
-    getXField: function() {
-        return this.getAngleField()
-    },
-    updateXField: function(a) {
-        this.setAngleField(a)
-    },
-    getYField: function() {
-        return this.getRadiusField()
-    },
-    updateYField: function(a) {
-        this.setRadiusField(a)
-    },
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b
-    },
-    isStoreDependantColorCount: true,
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            centerX: 0,
-            centerY: 0,
-            rotationCenterX: 0,
-            rotationCenterY: 0
-        }
-    },
-    applyRotation: function(a) {
-        return Ext.draw.sprite.AttributeParser.angle(a)
-    },
-    updateRotation: function(a) {
-        var b = this.getSprites();
-        if (b && b[0]) {
-            b[0].setAttributes({
-                baseRotation: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.Gauge", {
-    alias: "series.gauge",
-    extend: "Ext.chart.series.Polar",
-    type: "gauge",
-    seriesType: "pieslice",
-    requires: ["Ext.draw.sprite.Sector"],
-    config: {
-        needle: false,
-        needleLength: 90,
-        needleWidth: 4,
-        donut: 30,
-        showInLegend: false,
-        value: null,
-        colors: null,
-        sectors: null,
-        minimum: 0,
-        maximum: 100,
-        rotation: 0,
-        totalAngle: Math.PI / 2,
-        rect: [0, 0, 1, 1],
-        center: [0.5, 0.75],
-        radius: 0.5,
-        wholeDisk: false
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateNeedle: function(b) {
-        var a = this,
-            d = a.getSprites(),
-            c = a.valueToAngle(a.getValue());
-        if (d && d.length) {
-            d[0].setAttributes({
-                startAngle: (b ? c : 0),
-                endAngle: c,
-                strokeOpacity: (b ? 1 : 0),
-                lineWidth: (b ? a.getNeedleWidth() : 0)
-            });
-            a.doUpdateStyles()
-        }
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b + (c.getNeedle() ? 0 : 1)
-    },
-    updateColors: function(a, b) {
-        var f = this,
-            h = f.getSectors(),
-            j = h && h.length,
-            e = f.getSprites(),
-            c = Ext.Array.clone(a),
-            g = a && a.length,
-            d;
-        if (!g || !a[0]) {
-            return
-        }
-        for (d = 0; d < j; d++) {
-            c[d + 1] = h[d].color || c[d + 1] || a[d % g]
-        }
-        if (e.length) {
-            e[0].setAttributes({
-                strokeStyle: c[0]
-            })
-        }
-        this.setSubStyle({
-            fillStyle: c,
-            strokeStyle: c
-        });
-        this.doUpdateStyles()
-    },
-    updateRect: function(f) {
-        var d = this.getWholeDisk(),
-            c = d ? Math.PI : this.getTotalAngle() / 2,
-            g = this.getDonut() / 100,
-            e, b, a;
-        if (c <= Math.PI / 2) {
-            e = 2 * Math.sin(c);
-            b = 1 - g * Math.cos(c)
-        } else {
-            e = 2;
-            b = 1 - Math.cos(c)
-        }
-        a = Math.min(f[2] / e, f[3] / b);
-        this.setRadius(a);
-        this.setCenter([f[2] / 2, a + (f[3] - b * a) / 2])
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            centerX: a[0],
-            centerY: a[1],
-            rotationCenterX: a[0],
-            rotationCenterY: a[1]
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a - (this.getTotalAngle() + Math.PI) / 2
-        });
-        this.doUpdateStyles()
-    },
-    doUpdateShape: function(b, f) {
-        var a, d = this.getSectors(),
-            c = (d && d.length) || 0,
-            e = this.getNeedleLength() / 100;
-        a = [b * e, b];
-        while (c--) {
-            a.push(b)
-        }
-        this.setSubStyle({
-            endRho: a,
-            startRho: b / 100 * f
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        var b = this.getDonut();
-        this.doUpdateShape(a, b)
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.doUpdateShape(a, b)
-    },
-    valueToAngle: function(a) {
-        a = this.applyValue(a);
-        return this.getTotalAngle() * (a - this.getMinimum()) / (this.getMaximum() - this.getMinimum())
-    },
-    applyValue: function(a) {
-        return Math.min(this.getMaximum(), Math.max(a, this.getMinimum()))
-    },
-    updateValue: function(b) {
-        var a = this,
-            c = a.getNeedle(),
-            e = a.valueToAngle(b),
-            d = a.getSprites();
-        d[0].rendererData.value = b;
-        d[0].setAttributes({
-            startAngle: (c ? e : 0),
-            endAngle: e
-        });
-        a.doUpdateStyles()
-    },
-    processData: function() {
-        var f = this,
-            j = f.getStore(),
-            a, d, h, b, g, e = j && j.first(),
-            c, i;
-        if (e) {
-            c = f.getXField();
-            if (c) {
-                i = e.get(c)
-            }
-        }
-        if (a = f.getXAxis()) {
-            d = a.getMinimum();
-            h = a.getMaximum();
-            b = a.getSprites()[0].fx;
-            g = b.getDuration();
-            b.setDuration(0);
-            if (Ext.isNumber(d)) {
-                f.setMinimum(d)
-            } else {
-                a.setMinimum(f.getMinimum())
-            }
-            if (Ext.isNumber(h)) {
-                f.setMaximum(h)
-            } else {
-                a.setMaximum(f.getMaximum())
-            }
-            b.setDuration(g)
-        }
-        if (!Ext.isNumber(i)) {
-            i = f.getMinimum()
-        }
-        f.setValue(i)
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationCenterX: 0,
-                    rotationCenterY: 0,
-                    centerX: 0,
-                    centerY: 0,
-                    startRho: 0,
-                    endRho: 0,
-                    baseRotation: 0
-                }
-            }
-        }
-    },
-    normalizeSectors: function(f) {
-        var d = this,
-            c = (f && f.length) || 0,
-            b, e, g, a;
-        if (c) {
-            for (b = 0; b < c; b++) {
-                e = f[b];
-                if (typeof e === "number") {
-                    f[b] = {
-                        start: (b > 0 ? f[b - 1].end : d.getMinimum()),
-                        end: Math.min(e, d.getMaximum())
-                    };
-                    if (b == (c - 1) && f[b].end < d.getMaximum()) {
-                        f[b + 1] = {
-                            start: f[b].end,
-                            end: d.getMaximum()
-                        }
-                    }
-                } else {
-                    if (typeof e.start === "number") {
-                        g = Math.max(e.start, d.getMinimum())
-                    } else {
-                        g = (b > 0 ? f[b - 1].end : d.getMinimum())
-                    }
-                    if (typeof e.end === "number") {
-                        a = Math.min(e.end, d.getMaximum())
-                    } else {
-                        a = d.getMaximum()
-                    }
-                    f[b].start = g;
-                    f[b].end = a
-                }
-            }
-        } else {
-            f = [{
-                start: d.getMinimum(),
-                end: d.getMaximum()
-            }]
-        }
-        return f
-    },
-    getSprites: function() {
-        var j = this,
-            m = j.getStore(),
-            l = j.getValue(),
-            c, g;
-        if (!m && !Ext.isNumber(l)) {
-            return []
-        }
-        var h = j.getChart(),
-            b = j.getAnimation() || h && h.getAnimation(),
-            f = j.sprites,
-            k = 0,
-            o, n, e, d, a = [];
-        if (f && f.length) {
-            f[0].setAnimation(b);
-            return f
-        }
-        d = {
-            store: m,
-            field: j.getXField(),
-            angleField: j.getXField(),
-            value: l,
-            series: j
-        };
-        o = j.createSprite();
-        o.setAttributes({
-            zIndex: 10
-        }, true);
-        o.rendererData = d;
-        o.rendererIndex = k++;
-        a.push(j.getNeedleWidth());
-        j.getLabel().getTemplate().setField(true);
-        n = j.normalizeSectors(j.getSectors());
-        for (c = 0, g = n.length; c < g; c++) {
-            e = {
-                startAngle: j.valueToAngle(n[c].start),
-                endAngle: j.valueToAngle(n[c].end),
-                label: n[c].label,
-                fillStyle: n[c].color,
-                strokeOpacity: 0,
-                doCallout: false,
-                labelOverflowPadding: -1
-            };
-            Ext.apply(e, n[c].style);
-            o = j.createSprite();
-            o.rendererData = d;
-            o.rendererIndex = k++;
-            o.setAttributes(e, true);
-            a.push(e.lineWidth)
-        }
-        j.setSubStyle({
-            lineWidth: a
-        });
-        j.doUpdateStyles();
-        return f
-    }
-});
-Ext.define("Ext.chart.series.sprite.Line", {
-    alias: "sprite.lineSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                smooth: "bool",
-                fillArea: "bool",
-                step: "bool",
-                preciseStroke: "bool",
-                xAxis: "default",
-                yCap: "default"
-            },
-            defaults: {
-                smooth: false,
-                fillArea: false,
-                step: false,
-                preciseStroke: true,
-                xAxis: null,
-                yCap: Math.pow(2, 20),
-                yJump: 50
-            },
-            triggers: {
-                dataX: "dataX,bbox,smooth",
-                dataY: "dataY,bbox,smooth",
-                smooth: "smooth"
-            },
-            updaters: {
-                smooth: function(a) {
-                    var c = a.dataX,
-                        b = a.dataY;
-                    if (a.smooth && c && b && c.length > 2 && b.length > 2) {
-                        this.smoothX = Ext.draw.Draw.spline(c);
-                        this.smoothY = Ext.draw.Draw.spline(b)
-                    } else {
-                        delete this.smoothX;
-                        delete this.smoothY
-                    }
-                }
-            }
-        }
-    },
-    list: null,
-    updatePlainBBox: function(d) {
-        var b = this.attr,
-            c = Math.min(0, b.dataMinY),
-            a = Math.max(0, b.dataMaxY);
-        d.x = b.dataMinX;
-        d.y = c;
-        d.width = b.dataMaxX - b.dataMinX;
-        d.height = a - c
-    },
-    drawStrip: function(a, c) {
-        a.moveTo(c[0], c[1]);
-        for (var b = 2, d = c.length; b < d; b += 2) {
-            a.lineTo(c[b], c[b + 1])
-        }
-    },
-    drawStraightStroke: function(p, q, e, d, u, h) {
-        var w = this,
-            o = w.attr,
-            n = o.renderer,
-            g = o.step,
-            a = true,
-            l = {
-                type: "line",
-                smooth: false,
-                step: g
-            },
-            m = [],
-            l, z, v, f, k, j, t, c, s, b, r;
-        for (r = 3; r < u.length; r += 3) {
-            t = u[r - 3];
-            c = u[r - 2];
-            k = u[r];
-            j = u[r + 1];
-            s = u[r + 3];
-            b = u[r + 4];
-            if (n) {
-                l.x = k;
-                l.y = j;
-                l.x0 = t;
-                l.y0 = c;
-                v = [w, l, w.rendererData, e + r / 3];
-                z = Ext.callback(n, null, v, 0, w.getSeries())
-            }
-            if (Ext.isNumber(k + j + t + c)) {
-                if (a) {
-                    q.beginPath();
-                    q.moveTo(t, c);
-                    m.push(t, c);
-                    f = t;
-                    a = false
-                }
-            } else {
-                continue
-            }
-            if (g) {
-                q.lineTo(k, c);
-                m.push(k, c)
-            }
-            q.lineTo(k, j);
-            m.push(k, j);
-            if (z || !(Ext.isNumber(s + b))) {
-                q.save();
-                Ext.apply(q, z);
-                if (o.fillArea) {
-                    q.lineTo(k, h);
-                    q.lineTo(f, h);
-                    q.closePath();
-                    q.fill()
-                }
-                q.beginPath();
-                w.drawStrip(q, m);
-                m = [];
-                q.stroke();
-                q.restore();
-                q.beginPath();
-                a = true
-            }
-        }
-    },
-    calculateScale: function(c, a) {
-        var b = 0,
-            d = c;
-        while (d < a && c > 0) {
-            b++;
-            d += c >> b
-        }
-        return Math.pow(2, b > 0 ? b - 1 : b)
-    },
-    drawSmoothStroke: function(u, v, c, b, C, f) {
-        var G = this,
-            t = G.attr,
-            d = t.step,
-            z = t.matrix,
-            s = t.renderer,
-            e = z.getXX(),
-            p = z.getYY(),
-            m = z.getDX(),
-            k = z.getDY(),
-            r = G.smoothX,
-            q = G.smoothY,
-            I = G.calculateScale(t.dataX.length, b),
-            o, F, n, E, h, g, B, a, A, w, H, D, l = {
-                type: "line",
-                smooth: true,
-                step: d
-            };
-        v.beginPath();
-        v.moveTo(r[c * 3] * e + m, q[c * 3] * p + k);
-        for (A = 0, w = c * 3 + 1; A < C.length - 3; A += 3, w += 3 * I) {
-            o = r[w] * e + m;
-            F = q[w] * p + k;
-            n = r[w + 1] * e + m;
-            E = q[w + 1] * p + k;
-            h = u.roundPixel(C[A + 3]);
-            g = C[A + 4];
-            B = u.roundPixel(C[A]);
-            a = C[A + 1];
-            if (s) {
-                l.x0 = B;
-                l.y0 = a;
-                l.cx1 = o;
-                l.cy1 = F;
-                l.cx2 = n;
-                l.cy2 = E;
-                l.x = h;
-                l.y = g;
-                D = [G, l, G.rendererData, c + A / 3 + 1];
-                H = Ext.callback(s, null, D, 0, G.getSeries());
-                v.save();
-                Ext.apply(v, H)
-            }
-            if (t.fillArea) {
-                v.moveTo(B, a);
-                v.bezierCurveTo(o, F, n, E, h, g);
-                v.lineTo(h, f);
-                v.lineTo(B, f);
-                v.lineTo(B, a);
-                v.closePath();
-                v.fill();
-                v.beginPath()
-            }
-            v.moveTo(B, a);
-            v.bezierCurveTo(o, F, n, E, h, g);
-            v.stroke();
-            v.moveTo(B, a);
-            v.closePath();
-            if (s) {
-                v.restore()
-            }
-            v.beginPath();
-            v.moveTo(h, g)
-        }
-        v.beginPath()
-    },
-    drawLabel: function(k, i, h, o, a) {
-        var q = this,
-            n = q.attr,
-            e = q.getMarker("labels"),
-            d = e.getTemplate(),
-            m = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            g, f, j = n.labelOverflowPadding,
-            l, b, r, p, s;
-        m.x = c.x(i, h);
-        m.y = c.y(i, h);
-        if (n.flipXY) {
-            m.rotationRads = Math.PI * 0.5
-        } else {
-            m.rotationRads = 0
-        }
-        m.text = k;
-        if (d.attr.renderer) {
-            p = [k, e, m, q.rendererData, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                m.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        m.text = r.text
-                    }
-                    s = true
-                }
-            }
-        }
-        b = q.getMarkerBBox("labels", o, true);
-        if (!b) {
-            q.putMarker("labels", m, o);
-            b = q.getMarkerBBox("labels", o, true)
-        }
-        l = b.height / 2;
-        g = i;
-        switch (d.attr.display) {
-            case "under":
-                f = h - l - j;
-                break;
-            case "rotate":
-                g += j;
-                f = h - j;
-                m.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                f = h + l + j
-        }
-        m.x = c.x(g, f);
-        m.y = c.y(g, f);
-        if (s) {
-            Ext.apply(m, r)
-        }
-        q.putMarker("labels", m, o)
-    },
-    drawMarker: function(j, h, d) {
-        var g = this,
-            e = g.attr,
-            f = e.renderer,
-            c = g.surfaceMatrix,
-            b = {},
-            i, a;
-        if (f && g.getMarker("markers")) {
-            b.type = "marker";
-            b.x = j;
-            b.y = h;
-            a = [g, b, g.rendererData, d];
-            i = Ext.callback(f, null, a, 0, g.getSeries());
-            if (i) {
-                Ext.apply(b, i)
-            }
-        }
-        b.translationX = c.x(j, h);
-        b.translationY = c.y(j, h);
-        delete b.x;
-        delete b.y;
-        g.putMarker("markers", b, d, !f)
-    },
-    drawStroke: function(a, c, h, b, f, e) {
-        var d = this,
-            g = d.attr.smooth && d.smoothX && d.smoothY;
-        if (g) {
-            d.drawSmoothStroke(a, c, h, b, f, e)
-        } else {
-            d.drawStraightStroke(a, c, h, b, f, e)
-        }
-    },
-    renderAggregates: function(B, w, l, N, o, I, D) {
-        var m = this,
-            k = m.attr,
-            s = k.dataX,
-            r = k.dataY,
-            h = k.labels,
-            v = k.xAxis,
-            a = k.yCap,
-            g = k.smooth && m.smoothX && m.smoothY,
-            d = h && m.getMarker("labels"),
-            t = m.getMarker("markers"),
-            E = k.matrix,
-            u = N.devicePixelRatio,
-            C = E.getXX(),
-            f = E.getYY(),
-            c = E.getDX(),
-            b = E.getDY(),
-            q = m.list || (m.list = []),
-            F = B.minX,
-            e = B.maxX,
-            j = B.minY,
-            P = B.maxY,
-            U = B.startIdx,
-            S = true,
-            Q, T, L, K, R, G;
-        m.rendererData = {
-            store: m.getStore()
-        };
-        q.length = 0;
-        for (R = w; R < l; R++) {
-            var O = F[R],
-                p = e[R],
-                M = j[R],
-                n = P[R];
-            if (O < p) {
-                q.push(O * C + c, M * f + b, U[R]);
-                q.push(p * C + c, n * f + b, U[R])
-            } else {
-                if (O > p) {
-                    q.push(p * C + c, n * f + b, U[R]);
-                    q.push(O * C + c, M * f + b, U[R])
-                } else {
-                    q.push(p * C + c, n * f + b, U[R])
-                }
-            }
-        }
-        if (q.length) {
-            for (R = 0; R < q.length; R += 3) {
-                L = q[R];
-                K = q[R + 1];
-                if (Ext.isNumber(L + K)) {
-                    if (K > a) {
-                        K = a
-                    } else {
-                        if (K < -a) {
-                            K = -a
-                        }
-                    }
-                    q[R + 1] = K
-                } else {
-                    S = false;
-                    continue
-                }
-                G = q[R + 2];
-                if (t) {
-                    m.drawMarker(L, K, G)
-                }
-                if (d && h[G]) {
-                    m.drawLabel(h[G], L, K, G, D)
-                }
-            }
-            m.isContinuousLine = S;
-            if (g && !S) {
-                Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")
-            }
-            if (v) {
-                T = v.getAlignment() === "vertical";
-                if (Ext.isNumber(v.floatingAtCoord)) {
-                    Q = (T ? D[2] : D[3]) - v.floatingAtCoord
-                } else {
-                    Q = T ? D[0] : D[1]
-                }
-            } else {
-                Q = k.flipXY ? D[0] : D[1]
-            }
-            if (k.preciseStroke) {
-                if (k.fillArea) {
-                    o.fill()
-                }
-                if (k.transformFillStroke) {
-                    k.inverseMatrix.toContext(o)
-                }
-                m.drawStroke(N, o, w, l, q, Q);
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                o.stroke()
-            } else {
-                m.drawStroke(N, o, w, l, q, Q);
-                if (S && g && k.fillArea && !k.renderer) {
-                    var A = s[s.length - 1] * C + c + u,
-                        z = r[r.length - 1] * f + b,
-                        J = s[0] * C + c - u,
-                        H = r[0] * f + b;
-                    o.lineTo(A, z);
-                    o.lineTo(A, Q - k.lineWidth);
-                    o.lineTo(J, Q - k.lineWidth);
-                    o.lineTo(J, H)
-                }
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                if (k.fillArea) {
-                    o.fillStroke(k, true)
-                } else {
-                    o.stroke(true)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.Line", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.line",
-    type: "line",
-    seriesType: "lineSeries",
-    requires: ["Ext.chart.series.sprite.Line"],
-    config: {
-        selectionTolerance: 20,
-        smooth: false,
-        step: false,
-        fill: undefined,
-        aggregator: {
-            strategy: "double"
-        }
-    },
-    defaultSmoothness: 3,
-    overflowBuffer: 1,
-    themeMarkerCount: function() {
-        return 1
-    },
-    getDefaultSpriteConfig: function() {
-        var d = this,
-            e = d.callParent(arguments),
-            c = Ext.apply({}, d.getStyle()),
-            b, a = false;
-        if (typeof d.config.fill != "undefined") {
-            if (d.config.fill) {
-                a = true;
-                if (typeof c.fillStyle == "undefined") {
-                    if (typeof c.strokeStyle == "undefined") {
-                        b = d.getStyleWithTheme();
-                        c.fillStyle = b.fillStyle;
-                        c.strokeStyle = b.strokeStyle
-                    } else {
-                        c.fillStyle = c.strokeStyle
-                    }
-                }
-            }
-        } else {
-            if (c.fillStyle) {
-                a = true
-            }
-        }
-        if (!a) {
-            delete c.fillStyle
-        }
-        c = Ext.apply(e || {}, c);
-        return Ext.apply(c, {
-            fillArea: a,
-            step: d.config.step,
-            smooth: d.config.smooth,
-            selectionTolerance: d.config.selectionTolerance
-        })
-    },
-    updateStep: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.step !== b) {
-            a.setAttributes({
-                step: b
-            })
-        }
-    },
-    updateFill: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.fillArea !== b) {
-            a.setAttributes({
-                fillArea: b
-            })
-        }
-    },
-    updateSmooth: function(a) {
-        var b = this.getSprites()[0];
-        if (b && b.attr.smooth !== a) {
-            b.setAttributes({
-                smooth: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.PieSlice", {
-    extend: "Ext.draw.sprite.Sector",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pieslice",
-    inheritableStatics: {
-        def: {
-            processors: {
-                doCallout: "bool",
-                label: "string",
-                rotateLabels: "bool",
-                labelOverflowPadding: "number",
-                renderer: "default"
-            },
-            defaults: {
-                doCallout: true,
-                rotateLabels: true,
-                label: "",
-                labelOverflowPadding: 10,
-                renderer: null
-            }
-        }
-    },
-    config: {
-        rendererData: null,
-        rendererIndex: 0,
-        series: null
-    },
-    setGradientBBox: function(q, k) {
-        var j = this,
-            i = j.attr,
-            g = (i.fillStyle && i.fillStyle.isGradient) || (i.strokeStyle && i.strokeStyle.isGradient);
-        if (g && !i.constrainGradients) {
-            var b = j.getMidAngle(),
-                d = i.margin,
-                e = i.centerX,
-                c = i.centerY,
-                a = i.endRho,
-                l = i.matrix,
-                o = l.getScaleX(),
-                n = l.getScaleY(),
-                m = o * a,
-                f = n * a,
-                p = {
-                    width: m + m,
-                    height: f + f
-                };
-            if (d) {
-                e += d * Math.cos(b);
-                c += d * Math.sin(b)
-            }
-            p.x = l.x(e, c) - m;
-            p.y = l.y(e, c) - f;
-            q.setGradientBBox(p)
-        } else {
-            j.callParent([q, k])
-        }
-    },
-    render: function(b, c, g, f) {
-        var e = this,
-            a = e.attr,
-            h = {},
-            d;
-        if (a.renderer) {
-            h = {
-                type: "sector",
-                text: a.text,
-                centerX: a.centerX,
-                centerY: a.centerY,
-                margin: a.margin,
-                startAngle: Math.min(a.startAngle, a.endAngle),
-                endAngle: Math.max(a.startAngle, a.endAngle),
-                startRho: Math.min(a.startRho, a.endRho),
-                endRho: Math.max(a.startRho, a.endRho)
-            };
-            d = Ext.callback(a.renderer, null, [e, h, e.rendererData, e.rendererIndex], 0, e.getSeries());
-            e.setAttributes(d);
-            e.useAttributes(c, g)
-        }
-        e.callParent([b, c, g, f]);
-        if (a.label && e.getMarker("labels")) {
-            e.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            s = z.attr,
-            r = s.attributeId,
-            t = Math.min(s.startAngle, s.endAngle),
-            p = Math.max(s.startAngle, s.endAngle),
-            k = (t + p) * 0.5,
-            n = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            f = Math.sin(k),
-            c = Math.cos(k),
-            v = Math.min(s.startRho, s.endRho) + n,
-            m = Math.max(s.startRho, s.endRho) + n,
-            l = (v + m) * 0.5,
-            b = z.surfaceMatrix,
-            o = z.labelCfg || (z.labelCfg = {}),
-            e = z.getMarker("labels"),
-            d = e.getTemplate(),
-            a = d.getCalloutLine(),
-            q = a && a.length || 40,
-            u, j, i, A, w;
-        b.appendMatrix(s.matrix);
-        o.text = s.label;
-        j = h + c * l;
-        i = g + f * l;
-        o.x = b.x(j, i);
-        o.y = b.y(j, i);
-        j = h + c * m;
-        i = g + f * m;
-        o.calloutStartX = b.x(j, i);
-        o.calloutStartY = b.y(j, i);
-        j = h + c * (m + q);
-        i = g + f * (m + q);
-        o.calloutPlaceX = b.x(j, i);
-        o.calloutPlaceY = b.y(j, i);
-        if (!s.rotateLabels) {
-            o.rotationRads = 0
-        } else {
-            switch (d.attr.orientation) {
-                case "horizontal":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0)) + Math.PI / 2;
-                    break;
-                case "vertical":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0));
-                    break
-            }
-        }
-        o.calloutColor = (a && a.color) || z.attr.fillStyle;
-        if (a) {
-            if (a.width) {
-                o.calloutWidth = a.width
-            }
-        } else {
-            o.calloutHasLine = false
-        }
-        o.globalAlpha = s.globalAlpha * s.fillOpacity;
-        o.hidden = (s.startAngle == s.endAngle);
-        if (d.attr.renderer) {
-            w = [z.attr.label, e, o, z.rendererData, z.rendererIndex];
-            A = Ext.callback(d.attr.renderer, null, w, 0, z.getSeries());
-            if (typeof A === "string") {
-                o.text = A
-            } else {
-                Ext.apply(o, A)
-            }
-        }
-        z.putMarker("labels", o, r);
-        u = z.getMarkerBBox("labels", r, true);
-        if (u) {
-            if (s.doCallout) {
-                if (d.attr.display === "outside") {
-                    z.putMarker("labels", {
-                        callout: 1
-                    }, r)
-                } else {
-                    if (d.attr.display === "inside") {
-                        z.putMarker("labels", {
-                            callout: 0
-                        }, r)
-                    } else {
-                        z.putMarker("labels", {
-                            callout: 1 - z.sliceContainsLabel(s, u)
-                        }, r)
-                    }
-                }
-            } else {
-                z.putMarker("labels", {
-                    globalAlpha: z.sliceContainsLabel(s, u)
-                }, r)
-            }
-        }
-    },
-    sliceContainsLabel: function(d, f) {
-        var e = d.labelOverflowPadding,
-            h = (d.endRho + d.startRho) / 2,
-            g = h + (f.width + e) / 2,
-            i = h - (f.width + e) / 2,
-            j, c, b, a;
-        if (e < 0) {
-            return 1
-        }
-        if (f.width + e * 2 > (d.endRho - d.startRho)) {
-            return 0
-        }
-        c = Math.sqrt(d.endRho * d.endRho - g * g);
-        b = Math.sqrt(d.endRho * d.endRho - i * i);
-        j = Math.abs(d.endAngle - d.startAngle);
-        a = (j > Math.PI / 2 ? i : Math.abs(Math.tan(j / 2)) * i);
-        if (f.height + e * 2 > Math.min(c, b, a) * 2) {
-            return 0
-        }
-        return 1
-    }
-});
-Ext.define("Ext.chart.series.Pie", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.PieSlice"],
-    type: "pie",
-    alias: "series.pie",
-    seriesType: "pieslice",
-    config: {
-        donut: 0,
-        rotation: 0,
-        clockwise: true,
-        totalAngle: 2 * Math.PI,
-        hidden: [],
-        radiusFactor: 100,
-        highlightCfg: {
-            margin: 20
-        },
-        style: {}
-    },
-    directions: ["X"],
-    applyLabel: function(a, b) {
-        if (Ext.isObject(a) && !Ext.isString(a.orientation)) {
-            Ext.apply(a = Ext.Object.chain(a), {
-                orientation: "vertical"
-            })
-        }
-        return this.callParent([a, b])
-    },
-    updateLabelData: function() {
-        var h = this,
-            j = h.getStore(),
-            g = j.getData().items,
-            e = h.getSprites(),
-            a = h.getLabel().getTemplate().getField(),
-            d = h.getHidden(),
-            b, f, c, k;
-        if (e.length && a) {
-            c = [];
-            for (b = 0, f = g.length; b < f; b++) {
-                c.push(g[b].get(a))
-            }
-            for (b = 0, f = e.length; b < f; b++) {
-                k = e[b];
-                k.setAttributes({
-                    label: c[b]
-                });
-                k.putMarker("labels", {
-                    hidden: d[b]
-                }, k.attr.attributeId)
-            }
-        }
-    },
-    coordinateX: function() {
-        var t = this,
-            f = t.getStore(),
-            q = f.getData().items,
-            c = q.length,
-            b = t.getXField(),
-            e = t.getYField(),
-            l, a = 0,
-            m, k, s = 0,
-            o = t.getHidden(),
-            d = [],
-            p, g = 0,
-            h = t.getTotalAngle(),
-            r = t.getClockwise() ? 1 : -1,
-            j = t.getSprites(),
-            n;
-        if (!j) {
-            return
-        }
-        for (p = 0; p < c; p++) {
-            l = Math.abs(Number(q[p].get(b))) || 0;
-            k = e && Math.abs(Number(q[p].get(e))) || 0;
-            if (!o[p]) {
-                a += l;
-                if (k > s) {
-                    s = k
-                }
-            }
-            d[p] = a;
-            if (p >= o.length) {
-                o[p] = false
-            }
-        }
-        o.length = c;
-        t.maxY = s;
-        if (a !== 0) {
-            m = h / a
-        }
-        for (p = 0; p < c; p++) {
-            j[p].setAttributes({
-                startAngle: g,
-                endAngle: g = (m ? r * d[p] * m : 0),
-                globalAlpha: 1
-            })
-        }
-        if (c < t.sprites.length) {
-            for (p = c; p < t.sprites.length; p++) {
-                n = t.sprites[p];
-                n.getMarker("labels").clear(n.getId());
-                n.releaseMarker("labels");
-                n.destroy()
-            }
-            t.sprites.length = c
-        }
-        for (p = c; p < t.sprites.length; p++) {
-            j[p].setAttributes({
-                startAngle: h,
-                endAngle: h,
-                globalAlpha: 0
-            })
-        }
-        t.getChart().refreshLegendStore()
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            startRho: a * this.getDonut() * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    getStyleByIndex: function(c) {
-        var g = this,
-            j = g.getStore(),
-            k = j.getAt(c),
-            f = g.getYField(),
-            d = g.getRadius(),
-            a = {},
-            e, b, h;
-        if (k) {
-            h = f && Math.abs(Number(k.get(f))) || 0;
-            e = d * g.getDonut() * 0.01;
-            b = d * g.getRadiusFactor() * 0.01;
-            a = g.callParent([c]);
-            a.startRho = e;
-            a.endRho = g.maxY ? (e + (b - e) * h / g.maxY) : b
-        }
-        return a
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.setStyle({
-            startRho: a * b * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    rotationOffset: -Math.PI / 2,
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getSprites: function() {
-        var k = this,
-            h = k.getChart(),
-            n = k.getStore();
-        if (!h || !n) {
-            return []
-        }
-        k.getColors();
-        k.getSubStyle();
-        var j = n.getData().items,
-            b = j.length,
-            d = k.getAnimation() || h && h.getAnimation(),
-            g = k.sprites,
-            o, l = 0,
-            f, e, c = false,
-            m = k.getLabel(),
-            a = m.getTemplate();
-        f = {
-            store: n,
-            field: k.getXField(),
-            angleField: k.getXField(),
-            radiusField: k.getYField(),
-            series: k
-        };
-        for (e = 0; e < b; e++) {
-            o = g[e];
-            if (!o) {
-                o = k.createSprite();
-                if (k.getHighlight()) {
-                    o.config.highlight = k.getHighlight();
-                    o.addModifier("highlight", true)
-                }
-                if (a.getField()) {
-                    a.setAttributes({
-                        labelOverflowPadding: k.getLabelOverflowPadding()
-                    });
-                    a.fx.setCustomDurations({
-                        callout: 200
-                    })
-                }
-                o.setAttributes(k.getStyleByIndex(e));
-                o.rendererData = f;
-                o.rendererIndex = l++;
-                c = true
-            }
-            o.setAnimation(d)
-        }
-        if (c) {
-            k.doUpdateStyles()
-        }
-        return k.sprites
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        if (!this.getClockwise()) {
-            d *= -1;
-            f *= -1;
-            c *= -1;
-            f -= g;
-            c -= g
-        } else {
-            f += g;
-            c += g
-        }
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForAngle: function(a) {
-        var h = this,
-            f = h.getSprites(),
-            d;
-        a %= Math.PI * 2;
-        while (a < 0) {
-            a += Math.PI * 2
-        }
-        if (f) {
-            var j = h.getStore(),
-                g = j.getData().items,
-                c = h.getHidden(),
-                b = 0,
-                e = j.getCount();
-            for (; b < e; b++) {
-                if (!c[b]) {
-                    d = f[b].attr;
-                    if (d.startAngle <= a && d.endAngle >= a) {
-                        return {
-                            series: h,
-                            sprite: f[b],
-                            index: b,
-                            record: g[b],
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-        }
-        return null
-    },
-    getItemForPoint: function(f, e) {
-        var t = this,
-            c = t.getSprites();
-        if (c) {
-            var s = t.getCenter(),
-                q = t.getOffsetX(),
-                p = t.getOffsetY(),
-                j = f - s[0] + q,
-                h = e - s[1] + p,
-                b = t.getStore(),
-                g = t.getDonut(),
-                o = b.getData().items,
-                r = Math.atan2(h, j) - t.getRotation(),
-                a = Math.sqrt(j * j + h * h),
-                l = t.getRadius() * g * 0.01,
-                m = t.getHidden(),
-                n, d, k;
-            for (n = 0, d = o.length; n < d; n++) {
-                if (!m[n]) {
-                    k = c[n].attr;
-                    if (a >= l + k.margin && a <= k.endRho + k.margin) {
-                        if (t.betweenAngle(r, k.startAngle, k.endAngle)) {
-                            return {
-                                series: t,
-                                sprite: c[n],
-                                index: n,
-                                record: o[n],
-                                field: t.getXField()
-                            }
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            j = h.getStore();
-        if (j) {
-            var g = j.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                c = h.getXField(),
-                e = h.getHidden(),
-                d, a, k;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                k = a.fillStyle;
-                if (Ext.isObject(k)) {
-                    k = k.stops && k.stops[0].color
-                }
-                f.push({
-                    name: b ? String(g[d].get(b)) : c + " " + d,
-                    mark: k || a.strokeStyle || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Pie3DPart", {
-    extend: "Ext.draw.sprite.Path",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pie3dPart",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number",
-                thickness: "number",
-                bevelWidth: "number",
-                distortion: "number",
-                baseColor: "color",
-                colorSpread: "number",
-                baseRotation: "number",
-                part: "enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",
-                label: "string"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,partZIndex",
-                endAngle: "path,partZIndex",
-                startRho: "path",
-                endRho: "path,bbox",
-                margin: "path,bbox",
-                thickness: "path",
-                distortion: "path",
-                baseRotation: "path,partZIndex",
-                baseColor: "partZIndex,partColor",
-                colorSpread: "partColor",
-                part: "path,partZIndex",
-                globalAlpha: "canvas,alpha"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: Math.PI * 2,
-                endAngle: Math.PI * 2,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                thickness: 35,
-                distortion: 0.5,
-                baseRotation: 0,
-                baseColor: "white",
-                colorSpread: 1,
-                miterLimit: 1,
-                bevelWidth: 5,
-                strokeOpacity: 0,
-                part: "top",
-                label: ""
-            },
-            updaters: {
-                alpha: "alphaUpdater",
-                partColor: "partColorUpdater",
-                partZIndex: "partZIndexUpdater"
-            }
-        }
-    },
-    bevelParams: [],
-    constructor: function(a) {
-        this.callParent([a]);
-        this.bevelGradient = new Ext.draw.gradient.Linear({
-            stops: [{
-                offset: 0,
-                color: "rgba(255,255,255,0)"
-            }, {
-                offset: 0.7,
-                color: "rgba(255,255,255,0.6)"
-            }, {
-                offset: 1,
-                color: "rgba(255,255,255,0)"
-            }]
-        })
-    },
-    alphaUpdater: function(a) {
-        var d = this,
-            c = a.globalAlpha,
-            b = d.oldOpacity;
-        if (c !== b && (c === 1 || b === 1)) {
-            d.scheduleUpdater(a, "path", ["globalAlpha"]);
-            d.oldOpacity = c
-        }
-    },
-    partColorUpdater: function(a) {
-        var d = Ext.draw.Color.fly(a.baseColor),
-            b = d.toString(),
-            e = a.colorSpread,
-            c;
-        switch (a.part) {
-            case "top":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createLighter(0.1 * e)
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e)
-                    }]
-                });
-                break;
-            case "bottom":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.2 * e)
-                    }, {
-                        offset: 1,
-                        color: d.toString()
-                    }]
-                });
-                break;
-            case "outerFront":
-            case "outerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.15 * e).toString()
-                    }, {
-                        offset: 0.3,
-                        color: b
-                    }, {
-                        offset: 0.8,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.25 * e).toString()
-                    }]
-                });
-                break;
-            case "start":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "end":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "innerFront":
-            case "innerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 0.2,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 0.7,
-                        color: b
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e).toString()
-                    }]
-                });
-                break
-        }
-        a.fillStyle = c;
-        a.canvasAttributes.fillStyle = c
-    },
-    partZIndexUpdater: function(a) {
-        var c = Ext.draw.sprite.AttributeParser.angle,
-            e = a.baseRotation,
-            d = a.startAngle,
-            b = a.endAngle,
-            f;
-        switch (a.part) {
-            case "top":
-                a.zIndex = 5;
-                break;
-            case "outerFront":
-                d = c(d + e);
-                b = c(b + e);
-                if (d >= 0 && b < 0) {
-                    f = Math.sin(d)
-                } else {
-                    if (d <= 0 && b > 0) {
-                        f = Math.sin(b)
-                    } else {
-                        if (d >= 0 && b > 0) {
-                            if (d > b) {
-                                f = 0
-                            } else {
-                                f = Math.max(Math.sin(d), Math.sin(b))
-                            }
-                        } else {
-                            f = 1
-                        }
-                    }
-                }
-                a.zIndex = 4 + f;
-                break;
-            case "outerBack":
-                a.zIndex = 1;
-                break;
-            case "start":
-                a.zIndex = 4 + Math.sin(c(d + e));
-                break;
-            case "end":
-                a.zIndex = 4 + Math.sin(c(b + e));
-                break;
-            case "innerFront":
-                a.zIndex = 2;
-                break;
-            case "innerBack":
-                a.zIndex = 4 + Math.sin(c((d + b) / 2 + e));
-                break;
-            case "bottom":
-                a.zIndex = 0;
-                break
-        }
-        a.dirtyZIndex = true
-    },
-    updatePlainBBox: function(k) {
-        var f = this.attr,
-            a = f.part,
-            b = f.baseRotation,
-            e = f.centerX,
-            d = f.centerY,
-            j, c, i, h, g, l;
-        if (a === "start") {
-            c = f.startAngle + b
-        } else {
-            if (a === "end") {
-                c = f.endAngle + b
-            }
-        }
-        if (Ext.isNumber(c)) {
-            g = Math.sin(c);
-            l = Math.cos(c);
-            i = Math.min(e + l * f.startRho, e + l * f.endRho);
-            h = d + g * f.startRho * f.distortion;
-            k.x = i;
-            k.y = h;
-            k.width = l * (f.endRho - f.startRho);
-            k.height = f.thickness + g * (f.endRho - f.startRho) * 2;
-            return
-        }
-        if (a === "innerFront" || a === "innerBack") {
-            j = f.startRho
-        } else {
-            j = f.endRho
-        }
-        k.width = j * 2;
-        k.height = j * f.distortion * 2 + f.thickness;
-        k.x = f.centerX - j;
-        k.y = f.centerY - j * f.distortion
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.part === "start" || this.attr.part === "end") {
-            return this.callParent(arguments)
-        }
-        return this.updatePlainBBox(a)
-    },
-    updatePath: function(a) {
-        if (!this.attr.globalAlpha) {
-            return
-        }
-        if (this.attr.endAngle < this.attr.startAngle) {
-            return
-        }
-        this[this.attr.part + "Renderer"](a)
-    },
-    render: function(b, c) {
-        var d = this,
-            a = d.attr;
-        if (!a.globalAlpha) {
-            return
-        }
-        d.callParent([b, c]);
-        d.bevelRenderer(b, c);
-        if (a.label && d.getMarker("labels")) {
-            d.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            u = z.attr,
-            t = u.attributeId,
-            p = u.margin,
-            c = u.distortion,
-            i = u.centerX,
-            h = u.centerY,
-            j = u.baseRotation,
-            v = u.startAngle + j,
-            r = u.endAngle + j,
-            m = (v + r) / 2,
-            w = u.startRho + p,
-            o = u.endRho + p,
-            n = (w + o) / 2,
-            a = Math.sin(m),
-            b = Math.cos(m),
-            e = z.surfaceMatrix,
-            g = z.getMarker("labels"),
-            f = g.getTemplate(),
-            d = f.getCalloutLine(),
-            s = d && d.length || 40,
-            q = {},
-            l, k;
-        e.appendMatrix(u.matrix);
-        q.text = u.label;
-        l = i + b * n;
-        k = h + a * n * c;
-        q.x = e.x(l, k);
-        q.y = e.y(l, k);
-        l = i + b * o;
-        k = h + a * o * c;
-        q.calloutStartX = e.x(l, k);
-        q.calloutStartY = e.y(l, k);
-        l = i + b * (o + s);
-        k = h + a * (o + s) * c;
-        q.calloutPlaceX = e.x(l, k);
-        q.calloutPlaceY = e.y(l, k);
-        q.calloutWidth = 2;
-        z.putMarker("labels", q, t);
-        z.putMarker("labels", {
-            callout: 1
-        }, t)
-    },
-    bevelRenderer: function(b, c) {
-        var f = this,
-            a = f.attr,
-            e = a.bevelWidth,
-            g = f.bevelParams,
-            d;
-        for (d = 0; d < g.length; d++) {
-            c.beginPath();
-            c.ellipse.apply(c, g[d]);
-            c.save();
-            c.lineWidth = e;
-            c.strokeOpacity = e ? 1 : 0;
-            c.strokeGradient = f.bevelGradient;
-            c.stroke(a);
-            c.restore()
-        }
-    },
-    lidRenderer: function(o, m) {
-        var k = this.attr,
-            g = k.margin,
-            c = k.distortion,
-            i = k.centerX,
-            h = k.centerY,
-            f = k.baseRotation,
-            j = k.startAngle + f,
-            e = k.endAngle + f,
-            d = (j + e) / 2,
-            l = k.startRho,
-            b = k.endRho,
-            n = Math.sin(e),
-            a = Math.cos(e);
-        i += Math.cos(d) * g;
-        h += Math.sin(d) * g * c;
-        o.ellipse(i, h + m, l, l * c, 0, j, e, false);
-        o.lineTo(i + a * b, h + m + n * b * c);
-        o.ellipse(i, h + m, b, b * c, 0, e, j, true);
-        o.closePath()
-    },
-    topRenderer: function(a) {
-        this.lidRenderer(a, 0)
-    },
-    bottomRenderer: function(b) {
-        var a = this.attr;
-        if (a.globalAlpha < 1 || a.shadowColor !== Ext.draw.Color.RGBA_NONE) {
-            this.lidRenderer(b, a.thickness)
-        }
-    },
-    sideRenderer: function(l, s) {
-        var o = this.attr,
-            k = o.margin,
-            g = o.centerX,
-            f = o.centerY,
-            e = o.distortion,
-            h = o.baseRotation,
-            p = o.startAngle + h,
-            m = o.endAngle + h,
-            a = o.thickness,
-            q = o.startRho,
-            j = o.endRho,
-            r = (s === "start" && p) || (s === "end" && m),
-            b = Math.sin(r),
-            d = Math.cos(r),
-            c = o.globalAlpha < 1,
-            n = s === "start" && d < 0 || s === "end" && d > 0 || c,
-            i;
-        if (n) {
-            i = (p + m) / 2;
-            g += Math.cos(i) * k;
-            f += Math.sin(i) * k * e;
-            l.moveTo(g + d * q, f + b * q * e);
-            l.lineTo(g + d * j, f + b * j * e);
-            l.lineTo(g + d * j, f + b * j * e + a);
-            l.lineTo(g + d * q, f + b * q * e + a);
-            l.closePath()
-        }
-    },
-    startRenderer: function(a) {
-        this.sideRenderer(a, "start")
-    },
-    endRenderer: function(a) {
-        this.sideRenderer(a, "end")
-    },
-    rimRenderer: function(q, e, o, j) {
-        var w = this,
-            s = w.attr,
-            p = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            d = s.distortion,
-            i = s.baseRotation,
-            t = Ext.draw.sprite.AttributeParser.angle,
-            u = s.startAngle + i,
-            r = s.endAngle + i,
-            k = t((u + r) / 2),
-            a = s.thickness,
-            b = s.globalAlpha < 1,
-            c, n, v;
-        w.bevelParams = [];
-        u = t(u);
-        r = t(r);
-        h += Math.cos(k) * p;
-        g += Math.sin(k) * p * d;
-        c = u >= 0 && r >= 0;
-        n = u <= 0 && r <= 0;
-
-        function l() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, u, true);
-            q.lineTo(h + Math.cos(u) * e, g + Math.sin(u) * e * d);
-            v = [h, g, e, e * d, 0, u, Math.PI, false];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function f() {
-            q.ellipse(h, g + a, e, e * d, 0, 0, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, 0, true];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function x() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, Math.PI, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function m() {
-            q.ellipse(h, g + a, e, e * d, 0, u, 0, false);
-            q.lineTo(h + e, g);
-            v = [h, g, e, e * d, 0, 0, u, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-        if (j) {
-            if (!o || b) {
-                if (u >= 0 && r < 0) {
-                    l()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        f()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, 0, Math.PI, false);
-                                q.lineTo(h - e, g);
-                                v = [h, g, e, e * d, 0, Math.PI, 0, true];
-                                if (!o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                l();
-                                f()
-                            } else {
-                                v = [h, g, e, e * d, 0, u, r, false];
-                                if (c && !o || n && o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d + a);
-                                q.ellipse(h, g + a, e, e * d, 0, r, u, true);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        } else {
-            if (o || b) {
-                if (u >= 0 && r < 0) {
-                    x()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        m()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                x();
-                                m()
-                            } else {
-                                q.ellipse(h, g + a, e, e * d, 0, u, r, false);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-                                v = [h, g, e, e * d, 0, r, u, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, -Math.PI, 0, false);
-                                q.lineTo(h + e, g);
-                                v = [h, g, e, e * d, 0, 0, -Math.PI, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    innerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, true)
-    },
-    innerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, false)
-    },
-    outerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, true)
-    },
-    outerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, false)
-    }
-});
-Ext.define("Ext.draw.PathUtil", function() {
-    var a = Math.abs,
-        c = Math.pow,
-        e = Math.cos,
-        b = Math.acos,
-        d = Math.sqrt,
-        f = Math.PI;
-    return {
-        singleton: true,
-        requires: ["Ext.draw.overrides.Path", "Ext.draw.overrides.sprite.Path", "Ext.draw.overrides.sprite.Instancing", "Ext.draw.overrides.Surface"],
-        cubicRoots: function(m) {
-            var z = m[0],
-                x = m[1],
-                w = m[2],
-                v = m[3];
-            if (z === 0) {
-                return this.quadraticRoots(x, w, v)
-            }
-            var s = x / z,
-                r = w / z,
-                q = v / z,
-                k = (3 * r - c(s, 2)) / 9,
-                j = (9 * s * r - 27 * q - 2 * c(s, 3)) / 54,
-                p = c(k, 3) + c(j, 2),
-                n = [],
-                h, g, o, l, u, y = Ext.Number.sign;
-            if (p >= 0) {
-                h = y(j + d(p)) * c(a(j + d(p)), 1 / 3);
-                g = y(j - d(p)) * c(a(j - d(p)), 1 / 3);
-                n[0] = -s / 3 + (h + g);
-                n[1] = -s / 3 - (h + g) / 2;
-                n[2] = n[1];
-                o = a(d(3) * (h - g) / 2);
-                if (o !== 0) {
-                    n[1] = -1;
-                    n[2] = -1
-                }
-            } else {
-                l = b(j / d(-c(k, 3)));
-                n[0] = 2 * d(-k) * e(l / 3) - s / 3;
-                n[1] = 2 * d(-k) * e((l + 2 * f) / 3) - s / 3;
-                n[2] = 2 * d(-k) * e((l + 4 * f) / 3) - s / 3
-            }
-            for (u = 0; u < 3; u++) {
-                if (n[u] < 0 || n[u] > 1) {
-                    n[u] = -1
-                }
-            }
-            return n
-        },
-        quadraticRoots: function(h, g, n) {
-            var m, l, k, j;
-            if (h === 0) {
-                return this.linearRoot(g, n)
-            }
-            m = g * g - 4 * h * n;
-            if (m === 0) {
-                k = [-g / (2 * h)]
-            } else {
-                if (m > 0) {
-                    l = d(m);
-                    k = [(-g - l) / (2 * h), (-g + l) / (2 * h)]
-                } else {
-                    return []
-                }
-            }
-            for (j = 0; j < k.length; j++) {
-                if (k[j] < 0 || k[j] > 1) {
-                    k[j] = -1
-                }
-            }
-            return k
-        },
-        linearRoot: function(h, g) {
-            var i = -g / h;
-            if (h === 0 || i < 0 || i > 1) {
-                return []
-            }
-            return [i]
-        },
-        bezierCoeffs: function(h, g, k, j) {
-            var i = [];
-            i[0] = -h + 3 * g - 3 * k + j;
-            i[1] = 3 * h - 6 * g + 3 * k;
-            i[2] = -3 * h + 3 * g;
-            i[3] = h;
-            return i
-        },
-        cubicLineIntersections: function(I, G, F, E, l, k, j, h, M, p, K, n) {
-            var u = [],
-                N = [],
-                D = p - n,
-                z = K - M,
-                y = M * (n - p) - p * (K - M),
-                L = this.bezierCoeffs(I, G, F, E),
-                J = this.bezierCoeffs(l, k, j, h),
-                H, x, w, v, g, q, o, m;
-            u[0] = D * L[0] + z * J[0];
-            u[1] = D * L[1] + z * J[1];
-            u[2] = D * L[2] + z * J[2];
-            u[3] = D * L[3] + z * J[3] + y;
-            x = this.cubicRoots(u);
-            for (H = 0; H < x.length; H++) {
-                v = x[H];
-                if (v < 0 || v > 1) {
-                    continue
-                }
-                g = v * v;
-                q = g * v;
-                o = L[0] * q + L[1] * g + L[2] * v + L[3];
-                m = J[0] * q + J[1] * g + J[2] * v + J[3];
-                if ((K - M) !== 0) {
-                    w = (o - M) / (K - M)
-                } else {
-                    w = (m - p) / (n - p)
-                }
-                if (!(w < 0 || w > 1)) {
-                    N.push([o, m])
-                }
-            }
-            return N
-        },
-        splitCubic: function(g, q, p, o, m) {
-            var j = m * m,
-                n = m * j,
-                i = m - 1,
-                h = i * i,
-                k = i * h,
-                l = n * o - 3 * j * i * p + 3 * m * h * q - k * g;
-            return [
-                [g, m * q - i * g, j * p - 2 * m * i * q + h * g, l],
-                [l, j * o - 2 * m * i * p + h * q, m * o - i * p, o]
-            ]
-        },
-        cubicDimension: function(p, o, l, k) {
-            var j = 3 * (-p + 3 * (o - l) + k),
-                i = 6 * (p - 2 * o + l),
-                h = -3 * (p - o),
-                q, n, g = Math.min(p, k),
-                m = Math.max(p, k),
-                r;
-            if (j === 0) {
-                if (i === 0) {
-                    return [g, m]
-                } else {
-                    q = -h / i;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                }
-            } else {
-                r = i * i - 4 * j * h;
-                if (r >= 0) {
-                    r = d(r);
-                    q = (r - i) / 2 / j;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                    if (r > 0) {
-                        q -= r / j;
-                        if (0 < q && q < 1) {
-                            n = this.interpolateCubic(p, o, l, k, q);
-                            g = Math.min(g, n);
-                            m = Math.max(m, n)
-                        }
-                    }
-                }
-            }
-            return [g, m]
-        },
-        interpolateCubic: function(h, g, l, k, i) {
-            if (i === 0) {
-                return h
-            }
-            if (i === 1) {
-                return k
-            }
-            var j = (1 - i) / i;
-            return i * i * i * (k + j * (3 * l + j * (3 * g + j * h)))
-        },
-        cubicsIntersections: function(r, q, p, o, A, z, y, v, g, F, E, D, m, l, k, i) {
-            var C = this,
-                x = C.cubicDimension(r, q, p, o),
-                B = C.cubicDimension(A, z, y, v),
-                n = C.cubicDimension(g, F, E, D),
-                s = C.cubicDimension(m, l, k, i),
-                j, h, u, t, w = [];
-            if (x[0] > n[1] || x[1] < n[0] || B[0] > s[1] || B[1] < s[0]) {
-                return []
-            }
-            if (a(A - z) < 1 && a(y - v) < 1 && a(r - o) < 1 && a(q - p) < 1 && a(m - l) < 1 && a(k - i) < 1 && a(g - D) < 1 && a(F - E) < 1) {
-                return [
-                    [(r + o) * 0.5, (A + z) * 0.5]
-                ]
-            }
-            j = C.splitCubic(r, q, p, o, 0.5);
-            h = C.splitCubic(A, z, y, v, 0.5);
-            u = C.splitCubic(g, F, E, D, 0.5);
-            t = C.splitCubic(m, l, k, i, 0.5);
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[1], t[1])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[1], t[1])));
-            return w
-        },
-        linesIntersection: function(k, p, j, o, h, n, q, m) {
-            var l = (j - k) * (m - n) - (o - p) * (q - h),
-                i, g;
-            if (l === 0) {
-                return null
-            }
-            i = ((q - h) * (p - n) - (k - h) * (m - n)) / l;
-            g = ((j - k) * (p - n) - (o - p) * (k - h)) / l;
-            if (i >= 0 && i <= 1 && g >= 0 && g <= 1) {
-                return [k + i * (j - k), p + i * (o - p)]
-            }
-            return null
-        },
-        pointOnLine: function(j, m, h, l, g, n) {
-            var k, i;
-            if (a(h - j) < a(l - m)) {
-                i = j;
-                j = m;
-                m = i;
-                i = h;
-                h = l;
-                l = i;
-                i = g;
-                g = n;
-                n = i
-            }
-            k = (g - j) / (h - j);
-            if (k < 0 || k > 1) {
-                return false
-            }
-            return a(m + k * (l - m) - n) < 4
-        },
-        pointOnCubic: function(w, u, s, r, l, k, h, g, p, o) {
-            var C = this,
-                B = C.bezierCoeffs(w, u, s, r),
-                A = C.bezierCoeffs(l, k, h, g),
-                z, v, n, m, q;
-            B[3] -= p;
-            A[3] -= o;
-            n = C.cubicRoots(B);
-            m = C.cubicRoots(A);
-            for (z = 0; z < n.length; z++) {
-                q = n[z];
-                for (v = 0; v < m.length; v++) {
-                    if (q >= 0 && q <= 1 && a(q - m[v]) < 0.05) {
-                        return true
-                    }
-                }
-            }
-            return false
-        }
-    }
-});
-Ext.define("Ext.chart.series.Pie3D", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.Pie3DPart", "Ext.draw.PathUtil"],
-    type: "pie3d",
-    seriesType: "pie3d",
-    alias: "series.pie3d",
-    isPie3D: true,
-    config: {
-        rect: [0, 0, 0, 0],
-        thickness: 35,
-        distortion: 0.5,
-        donut: false,
-        hidden: [],
-        highlightCfg: {
-            margin: 20
-        },
-        shadow: false
-    },
-    rotationOffset: -Math.PI / 2,
-    setField: function(a) {
-        return this.setXField(a)
-    },
-    getField: function() {
-        return this.getXField()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            baseRotation: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateDistortion: function() {
-        this.setRadius()
-    },
-    updateThickness: function() {
-        this.setRadius()
-    },
-    updateColors: function(a) {
-        this.setSubStyle({
-            baseColor: a
-        })
-    },
-    applyShadow: function(a) {
-        if (a === true) {
-            a = {
-                shadowColor: "rgba(0,0,0,0.8)",
-                shadowBlur: 30
-            }
-        } else {
-            if (!Ext.isObject(a)) {
-                a = {
-                    shadowColor: Ext.draw.Color.RGBA_NONE
-                }
-            }
-        }
-        return a
-    },
-    updateShadow: function(g) {
-        var e = this,
-            f = e.getSprites(),
-            d = e.spritesPerSlice,
-            c = f && f.length,
-            b, a;
-        for (b = 1; b < c; b += d) {
-            a = f[b];
-            if (a.attr.part = "bottom") {
-                a.setAttributes(g)
-            }
-        }
-    },
-    getStyleByIndex: function(b) {
-        var d = this.callParent([b]),
-            c = this.getStyle(),
-            a = d.fillStyle || d.fill || d.color,
-            e = c.strokeStyle || c.stroke;
-        if (a) {
-            d.baseColor = a;
-            delete d.fillStyle;
-            delete d.fill;
-            delete d.color
-        }
-        if (e) {
-            d.strokeStyle = e
-        }
-        return d
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.getSprites(),
-            f = g.spritesPerSlice,
-            e = h && h.length,
-            c = 0,
-            b = 0,
-            a, d;
-        for (; c < e; c += f, b++) {
-            d = g.getStyleByIndex(b);
-            for (a = 0; a < f; a++) {
-                h[c + a].setAttributes(d)
-            }
-        }
-    },
-    coordinateX: function() {
-        var w = this,
-            m = w.getChart(),
-            u = m && m.getAnimation(),
-            f = w.getStore(),
-            t = f.getData().items,
-            d = t.length,
-            b = w.getXField(),
-            p = w.getRotation(),
-            s = w.getHidden(),
-            n, c = 0,
-            h, e = [],
-            k = w.getSprites(),
-            a = k.length,
-            l = w.spritesPerSlice,
-            g = 0,
-            o = Math.PI * 2,
-            v = 1e-10,
-            r, q;
-        for (r = 0; r < d; r++) {
-            n = Math.abs(Number(t[r].get(b))) || 0;
-            if (!s[r]) {
-                c += n
-            }
-            e[r] = c;
-            if (r >= s.length) {
-                s[r] = false
-            }
-        }
-        s.length = d;
-        if (c === 0) {
-            return
-        }
-        h = 2 * Math.PI / c;
-        for (r = 0; r < d; r++) {
-            e[r] *= h
-        }
-        for (r = 0; r < a; r++) {
-            k[r].setAnimation(u)
-        }
-        for (r = 0; r < d; r++) {
-            for (q = 0; q < l; q++) {
-                k[r * l + q].setAttributes({
-                    startAngle: g,
-                    endAngle: e[r] - v,
-                    globalAlpha: 1,
-                    baseRotation: p
-                })
-            }
-            g = e[r]
-        }
-        for (r *= l; r < a; r++) {
-            k[r].setAnimation(u);
-            k[r].setAttributes({
-                startAngle: o,
-                endAngle: o,
-                globalAlpha: 0,
-                baseRotation: p
-            })
-        }
-    },
-    updateLabelData: function() {
-        var l = this,
-            m = l.getStore(),
-            k = m.getData().items,
-            h = l.getSprites(),
-            b = l.getLabel().getTemplate().getField(),
-            f = l.getHidden(),
-            a = l.spritesPerSlice,
-            d, c, g, e, n;
-        if (h.length && b) {
-            e = [];
-            for (d = 0, g = k.length; d < g; d++) {
-                e.push(k[d].get(b))
-            }
-            for (d = 0, c = 0, g = h.length; d < g; d += a, c++) {
-                n = h[d];
-                n.setAttributes({
-                    label: e[c]
-                });
-                n.putMarker("labels", {
-                    hidden: f[c]
-                }, n.attr.attributeId)
-            }
-        }
-    },
-    applyRadius: function() {
-        var f = this,
-            d = f.getChart(),
-            h = d.getInnerPadding(),
-            e = d.getMainRect() || [0, 0, 1, 1],
-            c = e[2] - h * 2,
-            a = e[3] - h * 2 - f.getThickness(),
-            g = c / 2,
-            b = g * f.getDistortion();
-        if (b > a / 2) {
-            return a / (f.getDistortion() * 2)
-        } else {
-            return g
-        }
-    },
-    getSprites: function() {
-        var y = this,
-            e = y.getStore();
-        if (!e) {
-            return []
-        }
-        var n = y.getChart(),
-            p = y.getSurface(),
-            t = e.getData().items,
-            l = y.spritesPerSlice,
-            a = t.length,
-            v = y.getAnimation() || n && n.getAnimation(),
-            x = y.getCenter(),
-            w = y.getOffsetX(),
-            u = y.getOffsetY(),
-            b = y.getRadius(),
-            q = y.getRotation(),
-            d = y.getHighlight(),
-            c = {
-                centerX: x[0] + w,
-                centerY: x[1] + u - y.getThickness() / 2,
-                endRho: b,
-                startRho: b * y.getDonut() / 100,
-                thickness: y.getThickness(),
-                distortion: y.getDistortion()
-            },
-            k = y.sprites,
-            h = y.getLabel(),
-            f = h.getTemplate(),
-            m, g, o, s, r;
-        for (s = 0; s < a; s++) {
-            g = Ext.apply({}, this.getStyleByIndex(s), c);
-            if (!k[s * l]) {
-                for (r = 0; r < y.partNames.length; r++) {
-                    o = p.add({
-                        type: "pie3dPart",
-                        part: y.partNames[r]
-                    });
-                    if (r === 0 && f.getField()) {
-                        o.bindMarker("labels", h)
-                    }
-                    o.fx.setDurationOn("baseRotation", q);
-                    if (d) {
-                        o.config.highlight = d;
-                        o.addModifier("highlight", true)
-                    }
-                    o.setAttributes(g);
-                    k.push(o)
-                }
-            } else {
-                m = k.slice(s * l, (s + 1) * l);
-                for (r = 0; r < m.length; r++) {
-                    o = m[r];
-                    if (v) {
-                        o.setAnimation(v)
-                    }
-                    o.setAttributes(g)
-                }
-            }
-        }
-        return k
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        f += g;
-        c += g;
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            g = h.getSprites();
-        if (g) {
-            var l = h.getStore(),
-                b = l.getData().items,
-                a = h.spritesPerSlice,
-                e = h.getHidden(),
-                c, f, m, d;
-            for (c = 0, f = b.length; c < f; c++) {
-                if (!e[c]) {
-                    d = c * a;
-                    m = g[d];
-                    if (m.hitTest([k, j])) {
-                        return {
-                            series: h,
-                            sprite: g.slice(d, d + a),
-                            index: c,
-                            record: b[c],
-                            category: "sprites",
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            k = h.getStore();
-        if (k) {
-            var g = k.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                j = h.getField(),
-                e = h.getHidden(),
-                d, a, c;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                c = a.baseColor;
-                f.push({
-                    name: b ? String(g[d].get(b)) : j + " " + d,
-                    mark: c || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-}, function() {
-    var b = this.prototype,
-        a = Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;
-    b.partNames = a.replace(/^enums\(|\)/g, "").split(",");
-    b.spritesPerSlice = b.partNames.length
-});
-Ext.define("Ext.chart.series.sprite.Polar", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                baseRotation: "number",
-                labels: "default",
-                labelOverflowPadding: "number"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: Math.PI,
-                startRho: 0,
-                endRho: 150,
-                baseRotation: 0,
-                labels: null,
-                labelOverflowPadding: 10
-            },
-            triggers: {
-                centerX: "bbox",
-                centerY: "bbox",
-                startAngle: "bbox",
-                endAngle: "bbox",
-                startRho: "bbox",
-                endRho: "bbox",
-                baseRotation: "bbox"
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.centerX - a.endRho;
-        b.y = a.centerY + a.endRho;
-        b.width = a.endRho * 2;
-        b.height = a.endRho * 2
-    }
-});
-Ext.define("Ext.chart.series.sprite.Radar", {
-    alias: "sprite.radar",
-    extend: "Ext.chart.series.sprite.Polar",
-    getDataPointXY: function(d) {
-        var u = this,
-            n = u.attr,
-            f = n.centerX,
-            e = n.centerY,
-            o = n.matrix,
-            t = n.dataMinX,
-            s = n.dataMaxX,
-            k = n.dataX,
-            j = n.dataY,
-            l = n.endRho,
-            p = n.startRho,
-            g = n.baseRotation,
-            i, h, m, c, b, a, q;
-        if (n.rangeY) {
-            q = n.rangeY[1]
-        } else {
-            q = n.dataMaxY
-        }
-        c = (k[d] - t) / (s - t + 1) * 2 * Math.PI + g;
-        m = j[d] / q * (l - p) + p;
-        b = f + Math.cos(c) * m;
-        a = e + Math.sin(c) * m;
-        i = o.x(b, a);
-        h = o.y(b, a);
-        return [i, h]
-    },
-    render: function(a, l) {
-        var h = this,
-            f = h.attr,
-            g = f.dataX,
-            b = g.length,
-            e = h.surfaceMatrix,
-            d = {},
-            c, k, j, m;
-        l.beginPath();
-        for (c = 0; c < b; c++) {
-            m = h.getDataPointXY(c);
-            k = m[0];
-            j = m[1];
-            if (c === 0) {
-                l.moveTo(k, j)
-            }
-            l.lineTo(k, j);
-            d.translationX = e.x(k, j);
-            d.translationY = e.y(k, j);
-            h.putMarker("markers", d, c, true)
-        }
-        l.closePath();
-        l.fillStroke(f)
-    }
-});
-Ext.define("Ext.chart.series.Radar", {
-    extend: "Ext.chart.series.Polar",
-    type: "radar",
-    seriesType: "radar",
-    alias: "series.radar",
-    requires: ["Ext.chart.series.sprite.Radar"],
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 1
-    },
-    updateAngularAxis: function(a) {
-        a.processData(this)
-    },
-    updateRadialAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            endRho: a
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            m = h.sprites && h.sprites[0],
-            f = m.attr,
-            g = f.dataX,
-            a = g.length,
-            l = h.getStore(),
-            e = h.getMarker(),
-            b, o, p, d, n, c;
-        if (h.getHidden()) {
-            return null
-        }
-        if (m && e) {
-            c = m.getMarker("markers");
-            for (d = 0; d < a; d++) {
-                n = c.getBBoxFor(d);
-                b = (n.width + n.height) * 0.25;
-                p = m.getDataPointXY(d);
-                if (Math.abs(p[0] - k) < b && Math.abs(p[1] - j) < b) {
-                    o = {
-                        series: h,
-                        sprite: m,
-                        index: d,
-                        category: "markers",
-                        record: l.getData().items[d],
-                        field: h.getYField()
-                    };
-                    return o
-                }
-            }
-        }
-        return h.callParent(arguments)
-    },
-    getDefaultSpriteConfig: function() {
-        var a = this.callParent(),
-            b = {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationRads: 0,
-                    dataMinX: 0,
-                    dataMaxX: 0
-                }
-            };
-        if (a.fx) {
-            Ext.apply(a.fx, b)
-        } else {
-            a.fx = b
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = d.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.sprites[0],
-            a;
-        if (!c) {
-            return []
-        }
-        if (!b) {
-            b = d.createSprite()
-        }
-        if (e) {
-            a = b.getMarker("markers");
-            if (a) {
-                a.getTemplate().setAnimation(e)
-            }
-            b.setAnimation(e)
-        }
-        return d.sprites
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.series.sprite.Scatter", {
-    alias: "sprite.scatterSeries",
-    extend: "Ext.chart.series.sprite.Cartesian",
-    renderClipped: function(r, s, w, u) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var C = this,
-            q = C.attr,
-            l = q.dataX,
-            h = q.dataY,
-            z = q.labels,
-            j = C.getSeries(),
-            b = z && C.getMarker("labels"),
-            t = C.attr.matrix,
-            c = t.getXX(),
-            p = t.getYY(),
-            m = t.getDX(),
-            k = t.getDY(),
-            n = {},
-            D, B, d = r.getInherited().rtl && !q.flipXY ? -1 : 1,
-            a, A, o, e, g, f, v;
-        if (q.flipXY) {
-            a = u[1] - c * d;
-            A = u[1] + u[3] + c * d;
-            o = u[0] - p;
-            e = u[0] + u[2] + p
-        } else {
-            a = u[0] - c * d;
-            A = u[0] + u[2] + c * d;
-            o = u[1] - p;
-            e = u[1] + u[3] + p
-        }
-        for (v = 0; v < l.length; v++) {
-            g = l[v];
-            f = h[v];
-            g = g * c + m;
-            f = f * p + k;
-            if (a <= g && g <= A && o <= f && f <= e) {
-                if (q.renderer) {
-                    n = {
-                        type: "items",
-                        translationX: g,
-                        translationY: f
-                    };
-                    B = [C, n, {
-                        store: C.getStore()
-                    }, v];
-                    D = Ext.callback(q.renderer, null, B, 0, j);
-                    n = Ext.apply(n, D)
-                } else {
-                    n.translationX = g;
-                    n.translationY = f
-                }
-                C.putMarker("items", n, v, !q.renderer);
-                if (b && z[v]) {
-                    C.drawLabel(z[v], g, f, v, u)
-                }
-            }
-        }
-    },
-    drawLabel: function(j, h, g, p, a) {
-        var r = this,
-            m = r.attr,
-            d = r.getMarker("labels"),
-            c = d.getTemplate(),
-            l = r.labelCfg || (r.labelCfg = {}),
-            b = r.surfaceMatrix,
-            f, e, i = m.labelOverflowPadding,
-            o = m.flipXY,
-            k, n, s, q;
-        l.text = j;
-        n = r.getMarkerBBox("labels", p, true);
-        if (!n) {
-            r.putMarker("labels", l, p);
-            n = r.getMarkerBBox("labels", p, true)
-        }
-        if (o) {
-            l.rotationRads = Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        k = n.height / 2;
-        f = h;
-        switch (c.attr.display) {
-            case "under":
-                e = g - k - i;
-                break;
-            case "rotate":
-                f += i;
-                e = g - i;
-                l.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                e = g + k + i
-        }
-        l.x = b.x(f, e);
-        l.y = b.y(f, e);
-        if (c.attr.renderer) {
-            q = [j, d, l, {
-                store: r.getStore()
-            }, p];
-            s = Ext.callback(c.attr.renderer, null, q, 0, r.getSeries());
-            if (typeof s === "string") {
-                l.text = s
-            } else {
-                Ext.apply(l, s)
-            }
-        }
-        r.putMarker("labels", l, p)
-    }
-});
-Ext.define("Ext.chart.series.Scatter", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.scatter",
-    type: "scatter",
-    seriesType: "scatterSeries",
-    requires: ["Ext.chart.series.sprite.Scatter"],
-    config: {
-        itemInstancing: {
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0
-                }
-            }
-        }
-    },
-    themeMarkerCount: function() {
-        return 1
-    },
-    applyMarker: function(b, a) {
-        this.getItemInstancing();
-        this.setItemInstancing(b);
-        return this.callParent(arguments)
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getMarkerStyleByIndex(0),
-            c = a.fillStyle;
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.theme.Blue", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue", "chart.theme.Blue"],
-    config: {
-        baseColor: "#4d7fe6"
-    }
-});
-Ext.define("Ext.chart.theme.BlueGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue-gradients", "chart.theme.Blue:gradients"],
-    config: {
-        baseColor: "#4d7fe6",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category1", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1", "chart.theme.Category1"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"]
-    }
-});
-Ext.define("Ext.chart.theme.Category1Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1-gradients", "chart.theme.Category1:gradients"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category2", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2", "chart.theme.Category2"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"]
-    }
-});
-Ext.define("Ext.chart.theme.Category2Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2-gradients", "chart.theme.Category2:gradients"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category3", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3", "chart.theme.Category3"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"]
-    }
-});
-Ext.define("Ext.chart.theme.Category3Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3-gradients", "chart.theme.Category3:gradients"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category4", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4", "chart.theme.Category4"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"]
-    }
-});
-Ext.define("Ext.chart.theme.Category4Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4-gradients", "chart.theme.Category4:gradients"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category5", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5", "chart.theme.Category5"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"]
-    }
-});
-Ext.define("Ext.chart.theme.Category5Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5-gradients", "chart.theme.Category5:gradients"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category6", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6", "chart.theme.Category6"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"]
-    }
-});
-Ext.define("Ext.chart.theme.Category6Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6-gradients", "chart.theme.Category6:gradients"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.DefaultGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default-gradients", "chart.theme.Base:gradients"],
-    config: {
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Green", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green", "chart.theme.Green"],
-    config: {
-        baseColor: "#b1da5a"
-    }
-});
-Ext.define("Ext.chart.theme.GreenGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green-gradients", "chart.theme.Green:gradients"],
-    config: {
-        baseColor: "#b1da5a",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Midnight", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.midnight", "chart.theme.Midnight"],
-    config: {
-        colors: ["#A837FF", "#4AC0F2", "#FF4D35", "#FF8809", "#61C102", "#FF37EA"],
-        chart: {
-            defaults: {
-                background: "rgb(52, 52, 53)"
-            }
-        },
-        axis: {
-            defaults: {
-                style: {
-                    strokeStyle: "rgb(224, 224, 227)"
-                },
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                title: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                grid: {
-                    strokeStyle: "rgb(112, 112, 115)"
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                }
-            }
-        },
-        sprites: {
-            text: {
-                fillStyle: "rgb(224, 224, 227)"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Muted", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.muted", "chart.theme.Muted"],
-    config: {
-        colors: ["#8ca640", "#974144", "#4091ba", "#8e658e", "#3b8d8b", "#b86465", "#d2af69", "#6e8852", "#3dcc7e", "#a6bed1", "#cbaa4b", "#998baa"]
-    }
-});
-Ext.define("Ext.chart.theme.Purple", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple", "chart.theme.Purple"],
-    config: {
-        baseColor: "#da5abd"
-    }
-});
-Ext.define("Ext.chart.theme.PurpleGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple-gradients", "chart.theme.Purple:gradients"],
-    config: {
-        baseColor: "#da5abd",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Red", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red", "chart.theme.Red"],
-    config: {
-        baseColor: "#e84b67"
-    }
-});
-Ext.define("Ext.chart.theme.RedGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red-gradients", "chart.theme.Red:gradients"],
-    config: {
-        baseColor: "#e84b67",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Sky", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky", "chart.theme.Sky"],
-    config: {
-        baseColor: "#4ce0e7"
-    }
-});
-Ext.define("Ext.chart.theme.SkyGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky-gradients", "chart.theme.Sky:gradients"],
-    config: {
-        baseColor: "#4ce0e7",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Yellow", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow", "chart.theme.Yellow"],
-    config: {
-        baseColor: "#fec935"
-    }
-});
-Ext.define("Ext.chart.theme.YellowGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow-gradients", "chart.theme.Yellow:gradients"],
-    config: {
-        baseColor: "#fec935",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.draw.Point", {
-    requires: ["Ext.draw.Draw", "Ext.draw.Matrix"],
-    isPoint: true,
-    x: 0,
-    y: 0,
-    length: 0,
-    angle: 0,
-    angleUnits: "degrees",
-    statics: {
-        fly: (function() {
-            var a = null;
-            return function(b, c) {
-                if (!a) {
-                    a = new Ext.draw.Point()
-                }
-                a.constructor(b, c);
-                return a
-            }
-        })()
-    },
-    constructor: function(a, c) {
-        var b = this;
-        if (typeof a === "number") {
-            b.x = a;
-            if (typeof c === "number") {
-                b.y = c
-            } else {
-                b.y = a
-            }
-        } else {
-            if (Ext.isArray(a)) {
-                b.x = a[0];
-                b.y = a[1]
-            } else {
-                if (a) {
-                    b.x = a.x;
-                    b.y = a.y
-                }
-            }
-        }
-        b.calculatePolar()
-    },
-    calculateCartesian: function() {
-        var b = this,
-            a = b.length,
-            c = b.angle;
-        if (b.angleUnits === "degrees") {
-            c = Ext.draw.Draw.rad(c)
-        }
-        b.x = Math.cos(c) * a;
-        b.y = Math.sin(c) * a
-    },
-    calculatePolar: function() {
-        var b = this,
-            a = b.x,
-            c = b.y;
-        b.length = Math.sqrt(a * a + c * c);
-        b.angle = Math.atan2(c, a);
-        if (b.angleUnits === "degrees") {
-            b.angle = Ext.draw.Draw.degrees(b.angle)
-        }
-    },
-    setX: function(a) {
-        this.x = a;
-        this.calculatePolar()
-    },
-    setY: function(a) {
-        this.y = a;
-        this.calculatePolar()
-    },
-    set: function(a, b) {
-        this.constructor(a, b)
-    },
-    setAngle: function(a) {
-        this.angle = a;
-        this.calculateCartesian()
-    },
-    setLength: function(a) {
-        this.length = a;
-        this.calculateCartesian()
-    },
-    setPolar: function(b, a) {
-        this.angle = b;
-        this.length = a;
-        this.calculateCartesian()
-    },
-    clone: function() {
-        return new Ext.draw.Point(this.x, this.y)
-    },
-    add: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x + b.x, this.y + b.y)
-    },
-    sub: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x - b.x, this.y - b.y)
-    },
-    mul: function(a) {
-        return new Ext.draw.Point(this.x * a, this.y * a)
-    },
-    div: function(a) {
-        return new Ext.draw.Point(this.x / a, this.y / a)
-    },
-    dot: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x * b.x + this.y * b.y
-    },
-    equals: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x === b.x && this.y === b.y
-    },
-    rotate: function(f, c) {
-        var d, e, b, g, a;
-        if (this.angleUnits === "degrees") {
-            f = Ext.draw.Draw.rad(f);
-            d = Math.sin(f);
-            e = Math.cos(f)
-        }
-        if (c) {
-            b = c.x;
-            g = c.y
-        } else {
-            b = 0;
-            g = 0
-        }
-        a = Ext.draw.Matrix.fly([e, d, -d, e, b - e * b + g * d, g - e * g + b * -d]).transformPoint(this);
-        return new Ext.draw.Point(a)
-    },
-    transform: function(a) {
-        if (a && a.isMatrix) {
-            return new Ext.draw.Point(a.transformPoint(this))
-        } else {
-            if (arguments.length === 6) {
-                return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))
-            } else {
-                Ext.raise("Invalid parameters.")
-            }
-        }
-    },
-    round: function() {
-        return new Ext.draw.Point(Math.round(this.x), Math.round(this.y))
-    },
-    ceil: function() {
-        return new Ext.draw.Point(Math.ceil(this.x), Math.ceil(this.y))
-    },
-    floor: function() {
-        return new Ext.draw.Point(Math.floor(this.x), Math.floor(this.y))
-    },
-    abs: function(a, b) {
-        return new Ext.draw.Point(Math.abs(this.x), Math.abs(this.y))
-    },
-    normalize: function(c) {
-        var b = this.x,
-            f = this.y,
-            a, e, d;
-        c = c || 1;
-        if (b === 0) {
-            a = 0;
-            e = c * Ext.Number.sign(f)
-        } else {
-            d = f / b;
-            a = c / Math.sqrt(1 + d * d);
-            e = a * d
-        }
-        return new Ext.draw.Point(a, e)
-    },
-    getDistanceToLine: function(c, b) {
-        if (arguments.length === 4) {
-            c = new Ext.draw.Point(arguments[0], arguments[1]);
-            b = new Ext.draw.Point(arguments[2], arguments[3])
-        }
-        var d = b.sub(c).normalize(),
-            a = c.sub(this);
-        return a.sub(d.mul(a.dot(d)))
-    },
-    isZero: function() {
-        return this.x === 0 && this.y === 0
-    },
-    isNumber: function() {
-        return Ext.isNumber(this.x + this.y)
-    }
-});
-Ext.define("Ext.draw.plugin.SpriteEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.spriteevents",
-    requires: ["Ext.draw.PathUtil"],
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    spriteMouseMoveEvents: {
-        spritemousemove: true,
-        spritemouseover: true,
-        spritemouseout: true
-    },
-    init: function(a) {
-        var b = "handleEvent";
-        this.drawContainer = a;
-        a.addElementListener({
-            click: b,
-            dblclick: b,
-            mousedown: b,
-            mousemove: b,
-            mouseup: b,
-            mouseover: b,
-            mouseout: b,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasSpriteMouseMoveListeners: function() {
-        var b = this.drawContainer.hasListeners,
-            a;
-        for (a in this.spriteMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    hitTestEvent: function(f) {
-        var b = this.drawContainer.getItems(),
-            a, d, c;
-        for (c = b.length - 1; c >= 0; c--) {
-            a = b.get(c);
-            d = a.hitTestEvent(f);
-            if (d) {
-                return d
-            }
-        }
-        return null
-    },
-    handleEvent: function(f) {
-        var d = this,
-            b = d.drawContainer,
-            g = f.type in d.mouseMoveEvents,
-            a = d.lastSprite,
-            c;
-        if (g && !d.hasSpriteMouseMoveListeners()) {
-            return
-        }
-        c = d.hitTestEvent(f);
-        if (g && !Ext.Object.equals(c, a)) {
-            if (a) {
-                b.fireEvent("spritemouseout", a, f)
-            }
-            if (c) {
-                b.fireEvent("spritemouseover", c, f)
-            }
-        }
-        if (c) {
-            b.fireEvent("sprite" + f.type, c, f)
-        }
-        d.lastSprite = c
-    }
-});
-Ext.define("Ext.chart.TipSurface", {
-    extend: "Ext.draw.Container",
-    spriteArray: false,
-    renderFirst: true,
-    constructor: function(a) {
-        this.callParent([a]);
-        if (a.sprites) {
-            this.spriteArray = [].concat(a.sprites);
-            delete a.sprites
-        }
-    },
-    onRender: function() {
-        var c = this,
-            b = 0,
-            a = 0,
-            d, e;
-        this.callParent(arguments);
-        e = c.spriteArray;
-        if (c.renderFirst && e) {
-            c.renderFirst = false;
-            for (a = e.length; b < a; b++) {
-                d = c.surface.add(e[b]);
-                d.setAttributes({
-                    hidden: false
-                }, true)
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.interactions.ItemInfo", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "iteminfo",
-    alias: "interaction.iteminfo",
-    config: {
-        extjsGestures: {
-            start: {
-                event: "click",
-                handler: "onInfoGesture"
-            },
-            move: {
-                event: "mousemove",
-                handler: "onInfoGesture"
-            },
-            end: {
-                event: "mouseleave",
-                handler: "onInfoGesture"
-            }
-        }
-    },
-    item: null,
-    onInfoGesture: function(f, a) {
-        var c = this,
-            b = c.getItemForEvent(f),
-            d = b && b.series.tooltip;
-        if (d) {
-            d.onMouseMove.call(d, f)
-        }
-        if (b !== c.item) {
-            if (b) {
-                b.series.showTip(b)
-            } else {
-                c.item.series.hideTip(c.item)
-            }
-            c.item = b
-        }
-        return false
-    }
-});
\ No newline at end of file
diff --git a/serverside/jsmod/6.0-4/charts.js.original b/serverside/jsmod/6.0-4/charts.js.original
deleted file mode 100644
index 2b8dd713bdd4e76d779e6b231b21d41c860a930a..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/charts.js.original
+++ /dev/null
@@ -1 +0,0 @@
-Ext.define("Ext.draw.ContainerBase",{extend:"Ext.panel.Panel",requires:["Ext.window.Window"],previewTitleText:"Chart Preview",previewAltText:"Chart preview",layout:"container",addElementListener:function(){var b=this,a=arguments;if(b.rendered){b.el.on.apply(b.el,a)}else{b.on("render",function(){b.el.on.apply(b.el,a)})}},removeElementListener:function(){var b=this,a=arguments;if(b.rendered){b.el.un.apply(b.el,a)}},afterRender:function(){this.callParent(arguments);this.initAnimator()},getItems:function(){var b=this,a=b.items;if(!a||!a.isMixedCollection){b.initItems()}return b.items},onRender:function(){this.callParent(arguments);this.element=this.el;this.innerElement=this.body},setItems:function(a){this.items=a;return a},setSurfaceSize:function(b,a){this.resizeHandler({width:b,height:a});this.renderFrame()},onResize:function(c,a,b,e){var d=this;d.callParent([c,a,b,e]);d.setBodySize({width:c,height:a})},preview:function(){var a=this.getImage();new Ext.window.Window({title:this.previewTitleText,closeable:true,renderTo:Ext.getBody(),autoShow:true,maximizeable:true,maximized:true,border:true,layout:{type:"hbox",pack:"center",align:"middle"},items:{xtype:"container",items:{xtype:"image",mode:"img",cls:Ext.baseCSSPrefix+"chart-image",alt:this.previewAltText,src:a.data,listeners:{afterrender:function(){var e=this,b=e.imgEl.dom,d=a.type==="svg"?1:(window.devicePixelRatio||1),c;if(!b.naturalWidth||!b.naturalHeight){b.onload=function(){var g=b.naturalWidth,f=b.naturalHeight;e.setWidth(Math.floor(g/d));e.setHeight(Math.floor(f/d))}}else{c=e.getSize();e.setWidth(Math.floor(c.width/d));e.setHeight(Math.floor(c.height/d))}}}}}})},privates:{getTargetEl:function(){return this.innerElement},reattachToBody:function(){var a=this;if(a.pendingDetachSize){a.onBodyResize()}a.pendingDetachSize=false;a.callParent()}}});Ext.define("Ext.draw.SurfaceBase",{extend:"Ext.Widget",getOwnerBody:function(){return this.ownerCt.body},destroy:function(){var a=this;if(a.hasListeners.destroy){a.fireEvent("destroy",a)}a.callParent()}});Ext.define("Ext.draw.Color",{statics:{colorToHexRe:/(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,rgbToHexRe:/\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,rgbaToHexRe:/\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,hexRe:/\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,NONE:"none",RGBA_NONE:"rgba(0, 0, 0, 0)"},isColor:true,lightnessFactor:0.2,constructor:function(d,b,a,c){this.setRGB(d,b,a,c)},setRGB:function(e,c,a,d){var b=this;b.r=Math.min(255,Math.max(0,e));b.g=Math.min(255,Math.max(0,c));b.b=Math.min(255,Math.max(0,a));if(d===undefined){b.a=1}else{b.a=Math.min(1,Math.max(0,d))}},getGrayscale:function(){return this.r*0.3+this.g*0.59+this.b*0.11},getHSL:function(){var i=this,a=i.r/255,f=i.g/255,j=i.b/255,k=Math.max(a,f,j),d=Math.min(a,f,j),m=k-d,e,n=0,c=0.5*(k+d);if(d!==k){n=(c<=0.5)?m/(k+d):m/(2-k-d);if(a===k){e=60*(f-j)/m}else{if(f===k){e=120+60*(j-a)/m}else{e=240+60*(a-f)/m}}if(e<0){e+=360}if(e>=360){e-=360}}return[e,n,c]},getHSV:function(){var i=this,a=i.r/255,f=i.g/255,j=i.b/255,k=Math.max(a,f,j),d=Math.min(a,f,j),c=k-d,e,m=0,l=k;if(d!=k){m=l?c/l:0;if(a===k){e=60*(f-j)/c}else{if(f===k){e=60*(j-a)/c+120}else{e=60*(a-f)/c+240}}if(e<0){e+=360}if(e>=360){e-=360}}return[e,m,l]},setHSL:function(g,f,e){var i=this,d=Math.abs,j,b,a;g=(g%360+360)%360;f=f>1?1:f<0?0:f;e=e>1?1:e<0?0:e;if(f===0||g===null){e*=255;i.setRGB(e,e,e)}else{g/=60;j=f*(1-d(2*e-1));b=j*(1-d(g%2-1));a=e-j/2;a*=255;j*=255;b*=255;switch(Math.floor(g)){case 0:i.setRGB(j+a,b+a,a);break;case 1:i.setRGB(b+a,j+a,a);break;case 2:i.setRGB(a,j+a,b+a);break;case 3:i.setRGB(a,b+a,j+a);break;case 4:i.setRGB(b+a,a,j+a);break;case 5:i.setRGB(j+a,a,b+a);break}}return i},setHSV:function(f,e,d){var g=this,i,b,a;f=(f%360+360)%360;e=e>1?1:e<0?0:e;d=d>1?1:d<0?0:d;if(e===0||f===null){d*=255;g.setRGB(d,d,d)}else{f/=60;i=d*e;b=i*(1-Math.abs(f%2-1));a=d-i;a*=255;i*=255;b*=255;switch(Math.floor(f)){case 0:g.setRGB(i+a,b+a,a);break;case 1:g.setRGB(b+a,i+a,a);break;case 2:g.setRGB(a,i+a,b+a);break;case 3:g.setRGB(a,b+a,i+a);break;case 4:g.setRGB(b+a,a,i+a);break;case 5:g.setRGB(i+a,a,b+a);break}}return g},createLighter:function(b){if(!b&&b!==0){b=this.lightnessFactor}var a=this.getHSL();a[2]=Ext.Number.constrain(a[2]+b,0,1);return Ext.draw.Color.fromHSL(a[0],a[1],a[2])},createDarker:function(a){if(!a&&a!==0){a=this.lightnessFactor}return this.createLighter(-a)},toString:function(){var f=this,c=Math.round;if(f.a===1){var e=c(f.r).toString(16),d=c(f.g).toString(16),a=c(f.b).toString(16);e=(e.length===1)?"0"+e:e;d=(d.length===1)?"0"+d:d;a=(a.length===1)?"0"+a:a;return["#",e,d,a].join("")}else{return"rgba("+[c(f.r),c(f.g),c(f.b),f.a===0?0:f.a.toFixed(15)].join(", ")+")"}},toHex:function(b){if(Ext.isArray(b)){b=b[0]}if(!Ext.isString(b)){return""}if(b.substr(0,1)==="#"){return b}var e=Ext.draw.Color.colorToHexRe.exec(b);if(Ext.isArray(e)){var f=parseInt(e[2],10),d=parseInt(e[3],10),a=parseInt(e[4],10),c=a|(d<<8)|(f<<16);return e[1]+"#"+("000000"+c.toString(16)).slice(-6)}else{return""}},setFromString:function(j){var e,h,f,c,d=1,i=parseInt;if(j===Ext.draw.Color.NONE){this.r=this.g=this.b=this.a=0;return this}if((j.length===4||j.length===7)&&j.substr(0,1)==="#"){e=j.match(Ext.draw.Color.hexRe);if(e){h=i(e[1],16)>>0;f=i(e[2],16)>>0;c=i(e[3],16)>>0;if(j.length===4){h+=(h*16);f+=(f*16);c+=(c*16)}}}else{if((e=j.match(Ext.draw.Color.rgbToHexRe))){h=+e[1];f=+e[2];c=+e[3]}else{if((e=j.match(Ext.draw.Color.rgbaToHexRe))){h=+e[1];f=+e[2];c=+e[3];d=+e[4]}else{if(Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())){return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])}}}}if(typeof h==="undefined"){return this}this.r=h;this.g=f;this.b=c;this.a=d;return this}},function(){var a=new this();this.addStatics({fly:function(f,e,c,d){switch(arguments.length){case 1:a.setFromString(f);break;case 3:case 4:a.setRGB(f,e,c,d);break;default:return null}return a},ColorList:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},fromHSL:function(d,c,b){return(new this(0,0,0,0)).setHSL(d,c,b)},fromHSV:function(d,c,b){return(new this(0,0,0,0)).setHSL(d,c,b)},fromString:function(b){return(new this(0,0,0,0)).setFromString(b)},create:function(b){if(b instanceof this){return b}else{if(Ext.isArray(b)){return new Ext.draw.Color(b[0],b[1],b[2],b[3])}else{if(Ext.isString(b)){return Ext.draw.Color.fromString(b)}else{if(arguments.length>2){return new Ext.draw.Color(arguments[0],arguments[1],arguments[2],arguments[3])}else{return new Ext.draw.Color(0,0,0,0)}}}}}})});Ext.define("Ext.draw.sprite.AnimationParser",function(){function a(d,c,b){return d+(c-d)*b}return{singleton:true,attributeRe:/^url\(#([a-zA-Z\-]+)\)$/,requires:["Ext.draw.Color"],color:{parseInitial:function(c,b){if(Ext.isString(c)){c=Ext.draw.Color.create(c)}if(Ext.isString(b)){b=Ext.draw.Color.create(b)}if((c instanceof Ext.draw.Color)&&(b instanceof Ext.draw.Color)){return[[c.r,c.g,c.b,c.a],[b.r,b.g,b.b,b.a]]}else{return[c||b,b||c]}},compute:function(d,c,b){if(!Ext.isArray(d)||!Ext.isArray(c)){return c||d}else{return[a(d[0],c[0],b),a(d[1],c[1],b),a(d[2],c[2],b),a(d[3],c[3],b)]}},serve:function(c){var b=Ext.draw.Color.fly(c[0],c[1],c[2],c[3]);return b.toString()}},number:{parse:function(b){return b===null?null:+b},compute:function(d,c,b){if(!Ext.isNumber(d)||!Ext.isNumber(c)){return c||d}else{return a(d,c,b)}}},angle:{parseInitial:function(c,b){if(b-c>Math.PI){b-=Math.PI*2}else{if(b-c<-Math.PI){b+=Math.PI*2}}return[c,b]},compute:function(d,c,b){if(!Ext.isNumber(d)||!Ext.isNumber(c)){return c||d}else{return a(d,c,b)}}},path:{parseInitial:function(m,n){var c=m.toStripes(),o=n.toStripes(),e,d,k=c.length,p=o.length,h,f,b,g=o[p-1],l=[g[g.length-2],g[g.length-1]];for(e=k;e<p;e++){c.push(c[k-1].slice(0))}for(e=p;e<k;e++){o.push(l.slice(0))}b=c.length;o.path=n;o.temp=new Ext.draw.Path();for(e=0;e<b;e++){h=c[e];f=o[e];k=h.length;p=f.length;o.temp.commands.push("M");for(d=p;d<k;d+=6){f.push(l[0],l[1],l[0],l[1],l[0],l[1])}g=o[o.length-1];l=[g[g.length-2],g[g.length-1]];for(d=k;d<p;d+=6){h.push(l[0],l[1],l[0],l[1],l[0],l[1])}for(e=0;e<f.length;e++){f[e]-=h[e]}for(e=2;e<f.length;e+=6){o.temp.commands.push("C")}}return[c,o]},compute:function(c,l,m){if(m>=1){return l.path}var e=0,f=c.length,d=0,b,k,h,n=l.temp.params,g=0;for(;e<f;e++){k=c[e];h=l[e];b=k.length;for(d=0;d<b;d++){n[g++]=h[d]*m+k[d]}}return l.temp}},data:{compute:function(h,j,k,g){var m=h.length-1,b=j.length-1,e=Math.max(m,b),d,l,c;if(!g||g===h){g=[]}g.length=e+1;for(c=0;c<=e;c++){d=h[Math.min(c,m)];l=j[Math.min(c,b)];if(Ext.isNumber(d)){if(!Ext.isNumber(l)){l=0}g[c]=(l-d)*k+d}else{g[c]=l}}return g}},text:{compute:function(d,c,b){return d.substr(0,Math.round(d.length*(1-b)))+c.substr(Math.round(c.length*(1-b)))}},limited:"number",limited01:"number"}});(function(){if(!Ext.global.Float32Array){var a=function(d){if(typeof d==="number"){this.length=d}else{if("length" in d){this.length=d.length;for(var c=0,b=d.length;c<b;c++){this[c]=+d[c]}}}};a.prototype=[];Ext.global.Float32Array=a}})();Ext.define("Ext.draw.Draw",{singleton:true,radian:Math.PI/180,pi2:Math.PI*2,reflectFn:function(b){return b},rad:function(a){return(a%360)*this.radian},degrees:function(a){return(a/this.radian)%360},isBBoxIntersect:function(b,a,c){c=c||0;return(Math.max(b.x,a.x)-c>Math.min(b.x+b.width,a.x+a.width))||(Math.max(b.y,a.y)-c>Math.min(b.y+b.height,a.y+a.height))},isPointInBBox:function(a,c,b){return !!b&&a>=b.x&&a<=(b.x+b.width)&&c>=b.y&&c<=(b.y+b.height)},spline:function(m){var e,c,k=m.length,b,h,l,f,a=0,g=new Float32Array(m.length),n=new Float32Array(m.length*3-2);g[0]=0;g[k-1]=0;for(e=1;e<k-1;e++){g[e]=(m[e+1]+m[e-1]-2*m[e])-g[e-1];a=1/(4-a);g[e]*=a}for(e=k-2;e>0;e--){a=3.732050807568877+48.248711305964385/(-13.928203230275537+Math.pow(0.07179676972449123,e));g[e]-=g[e+1]*a}f=m[0];b=f-g[0];for(e=0,c=0;e<k-1;c+=3){l=f;h=b;e++;f=m[e];b=f-g[e];n[c]=l;n[c+1]=(b+2*h)/3;n[c+2]=(b*2+h)/3}n[c]=f;return n},getAnchors:function(e,d,i,h,t,s,o){o=o||4;var n=Math.PI,p=n/2,k=Math.abs,a=Math.sin,b=Math.cos,f=Math.atan,r,q,g,j,m,l,v,u,c;r=(i-e)/o;q=(t-i)/o;if((h>=d&&h>=s)||(h<=d&&h<=s)){g=j=p}else{g=f((i-e)/k(h-d));if(d<h){g=n-g}j=f((t-i)/k(h-s));if(s<h){j=n-j}}c=p-((g+j)%(n*2))/2;if(c>p){c-=n}g+=c;j+=c;m=i-r*a(g);l=h+r*b(g);v=i+q*a(j);u=h+q*b(j);if((h>d&&l<d)||(h<d&&l>d)){m+=k(d-l)*(m-i)/(l-h);l=d}if((h>s&&u<s)||(h<s&&u>s)){v-=k(s-u)*(v-i)/(u-h);u=s}return{x1:m,y1:l,x2:v,y2:u}},smooth:function(l,j,o){var k=l.length,h,g,c,b,q,p,n,m,f=[],e=[],d,a;for(d=0;d<k-1;d++){h=l[d];g=j[d];if(d===0){n=h;m=g;f.push(n);e.push(m);if(k===1){break}}c=l[d+1];b=j[d+1];q=l[d+2];p=j[d+2];if(!Ext.isNumber(q+p)){f.push(n,c,c);e.push(m,b,b);break}a=this.getAnchors(h,g,c,b,q,p,o);f.push(n,a.x1,c);e.push(m,a.y1,b);n=a.x2;m=a.y2}return{smoothX:f,smoothY:e}},beginUpdateIOS:Ext.os.is.iOS?function(){this.iosUpdateEl=Ext.getBody().createChild({style:"position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"})}:Ext.emptyFn,endUpdateIOS:function(){this.iosUpdateEl=Ext.destroy(this.iosUpdateEl)}});Ext.define("Ext.draw.gradient.Gradient",{requires:["Ext.draw.Color"],isGradient:true,config:{stops:[]},applyStops:function(f){var e=[],d=f.length,c,b,a;for(c=0;c<d;c++){b=f[c];a=b.color;if(!(a&&a.isColor)){a=Ext.draw.Color.fly(a||Ext.draw.Color.NONE)}e.push({offset:Math.min(1,Math.max(0,"offset" in b?b.offset:b.position||0)),color:a.toString()})}e.sort(function(h,g){return h.offset-g.offset});return e},onClassExtended:function(a,b){if(!b.alias&&b.type){b.alias="gradient."+b.type}},constructor:function(a){this.initConfig(a)},generateGradient:Ext.emptyFn});Ext.define("Ext.draw.gradient.GradientDefinition",{singleton:true,urlStringRe:/^url\(#([\w\-]+)\)$/,gradients:{},add:function(a){var b=this.gradients,c,e,d;for(c=0,e=a.length;c<e;c++){d=a[c];if(Ext.isString(d.id)){b[d.id]=d}}},get:function(d){var a=this.gradients,b=d.match(this.urlStringRe),c;if(b&&b[1]&&(c=a[b[1]])){return c||d}return d}});Ext.define("Ext.draw.sprite.AttributeParser",{singleton:true,attributeRe:/^url\(#([a-zA-Z\-]+)\)$/,requires:["Ext.draw.Color","Ext.draw.gradient.GradientDefinition"],"default":Ext.identityFn,string:function(a){return String(a)},number:function(a){if(Ext.isNumber(+a)){return a}},angle:function(a){if(Ext.isNumber(a)){a%=Math.PI*2;if(a<-Math.PI){a+=Math.PI*2}else{if(a>=Math.PI){a-=Math.PI*2}}return a}},data:function(a){if(Ext.isArray(a)){return a.slice()}else{if(a instanceof Float32Array){return new Float32Array(a)}}},bool:function(a){return !!a},color:function(a){if(a instanceof Ext.draw.Color){return a.toString()}else{if(a instanceof Ext.draw.gradient.Gradient){return a}else{if(!a){return Ext.draw.Color.NONE}else{if(Ext.isString(a)){if(a.substr(0,3)==="url"){a=Ext.draw.gradient.GradientDefinition.get(a);if(Ext.isString(a)){return a}}else{return Ext.draw.Color.fly(a).toString()}}}}}if(a.type==="linear"){return Ext.create("Ext.draw.gradient.Linear",a)}else{if(a.type==="radial"){return Ext.create("Ext.draw.gradient.Radial",a)}else{if(a.type==="pattern"){return Ext.create("Ext.draw.gradient.Pattern",a)}else{return Ext.draw.Color.NONE}}}},limited:function(a,b){return function(c){c=+c;return Ext.isNumber(c)?Math.min(Math.max(c,a),b):undefined}},limited01:function(a){a=+a;return Ext.isNumber(a)?Math.min(Math.max(a,0),1):undefined},enums:function(){var d={},a=Array.prototype.slice.call(arguments,0),b,c;for(b=0,c=a.length;b<c;b++){d[a[b]]=true}return function(e){return e in d?e:undefined}}});Ext.define("Ext.draw.sprite.AttributeDefinition",{requires:["Ext.draw.sprite.AttributeParser","Ext.draw.sprite.AnimationParser"],config:{defaults:{$value:{},lazy:true},aliases:{},animationProcessors:{},processors:{$value:{},lazy:true},dirtyTriggers:{},triggers:{},updaters:{}},inheritableStatics:{processorFactoryRe:/^(\w+)\(([\w\-,]*)\)$/},spriteClass:null,constructor:function(a){var b=this;b.initConfig(a)},applyDefaults:function(b,a){a=Ext.apply(a||{},this.normalize(b));return a},applyAliases:function(b,a){return Ext.apply(a||{},b)},applyProcessors:function(e,i){this.getAnimationProcessors();var j=i||{},h=Ext.draw.sprite.AttributeParser,a=this.self.processorFactoryRe,g={},d,b,c,f;for(b in e){f=e[b];if(typeof f==="string"){c=f.match(a);if(c){f=h[c[1]].apply(h,c[2].split(","))}else{if(h[f]){g[b]=f;d=true;f=h[f]}}}j[b]=f}if(d){this.setAnimationProcessors(g)}return j},applyAnimationProcessors:function(c,a){var e=Ext.draw.sprite.AnimationParser,b,d;if(!a){a={}}for(b in c){d=c[b];if(d==="none"){a[b]=null}else{if(Ext.isString(d)&&!(b in a)){if(d in e){while(Ext.isString(e[d])){d=e[d]}a[b]=e[d]}}else{if(Ext.isObject(d)){a[b]=d}}}}return a},updateDirtyTriggers:function(a){this.setTriggers(a)},applyTriggers:function(b,c){if(!c){c={}}for(var a in b){c[a]=b[a].split(",")}return c},applyUpdaters:function(b,a){return Ext.apply(a||{},b)},batchedNormalize:function(f,n){if(!f){return{}}var j=this.getProcessors(),d=this.getAliases(),a=f.translation||f.translate,o={},g,h,b,e,p,c,m,l,k;if("rotation" in f){p=f.rotation}else{p=("rotate" in f)?f.rotate:undefined}if("scaling" in f){c=f.scaling}else{c=("scale" in f)?f.scale:undefined}if(typeof c!=="undefined"){if(Ext.isNumber(c)){o.scalingX=c;o.scalingY=c}else{if("x" in c){o.scalingX=c.x}if("y" in c){o.scalingY=c.y}if("centerX" in c){o.scalingCenterX=c.centerX}if("centerY" in c){o.scalingCenterY=c.centerY}}}if(typeof p!=="undefined"){if(Ext.isNumber(p)){p=Ext.draw.Draw.rad(p);o.rotationRads=p}else{if("rads" in p){o.rotationRads=p.rads}else{if("degrees" in p){if(Ext.isArray(p.degrees)){o.rotationRads=Ext.Array.map(p.degrees,function(i){return Ext.draw.Draw.rad(i)})}else{o.rotationRads=Ext.draw.Draw.rad(p.degrees)}}}if("centerX" in p){o.rotationCenterX=p.centerX}if("centerY" in p){o.rotationCenterY=p.centerY}}}if(typeof a!=="undefined"){if("x" in a){o.translationX=a.x}if("y" in a){o.translationY=a.y}}if("matrix" in f){m=Ext.draw.Matrix.create(f.matrix);k=m.split();o.matrix=m;o.rotationRads=k.rotation;o.rotationCenterX=0;o.rotationCenterY=0;o.scalingX=k.scaleX;o.scalingY=k.scaleY;o.scalingCenterX=0;o.scalingCenterY=0;o.translationX=k.translateX;o.translationY=k.translateY}for(b in f){e=f[b];if(typeof e==="undefined"){continue}else{if(Ext.isArray(e)){if(b in d){b=d[b]}if(b in j){o[b]=[];for(g=0,h=e.length;g<h;g++){l=j[b].call(this,e[g]);if(typeof l!=="undefined"){o[b][g]=l}}}else{if(n){o[b]=e}}}else{if(b in d){b=d[b]}if(b in j){e=j[b].call(this,e);if(typeof e!=="undefined"){o[b]=e}}else{if(n){o[b]=e}}}}}return o},normalize:function(i,j){if(!i){return{}}var f=this.getProcessors(),d=this.getAliases(),a=i.translation||i.translate,k={},b,e,l,c,h,g;if("rotation" in i){l=i.rotation}else{l=("rotate" in i)?i.rotate:undefined}if("scaling" in i){c=i.scaling}else{c=("scale" in i)?i.scale:undefined}if(a){if("x" in a){k.translationX=a.x}if("y" in a){k.translationY=a.y}}if(typeof c!=="undefined"){if(Ext.isNumber(c)){k.scalingX=c;k.scalingY=c}else{if("x" in c){k.scalingX=c.x}if("y" in c){k.scalingY=c.y}if("centerX" in c){k.scalingCenterX=c.centerX}if("centerY" in c){k.scalingCenterY=c.centerY}}}if(typeof l!=="undefined"){if(Ext.isNumber(l)){l=Ext.draw.Draw.rad(l);k.rotationRads=l}else{if("rads" in l){k.rotationRads=l.rads}else{if("degrees" in l){k.rotationRads=Ext.draw.Draw.rad(l.degrees)}}if("centerX" in l){k.rotationCenterX=l.centerX}if("centerY" in l){k.rotationCenterY=l.centerY}}}if("matrix" in i){h=Ext.draw.Matrix.create(i.matrix);g=h.split();k.matrix=h;k.rotationRads=g.rotation;k.rotationCenterX=0;k.rotationCenterY=0;k.scalingX=g.scaleX;k.scalingY=g.scaleY;k.scalingCenterX=0;k.scalingCenterY=0;k.translationX=g.translateX;k.translationY=g.translateY}for(b in i){e=i[b];if(typeof e==="undefined"){continue}if(b in d){b=d[b]}if(b in f){e=f[b].call(this,e);if(typeof e!=="undefined"){k[b]=e}}else{if(j){k[b]=e}}}return k},setBypassingNormalization:function(a,c,b){return c.pushDown(a,b)},set:function(a,c,b){b=this.normalize(b);return this.setBypassingNormalization(a,c,b)}});Ext.define("Ext.draw.Matrix",{isMatrix:true,statics:{createAffineMatrixFromTwoPair:function(h,t,g,s,k,o,i,j){var v=g-h,u=s-t,e=i-k,q=j-o,d=1/(v*v+u*u),p=v*e+u*q,n=e*u-v*q,m=-p*h-n*t,l=n*h-p*t;return new this(p*d,-n*d,n*d,p*d,m*d+k,l*d+o)},createPanZoomFromTwoPair:function(q,e,p,c,h,s,n,g){if(arguments.length===2){return this.createPanZoomFromTwoPair.apply(this,q.concat(e))}var k=p-q,j=c-e,d=(q+p)*0.5,b=(e+c)*0.5,o=n-h,a=g-s,f=(h+n)*0.5,l=(s+g)*0.5,m=k*k+j*j,i=o*o+a*a,t=Math.sqrt(i/m);return new this(t,0,0,t,f-t*d,l-t*b)},fly:(function(){var a=null,b=function(c){a.elements=c;return a};return function(c){if(!a){a=new Ext.draw.Matrix()}a.elements=c;Ext.draw.Matrix.fly=b;return a}})(),create:function(a){if(a instanceof this){return a}return new this(a)}},constructor:function(e,d,a,f,c,b){if(e&&e.length===6){this.elements=e.slice()}else{if(e!==undefined){this.elements=[e,d,a,f,c,b]}else{this.elements=[1,0,0,1,0,0]}}},prepend:function(a,l,h,g,m,k){var b=this.elements,d=b[0],j=b[1],e=b[2],c=b[3],i=b[4],f=b[5];b[0]=a*d+h*j;b[1]=l*d+g*j;b[2]=a*e+h*c;b[3]=l*e+g*c;b[4]=a*i+h*f+m;b[5]=l*i+g*f+k;return this},prependMatrix:function(a){return this.prepend.apply(this,a.elements)},append:function(a,l,h,g,m,k){var b=this.elements,d=b[0],j=b[1],e=b[2],c=b[3],i=b[4],f=b[5];b[0]=a*d+l*e;b[1]=a*j+l*c;b[2]=h*d+g*e;b[3]=h*j+g*c;b[4]=m*d+k*e+i;b[5]=m*j+k*c+f;return this},appendMatrix:function(a){return this.append.apply(this,a.elements)},set:function(f,e,a,g,c,b){var d=this.elements;d[0]=f;d[1]=e;d[2]=a;d[3]=g;d[4]=c;d[5]=b;return this},inverse:function(i){var g=this.elements,o=g[0],m=g[1],l=g[2],k=g[3],j=g[4],h=g[5],n=1/(o*k-m*l);o*=n;m*=n;l*=n;k*=n;if(i){i.set(k,-m,-l,o,l*h-k*j,m*j-o*h);return i}else{return new Ext.draw.Matrix(k,-m,-l,o,l*h-k*j,m*j-o*h)}},translate:function(a,c,b){if(b){return this.prepend(1,0,0,1,a,c)}else{return this.append(1,0,0,1,a,c)}},scale:function(f,e,c,a,b){var d=this;if(e==null){e=f}if(c===undefined){c=0}if(a===undefined){a=0}if(b){return d.prepend(f,0,0,e,c-c*f,a-a*e)}else{return d.append(f,0,0,e,c-c*f,a-a*e)}},rotate:function(g,e,c,b){var d=this,f=Math.cos(g),a=Math.sin(g);e=e||0;c=c||0;if(b){return d.prepend(f,a,-a,f,e-f*e+c*a,c-f*c-e*a)}else{return d.append(f,a,-a,f,e-f*e+c*a,c-f*c-e*a)}},rotateFromVector:function(a,h,c){var e=this,g=Math.sqrt(a*a+h*h),f=a/g,b=h/g;if(c){return e.prepend(f,b,-b,f,0,0)}else{return e.append(f,b,-b,f,0,0)}},clone:function(){return new Ext.draw.Matrix(this.elements)},flipX:function(){return this.append(-1,0,0,1,0,0)},flipY:function(){return this.append(1,0,0,-1,0,0)},skewX:function(a){return this.append(1,0,Math.tan(a),1,0,0)},skewY:function(a){return this.append(1,Math.tan(a),0,1,0,0)},shearX:function(a){return this.append(1,0,a,1,0,0)},shearY:function(a){return this.append(1,a,0,1,0,0)},reset:function(){return this.set(1,0,0,1,0,0)},precisionCompensate:function(j,g){var c=this.elements,f=c[0],e=c[1],i=c[2],h=c[3],d=c[4],b=c[5],a=e*i-f*h;g.b=j*e/f;g.c=j*i/h;g.d=j;g.xx=f/j;g.yy=h/j;g.dx=(b*f*i-d*f*h)/a/j;g.dy=(d*e*h-b*f*h)/a/j},precisionCompensateRect:function(j,g){var b=this.elements,f=b[0],e=b[1],i=b[2],h=b[3],c=b[4],a=b[5],d=i/f;g.b=j*e/f;g.c=j*d;g.d=j*h/f;g.xx=f/j;g.yy=f/j;g.dx=(a*i-c*h)/(e*d-h)/j;g.dy=-(a*f-c*e)/(e*d-h)/j},x:function(a,c){var b=this.elements;return a*b[0]+c*b[2]+b[4]},y:function(a,c){var b=this.elements;return a*b[1]+c*b[3]+b[5]},get:function(b,a){return +this.elements[b+a*2].toFixed(4)},transformPoint:function(b){var c=this.elements,a,d;if(b.isPoint){a=b.x;d=b.y}else{a=b[0];d=b[1]}return[a*c[0]+d*c[2]+c[4],a*c[1]+d*c[3]+c[5]]},transformBBox:function(q,i,j){var b=this.elements,d=q.x,r=q.y,g=q.width*0.5,o=q.height*0.5,a=b[0],s=b[1],n=b[2],k=b[3],e=d+g,c=r+o,p,f,m;if(i){g-=i;o-=i;m=[Math.sqrt(b[0]*b[0]+b[2]*b[2]),Math.sqrt(b[1]*b[1]+b[3]*b[3])];p=Math.abs(g*a)+Math.abs(o*n)+Math.abs(m[0]*i);f=Math.abs(g*s)+Math.abs(o*k)+Math.abs(m[1]*i)}else{p=Math.abs(g*a)+Math.abs(o*n);f=Math.abs(g*s)+Math.abs(o*k)}if(!j){j={}}j.x=e*a+c*n+b[4]-p;j.y=e*s+c*k+b[5]-f;j.width=p+p;j.height=f+f;return j},transformList:function(e){var b=this.elements,a=b[0],h=b[2],l=b[4],k=b[1],g=b[3],j=b[5],f=e.length,c,d;for(d=0;d<f;d++){c=e[d];e[d]=[c[0]*a+c[1]*h+l,c[0]*k+c[1]*g+j]}return e},isIdentity:function(){var a=this.elements;return a[0]===1&&a[1]===0&&a[2]===0&&a[3]===1&&a[4]===0&&a[5]===0},isEqual:function(a){var c=a&&a.isMatrix?a.elements:a,b=this.elements;return b[0]===c[0]&&b[1]===c[1]&&b[2]===c[2]&&b[3]===c[3]&&b[4]===c[4]&&b[5]===c[5]},equals:function(a){return this.isEqual(a)},toArray:function(){var a=this.elements;return[a[0],a[2],a[4],a[1],a[3],a[5]]},toVerticalArray:function(){return this.elements.slice()},toString:function(){var a=this;return[a.get(0,0),a.get(0,1),a.get(1,0),a.get(1,1),a.get(2,0),a.get(2,1)].join(",")},toContext:function(a){a.transform.apply(a,this.elements);return this},toSvg:function(){var a=this.elements;return"matrix("+a[0].toFixed(9)+","+a[1].toFixed(9)+","+a[2].toFixed(9)+","+a[3].toFixed(9)+","+a[4].toFixed(9)+","+a[5].toFixed(9)+")"},getScaleX:function(){var a=this.elements;return Math.sqrt(a[0]*a[0]+a[2]*a[2])},getScaleY:function(){var a=this.elements;return Math.sqrt(a[1]*a[1]+a[3]*a[3])},getXX:function(){return this.elements[0]},getXY:function(){return this.elements[1]},getYX:function(){return this.elements[2]},getYY:function(){return this.elements[3]},getDX:function(){return this.elements[4]},getDY:function(){return this.elements[5]},split:function(){var b=this.elements,d=b[0],c=b[1],e=b[3],a={translateX:b[4],translateY:b[5]};a.rotate=a.rotation=Math.atan2(c,d);a.scaleX=d/Math.cos(a.rotate);a.scaleY=e/d*a.scaleX;return a}},function(){function b(e,c,d){e[c]={get:function(){return this.elements[d]},set:function(f){this.elements[d]=f}}}if(Object.defineProperties){var a={};b(a,"a",0);b(a,"b",1);b(a,"c",2);b(a,"d",3);b(a,"e",4);b(a,"f",5);Object.defineProperties(this.prototype,a)}this.prototype.multiply=this.prototype.appendMatrix});Ext.define("Ext.draw.modifier.Modifier",{mixins:{observable:"Ext.mixin.Observable"},config:{previous:null,next:null,sprite:null},constructor:function(a){this.mixins.observable.constructor.call(this,a)},updateNext:function(a){if(a){a.setPrevious(this)}},updatePrevious:function(a){if(a){a.setNext(this)}},prepareAttributes:function(a){if(this._previous){this._previous.prepareAttributes(a)}},popUp:function(a,b){if(this._next){this._next.popUp(a,b)}else{Ext.apply(a,b)}},pushDown:function(a,c){if(this._previous){return this._previous.pushDown(a,c)}else{for(var b in c){if(c[b]===a[b]){delete c[b]}}return c}}});Ext.define("Ext.draw.modifier.Target",{requires:["Ext.draw.Matrix"],extend:"Ext.draw.modifier.Modifier",alias:"modifier.target",statics:{uniqueId:0},prepareAttributes:function(a){var b=this.getPrevious();if(b){b.prepareAttributes(a)}a.attributeId="attribute-"+Ext.draw.modifier.Target.uniqueId++;if(!a.hasOwnProperty("canvasAttributes")){a.bbox={plain:{dirty:true},transform:{dirty:true}};a.dirty=true;a.pendingUpdaters={};a.canvasAttributes={};a.matrix=new Ext.draw.Matrix();a.inverseMatrix=new Ext.draw.Matrix()}},applyChanges:function(f,k){Ext.apply(f,k);var l=this.getSprite(),o=f.pendingUpdaters,h=l.self.def.getTriggers(),p,a,m,b,e,n,d,c,g;for(b in k){e=true;if((p=h[b])){l.scheduleUpdaters(f,p,[b])}if(f.template&&k.removeFromInstance&&k.removeFromInstance[b]){delete f[b]}}if(!e){return}if(o.canvas){n=o.canvas;delete o.canvas;for(d=0,g=n.length;d<g;d++){b=n[d];f.canvasAttributes[b]=f[b]}}if(f.hasOwnProperty("children")){a=f.children;for(d=0,g=a.length;d<g;d++){m=a[d];Ext.apply(m.pendingUpdaters,o);if(n){for(c=0;c<n.length;c++){b=n[c];m.canvasAttributes[b]=m[b]}}l.callUpdaters(m)}}l.setDirty(true);l.callUpdaters(f)},popUp:function(a,b){this.applyChanges(a,b)},pushDown:function(a,b){var c=this.getPrevious();if(c){b=c.pushDown(a,b)}this.applyChanges(a,b);return b}});Ext.define("Ext.draw.TimingFunctions",function(){var g=Math.pow,j=Math.sin,m=Math.cos,l=Math.sqrt,e=Math.PI,b=["quad","cube","quart","quint"],c={pow:function(o,i){return g(o,i||6)},expo:function(i){return g(2,8*(i-1))},circ:function(i){return 1-l(1-i*i)},sine:function(i){return 1-j((1-i)*e/2)},back:function(i,o){o=o||1.616;return i*i*((o+1)*i-o)},bounce:function(q){for(var o=0,i=1;1;o+=i,i/=2){if(q>=(7-4*o)/11){return i*i-g((11-6*o-11*q)/4,2)}}},elastic:function(o,i){return g(2,10*--o)*m(20*o*e*(i||1)/3)}},k={},a,f,d;function h(i){return function(o){return g(o,i)}}function n(i,o){k[i+"In"]=function(p){return o(p)};k[i+"Out"]=function(p){return 1-o(1-p)};k[i+"InOut"]=function(p){return(p<=0.5)?o(2*p)/2:(2-o(2*(1-p)))/2}}for(d=0,f=b.length;d<f;++d){c[b[d]]=h(d+2)}for(a in c){n(a,c[a])}k.linear=Ext.identityFn;k.easeIn=k.quadIn;k.easeOut=k.quadOut;k.easeInOut=k.quadInOut;return{singleton:true,easingMap:k}},function(a){Ext.apply(a,a.easingMap)});Ext.define("Ext.draw.Animator",{uses:["Ext.draw.Draw"],singleton:true,frameCallbacks:{},frameCallbackId:0,scheduled:0,frameStartTimeOffset:Ext.now(),animations:[],running:false,animationTime:function(){return Ext.AnimationQueue.frameStartTime-this.frameStartTimeOffset},add:function(b){var a=this;if(!a.contains(b)){a.animations.push(b);a.ignite();if("fireEvent" in b){b.fireEvent("animationstart",b)}}},remove:function(d){var c=this,e=c.animations,b=0,a=e.length;for(;b<a;++b){if(e[b]===d){e.splice(b,1);if("fireEvent" in d){d.fireEvent("animationend",d)}return}}},contains:function(a){return Ext.Array.indexOf(this.animations,a)>-1},empty:function(){return this.animations.length===0},step:function(d){var c=this,f=c.animations,e,a=0,b=f.length;for(;a<b;a++){e=f[a];e.step(d);if(!e.animating){f.splice(a,1);a--;b--;if(e.fireEvent){e.fireEvent("animationend",e)}}}},schedule:function(c,a){a=a||this;var b="frameCallback"+(this.frameCallbackId++);if(Ext.isString(c)){c=a[c]}Ext.draw.Animator.frameCallbacks[b]={fn:c,scope:a,once:true};this.scheduled++;Ext.draw.Animator.ignite();return b},scheduleIf:function(e,b){b=b||this;var c=Ext.draw.Animator.frameCallbacks,a,d;if(Ext.isString(e)){e=b[e]}for(d in c){a=c[d];if(a.once&&a.fn===e&&a.scope===b){return null}}return this.schedule(e,b)},cancel:function(a){if(Ext.draw.Animator.frameCallbacks[a]&&Ext.draw.Animator.frameCallbacks[a].once){this.scheduled--;delete Ext.draw.Animator.frameCallbacks[a]}},addFrameCallback:function(c,a){a=a||this;if(Ext.isString(c)){c=a[c]}var b="frameCallback"+(this.frameCallbackId++);Ext.draw.Animator.frameCallbacks[b]={fn:c,scope:a};return b},removeFrameCallback:function(a){delete Ext.draw.Animator.frameCallbacks[a]},fireFrameCallbacks:function(){var c=this.frameCallbacks,d,b,a;for(d in c){a=c[d];b=a.fn;if(Ext.isString(b)){b=a.scope[b]}b.call(a.scope);if(c[d]&&a.once){this.scheduled--;delete c[d]}}},handleFrame:function(){this.step(this.animationTime());this.fireFrameCallbacks();if(!this.scheduled&&this.empty()){Ext.AnimationQueue.stop(this.handleFrame,this);this.running=false;Ext.draw.Draw.endUpdateIOS()}},ignite:function(){if(!this.running){this.running=true;Ext.AnimationQueue.start(this.handleFrame,this);Ext.draw.Draw.beginUpdateIOS()}}});Ext.define("Ext.draw.modifier.Animation",{requires:["Ext.draw.TimingFunctions","Ext.draw.Animator"],extend:"Ext.draw.modifier.Modifier",alias:"modifier.animation",config:{easing:Ext.identityFn,duration:0,customEasings:{},customDurations:{},customDuration:null},constructor:function(a){var b=this;b.anyAnimation=b.anySpecialAnimations=false;b.animating=0;b.animatingPool=[];b.callParent([a])},prepareAttributes:function(a){if(!a.hasOwnProperty("timers")){a.animating=false;a.timers={};a.animationOriginal=Ext.Object.chain(a);a.animationOriginal.prototype=a}if(this._previous){this._previous.prepareAttributes(a.animationOriginal)}},updateSprite:function(a){this.setConfig(a.config.fx)},updateDuration:function(a){this.anyAnimation=a>0},applyEasing:function(a){if(typeof a==="string"){a=Ext.draw.TimingFunctions.easingMap[a]}return a},applyCustomEasings:function(a,e){e=e||{};var g,d,b,h,c,f;for(d in a){g=true;h=a[d];b=d.split(",");if(typeof h==="string"){h=Ext.draw.TimingFunctions.easingMap[h]}for(c=0,f=b.length;c<f;c++){e[b[c]]=h}}if(g){this.anySpecialAnimations=g}return e},setEasingOn:function(a,e){a=Ext.Array.from(a).slice();var c={},d=a.length,b=0;for(;b<d;b++){c[a[b]]=e}this.setCustomEasings(c)},clearEasingOn:function(a){a=Ext.Array.from(a,true);var b=0,c=a.length;for(;b<c;b++){delete this._customEasings[a[b]]}},applyCustomDurations:function(g,h){h=h||{};var e,c,f,a,b,d;for(c in g){e=true;f=g[c];a=c.split(",");for(b=0,d=a.length;b<d;b++){h[a[b]]=f}}if(e){this.anySpecialAnimations=e}return h},applyCustomDuration:function(a,b){if(a){this.getCustomDurations();this.setCustomDurations(a)}},setDurationOn:function(b,e){b=Ext.Array.from(b).slice();var a={},c=0,d=b.length;for(;c<d;c++){a[b[c]]=e}this.setCustomDurations(a)},clearDurationOn:function(a){a=Ext.Array.from(a,true);var b=0,c=a.length;for(;b<c;b++){delete this._customDurations[a[b]]}},setAnimating:function(a,b){var e=this,d=e.animatingPool;if(a.animating!==b){a.animating=b;if(b){d.push(a);if(e.animating===0){Ext.draw.Animator.add(e)}e.animating++}else{for(var c=d.length;c--;){if(d[c]===a){d.splice(c,1)}}e.animating=d.length}}},setAttrs:function(r,t){var s=this,m=r.timers,h=s._sprite.self.def._animationProcessors,f=s._easing,e=s._duration,j=s._customDurations,i=s._customEasings,g=s.anySpecialAnimations,n=s.anyAnimation||g,o=r.animationOriginal,d=false,k,u,l,p,c,q,a;if(!n){for(u in t){if(r[u]===t[u]){delete t[u]}else{r[u]=t[u]}delete o[u];delete m[u]}return t}else{for(u in t){l=t[u];p=r[u];if(l!==p&&p!==undefined&&p!==null&&(c=h[u])){q=f;a=e;if(g){if(u in i){q=i[u]}if(u in j){a=j[u]}}if(p&&p.isGradient||l&&l.isGradient){a=0}if(a){if(!m[u]){m[u]={}}k=m[u];k.start=0;k.easing=q;k.duration=a;k.compute=c.compute;k.serve=c.serve||Ext.identityFn;k.remove=t.removeFromInstance&&t.removeFromInstance[u];if(c.parseInitial){var b=c.parseInitial(p,l);k.source=b[0];k.target=b[1]}else{if(c.parse){k.source=c.parse(p);k.target=c.parse(l)}else{k.source=p;k.target=l}}o[u]=l;delete t[u];d=true;continue}else{delete o[u]}}else{delete o[u]}delete m[u]}}if(d&&!r.animating){s.setAnimating(r,true)}return t},updateAttributes:function(g){if(!g.animating){return{}}var h={},e=false,d=g.timers,f=g.animationOriginal,c=Ext.draw.Animator.animationTime(),a,b,i;if(g.lastUpdate===c){return null}for(a in d){b=d[a];if(!b.start){b.start=c;i=0}else{i=(c-b.start)/b.duration}if(i>=1){h[a]=f[a];delete f[a];if(d[a].remove){h.removeFromInstance=h.removeFromInstance||{};h.removeFromInstance[a]=true}delete d[a]}else{h[a]=b.serve(b.compute(b.source,b.target,b.easing(i),g[a]));e=true}}g.lastUpdate=c;this.setAnimating(g,e);return h},pushDown:function(a,b){b=this.callParent([a.animationOriginal,b]);return this.setAttrs(a,b)},popUp:function(a,b){a=a.prototype;b=this.setAttrs(a,b);if(this._next){return this._next.popUp(a,b)}else{return Ext.apply(a,b)}},step:function(g){var f=this,c=f.animatingPool.slice(),e=c.length,b=0,a,d;for(;b<e;b++){a=c[b];d=f.updateAttributes(a);if(d&&f._next){f._next.popUp(a,d)}}},stop:function(){this.step();var d=this,b=d.animatingPool,a,c;for(a=0,c=b.length;a<c;a++){b[a].animating=false}d.animatingPool.length=0;d.animating=0;Ext.draw.Animator.remove(d)},destroy:function(){this.animatingPool.length=0;this.animating=0;this.callParent()}});Ext.define("Ext.draw.modifier.Highlight",{extend:"Ext.draw.modifier.Modifier",alias:"modifier.highlight",config:{enabled:false,highlightStyle:null},preFx:true,applyHighlightStyle:function(b,a){a=a||{};if(this.getSprite()){Ext.apply(a,this.getSprite().self.def.normalize(b))}else{Ext.apply(a,b)}return a},prepareAttributes:function(a){if(!a.hasOwnProperty("highlightOriginal")){a.highlighted=false;a.highlightOriginal=Ext.Object.chain(a);a.highlightOriginal.prototype=a;a.highlightOriginal.removeFromInstance={}}if(this._previous){this._previous.prepareAttributes(a.highlightOriginal)}},updateSprite:function(b,a){if(b){if(this.getHighlightStyle()){this._highlightStyle=b.self.def.normalize(this.getHighlightStyle())}this.setHighlightStyle(b.config.highlight)}b.self.def.setConfig({defaults:{highlighted:false},processors:{highlighted:"bool"}});this.setSprite(b)},filterChanges:function(a,d){var e=this,f=a.highlightOriginal,c=e.getHighlightStyle(),b;if(a.highlighted){for(b in d){if(c.hasOwnProperty(b)){f[b]=d[b];delete d[b]}}}for(b in d){if(b!=="highlighted"&&f[b]===d[b]){delete d[b]}}return d},pushDown:function(e,g){var f=this.getHighlightStyle(),c=e.highlightOriginal,i=c.removeFromInstance,d,a,h,b;if(g.hasOwnProperty("highlighted")){d=g.highlighted;delete g.highlighted;if(this._previous){g=this._previous.pushDown(c,g)}g=this.filterChanges(e,g);if(d!==e.highlighted){if(d){for(a in f){if(a in g){c[a]=g[a]}else{h=e.template&&e.template.ownAttr;if(h&&!e.prototype.hasOwnProperty(a)){i[a]=true;c[a]=h.animationOriginal[a]}else{b=c.timers[a];if(b&&b.remove){i[a]=true}c[a]=e[a]}}if(c[a]!==f[a]){g[a]=f[a]}}}else{for(a in f){if(!(a in g)){g[a]=c[a]}delete c[a]}g.removeFromInstance=g.removeFromInstance||{};Ext.apply(g.removeFromInstance,i);c.removeFromInstance={}}g.highlighted=d}}else{if(this._previous){g=this._previous.pushDown(c,g)}g=this.filterChanges(e,g)}return g},popUp:function(a,b){b=this.filterChanges(a,b);Ext.draw.modifier.Modifier.prototype.popUp.call(this,a,b)}});Ext.define("Ext.draw.sprite.Sprite",{alias:"sprite.sprite",mixins:{observable:"Ext.mixin.Observable"},requires:["Ext.draw.Draw","Ext.draw.gradient.Gradient","Ext.draw.sprite.AttributeDefinition","Ext.draw.modifier.Target","Ext.draw.modifier.Animation","Ext.draw.modifier.Highlight"],isSprite:true,statics:{defaultHitTestOptions:{fill:true,stroke:true}},inheritableStatics:{def:{processors:{strokeStyle:"color",fillStyle:"color",strokeOpacity:"limited01",fillOpacity:"limited01",lineWidth:"number",lineCap:"enums(butt,round,square)",lineJoin:"enums(round,bevel,miter)",lineDash:"data",lineDashOffset:"number",miterLimit:"number",shadowColor:"color",shadowOffsetX:"number",shadowOffsetY:"number",shadowBlur:"number",globalAlpha:"limited01",globalCompositeOperation:"enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",hidden:"bool",transformFillStroke:"bool",zIndex:"number",translationX:"number",translationY:"number",rotationRads:"number",rotationCenterX:"number",rotationCenterY:"number",scalingX:"number",scalingY:"number",scalingCenterX:"number",scalingCenterY:"number",constrainGradients:"bool"},aliases:{stroke:"strokeStyle",fill:"fillStyle",color:"fillStyle","stroke-width":"lineWidth","stroke-linecap":"lineCap","stroke-linejoin":"lineJoin","stroke-miterlimit":"miterLimit","text-anchor":"textAlign",opacity:"globalAlpha",translateX:"translationX",translateY:"translationY",rotateRads:"rotationRads",rotateCenterX:"rotationCenterX",rotateCenterY:"rotationCenterY",scaleX:"scalingX",scaleY:"scalingY",scaleCenterX:"scalingCenterX",scaleCenterY:"scalingCenterY"},defaults:{hidden:false,zIndex:0,strokeStyle:"none",fillStyle:"none",lineWidth:1,lineDash:[],lineDashOffset:0,lineCap:"butt",lineJoin:"miter",miterLimit:10,shadowColor:"none",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0,globalAlpha:1,strokeOpacity:1,fillOpacity:1,transformFillStroke:false,translationX:0,translationY:0,rotationRads:0,rotationCenterX:null,rotationCenterY:null,scalingX:1,scalingY:1,scalingCenterX:null,scalingCenterY:null,constrainGradients:false},triggers:{zIndex:"zIndex",globalAlpha:"canvas",globalCompositeOperation:"canvas",transformFillStroke:"canvas",strokeStyle:"canvas",fillStyle:"canvas",strokeOpacity:"canvas",fillOpacity:"canvas",lineWidth:"canvas",lineCap:"canvas",lineJoin:"canvas",lineDash:"canvas",lineDashOffset:"canvas",miterLimit:"canvas",shadowColor:"canvas",shadowOffsetX:"canvas",shadowOffsetY:"canvas",shadowBlur:"canvas",translationX:"transform",translationY:"transform",rotationRads:"transform",rotationCenterX:"transform",rotationCenterY:"transform",scalingX:"transform",scalingY:"transform",scalingCenterX:"transform",scalingCenterY:"transform",constrainGradients:"canvas"},updaters:{bbox:"bboxUpdater",zIndex:function(a){a.dirtyZIndex=true},transform:function(a){a.dirtyTransform=true;a.bbox.transform.dirty=true}}}},config:{parent:null,surface:null},onClassExtended:function(d,c){var b=d.superclass.self.def.initialConfig,e=c.inheritableStatics&&c.inheritableStatics.def,a;if(e){a=Ext.Object.merge({},b,e);d.def=new Ext.draw.sprite.AttributeDefinition(a);delete c.inheritableStatics.def}else{d.def=new Ext.draw.sprite.AttributeDefinition(b)}d.def.spriteClass=d},constructor:function(b){var d=this,c=d.self.def,e=c.getDefaults(),a;b=Ext.isObject(b)?b:{};d.id=b.id||Ext.id(null,"ext-sprite-");d.attr={};d.mixins.observable.constructor.apply(d,arguments);a=Ext.Array.from(b.modifiers,true);d.prepareModifiers(a);d.initializeAttributes();d.setAttributes(e,true);d.setAttributes(b)},getDirty:function(){return this.attr.dirty},setDirty:function(b){this.attr.dirty=b;if(b){var a=this.getParent();if(a){a.setDirty(true)}}},addModifier:function(a,b){var c=this;if(!(a instanceof Ext.draw.modifier.Modifier)){a=Ext.factory(a,null,null,"modifier")}a.setSprite(c);if(a.preFx||a.config&&a.config.preFx){if(c.fx.getPrevious()){c.fx.getPrevious().setNext(a)}a.setNext(c.fx)}else{c.topModifier.getPrevious().setNext(a);a.setNext(c.topModifier)}if(b){c.initializeAttributes()}return a},prepareModifiers:function(d){var c=this,a,b;c.topModifier=new Ext.draw.modifier.Target({sprite:c});c.fx=new Ext.draw.modifier.Animation({sprite:c});c.fx.setNext(c.topModifier);for(a=0,b=d.length;a<b;a++){c.addModifier(d[a],false)}},getAnimation:function(){return this.fx},setAnimation:function(a){this.fx.setConfig(a)},initializeAttributes:function(){this.topModifier.prepareAttributes(this.attr)},callUpdaters:function(d){var e=this,h=d.pendingUpdaters,i=e.self.def.getUpdaters(),c=false,a=false,b,g,f;e.callUpdaters=Ext.emptyFn;do{c=false;for(g in h){c=true;b=h[g];delete h[g];f=i[g];if(typeof f==="string"){f=e[f]}if(f){f.call(e,d,b)}}a=a||c}while(c);delete e.callUpdaters;if(a){e.setDirty(true)}},scheduleUpdaters:function(a,e,c){var f;if(c){for(var b=0,d=e.length;b<d;b++){f=e[b];this.scheduleUpdater(a,f,c)}}else{for(f in e){c=e[f];this.scheduleUpdater(a,f,c)}}},scheduleUpdater:function(a,c,b){b=b||[];var d=a.pendingUpdaters;if(c in d){if(b.length){d[c]=Ext.Array.merge(d[c],b)}}else{d[c]=b}},setAttributes:function(d,g,c){var a=this.attr,b,e,f;if(g){if(c){this.topModifier.pushDown(a,d)}else{f={};for(b in d){e=d[b];if(e!==a[b]){f[b]=e}}this.topModifier.pushDown(a,f)}}else{this.topModifier.pushDown(a,this.self.def.normalize(d))}},setAttributesBypassingNormalization:function(b,a){return this.setAttributes(b,true,a)},bboxUpdater:function(b){var c=b.rotationRads!==0,a=b.scalingX!==1||b.scalingY!==1,d=b.rotationCenterX===null||b.rotationCenterY===null,e=b.scalingCenterX===null||b.scalingCenterY===null;b.bbox.plain.dirty=true;b.bbox.transform.dirty=true;if(c&&d||a&&e){this.scheduleUpdater(b,"transform")}},getBBox:function(d){var e=this,a=e.attr,f=a.bbox,c=f.plain,b=f.transform;if(c.dirty){e.updatePlainBBox(c);c.dirty=false}if(!d){e.applyTransformations();if(b.dirty){e.updateTransformedBBox(b,c);b.dirty=false}return b}return c},updatePlainBBox:Ext.emptyFn,updateTransformedBBox:function(a,b){this.attr.matrix.transformBBox(b,0,a)},getBBoxCenter:function(a){var b=this.getBBox(a);if(b){return[b.x+b.width*0.5,b.y+b.height*0.5]}else{return[0,0]}},hide:function(){this.attr.hidden=true;this.setDirty(true);return this},show:function(){this.attr.hidden=false;this.setDirty(true);return this},useAttributes:function(i,f){this.applyTransformations();var d=this.attr,h=d.canvasAttributes,e=h.strokeStyle,g=h.fillStyle,b=h.lineDash,c=h.lineDashOffset,a;if(e){if(e.isGradient){i.strokeStyle="black";i.strokeGradient=e}else{i.strokeGradient=false}}if(g){if(g.isGradient){i.fillStyle="black";i.fillGradient=g}else{i.fillGradient=false}}if(b){i.setLineDash(b)}if(Ext.isNumber(c+i.lineDashOffset)){i.lineDashOffset=c}for(a in h){if(h[a]!==undefined&&h[a]!==i[a]){i[a]=h[a]}}this.setGradientBBox(i,f)},setGradientBBox:function(b,c){var a=this.attr;if(a.constrainGradients){b.setGradientBBox({x:c[0],y:c[1],width:c[2],height:c[3]})}else{b.setGradientBBox(this.getBBox(a.transformFillStroke))}},applyTransformations:function(b){if(!b&&!this.attr.dirtyTransform){return}var r=this,k=r.attr,p=r.getBBoxCenter(true),g=p[0],f=p[1],q=k.translationX,o=k.translationY,j=k.scalingX,i=k.scalingY===null?k.scalingX:k.scalingY,m=k.scalingCenterX===null?g:k.scalingCenterX,l=k.scalingCenterY===null?f:k.scalingCenterY,s=k.rotationRads,e=k.rotationCenterX===null?g:k.rotationCenterX,d=k.rotationCenterY===null?f:k.rotationCenterY,c=Math.cos(s),a=Math.sin(s),n,h;if(j===1&&i===1){m=0;l=0}if(s===0){e=0;d=0}n=m*(1-j)-e;h=l*(1-i)-d;k.matrix.elements=[c*j,a*j,-a*i,c*i,c*n-a*h+e+q,a*n+c*h+d+o];k.matrix.inverse(k.inverseMatrix);k.dirtyTransform=false;k.bbox.transform.dirty=true},transform:function(b,c){var a=this.attr,e=a.matrix,d;if(b&&b.isMatrix){d=b.elements}else{d=b}e.prepend.apply(e,d.slice());e.inverse(a.inverseMatrix);if(c){this.updateTransformAttributes()}a.dirtyTransform=false;a.bbox.transform.dirty=true;this.setDirty(true);return this},updateTransformAttributes:function(){var a=this.attr,b=a.matrix.split();a.rotationRads=b.rotate;a.rotationCenterX=0;a.rotationCenterY=0;a.scalingX=b.scaleX;a.scalingY=b.scaleY;a.scalingCenterX=0;a.scalingCenterY=0;a.translationX=b.translateX;a.translationY=b.translateY},resetTransform:function(b){var a=this.attr;a.matrix.reset();a.inverseMatrix.reset();if(!b){this.updateTransformAttributes()}a.dirtyTransform=false;a.bbox.transform.dirty=true;this.setDirty(true);return this},setTransform:function(a,b){this.resetTransform(true);this.transform.call(this,a,b);return this},preRender:Ext.emptyFn,render:Ext.emptyFn,hitTest:function(b,c){if(this.isVisible()){var a=b[0],f=b[1],e=this.getBBox(),d=e&&a>=e.x&&a<=(e.x+e.width)&&f>=e.y&&f<=(e.y+e.height);if(d){return{sprite:this}}}return null},isVisible:function(){var e=this.attr,f=this.getParent(),g=f&&(f.isSurface||f.isVisible()),d=g&&!e.hidden&&e.globalAlpha,b=Ext.draw.Color.NONE,a=Ext.draw.Color.RGBA_NONE,c=e.fillOpacity&&e.fillStyle!==b&&e.fillStyle!==a,i=e.strokeOpacity&&e.strokeStyle!==b&&e.strokeStyle!==a,h=d&&(c||i);return !!h},repaint:function(){var a=this.getSurface();if(a){a.renderFrame()}},remove:function(){var a=this.getSurface();if(a&&a.isSurface){return a.remove(this)}return null},destroy:function(){var b=this,a=b.topModifier,c;while(a){c=a;a=a.getPrevious();c.destroy()}delete b.attr;b.remove();if(b.fireEvent("beforedestroy",b)!==false){b.fireEvent("destroy",b)}b.callParent()}},function(){this.def=new Ext.draw.sprite.AttributeDefinition(this.def);this.def.spriteClass=this});Ext.define("Ext.draw.Path",{requires:["Ext.draw.Draw"],statics:{pathRe:/,?([achlmqrstvxz]),?/gi,pathRe2:/-/gi,pathSplitRe:/\s|,/g},svgString:"",constructor:function(a){var b=this;b.commands=[];b.params=[];b.cursor=null;b.startX=0;b.startY=0;if(a){b.fromSvgString(a)}},clear:function(){var a=this;a.params.length=0;a.commands.length=0;a.cursor=null;a.startX=0;a.startY=0;a.dirt()},dirt:function(){this.svgString=""},moveTo:function(a,c){var b=this;if(!b.cursor){b.cursor=[a,c]}b.params.push(a,c);b.commands.push("M");b.startX=a;b.startY=c;b.cursor[0]=a;b.cursor[1]=c;b.dirt()},lineTo:function(a,c){var b=this;if(!b.cursor){b.cursor=[a,c];b.params.push(a,c);b.commands.push("M")}else{b.params.push(a,c);b.commands.push("L")}b.cursor[0]=a;b.cursor[1]=c;b.dirt()},bezierCurveTo:function(c,e,b,d,a,g){var f=this;if(!f.cursor){f.moveTo(c,e)}f.params.push(c,e,b,d,a,g);f.commands.push("C");f.cursor[0]=a;f.cursor[1]=g;f.dirt()},quadraticCurveTo:function(b,e,a,d){var c=this;if(!c.cursor){c.moveTo(b,e)}c.bezierCurveTo((2*b+c.cursor[0])/3,(2*e+c.cursor[1])/3,(2*b+a)/3,(2*e+d)/3,a,d)},closePath:function(){var a=this;if(a.cursor){a.cursor=null;a.commands.push("Z");a.dirt()}},arcTo:function(A,f,z,d,j,i,v){var E=this;if(i===undefined){i=j}if(v===undefined){v=0}if(!E.cursor){E.moveTo(A,f);return}if(j===0||i===0){E.lineTo(A,f);return}z-=A;d-=f;var B=E.cursor[0]-A,g=E.cursor[1]-f,C=z*g-d*B,b,a,l,r,k,q,x=Math.sqrt(B*B+g*g),u=Math.sqrt(z*z+d*d),t,e,c;if(C===0){E.lineTo(A,f);return}if(i!==j){b=Math.cos(v);a=Math.sin(v);l=b/j;r=a/i;k=-a/j;q=b/i;var D=l*B+r*g;g=k*B+q*g;B=D;D=l*z+r*d;d=k*z+q*d;z=D}else{B/=j;g/=i;z/=j;d/=i}e=B*u+z*x;c=g*u+d*x;t=1/(Math.sin(Math.asin(Math.abs(C)/(x*u))*0.5)*Math.sqrt(e*e+c*c));e*=t;c*=t;var o=(e*B+c*g)/(B*B+g*g),m=(e*z+c*d)/(z*z+d*d);var n=B*o-e,p=g*o-c,h=z*m-e,y=d*m-c,w=Math.atan2(p,n),s=Math.atan2(y,h);if(C>0){if(s<w){s+=Math.PI*2}}else{if(w<s){w+=Math.PI*2}}if(i!==j){e=b*e*j-a*c*i+A;c=a*c*i+b*c*i+f;E.lineTo(b*j*n-a*i*p+e,a*j*n+b*i*p+c);E.ellipse(e,c,j,i,v,w,s,C<0)}else{e=e*j+A;c=c*i+f;E.lineTo(j*n+e,i*p+c);E.ellipse(e,c,j,i,v,w,s,C<0)}},ellipse:function(h,f,c,a,q,n,d,e){var o=this,g=o.params,b=g.length,m,l,k;if(d-n>=Math.PI*2){o.ellipse(h,f,c,a,q,n,n+Math.PI,e);o.ellipse(h,f,c,a,q,n+Math.PI,d,e);return}if(!e){if(d<n){d+=Math.PI*2}m=o.approximateArc(g,h,f,c,a,q,n,d)}else{if(n<d){n+=Math.PI*2}m=o.approximateArc(g,h,f,c,a,q,d,n);for(l=b,k=g.length-2;l<k;l+=2,k-=2){var p=g[l];g[l]=g[k];g[k]=p;p=g[l+1];g[l+1]=g[k+1];g[k+1]=p}}if(!o.cursor){o.cursor=[g[g.length-2],g[g.length-1]];o.commands.push("M")}else{o.cursor[0]=g[g.length-2];o.cursor[1]=g[g.length-1];o.commands.push("L")}for(l=2;l<m;l+=6){o.commands.push("C")}o.dirt()},arc:function(b,f,a,d,c,e){this.ellipse(b,f,a,a,0,d,c,e)},rect:function(b,e,c,a){if(c==0||a==0){return}var d=this;d.moveTo(b,e);d.lineTo(b+c,e);d.lineTo(b+c,e+a);d.lineTo(b,e+a);d.closePath()},approximateArc:function(s,i,f,o,n,d,x,v){var e=Math.cos(d),z=Math.sin(d),k=Math.cos(x),l=Math.sin(x),q=e*k*o-z*l*n,y=-e*l*o-z*k*n,p=z*k*o+e*l*n,w=-z*l*o+e*k*n,m=Math.PI/2,r=2,j=q,u=y,h=p,t=w,b=0.547443256150549,C,g,A,a,B,c;v-=x;if(v<0){v+=Math.PI*2}s.push(q+i,p+f);while(v>=m){s.push(j+u*b+i,h+t*b+f,j*b+u+i,h*b+t+f,u+i,t+f);r+=6;v-=m;C=j;j=u;u=-C;C=h;h=t;t=-C}if(v){g=(0.3294738052815987+0.012120855841304373*v)*v;A=Math.cos(v);a=Math.sin(v);B=A+g*a;c=a-g*A;s.push(j+u*g+i,h+t*g+f,j*B+u*c+i,h*B+t*c+f,j*A+u*a+i,h*A+t*a+f);r+=6}return r},arcSvg:function(j,h,r,m,w,t,c){if(j<0){j=-j}if(h<0){h=-h}var x=this,u=x.cursor[0],f=x.cursor[1],a=(u-t)/2,y=(f-c)/2,d=Math.cos(r),s=Math.sin(r),o=a*d+y*s,v=-a*s+y*d,i=o/j,g=v/h,p=i*i+g*g,e=(u+t)*0.5,b=(f+c)*0.5,l=0,k=0;if(p>=1){p=Math.sqrt(p);j*=p;h*=p}else{p=Math.sqrt(1/p-1);if(m===w){p=-p}l=p*j*g;k=-p*h*i;e+=d*l-s*k;b+=s*l+d*k}var q=Math.atan2((v-k)/h,(o-l)/j),n=Math.atan2((-v-k)/h,(-o-l)/j)-q;if(w){if(n<=0){n+=Math.PI*2}}else{if(n>=0){n-=Math.PI*2}}x.ellipse(e,b,j,h,r,q,q+n,1-w)},fromSvgString:function(e){if(!e){return}var m=this,h,l={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0,A:7,C:6,H:1,L:2,M:2,Q:4,S:4,T:2,V:1,Z:0},k="",g,f,c=0,b=0,d=false,j,n,a;if(Ext.isString(e)){h=e.replace(Ext.draw.Path.pathRe," $1 ").replace(Ext.draw.Path.pathRe2," -").split(Ext.draw.Path.pathSplitRe)}else{if(Ext.isArray(e)){h=e.join(",").split(Ext.draw.Path.pathSplitRe)}}for(j=0,n=0;j<h.length;j++){if(h[j]!==""){h[n++]=h[j]}}h.length=n;m.clear();for(j=0;j<h.length;){k=d;d=h[j];a=(d.toUpperCase()!==d);j++;switch(d){case"M":m.moveTo(c=+h[j],b=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b=+h[j+1]);j+=2}break;case"L":m.lineTo(c=+h[j],b=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b=+h[j+1]);j+=2}break;case"A":while(j<n&&!l.hasOwnProperty(h[j])){m.arcSvg(+h[j],+h[j+1],+h[j+2]*Math.PI/180,+h[j+3],+h[j+4],c=+h[j+5],b=+h[j+6]);j+=7}break;case"C":while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(+h[j],+h[j+1],g=+h[j+2],f=+h[j+3],c=+h[j+4],b=+h[j+5]);j+=6}break;case"Z":m.closePath();break;case"m":m.moveTo(c+=+h[j],b+=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2}break;case"l":m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2}break;case"a":while(j<n&&!l.hasOwnProperty(h[j])){m.arcSvg(+h[j],+h[j+1],+h[j+2]*Math.PI/180,+h[j+3],+h[j+4],c+=+h[j+5],b+=+h[j+6]);j+=7}break;case"c":while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+(+h[j]),b+(+h[j+1]),g=c+(+h[j+2]),f=b+(+h[j+3]),c+=+h[j+4],b+=+h[j+5]);j+=6}break;case"z":m.closePath();break;case"s":if(!(k==="c"||k==="C"||k==="s"||k==="S")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+c-g,b+b-f,g=c+(+h[j]),f=b+(+h[j+1]),c+=+h[j+2],b+=+h[j+3]);j+=4}break;case"S":if(!(k==="c"||k==="C"||k==="s"||k==="S")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+c-g,b+b-f,g=+h[j],f=+h[j+1],c=(+h[j+2]),b=(+h[j+3]));j+=4}break;case"q":while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+(+h[j]),f=b+(+h[j+1]),c+=+h[j+2],b+=+h[j+3]);j+=4}break;case"Q":while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=+h[j],f=+h[j+1],c=+h[j+2],b=+h[j+3]);j+=4}break;case"t":if(!(k==="q"||k==="Q"||k==="t"||k==="T")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+c-g,f=b+b-f,c+=+h[j+1],b+=+h[j+2]);j+=2}break;case"T":if(!(k==="q"||k==="Q"||k==="t"||k==="T")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+c-g,f=b+b-f,c=(+h[j+1]),b=(+h[j+2]));j+=2}break;case"h":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b);j++}break;case"H":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b);j++}break;case"v":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c,b+=+h[j]);j++}break;case"V":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c,b=+h[j]);j++}break}}},clone:function(){var a=this,b=new Ext.draw.Path();b.params=a.params.slice(0);b.commands=a.commands.slice(0);b.cursor=a.cursor?a.cursor.slice(0):null;b.startX=a.startX;b.startY=a.startY;b.svgString=a.svgString;return b},transform:function(j){if(j.isIdentity()){return}var a=j.getXX(),f=j.getYX(),m=j.getDX(),l=j.getXY(),e=j.getYY(),k=j.getDY(),b=this.params,c=0,d=b.length,h,g;for(;c<d;c+=2){h=b[c];g=b[c+1];b[c]=h*a+g*f+m;b[c+1]=h*l+g*e+k}this.dirt()},getDimension:function(f){if(!f){f={}}if(!this.commands||!this.commands.length){f.x=0;f.y=0;f.width=0;f.height=0;return f}f.left=Infinity;f.top=Infinity;f.right=-Infinity;f.bottom=-Infinity;var d=0,c=0,b=this.commands,g=this.params,e=b.length,a,h;for(;d<e;d++){switch(b[d]){case"M":case"L":a=g[c];h=g[c+1];f.left=Math.min(a,f.left);f.top=Math.min(h,f.top);f.right=Math.max(a,f.right);f.bottom=Math.max(h,f.bottom);c+=2;break;case"C":this.expandDimension(f,a,h,g[c],g[c+1],g[c+2],g[c+3],a=g[c+4],h=g[c+5]);c+=6;break}}f.x=f.left;f.y=f.top;f.width=f.right-f.left;f.height=f.bottom-f.top;return f},getDimensionWithTransform:function(n,f){if(!this.commands||!this.commands.length){if(!f){f={}}f.x=0;f.y=0;f.width=0;f.height=0;return f}f.left=Infinity;f.top=Infinity;f.right=-Infinity;f.bottom=-Infinity;var a=n.getXX(),k=n.getYX(),q=n.getDX(),p=n.getXY(),h=n.getYY(),o=n.getDY(),e=0,d=0,b=this.commands,c=this.params,g=b.length,m,l;for(;e<g;e++){switch(b[e]){case"M":case"L":m=c[d]*a+c[d+1]*k+q;l=c[d]*p+c[d+1]*h+o;f.left=Math.min(m,f.left);f.top=Math.min(l,f.top);f.right=Math.max(m,f.right);f.bottom=Math.max(l,f.bottom);d+=2;break;case"C":this.expandDimension(f,m,l,c[d]*a+c[d+1]*k+q,c[d]*p+c[d+1]*h+o,c[d+2]*a+c[d+3]*k+q,c[d+2]*p+c[d+3]*h+o,m=c[d+4]*a+c[d+5]*k+q,l=c[d+4]*p+c[d+5]*h+o);d+=6;break}}if(!f){f={}}f.x=f.left;f.y=f.top;f.width=f.right-f.left;f.height=f.bottom-f.top;return f},expandDimension:function(i,d,p,k,g,j,e,c,o){var m=this,f=i.left,a=i.right,q=i.top,n=i.bottom,h=m.dim||(m.dim=[]);m.curveDimension(d,k,j,c,h);f=Math.min(f,h[0]);a=Math.max(a,h[1]);m.curveDimension(p,g,e,o,h);q=Math.min(q,h[0]);n=Math.max(n,h[1]);i.left=f;i.right=a;i.top=q;i.bottom=n},curveDimension:function(p,n,k,j,h){var i=3*(-p+3*(n-k)+j),g=6*(p-2*n+k),f=-3*(p-n),o,m,e=Math.min(p,j),l=Math.max(p,j),q;if(i===0){if(g===0){h[0]=e;h[1]=l;return}else{o=-f/g;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}}}else{q=g*g-4*i*f;if(q>=0){q=Math.sqrt(q);o=(q-g)/2/i;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}if(q>0){o-=q/i;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}}}}h[0]=e;h[1]=l},interpolate:function(f,e,j,i,g){if(g===0){return f}if(g===1){return i}var h=(1-g)/g;return g*g*g*(i+h*(3*j+h*(3*e+h*f)))},fromStripes:function(g){var e=this,c=0,d=g.length,b,a,f;e.clear();for(;c<d;c++){f=g[c];e.params.push.apply(e.params,f);e.commands.push("M");for(b=2,a=f.length;b<a;b+=6){e.commands.push("C")}}if(!e.cursor){e.cursor=[]}e.cursor[0]=e.params[e.params.length-2];e.cursor[1]=e.params[e.params.length-1];e.dirt()},toStripes:function(k){var o=k||[],p,n,m,b,a,h,g,f,e,c=this.commands,d=this.params,l=c.length;for(f=0,e=0;f<l;f++){switch(c[f]){case"M":p=[h=b=d[e++],g=a=d[e++]];o.push(p);break;case"L":n=d[e++];m=d[e++];p.push((b+b+n)/3,(a+a+m)/3,(b+n+n)/3,(a+m+m)/3,b=n,a=m);break;case"C":p.push(d[e++],d[e++],d[e++],d[e++],b=d[e++],a=d[e++]);break;case"Z":n=h;m=g;p.push((b+b+n)/3,(a+a+m)/3,(b+n+n)/3,(a+m+m)/3,b=n,a=m);break}}return o},updateSvgString:function(){var b=[],a=this.commands,f=this.params,e=a.length,d=0,c=0;for(;d<e;d++){switch(a[d]){case"M":b.push("M"+f[c]+","+f[c+1]);c+=2;break;case"L":b.push("L"+f[c]+","+f[c+1]);c+=2;break;case"C":b.push("C"+f[c]+","+f[c+1]+" "+f[c+2]+","+f[c+3]+" "+f[c+4]+","+f[c+5]);c+=6;break;case"Z":b.push("Z");break}}this.svgString=b.join("")},toString:function(){if(!this.svgString){this.updateSvgString()}return this.svgString}});Ext.define("Ext.draw.overrides.Path",{override:"Ext.draw.Path",rayOrigin:{x:-10000,y:-10000},isPointInPath:function(o,n){var m=this,c=m.commands,q=Ext.draw.PathUtil,p=m.rayOrigin,f=m.params,l=c.length,e=null,d=null,b=0,a=0,k=0,h,g;for(h=0,g=0;h<l;h++){switch(c[h]){case"M":if(e!==null){if(q.linesIntersection(e,d,b,a,p.x,p.y,o,n)){k+=1}}e=b=f[g];d=a=f[g+1];g+=2;break;case"L":if(q.linesIntersection(b,a,f[g],f[g+1],p.x,p.y,o,n)){k+=1}b=f[g];a=f[g+1];g+=2;break;case"C":k+=q.cubicLineIntersections(b,f[g],f[g+2],f[g+4],a,f[g+1],f[g+3],f[g+5],p.x,p.y,o,n).length;b=f[g+4];a=f[g+5];g+=6;break;case"Z":if(e!==null){if(q.linesIntersection(e,d,b,a,p.x,p.y,o,n)){k+=1}}break}}return k%2===1},isPointOnPath:function(n,m){var l=this,c=l.commands,o=Ext.draw.PathUtil,f=l.params,k=c.length,e=null,d=null,b=0,a=0,h,g;for(h=0,g=0;h<k;h++){switch(c[h]){case"M":if(e!==null){if(o.pointOnLine(e,d,b,a,n,m)){return true}}e=b=f[g];d=a=f[g+1];g+=2;break;case"L":if(o.pointOnLine(b,a,f[g],f[g+1],n,m)){return true}b=f[g];a=f[g+1];g+=2;break;case"C":if(o.pointOnCubic(b,f[g],f[g+2],f[g+4],a,f[g+1],f[g+3],f[g+5],n,m)){return true}b=f[g+4];a=f[g+5];g+=6;break;case"Z":if(e!==null){if(o.pointOnLine(e,d,b,a,n,m)){return true}}break}}return false},getSegmentIntersections:function(t,d,s,c,r,b,o,a){var w=this,g=arguments.length,v=Ext.draw.PathUtil,f=w.commands,u=w.params,k=f.length,m=null,l=null,h=0,e=0,x=[],q,n,p;for(q=0,n=0;q<k;q++){switch(f[q]){case"M":if(m!==null){switch(g){case 4:p=v.linesIntersection(m,l,h,e,t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,m,l,h,e);x.push.apply(x,p);break}}m=h=u[n];l=e=u[n+1];n+=2;break;case"L":switch(g){case 4:p=v.linesIntersection(h,e,u[n],u[n+1],t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,h,e,u[n],u[n+1]);x.push.apply(x,p);break}h=u[n];e=u[n+1];n+=2;break;case"C":switch(g){case 4:p=v.cubicLineIntersections(h,u[n],u[n+2],u[n+4],e,u[n+1],u[n+3],u[n+5],t,d,s,c);x.push.apply(x,p);break;case 8:p=v.cubicsIntersections(h,u[n],u[n+2],u[n+4],e,u[n+1],u[n+3],u[n+5],t,s,r,o,d,c,b,a);x.push.apply(x,p);break}h=u[n+4];e=u[n+5];n+=6;break;case"Z":if(m!==null){switch(g){case 4:p=v.linesIntersection(m,l,h,e,t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,m,l,h,e);x.push.apply(x,p);break}}break}}return x},getIntersections:function(o){var m=this,c=m.commands,g=m.params,l=c.length,f=null,e=null,b=0,a=0,d=[],k,h,n;for(k=0,h=0;k<l;k++){switch(c[k]){case"M":if(f!==null){n=o.getSegmentIntersections.call(o,f,e,b,a);d.push.apply(d,n)}f=b=g[h];e=a=g[h+1];h+=2;break;case"L":n=o.getSegmentIntersections.call(o,b,a,g[h],g[h+1]);d.push.apply(d,n);b=g[h];a=g[h+1];h+=2;break;case"C":n=o.getSegmentIntersections.call(o,b,a,g[h],g[h+1],g[h+2],g[h+3],g[h+4],g[h+5]);d.push.apply(d,n);b=g[h+4];a=g[h+5];h+=6;break;case"Z":if(f!==null){n=o.getSegmentIntersections.call(o,f,e,b,a);d.push.apply(d,n)}break}}return d}});Ext.define("Ext.draw.sprite.Path",{extend:"Ext.draw.sprite.Sprite",requires:["Ext.draw.Draw","Ext.draw.Path"],alias:["sprite.path","Ext.draw.Sprite"],type:"path",isPath:true,inheritableStatics:{def:{processors:{path:function(b,a){if(!(b instanceof Ext.draw.Path)){b=new Ext.draw.Path(b)}return b}},aliases:{d:"path"},triggers:{path:"bbox"},updaters:{path:function(a){var b=a.path;if(!b||b.bindAttr!==a){b=new Ext.draw.Path();b.bindAttr=a;a.path=b}b.clear();this.updatePath(b,a);this.scheduleUpdater(a,"bbox",["path"])}}}},updatePlainBBox:function(a){if(this.attr.path){this.attr.path.getDimension(a)}},updateTransformedBBox:function(a){if(this.attr.path){this.attr.path.getDimensionWithTransform(this.attr.matrix,a)}},render:function(b,c){var d=this.attr.matrix,a=this.attr;if(!a.path||a.path.params.length===0){return}d.toContext(c);c.appendPath(a.path);c.fillStroke(a)},updatePath:function(b,a){}});Ext.define("Ext.draw.overrides.sprite.Path",{override:"Ext.draw.sprite.Path",requires:["Ext.draw.Color"],isPointInPath:function(c,g){var b=this.attr;if(b.fillStyle===Ext.draw.Color.RGBA_NONE){return this.isPointOnPath(c,g)}var e=b.path,d=b.matrix,f,a;if(!d.isIdentity()){f=e.params.slice(0);e.transform(b.matrix)}a=e.isPointInPath(c,g);if(f){e.params=f}return a},isPointOnPath:function(c,g){var b=this.attr,e=b.path,d=b.matrix,f,a;if(!d.isIdentity()){f=e.params.slice(0);e.transform(b.matrix)}a=e.isPointOnPath(c,g);if(f){e.params=f}return a},hitTest:function(i,l){var e=this,c=e.attr,k=c.path,g=c.matrix,h=i[0],f=i[1],d=e.callParent([i,l]),j=null,a,b;if(!d){return j}l=l||Ext.draw.sprite.Sprite.defaultHitTestOptions;if(!g.isIdentity()){a=k.params.slice(0);k.transform(c.matrix)}if(l.fill&&l.stroke){b=c.fillStyle!==Ext.draw.Color.NONE&&c.fillStyle!==Ext.draw.Color.RGBA_NONE;if(b){if(k.isPointInPath(h,f)){j={sprite:e}}}else{if(k.isPointInPath(h,f)||k.isPointOnPath(h,f)){j={sprite:e}}}}else{if(l.stroke&&!l.fill){if(k.isPointOnPath(h,f)){j={sprite:e}}}else{if(l.fill&&!l.stroke){if(k.isPointInPath(h,f)){j={sprite:e}}}}}if(a){k.params=a}return j},getIntersections:function(j){if(!(j.isSprite&&j.isPath)){return[]}var e=this.attr,d=j.attr,i=e.path,h=d.path,g=e.matrix,a=d.matrix,c,f,b;if(!g.isIdentity()){c=i.params.slice(0);i.transform(e.matrix)}if(!a.isIdentity()){f=h.params.slice(0);h.transform(d.matrix)}b=i.getIntersections(h);if(c){i.params=c}if(f){h.params=f}return b}});Ext.define("Ext.draw.sprite.Circle",{extend:"Ext.draw.sprite.Path",alias:"sprite.circle",type:"circle",inheritableStatics:{def:{processors:{cx:"number",cy:"number",r:"number"},aliases:{radius:"r",x:"cx",y:"cy",centerX:"cx",centerY:"cy"},defaults:{cx:0,cy:0,r:4},triggers:{cx:"path",cy:"path",r:"path"}}},updatePlainBBox:function(c){var b=this.attr,a=b.cx,e=b.cy,d=b.r;c.x=a-d;c.y=e-d;c.width=d+d;c.height=d+d},updateTransformedBBox:function(d){var g=this.attr,f=g.cx,e=g.cy,a=g.r,h=g.matrix,j=h.getScaleX(),i=h.getScaleY(),c,b;c=j*a;b=i*a;d.x=h.x(f,e)-c;d.y=h.y(f,e)-b;d.width=c+c;d.height=b+b},updatePath:function(b,a){b.arc(a.cx,a.cy,a.r,0,Math.PI*2,false)}});Ext.define("Ext.draw.sprite.Arc",{extend:"Ext.draw.sprite.Circle",alias:"sprite.arc",type:"arc",inheritableStatics:{def:{processors:{startAngle:"number",endAngle:"number",anticlockwise:"bool"},aliases:{from:"startAngle",to:"endAngle",start:"startAngle",end:"endAngle"},defaults:{startAngle:0,endAngle:Math.PI*2,anticlockwise:false},triggers:{startAngle:"path",endAngle:"path",anticlockwise:"path"}}},updatePath:function(b,a){b.arc(a.cx,a.cy,a.r,a.startAngle,a.endAngle,a.anticlockwise)}});Ext.define("Ext.draw.sprite.Arrow",{extend:"Ext.draw.sprite.Path",alias:"sprite.arrow",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*1.5,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c*0.7,",",e-c*0.4,"l",[c*0.6,0,0,-c*0.4,c,c*0.8,-c,c*0.8,0,-c*0.4,-c*0.6,0],"z"))}});Ext.define("Ext.draw.sprite.Composite",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.composite",type:"composite",isComposite:true,config:{sprites:[]},constructor:function(){this.sprites=[];this.sprites.map={};this.callParent(arguments)},add:function(c){if(!c){return null}if(!c.isSprite){c=Ext.create("sprite."+c.type,c);c.setParent(this);c.setSurface(this.getSurface())}var d=this,a=d.attr,b=c.applyTransformations;c.applyTransformations=function(){if(c.attr.dirtyTransform){a.dirtyTransform=true;a.bbox.plain.dirty=true;a.bbox.transform.dirty=true}b.call(c)};d.sprites.push(c);d.sprites.map[c.id]=c.getId();a.bbox.plain.dirty=true;a.bbox.transform.dirty=true;return c},updateSurface:function(a){for(var b=0,c=this.sprites.length;b<c;b++){this.sprites[b].setSurface(a)}},addAll:function(b){if(b.isSprite||b.type){this.add(b)}else{if(Ext.isArray(b)){var a=0;while(a<b.length){this.add(b[a++])}}}},updatePlainBBox:function(g){var e=this,b=Infinity,h=-Infinity,f=Infinity,a=-Infinity,j,k,c,d;for(c=0,d=e.sprites.length;c<d;c++){j=e.sprites[c];j.applyTransformations();k=j.getBBox();if(b>k.x){b=k.x}if(h<k.x+k.width){h=k.x+k.width}if(f>k.y){f=k.y}if(a<k.y+k.height){a=k.y+k.height}}g.x=b;g.y=f;g.width=h-b;g.height=a-f},render:function(a,b,f){var d=this.attr.matrix,c,e;d.toContext(b);for(c=0,e=this.sprites.length;c<e;c++){a.renderSprite(this.sprites[c],f)}},destroy:function(){var c=this,d=c.sprites,b=d.length,a;c.callParent();for(a=0;a<b;a++){d[a].destroy()}d.length=0}});Ext.define("Ext.draw.sprite.Cross",{extend:"Ext.draw.sprite.Path",alias:"sprite.cross",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size/1.7,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c,",",e,"l",[-c,-c,c,-c,c,c,c,-c,c,c,-c,c,c,c,-c,c,-c,-c,-c,c,-c,-c,"z"]))}});Ext.define("Ext.draw.sprite.Diamond",{extend:"Ext.draw.sprite.Path",alias:"sprite.diamond",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*1.25,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString(["M",a,e-c,"l",c,c,-c,c,-c,-c,c,-c,"z"])}});Ext.define("Ext.draw.sprite.Ellipse",{extend:"Ext.draw.sprite.Path",alias:"sprite.ellipse",type:"ellipse",inheritableStatics:{def:{processors:{cx:"number",cy:"number",rx:"number",ry:"number",axisRotation:"number"},aliases:{radius:"r",x:"cx",y:"cy",centerX:"cx",centerY:"cy",radiusX:"rx",radiusY:"ry"},defaults:{cx:0,cy:0,rx:1,ry:1,axisRotation:0},triggers:{cx:"path",cy:"path",rx:"path",ry:"path",axisRotation:"path"}}},updatePlainBBox:function(c){var b=this.attr,a=b.cx,f=b.cy,e=b.rx,d=b.ry;c.x=a-e;c.y=f-d;c.width=e+e;c.height=d+d},updateTransformedBBox:function(d){var i=this.attr,f=i.cx,e=i.cy,c=i.rx,b=i.ry,l=b/c,m=i.matrix.clone(),a,q,k,j,p,o,n,g;m.append(1,0,0,l,0,e*(1-l));a=m.getXX();k=m.getYX();p=m.getDX();q=m.getXY();j=m.getYY();o=m.getDY();n=Math.sqrt(a*a+k*k)*c;g=Math.sqrt(q*q+j*j)*c;d.x=f*a+e*k+p-n;d.y=f*q+e*j+o-g;d.width=n+n;d.height=g+g},updatePath:function(b,a){b.ellipse(a.cx,a.cy,a.rx,a.ry,a.axisRotation,0,Math.PI*2,false)}});Ext.define("Ext.draw.sprite.EllipticalArc",{extend:"Ext.draw.sprite.Ellipse",alias:"sprite.ellipticalArc",type:"ellipticalArc",inheritableStatics:{def:{processors:{startAngle:"number",endAngle:"number",anticlockwise:"bool"},aliases:{from:"startAngle",to:"endAngle",start:"startAngle",end:"endAngle"},defaults:{startAngle:0,endAngle:Math.PI*2,anticlockwise:false},triggers:{startAngle:"path",endAngle:"path",anticlockwise:"path"}}},updatePath:function(b,a){b.ellipse(a.cx,a.cy,a.rx,a.ry,a.axisRotation,a.startAngle,a.endAngle,a.anticlockwise)}});Ext.define("Ext.draw.sprite.Rect",{extend:"Ext.draw.sprite.Path",alias:"sprite.rect",type:"rect",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number",radius:"number"},aliases:{},triggers:{x:"path",y:"path",width:"path",height:"path",radius:"path"},defaults:{x:0,y:0,width:8,height:8,radius:0}}},updatePlainBBox:function(b){var a=this.attr;b.x=a.x;b.y=a.y;b.width=a.width;b.height=a.height},updateTransformedBBox:function(a,b){this.attr.matrix.transformBBox(b,this.attr.radius,a)},updatePath:function(f,d){var c=d.x,g=d.y,e=d.width,b=d.height,a=Math.min(d.radius,Math.abs(d.height)*0.5,Math.abs(d.width)*0.5);if(a===0){f.rect(c,g,e,b)}else{f.moveTo(c+a,g);f.arcTo(c+e,g,c+e,g+b,a);f.arcTo(c+e,g+b,c,g+b,a);f.arcTo(c,g+b,c,g,a);f.arcTo(c,g,c+a,g,a)}}});Ext.define("Ext.draw.sprite.Image",{extend:"Ext.draw.sprite.Rect",alias:"sprite.image",type:"image",statics:{imageLoaders:{}},inheritableStatics:{def:{processors:{src:"string"},defaults:{src:"",width:null,height:null}}},render:function(c,o){var j=this,h=j.attr,n=h.matrix,a=h.src,l=h.x,k=h.y,b=h.width,m=h.height,g=Ext.draw.sprite.Image.imageLoaders[a],f,d,e;if(g&&g.done){n.toContext(o);d=g.image;o.drawImage(d,l,k,b||(d.naturalWidth||d.width)/c.devicePixelRatio,m||(d.naturalHeight||d.height)/c.devicePixelRatio)}else{if(!g){f=new Image();g=Ext.draw.sprite.Image.imageLoaders[a]={image:f,done:false,pendingSprites:[j],pendingSurfaces:[c]};f.width=b;f.height=m;f.onload=function(){if(!g.done){g.done=true;for(e=0;e<g.pendingSprites.length;e++){g.pendingSprites[e].setDirty(true)}for(e in g.pendingSurfaces){g.pendingSurfaces[e].renderFrame()}}};f.src=a}else{Ext.Array.include(g.pendingSprites,j);Ext.Array.include(g.pendingSurfaces,c)}}}});Ext.define("Ext.draw.sprite.Instancing",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.instancing",type:"instancing",isInstancing:true,config:{template:null},instances:null,applyTemplate:function(a){if(!a.isSprite){if(!a.xclass&&!a.type){a.type="circle"}a=Ext.create(a.xclass||"sprite."+a.type,a)}a.setParent(this);return a},updateTemplate:function(a,b){if(b){delete b.ownAttr}a.setSurface(this.getSurface());a.ownAttr=a.attr;this.clearAll()},updateSurface:function(a){var b=this.getTemplate();if(b){b.setSurface(a)}},get:function(a){return this.instances[a]},getCount:function(){return this.instances.length},clearAll:function(){var a=this.getTemplate();a.attr.children=this.instances=[];this.position=0},createInstance:function(d,f,c){var e=this.getTemplate(),b=e.attr,a=Ext.Object.chain(b);e.topModifier.prepareAttributes(a);e.attr=a;e.setAttributes(d,f,c);a.template=e;this.instances.push(a);e.attr=b;this.position++;return a},getBBox:function(){return null},getBBoxFor:function(b,d){var c=this.getTemplate(),a=c.attr,e;c.attr=this.instances[b];e=c.getBBox(d);c.attr=a;return e},isVisible:function(){var b=this.attr,c=this.getParent(),a;a=c&&c.isSurface&&!b.hidden&&b.globalAlpha;return !!a},isInstanceVisible:function(c){var e=this,d=e.getTemplate(),b=d.attr,f=e.instances,a=false;if(!Ext.isNumber(c)||c<0||c>=f.length||!e.isVisible()){return a}d.attr=f[c];a=d.isVisible(point,options);d.attr=b;return a},render:function(b,l,d,h){var g=this,j=g.getTemplate(),k=g.attr.matrix,c=j.attr,a=g.instances,e,f=g.position;k.toContext(l);j.preRender(b,l,d,h);j.useAttributes(l,h);for(e=0;e<f;e++){if(a[e].dirtyZIndex){break}}for(e=0;e<f;e++){if(a[e].hidden){continue}l.save();j.attr=a[e];j.useAttributes(l,h);j.render(b,l,d,h);l.restore()}j.attr=c},setAttributesFor:function(c,e,f){var d=this.getTemplate(),b=d.attr,a=this.instances[c];if(!a){return}d.attr=a;if(f){e=Ext.apply({},e)}else{e=d.self.def.normalize(e)}d.topModifier.pushDown(a,e);d.attr=b},destroy:function(){var b=this,a=b.getTemplate();b.instances=null;if(a){a.destroy()}b.callParent()}});Ext.define("Ext.draw.overrides.sprite.Instancing",{override:"Ext.draw.sprite.Instancing",hitTest:function(f,j){var e=this,g=e.getTemplate(),b=g.attr,a=e.instances,d=a.length,c=0,h=null;if(!e.isVisible()){return h}for(;c<d;c++){g.attr=a[c];h=g.hitTest(f,j);if(h){h.isInstance=true;h.template=h.sprite;h.sprite=this;h.instance=a[c];h.index=c;return h}}g.attr=b;return h}});Ext.define("Ext.draw.sprite.Line",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.line",type:"line",inheritableStatics:{def:{processors:{fromX:"number",fromY:"number",toX:"number",toY:"number"},defaults:{fromX:0,fromY:0,toX:1,toY:1,strokeStyle:"black"},aliases:{x1:"fromX",y1:"fromY",x2:"toX",y2:"toY"}}},updateLineBBox:function(b,i,s,g,r,f){var o=this.attr,q=o.matrix,h=o.lineWidth/2,m,l,d,c,k,j,n;if(i){n=q.transformPoint([s,g]);s=n[0];g=n[1];n=q.transformPoint([r,f]);r=n[0];f=n[1]}m=Math.min(s,r);d=Math.max(s,r);l=Math.min(g,f);c=Math.max(g,f);var t=Math.atan2(d-m,c-l),a=Math.sin(t),e=Math.cos(t),k=h*e,j=h*a;m-=k;l-=j;d+=k;c+=j;b.x=m;b.y=l;b.width=d-m;b.height=c-l},updatePlainBBox:function(b){var a=this.attr;this.updateLineBBox(b,false,a.fromX,a.fromY,a.toX,a.toY)},updateTransformedBBox:function(b,c){var a=this.attr;this.updateLineBBox(b,true,a.fromX,a.fromY,a.toX,a.toY)},render:function(b,c){var a=this.attr,d=this.attr.matrix;d.toContext(c);c.beginPath();c.moveTo(a.fromX,a.fromY);c.lineTo(a.toX,a.toY);c.stroke()}});Ext.define("Ext.draw.sprite.Plus",{extend:"Ext.draw.sprite.Path",alias:"sprite.plus",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size/1.3,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c/2,",",e-c/2,"l",[0,-c,c,0,0,c,c,0,0,c,-c,0,0,c,-c,0,0,-c,-c,0,0,-c,"z"]))}});Ext.define("Ext.draw.sprite.Sector",{extend:"Ext.draw.sprite.Path",alias:"sprite.sector",type:"sector",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",margin:"number"},aliases:{rho:"endRho"},triggers:{centerX:"path,bbox",centerY:"path,bbox",startAngle:"path,bbox",endAngle:"path,bbox",startRho:"path,bbox",endRho:"path,bbox",margin:"path,bbox"},defaults:{centerX:0,centerY:0,startAngle:0,endAngle:0,startRho:0,endRho:150,margin:0,path:"M 0,0"}}},getMidAngle:function(){return this.midAngle||0},updatePath:function(j,h){var g=Math.min(h.startAngle,h.endAngle),c=Math.max(h.startAngle,h.endAngle),b=this.midAngle=(g+c)*0.5,d=h.margin,f=h.centerX,e=h.centerY,i=Math.min(h.startRho,h.endRho),a=Math.max(h.startRho,h.endRho);if(d){f+=d*Math.cos(b);e+=d*Math.sin(b)}j.moveTo(f+i*Math.cos(g),e+i*Math.sin(g));j.lineTo(f+a*Math.cos(g),e+a*Math.sin(g));j.arc(f,e,a,g,c,false);j.lineTo(f+i*Math.cos(c),e+i*Math.sin(c));j.arc(f,e,i,c,g,true)}});Ext.define("Ext.draw.sprite.Square",{extend:"Ext.draw.sprite.Rect",alias:"sprite.square",inheritableStatics:{def:{processors:{size:"number"},defaults:{size:4},triggers:{size:"size"},updaters:{size:function(a){var c=a.size,b=a.lineWidth/2;this.setAttributes({x:a.x-c-b,y:a.y-c,height:2*c,width:2*c})}}}}});Ext.define("Ext.draw.TextMeasurer",{singleton:true,requires:["Ext.util.TextMetrics"],measureDiv:null,measureCache:{},precise:Ext.isIE8,measureDivTpl:{tag:"div",style:{overflow:"hidden",position:"relative","float":"left",width:0,height:0},children:{tag:"div",style:{display:"block",position:"absolute",x:-100000,y:-100000,padding:0,margin:0,"z-index":-100000,"white-space":"nowrap"}}},actualMeasureText:function(g,b){var e=Ext.draw.TextMeasurer,f=e.measureDiv,a=100000,c;if(!f){var d=Ext.Element.create({style:{overflow:"hidden",position:"relative","float":"left",width:0,height:0}});e.measureDiv=f=Ext.Element.create({style:{position:"absolute",x:a,y:a,"z-index":-a,"white-space":"nowrap",display:"block",padding:0,margin:0}});Ext.getBody().appendChild(d);d.appendChild(f)}if(b){f.setStyle({font:b,lineHeight:"normal"})}f.setText("("+g+")");c=f.getSize();f.setText("()");c.width-=f.getSize().width;return c},measureTextSingleLine:function(h,d){if(this.precise){return this.preciseMeasureTextSingleLine(h,d)}h=h.toString();var a=this.measureCache,g=h.split(""),c=0,j=0,l,b,e,f,k;if(!a[d]){a[d]={}}a=a[d];if(a[h]){return a[h]}for(e=0,f=g.length;e<f;e++){b=g[e];if(!(l=a[b])){k=this.actualMeasureText(b,d);l=a[b]=k}c+=l.width;j=Math.max(j,l.height)}return a[h]={width:c,height:j}},preciseMeasureTextSingleLine:function(c,a){c=c.toString();var b=this.measureDiv||(this.measureDiv=Ext.getBody().createChild(this.measureDivTpl).down("div"));b.setStyle({font:a||""});return Ext.util.TextMetrics.measure(b,c)},measureText:function(e,b){var h=e.split("\n"),d=h.length,f=0,a=0,j,c,g;if(d===1){return this.measureTextSingleLine(e,b)}g=[];for(c=0;c<d;c++){j=this.measureTextSingleLine(h[c],b);g.push(j);f+=j.height;a=Math.max(a,j.width)}return{width:a,height:f,sizes:g}}});Ext.define("Ext.draw.sprite.Text",function(){var d={"xx-small":true,"x-small":true,small:true,medium:true,large:true,"x-large":true,"xx-large":true};var b={normal:true,bold:true,bolder:true,lighter:true,100:true,200:true,300:true,400:true,500:true,600:true,700:true,800:true,900:true};var a={start:"start",left:"start",center:"center",middle:"center",end:"end",right:"end"};var c={top:"top",hanging:"hanging",middle:"middle",center:"middle",alphabetic:"alphabetic",ideographic:"ideographic",bottom:"bottom"};return{extend:"Ext.draw.sprite.Sprite",requires:["Ext.draw.TextMeasurer","Ext.draw.Color"],alias:"sprite.text",type:"text",lineBreakRe:/\r?\n/g,inheritableStatics:{def:{animationProcessors:{text:"text"},processors:{x:"number",y:"number",text:"string",fontSize:function(e){if(Ext.isNumber(+e)){return e+"px"}else{if(e.match(Ext.dom.Element.unitRe)){return e}else{if(e in d){return e}}}},fontStyle:"enums(,italic,oblique)",fontVariant:"enums(,small-caps)",fontWeight:function(e){if(e in b){return String(e)}else{return""}},fontFamily:"string",textAlign:function(e){return a[e]||"center"},textBaseline:function(e){return c[e]||"alphabetic"},font:"string"},aliases:{"font-size":"fontSize","font-family":"fontFamily","font-weight":"fontWeight","font-variant":"fontVariant","text-anchor":"textAlign"},defaults:{fontStyle:"",fontVariant:"",fontWeight:"",fontSize:"10px",fontFamily:"sans-serif",font:"10px sans-serif",textBaseline:"alphabetic",textAlign:"start",strokeStyle:"rgba(0, 0, 0, 0)",fillStyle:"#000",x:0,y:0,text:""},triggers:{fontStyle:"fontX,bbox",fontVariant:"fontX,bbox",fontWeight:"fontX,bbox",fontSize:"fontX,bbox",fontFamily:"fontX,bbox",font:"font,bbox,canvas",textBaseline:"bbox",textAlign:"bbox",x:"bbox",y:"bbox",text:"bbox"},updaters:{fontX:"makeFontShorthand",font:"parseFontShorthand"}}},constructor:function(e){if(e&&e.font){e=Ext.clone(e);for(var f in e){if(f!=="font"&&f.indexOf("font")===0){delete e[f]}}}Ext.draw.sprite.Sprite.prototype.constructor.call(this,e)},fontValuesMap:{italic:"fontStyle",oblique:"fontStyle","small-caps":"fontVariant",bold:"fontWeight",bolder:"fontWeight",lighter:"fontWeight","100":"fontWeight","200":"fontWeight","300":"fontWeight","400":"fontWeight","500":"fontWeight","600":"fontWeight","700":"fontWeight","800":"fontWeight","900":"fontWeight","xx-small":"fontSize","x-small":"fontSize",small:"fontSize",medium:"fontSize",large:"fontSize","x-large":"fontSize","xx-large":"fontSize"},makeFontShorthand:function(e){var f=[];if(e.fontStyle){f.push(e.fontStyle)}if(e.fontVariant){f.push(e.fontVariant)}if(e.fontWeight){f.push(e.fontWeight)}if(e.fontSize){f.push(e.fontSize)}if(e.fontFamily){f.push(e.fontFamily)}this.setAttributes({font:f.join(" ")},true)},parseFontShorthand:function(j){var m=j.font,k=m.length,l={},n=this.fontValuesMap,e=0,i,g,f,h;while(e<k&&i!==-1){i=m.indexOf(" ",e);if(i<0){f=m.substr(e)}else{if(i>e){f=m.substr(e,i-e)}else{continue}}g=f.indexOf("/");if(g>0){f=f.substr(0,g)}else{if(g===0){continue}}if(f!=="normal"&&f!=="inherit"){h=n[f];if(h){l[h]=f}else{if(f.match(Ext.dom.Element.unitRe)){l.fontSize=f}else{l.fontFamily=m.substr(e);break}}}e=i+1}if(!l.fontStyle){l.fontStyle=""}if(!l.fontVariant){l.fontVariant=""}if(!l.fontWeight){l.fontWeight=""}this.setAttributes(l,true)},fontProperties:{fontStyle:true,fontVariant:true,fontWeight:true,fontSize:true,fontFamily:true},setAttributes:function(g,i,e){var f,h;if(g&&g.font){h={};for(f in g){if(!(f in this.fontProperties)){h[f]=g[f]}}g=h}this.callParent([g,i,e])},getBBox:function(g){var h=this,f=h.attr.bbox.plain,e=h.getSurface();if(f.dirty){h.updatePlainBBox(f);f.dirty=false}if(e.getInherited().rtl&&e.getFlipRtlText()){h.updatePlainBBox(f,true)}return h.callParent([g])},rtlAlignments:{start:"end",center:"center",end:"start"},updatePlainBBox:function(k,B){var C=this,w=C.attr,o=w.x,n=w.y,q=[],t=w.font,r=w.text,s=w.textBaseline,l=w.textAlign,u=(B&&C.oldSize)?C.oldSize:(C.oldSize=Ext.draw.TextMeasurer.measureText(r,t)),z=C.getSurface(),p=z.getInherited().rtl,v=p&&z.getFlipRtlText(),h=z.getRect(),f=u.sizes,g=u.height,j=u.width,m=f?f.length:0,e,A=0;switch(s){case"hanging":case"top":break;case"ideographic":case"bottom":n-=g;break;case"alphabetic":n-=g*0.8;break;case"middle":n-=g*0.5;break}if(v){o=h[2]-h[0]-o;l=C.rtlAlignments[l]}switch(l){case"start":if(p){for(;A<m;A++){e=f[A].width;q.push(-(j-e))}}break;case"end":o-=j;if(p){break}for(;A<m;A++){e=f[A].width;q.push(j-e)}break;case"center":o-=j*0.5;for(;A<m;A++){e=f[A].width;q.push((p?-1:1)*(j-e)*0.5)}break}w.textAlignOffsets=q;k.x=o;k.y=n;k.width=j;k.height=g},setText:function(e){this.setAttributes({text:e},true)},render:function(e,q,k){var h=this,g=h.attr,p=Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),o=h.getBBox(true),s=g.textAlignOffsets,m=Ext.draw.Color.RGBA_NONE,l,j,f,r,n;if(g.text.length===0){return}r=g.text.split(h.lineBreakRe);n=o.height/r.length;l=g.bbox.plain.x;j=g.bbox.plain.y+n*0.78;p.toContext(q);if(e.getInherited().rtl){l+=g.bbox.plain.width}for(f=0;f<r.length;f++){if(q.fillStyle!==m){q.fillText(r[f],l+(s[f]||0),j+n*f)}if(q.strokeStyle!==m){q.strokeText(r[f],l+(s[f]||0),j+n*f)}}}}});Ext.define("Ext.draw.sprite.Tick",{extend:"Ext.draw.sprite.Line",alias:"sprite.tick",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"tick",y:"tick",size:"tick"},updaters:{tick:function(b){var d=b.size*1.5,c=b.lineWidth/2,a=b.x,e=b.y;this.setAttributes({fromX:a-c,fromY:e-d,toX:a-c,toY:e+d})}}}}});Ext.define("Ext.draw.sprite.Triangle",{extend:"Ext.draw.sprite.Path",alias:"sprite.triangle",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*2.2,a=b.x,e=b.y;d.fromSvgString("M".concat(a,",",e,"m0-",c*0.58,"l",c*0.5,",",c*0.87,"-",c,",0z"))}});Ext.define("Ext.draw.gradient.Linear",{extend:"Ext.draw.gradient.Gradient",requires:["Ext.draw.Color"],type:"linear",config:{degrees:0,radians:0},applyRadians:function(b,a){if(Ext.isNumber(b)){return b}return a},applyDegrees:function(b,a){if(Ext.isNumber(b)){return b}return a},updateRadians:function(a){this.setDegrees(Ext.draw.Draw.degrees(a))},updateDegrees:function(a){this.setRadians(Ext.draw.Draw.rad(a))},generateGradient:function(q,o){var c=this.getRadians(),p=Math.cos(c),j=Math.sin(c),m=o.width,f=o.height,d=o.x+m*0.5,b=o.y+f*0.5,n=this.getStops(),g=n.length,k,a,e;if(Ext.isNumber(d+b)&&f>0&&m>0){a=(Math.sqrt(f*f+m*m)*Math.abs(Math.cos(c-Math.atan(f/m))))/2;k=q.createLinearGradient(d+p*a,b+j*a,d-p*a,b-j*a);for(e=0;e<g;e++){k.addColorStop(n[e].offset,n[e].color)}return k}return Ext.draw.Color.NONE}});Ext.define("Ext.draw.gradient.Radial",{extend:"Ext.draw.gradient.Gradient",type:"radial",config:{start:{x:0,y:0,r:0},end:{x:0,y:0,r:1}},applyStart:function(a,b){if(!b){return a}var c={x:b.x,y:b.y,r:b.r};if("x" in a){c.x=a.x}else{if("centerX" in a){c.x=a.centerX}}if("y" in a){c.y=a.y}else{if("centerY" in a){c.y=a.centerY}}if("r" in a){c.r=a.r}else{if("radius" in a){c.r=a.radius}}return c},applyEnd:function(b,a){if(!a){return b}var c={x:a.x,y:a.y,r:a.r};if("x" in b){c.x=b.x}else{if("centerX" in b){c.x=b.centerX}}if("y" in b){c.y=b.y}else{if("centerY" in b){c.y=b.centerY}}if("r" in b){c.r=b.r}else{if("radius" in b){c.r=b.radius}}return c},generateGradient:function(n,m){var a=this.getStart(),b=this.getEnd(),k=m.width*0.5,d=m.height*0.5,j=m.x+k,f=m.y+d,g=n.createRadialGradient(j+a.x*k,f+a.y*d,a.r*Math.max(k,d),j+b.x*k,f+b.y*d,b.r*Math.max(k,d)),l=this.getStops(),e=l.length,c;for(c=0;c<e;c++){g.addColorStop(l[c].offset,l[c].color)}return g}});Ext.define("Ext.draw.Surface",{extend:"Ext.draw.SurfaceBase",xtype:"surface",requires:["Ext.draw.sprite.*","Ext.draw.gradient.*","Ext.draw.sprite.AttributeDefinition","Ext.draw.Matrix","Ext.draw.Draw"],uses:["Ext.draw.engine.Canvas"],devicePixelRatio:window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI,deprecated:{"5.1.0":{statics:{methods:{stableSort:function(a){return Ext.Array.sort(a,function(d,c){return d.attr.zIndex-c.attr.zIndex})}}}}},config:{cls:Ext.baseCSSPrefix+"surface",rect:null,background:null,items:[],dirty:false,flipRtlText:false},isSurface:true,isPendingRenderFrame:false,dirtyPredecessorCount:0,constructor:function(a){var b=this;b.predecessors=[];b.successors=[];b.map={};b.callParent([a]);b.matrix=new Ext.draw.Matrix();b.inverseMatrix=b.matrix.inverse()},roundPixel:function(a){return Math.round(this.devicePixelRatio*a)/this.devicePixelRatio},waitFor:function(a){var b=this,c=b.predecessors;if(!Ext.Array.contains(c,a)){c.push(a);a.successors.push(b);if(a.getDirty()){b.dirtyPredecessorCount++}}},updateDirty:function(d){var c=this.successors,e=c.length,b=0,a;for(;b<e;b++){a=c[b];if(d){a.dirtyPredecessorCount++;a.setDirty(true)}else{a.dirtyPredecessorCount--;if(a.dirtyPredecessorCount===0&&a.isPendingRenderFrame){a.renderFrame()}}}},applyBackground:function(a,b){this.setDirty(true);if(Ext.isString(a)){a={fillStyle:a}}return Ext.factory(a,Ext.draw.sprite.Rect,b)},applyRect:function(a,b){if(b&&a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]){return}if(Ext.isArray(a)){return[a[0],a[1],a[2],a[3]]}else{if(Ext.isObject(a)){return[a.x||a.left,a.y||a.top,a.width||(a.right-a.left),a.height||(a.bottom-a.top)]}}},updateRect:function(i){var h=this,c=i[0],f=i[1],g=c+i[2],a=f+i[3],e=h.getBackground(),d=h.element;d.setLocalXY(Math.floor(c),Math.floor(f));d.setSize(Math.ceil(g-Math.floor(c)),Math.ceil(a-Math.floor(f)));if(e){e.setAttributes({x:0,y:0,width:Math.ceil(g-Math.floor(c)),height:Math.ceil(a-Math.floor(f))})}h.setDirty(true)},resetTransform:function(){this.matrix.set(1,0,0,1,0,0);this.inverseMatrix.set(1,0,0,1,0,0);this.setDirty(true)},get:function(a){return this.map[a]||this.getItems()[a]},add:function(){var g=this,e=Array.prototype.slice.call(arguments),j=Ext.isArray(e[0]),a=g.map,c=[],f,k,h,b,d;f=Ext.Array.clean(j?e[0]:e);if(!f.length){return c}for(b=0,d=f.length;b<d;b++){k=f[b];h=null;if(k.isSprite&&!a[k.getId()]){h=k}else{if(!a[k.id]){h=this.createItem(k)}}if(h){a[h.getId()]=h;c.push(h);h.setParent(g);h.setSurface(g);g.onAdd(h)}}f=g.getItems();if(f){f.push.apply(f,c)}g.dirtyZIndex=true;g.setDirty(true);if(!j&&c.length===1){return c[0]}else{return c}},onAdd:Ext.emptyFn,remove:function(a,c){var b=this,e,d;if(a){if(a.charAt){a=b.map[a]}if(!a||!a.isSprite){return null}if(a.isDestroyed||a.isDestroying){return a}e=a.getId();d=b.map[e];delete b.map[e];if(c){a.destroy()}if(!d){return a}a.setParent(null);a.setSurface(null);Ext.Array.remove(b.getItems(),a);b.dirtyZIndex=true;b.setDirty(true)}return a||null},removeAll:function(d){var a=this.getItems(),b=a.length-1,c;if(d){for(;b>=0;b--){a[b].destroy()}}else{for(;b>=0;b--){c=a[b];c.setParent(null);c.setSurface(null)}}a.length=0;this.map={};this.dirtyZIndex=true},applyItems:function(a){if(this.getItems()){this.removeAll(true)}return Ext.Array.from(this.add(a))},createItem:function(a){return Ext.create(a.xclass||"sprite."+a.type,a)},getBBox:function(f,b){var f=Ext.Array.from(f),c=Infinity,h=-Infinity,g=Infinity,a=-Infinity,j,k,d,e;for(d=0,e=f.length;d<e;d++){j=f[d];k=j.getBBox(b);if(c>k.x){c=k.x}if(h<k.x+k.width){h=k.x+k.width}if(g>k.y){g=k.y}if(a<k.y+k.height){a=k.y+k.height}}return{x:c,y:g,width:h-c,height:a-g}},emptyRect:[0,0,0,0],getEventXY:function(d){var g=this,f=g.getInherited().rtl,c=d.getXY(),a=g.getOwnerBody(),i=a.getXY(),h=g.getRect()||g.emptyRect,j=[],b;if(f){b=a.getWidth();j[0]=i[0]-c[0]-h[0]+b}else{j[0]=c[0]-i[0]-h[0]}j[1]=c[1]-i[1]-h[1];return j},clear:Ext.emptyFn,orderByZIndex:function(){var d=this,a=d.getItems(),e=false,b,c;if(d.getDirty()){for(b=0,c=a.length;b<c;b++){if(a[b].attr.dirtyZIndex){e=true;break}}if(e){Ext.Array.sort(a,function(g,f){return g.attr.zIndex-f.attr.zIndex});this.setDirty(true)}for(b=0,c=a.length;b<c;b++){a[b].attr.dirtyZIndex=false}}},repaint:function(){var a=this;a.repaint=Ext.emptyFn;Ext.defer(function(){delete a.repaint;a.element.repaint()},1)},renderFrame:function(){var g=this;if(!g.element){return}if(g.dirtyPredecessorCount>0){g.isPendingRenderFrame=true;return}var f=g.getRect(),c=g.getBackground(),a=g.getItems(),e,b,d;if(!f){return}g.orderByZIndex();if(g.getDirty()){g.clear();g.clearTransform();if(c){g.renderSprite(c)}for(b=0,d=a.length;b<d;b++){e=a[b];if(g.renderSprite(e)===false){return}e.attr.textPositionCount=g.textPosition}g.setDirty(false)}},renderSprite:Ext.emptyFn,clearTransform:Ext.emptyFn,destroy:function(){var a=this;a.removeAll(true);a.predecessors=null;a.successors=null;a.callParent()}});Ext.define("Ext.draw.overrides.Surface",{override:"Ext.draw.Surface",hitTest:function(b,c){var f=this,g=f.getItems(),e,d,a;c=c||Ext.draw.sprite.Sprite.defaultHitTestOptions;for(e=g.length-1;e>=0;e--){d=g[e];if(d.hitTest){a=d.hitTest(b,c);if(a){return a}}}return null},hitTestEvent:function(b,a){var c=this.getEventXY(b);return this.hitTest(c,a)}});Ext.define("Ext.draw.engine.SvgContext",{requires:["Ext.draw.Color"],toSave:["strokeOpacity","strokeStyle","fillOpacity","fillStyle","globalAlpha","lineWidth","lineCap","lineJoin","lineDash","lineDashOffset","miterLimit","shadowOffsetX","shadowOffsetY","shadowBlur","shadowColor","globalCompositeOperation","position","fillGradient","strokeGradient"],strokeOpacity:1,strokeStyle:"none",fillOpacity:1,fillStyle:"none",lineDash:[],lineDashOffset:0,globalAlpha:1,lineWidth:1,lineCap:"butt",lineJoin:"miter",miterLimit:10,shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0,shadowColor:"none",globalCompositeOperation:"src",urlStringRe:/^url\(#([\w\-]+)\)$/,constructor:function(a){this.surface=a;this.state=[];this.matrix=new Ext.draw.Matrix();this.path=null;this.clear()},clear:function(){this.group=this.surface.mainGroup;this.position=0;this.path=null},getElement:function(a){return this.surface.getSvgElement(this.group,a,this.position++)},removeElement:function(d){var d=Ext.fly(d),h,g,b,f,a,e,c;if(!d){return}if(d.dom.tagName==="g"){a=d.dom.gradients;for(c in a){a[c].destroy()}}else{h=d.getAttribute("fill");g=d.getAttribute("stroke");b=h&&h.match(this.urlStringRe);f=g&&g.match(this.urlStringRe);if(b&&b[1]){e=Ext.fly(b[1]);if(e){e.destroy()}}if(f&&f[1]){e=Ext.fly(f[1]);if(e){e.destroy()}}}d.destroy()},save:function(){var c=this.toSave,e={},d=this.getElement("g"),b,a;for(a=0;a<c.length;a++){b=c[a];if(b in this){e[b]=this[b]}}this.position=0;e.matrix=this.matrix.clone();this.state.push(e);this.group=d;return d},restore:function(){var d=this.toSave,e=this.state.pop(),c=this.group.dom.childNodes,b,a;while(c.length>this.position){this.removeElement(c[c.length-1])}for(a=0;a<d.length;a++){b=d[a];if(b in e){this[b]=e[b]}else{delete this[b]}}this.setTransform.apply(this,e.matrix.elements);this.group=this.group.getParent()},transform:function(f,b,e,g,d,c){if(this.path){var a=Ext.draw.Matrix.fly([f,b,e,g,d,c]).inverse();this.path.transform(a)}this.matrix.append(f,b,e,g,d,c)},setTransform:function(e,a,d,f,c,b){if(this.path){this.path.transform(this.matrix)}this.matrix.reset();this.transform(e,a,d,f,c,b)},scale:function(a,b){this.transform(a,0,0,b,0,0)},rotate:function(d){var c=Math.cos(d),a=Math.sin(d),b=-Math.sin(d),e=Math.cos(d);this.transform(c,a,b,e,0,0)},translate:function(a,b){this.transform(1,0,0,1,a,b)},setGradientBBox:function(a){this.bbox=a},beginPath:function(){this.path=new Ext.draw.Path()},moveTo:function(a,b){if(!this.path){this.beginPath()}this.path.moveTo(a,b);this.path.element=null},lineTo:function(a,b){if(!this.path){this.beginPath()}this.path.lineTo(a,b);this.path.element=null},rect:function(b,d,c,a){this.moveTo(b,d);this.lineTo(b+c,d);this.lineTo(b+c,d+a);this.lineTo(b,d+a);this.closePath()},strokeRect:function(b,d,c,a){this.beginPath();this.rect(b,d,c,a);this.stroke()},fillRect:function(b,d,c,a){this.beginPath();this.rect(b,d,c,a);this.fill()},closePath:function(){if(!this.path){this.beginPath()}this.path.closePath();this.path.element=null},arcSvg:function(d,a,f,g,c,b,e){if(!this.path){this.beginPath()}this.path.arcSvg(d,a,f,g,c,b,e);this.path.element=null},arc:function(b,f,a,d,c,e){if(!this.path){this.beginPath()}this.path.arc(b,f,a,d,c,e);this.path.element=null},ellipse:function(a,h,g,f,d,c,b,e){if(!this.path){this.beginPath()}this.path.ellipse(a,h,g,f,d,c,b,e);this.path.element=null},arcTo:function(b,e,a,d,g,f,c){if(!this.path){this.beginPath()}this.path.arcTo(b,e,a,d,g,f,c);this.path.element=null},bezierCurveTo:function(d,f,b,e,a,c){if(!this.path){this.beginPath()}this.path.bezierCurveTo(d,f,b,e,a,c);this.path.element=null},strokeText:function(d,a,e){d=String(d);if(this.strokeStyle){var b=this.getElement("text"),c=this.surface.getSvgElement(b,"tspan",0);this.surface.setElementAttributes(b,{x:a,y:e,transform:this.matrix.toSvg(),stroke:this.strokeStyle,fill:"none",opacity:this.globalAlpha,"stroke-opacity":this.strokeOpacity,style:"font: "+this.font,"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset});if(this.lineDash.length){this.surface.setElementAttributes(b,{"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset})}if(c.dom.firstChild){c.dom.removeChild(c.dom.firstChild)}this.surface.setElementAttributes(c,{"alignment-baseline":"alphabetic"});c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))}},fillText:function(d,a,e){d=String(d);if(this.fillStyle){var b=this.getElement("text"),c=this.surface.getSvgElement(b,"tspan",0);this.surface.setElementAttributes(b,{x:a,y:e,transform:this.matrix.toSvg(),fill:this.fillStyle,opacity:this.globalAlpha,"fill-opacity":this.fillOpacity,style:"font: "+this.font});if(c.dom.firstChild){c.dom.removeChild(c.dom.firstChild)}this.surface.setElementAttributes(c,{"alignment-baseline":"alphabetic"});c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))}},drawImage:function(c,k,i,l,e,p,n,a,g){var f=this,d=f.getElement("image"),j=k,h=i,b=typeof l==="undefined"?c.width:l,m=typeof e==="undefined"?c.height:e,o=null;if(typeof g!=="undefined"){o=k+" "+i+" "+l+" "+e;j=p;h=n;b=a;m=g}d.dom.setAttributeNS("http://www.w3.org/1999/xlink","href",c.src);f.surface.setElementAttributes(d,{viewBox:o,x:j,y:h,width:b,height:m,opacity:f.globalAlpha,transform:f.matrix.toSvg()})},fill:function(){if(!this.path){return}if(this.fillStyle){var c,a=this.fillGradient,d=this.bbox,b=this.path.element;if(!b){c=this.path.toString();b=this.path.element=this.getElement("path");this.surface.setElementAttributes(b,{d:c,transform:this.matrix.toSvg()})}this.surface.setElementAttributes(b,{fill:a&&d?a.generateGradient(this,d):this.fillStyle,"fill-opacity":this.fillOpacity*this.globalAlpha})}},stroke:function(){if(!this.path){return}if(this.strokeStyle){var c,b=this.strokeGradient,d=this.bbox,a=this.path.element;if(!a||!this.path.svgString){c=this.path.toString();if(!c){return}a=this.path.element=this.getElement("path");this.surface.setElementAttributes(a,{fill:"none",d:c,transform:this.matrix.toSvg()})}this.surface.setElementAttributes(a,{stroke:b&&d?b.generateGradient(this,d):this.strokeStyle,"stroke-linecap":this.lineCap,"stroke-linejoin":this.lineJoin,"stroke-width":this.lineWidth,"stroke-opacity":this.strokeOpacity*this.globalAlpha,"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset});if(this.lineDash.length){this.surface.setElementAttributes(a,{"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset})}}},fillStroke:function(a,e){var b=this,d=b.fillStyle,g=b.strokeStyle,c=b.fillOpacity,f=b.strokeOpacity;if(e===undefined){e=a.transformFillStroke}if(!e){a.inverseMatrix.toContext(b)}if(d&&c!==0){b.fill()}if(g&&f!==0){b.stroke()}},appendPath:function(a){this.path=a.clone()},setLineDash:function(a){this.lineDash=a},getLineDash:function(){return this.lineDash},createLinearGradient:function(d,g,b,e){var f=this,c=f.surface.getNextDef("linearGradient"),a=f.group.dom.gradients||(f.group.dom.gradients={}),h;f.surface.setElementAttributes(c,{x1:d,y1:g,x2:b,y2:e,gradientUnits:"userSpaceOnUse"});h=new Ext.draw.engine.SvgContext.Gradient(f,f.surface,c);a[c.dom.id]=h;return h},createRadialGradient:function(b,j,d,a,i,c){var g=this,e=g.surface.getNextDef("radialGradient"),f=g.group.dom.gradients||(g.group.dom.gradients={}),h;g.surface.setElementAttributes(e,{fx:b,fy:j,cx:a,cy:i,r:c,gradientUnits:"userSpaceOnUse"});h=new Ext.draw.engine.SvgContext.Gradient(g,g.surface,e,d/c);f[e.dom.id]=h;return h}});Ext.define("Ext.draw.engine.SvgContext.Gradient",{statics:{map:{}},constructor:function(c,a,d,b){var f=this.statics().map,e;e=f[d.dom.id];if(e){e.element=null}f[d.dom.id]=this;this.ctx=c;this.surface=a;this.element=d;this.position=0;this.compression=b||0},addColorStop:function(d,b){var c=this.surface.getSvgElement(this.element,"stop",this.position++),a=this.compression;this.surface.setElementAttributes(c,{offset:(((1-a)*d+a)*100).toFixed(2)+"%","stop-color":b,"stop-opacity":Ext.draw.Color.fly(b).a.toFixed(15)})},toString:function(){var a=this.element.dom.childNodes;while(a.length>this.position){Ext.fly(a[a.length-1]).destroy()}return"url(#"+this.element.getId()+")"},destroy:function(){var b=this.statics().map,a=this.element;if(a&&a.dom){delete b[a.dom.id];a.destroy()}this.callParent()}});Ext.define("Ext.draw.engine.Svg",{extend:"Ext.draw.Surface",requires:["Ext.draw.engine.SvgContext"],statics:{BBoxTextCache:{}},config:{highPrecision:false},getElementConfig:function(){return{reference:"element",style:{position:"absolute"},children:[{reference:"innerElement",style:{width:"100%",height:"100%",position:"relative"},children:[{tag:"svg",reference:"svgElement",namespace:"http://www.w3.org/2000/svg",width:"100%",height:"100%",version:1.1}]}]}},constructor:function(a){var b=this;b.callParent([a]);b.mainGroup=b.createSvgNode("g");b.defElement=b.createSvgNode("defs");b.svgElement.appendChild(b.mainGroup);b.svgElement.appendChild(b.defElement);b.ctx=new Ext.draw.engine.SvgContext(b)},createSvgNode:function(a){var b=document.createElementNS("http://www.w3.org/2000/svg",a);return Ext.get(b)},getSvgElement:function(d,b,a){var c;if(d.dom.childNodes.length>a){c=d.dom.childNodes[a];if(c.tagName===b){return Ext.get(c)}else{Ext.destroy(c)}}c=Ext.get(this.createSvgNode(b));if(a===0){d.insertFirst(c)}else{c.insertAfter(Ext.fly(d.dom.childNodes[a-1]))}c.cache={};return c},setElementAttributes:function(d,b){var f=d.dom,a=d.cache,c,e;for(c in b){e=b[c];if(a[c]!==e){a[c]=e;f.setAttribute(c,e)}}},getNextDef:function(a){return this.getSvgElement(this.defElement,a,this.defPosition++)},clearTransform:function(){var a=this;a.mainGroup.set({transform:a.matrix.toSvg()})},clear:function(){this.ctx.clear();this.defPosition=0},renderSprite:function(b){var d=this,c=d.getRect(),a=d.ctx;if(b.attr.hidden||b.attr.globalAlpha===0){a.save();a.restore();return}b.element=a.save();b.preRender(this);b.useAttributes(a,c);if(false===b.render(this,a,[0,0,c[2],c[3]])){return false}b.setDirty(false);a.restore()},flatten:function(e,b){var c='<?xml version="1.0" standalone="yes"?>',f=Ext.getClassName(this),a,g,d;c+='<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="'+e.width+'" height="'+e.height+'">';for(d=0;d<b.length;d++){a=b[d];if(Ext.getClassName(a)!==f){continue}g=a.getRect();c+='<g transform="translate('+g[0]+","+g[1]+')">';c+=this.serializeNode(a.svgElement.dom);c+="</g>"}c+="</svg>";return{data:"data:image/svg+xml;utf8,"+encodeURIComponent(c),type:"svg"}},serializeNode:function(d){var b="",c,f,a,e;if(d.nodeType===document.TEXT_NODE){return d.nodeValue}b+="<"+d.nodeName;if(d.attributes.length){for(c=0,f=d.attributes.length;c<f;c++){a=d.attributes[c];b+=" "+a.name+'="'+a.value+'"'}}b+=">";if(d.childNodes&&d.childNodes.length){for(c=0,f=d.childNodes.length;c<f;c++){e=d.childNodes[c];b+=this.serializeNode(e)}}b+="</"+d.nodeName+">";return b},destroy:function(){var a=this;a.ctx.destroy();a.mainGroup.destroy();delete a.mainGroup;delete a.ctx;a.callParent()},remove:function(a,b){if(a&&a.element){if(this.ctx){this.ctx.removeElement(a.element)}else{a.element.destroy()}a.element=null}this.callParent(arguments)}});Ext.draw||(Ext.draw={});Ext.draw.engine||(Ext.draw.engine={});Ext.draw.engine.excanvas=true;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){Ext.onReady(function(){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.lineDash=j.lineDash;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.lineDash=[];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(an,j){var ah,Z,aj,ar,al,ak,ao,av;var ai=an.runtimeStyle.width;var am=an.runtimeStyle.height;an.runtimeStyle.width="auto";an.runtimeStyle.height="auto";var ag=an.width;var aq=an.height;an.runtimeStyle.width=ai;an.runtimeStyle.height=am;if(arguments.length==3){ah=arguments[1];Z=arguments[2];al=ak=0;ao=aj=ag;av=ar=aq}else{if(arguments.length==5){ah=arguments[1];Z=arguments[2];aj=arguments[3];ar=arguments[4];al=ak=0;ao=ag;av=aq}else{if(arguments.length==9){al=arguments[1];ak=arguments[2];ao=arguments[3];av=arguments[4];ah=arguments[5];Z=arguments[6];aj=arguments[7];ar=arguments[8]}else{throw Error("Invalid number of arguments")}}}var au=V(this,ah,Z);var at=[];var i=10;var p=10;var ap=this.m_;at.push(" <g_vml_:group",' coordsize="',d*i,",",d*p,'"',' coordorigin="0,0"',' style="width:',n(i*ap[0][0]),"px;height:",n(p*ap[1][1]),"px;position:absolute;","top:",n(au.y/d),"px;left:",n(au.x/d),"px; rotation:",n(Math.atan(ap[0][1]/ap[1][1])*180/Math.PI),";");at.push('" >','<g_vml_:image src="',an.src,'"',' style="width:',d*aj,"px;"," height:",d*ar,'px"',' cropleft="',al/ag,'"',' croptop="',ak/aq,'"',' cropright="',(ag-al-ao)/ag,'"',' cropbottom="',(aq-ak-av)/aq,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",at.join(""))};q.setLineDash=function(i){if(i.length===1){i=i.slice();i[1]=i[0]}this.lineDash=i};q.getLineDash=function(){return this.lineDash};q.stroke=function(ak){var ai=[];var m=10;var al=10;ai.push("<g_vml_:shape",' filled="',!!ak,'"',' style="position:absolute;width:',m,"px;height:",al,'px;left:0px;top:0px;"',' coordorigin="0,0"',' coordsize="',d*m,",",d*al,'"',' stroked="',!ak,'"',' path="');var Z={x:null,y:null};var aj={x:null,y:null};for(var ag=0;ag<this.currentPath_.length;ag++){var j=this.currentPath_[ag];var ah;switch(j.type){case"moveTo":ah=j;ai.push(" m ",n(j.x),",",n(j.y));break;case"lineTo":ai.push(" l ",n(j.x),",",n(j.y));break;case"close":ai.push(" x ");j=null;break;case"bezierCurveTo":ai.push(" c ",n(j.cp1x),",",n(j.cp1y),",",n(j.cp2x),",",n(j.cp2y),",",n(j.x),",",n(j.y));break;case"at":case"wa":ai.push(" ",j.type," ",n(j.x-this.arcScaleX_*j.radius),",",n(j.y-this.arcScaleY_*j.radius)," ",n(j.x+this.arcScaleX_*j.radius),",",n(j.y+this.arcScaleY_*j.radius)," ",n(j.xStart),",",n(j.yStart)," ",n(j.xEnd),",",n(j.yEnd));break}if(j){if(Z.x==null||j.x<Z.x){Z.x=j.x}if(aj.x==null||j.x>aj.x){aj.x=j.x}if(Z.y==null||j.y<Z.y){Z.y=j.y}if(aj.y==null||j.y>aj.y){aj.y=j.y}}}ai.push(' ">');if(!ak){w(this,ai)}else{G(this,ai,Z,aj)}ai.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",ai.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,'"',' dashstyle="',m.lineDash.join(" "),'"',' 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/3;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;left:0px;top:0px;">');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})()}Ext.define("Ext.draw.engine.Canvas",{extend:"Ext.draw.Surface",requires:["Ext.draw.engine.excanvas","Ext.draw.Animator","Ext.draw.Color"],config:{highPrecision:false},statics:{contextOverrides:{setGradientBBox:function(a){this.bbox=a},fill:function(){var c=this.fillStyle,a=this.fillGradient,b=this.fillOpacity,d=this.globalAlpha,e=this.bbox;if(c!==Ext.draw.Color.RGBA_NONE&&b!==0){if(a&&e){this.fillStyle=a.generateGradient(this,e)}if(b!==1){this.globalAlpha=d*b}this.$fill();if(b!==1){this.globalAlpha=d}if(a&&e){this.fillStyle=c}}},stroke:function(){var e=this.strokeStyle,c=this.strokeGradient,a=this.strokeOpacity,b=this.globalAlpha,d=this.bbox;if(e!==Ext.draw.Color.RGBA_NONE&&a!==0){if(c&&d){this.strokeStyle=c.generateGradient(this,d)}if(a!==1){this.globalAlpha=b*a}this.$stroke();if(a!==1){this.globalAlpha=b}if(c&&d){this.strokeStyle=e}}},fillStroke:function(d,e){var j=this,i=this.fillStyle,h=this.fillOpacity,f=this.strokeStyle,c=this.strokeOpacity,b=j.shadowColor,a=j.shadowBlur,g=Ext.draw.Color.RGBA_NONE;if(e===undefined){e=d.transformFillStroke}if(!e){d.inverseMatrix.toContext(j)}if(i!==g&&h!==0){j.fill();j.shadowColor=g;j.shadowBlur=0}if(f!==g&&c!==0){j.stroke()}j.shadowColor=b;j.shadowBlur=a},setLineDash:function(a){if(this.$setLineDash){this.$setLineDash(a)}},getLineDash:function(){if(this.$getLineDash){return this.$getLineDash()}},ellipse:function(g,e,c,a,j,b,f,d){var i=Math.cos(j),h=Math.sin(j);this.transform(i*c,h*c,-h*a,i*a,g,e);this.arc(0,0,1,b,f,d);this.transform(i/c,-h/a,h/c,i/a,-(i*g+h*e)/c,(h*g-i*e)/a)},appendPath:function(f){var e=this,c=0,b=0,a=f.commands,g=f.params,d=a.length;e.beginPath();for(;c<d;c++){switch(a[c]){case"M":e.moveTo(g[b],g[b+1]);b+=2;break;case"L":e.lineTo(g[b],g[b+1]);b+=2;break;case"C":e.bezierCurveTo(g[b],g[b+1],g[b+2],g[b+3],g[b+4],g[b+5]);b+=6;break;case"Z":e.closePath();break}}},save:function(){var c=this.toSave,d=c.length,e=d&&{},b=0,a;for(;b<d;b++){a=c[b];if(a in this){e[a]=this[a]}}this.state.push(e);this.$save()},restore:function(){var b=this.state.pop(),a;if(b){for(a in b){this[a]=b[a]}}this.$restore()}}},splitThreshold:3000,toSave:["fillGradient","strokeGradient"],element:{reference:"element",style:{position:"absolute"},children:[{reference:"innerElement",style:{width:"100%",height:"100%",position:"relative"}}]},createCanvas:function(){var c=Ext.Element.create({tag:"canvas",cls:Ext.baseCSSPrefix+"surface-canvas"});window.G_vmlCanvasManager&&G_vmlCanvasManager.initElement(c.dom);var d=Ext.draw.engine.Canvas.contextOverrides,a=c.dom.getContext("2d"),b;if(a.ellipse){delete d.ellipse}a.state=[];a.toSave=this.toSave;for(b in d){a["$"+b]=a[b]}Ext.apply(a,d);if(this.getHighPrecision()){this.enablePrecisionCompensation(a)}else{this.disablePrecisionCompensation(a)}this.innerElement.appendChild(c);this.canvases.push(c);this.contexts.push(a)},updateHighPrecision:function(d){var e=this.contexts,c=e.length,b,a;for(b=0;b<c;b++){a=e[b];if(d){this.enablePrecisionCompensation(a)}else{this.disablePrecisionCompensation(a)}}},precisionNames:["rect","fillRect","strokeRect","clearRect","moveTo","lineTo","arc","arcTo","save","restore","updatePrecisionCompensate","setTransform","transform","scale","translate","rotate","quadraticCurveTo","bezierCurveTo","createLinearGradient","createRadialGradient","fillText","strokeText","drawImage"],disablePrecisionCompensation:function(b){var a=Ext.draw.engine.Canvas.contextOverrides,f=this.precisionNames,e=f.length,d,c;for(d=0;d<e;d++){c=f[d];if(!(c in a)){delete b[c]}}this.setDirty(true)},enablePrecisionCompensation:function(j){var c=this,a=1,g=1,l=0,k=0,i=new Ext.draw.Matrix(),b=[],e={},d=Ext.draw.engine.Canvas.contextOverrides,h=j.constructor.prototype;var f={toSave:c.toSave,rect:function(m,p,n,o){return h.rect.call(this,m*a+l,p*g+k,n*a,o*g)},fillRect:function(m,p,n,o){this.updatePrecisionCompensateRect();h.fillRect.call(this,m*a+l,p*g+k,n*a,o*g);this.updatePrecisionCompensate()},strokeRect:function(m,p,n,o){this.updatePrecisionCompensateRect();h.strokeRect.call(this,m*a+l,p*g+k,n*a,o*g);this.updatePrecisionCompensate()},clearRect:function(m,p,n,o){return h.clearRect.call(this,m*a+l,p*g+k,n*a,o*g)},moveTo:function(m,n){return h.moveTo.call(this,m*a+l,n*g+k)},lineTo:function(m,n){return h.lineTo.call(this,m*a+l,n*g+k)},arc:function(n,r,m,p,o,q){this.updatePrecisionCompensateRect();h.arc.call(this,n*a+l,r*a+k,m*a,p,o,q);this.updatePrecisionCompensate()},arcTo:function(o,q,n,p,m){this.updatePrecisionCompensateRect();h.arcTo.call(this,o*a+l,q*g+k,n*a+l,p*g+k,m*a);this.updatePrecisionCompensate()},save:function(){b.push(i);i=i.clone();d.save.call(this);h.save.call(this)},restore:function(){i=b.pop();d.restore.call(this);h.restore.call(this);this.updatePrecisionCompensate()},updatePrecisionCompensate:function(){i.precisionCompensate(c.devicePixelRatio,e);a=e.xx;g=e.yy;l=e.dx;k=e.dy;h.setTransform.call(this,c.devicePixelRatio,e.b,e.c,e.d,0,0)},updatePrecisionCompensateRect:function(){i.precisionCompensateRect(c.devicePixelRatio,e);a=e.xx;g=e.yy;l=e.dx;k=e.dy;h.setTransform.call(this,c.devicePixelRatio,e.b,e.c,e.d,0,0)},setTransform:function(q,o,n,m,r,p){i.set(q,o,n,m,r,p);this.updatePrecisionCompensate()},transform:function(q,o,n,m,r,p){i.append(q,o,n,m,r,p);this.updatePrecisionCompensate()},scale:function(n,m){this.transform(n,0,0,m,0,0)},translate:function(n,m){this.transform(1,0,0,1,n,m)},rotate:function(o){var n=Math.cos(o),m=Math.sin(o);this.transform(n,m,-m,n,0,0)},quadraticCurveTo:function(n,p,m,o){h.quadraticCurveTo.call(this,n*a+l,p*g+k,m*a+l,o*g+k)},bezierCurveTo:function(r,p,o,n,m,q){h.bezierCurveTo.call(this,r*a+l,p*g+k,o*a+l,n*g+k,m*a+l,q*g+k)},createLinearGradient:function(n,p,m,o){this.updatePrecisionCompensateRect();var q=h.createLinearGradient.call(this,n*a+l,p*g+k,m*a+l,o*g+k);this.updatePrecisionCompensate();return q},createRadialGradient:function(p,r,o,n,q,m){this.updatePrecisionCompensateRect();var s=h.createLinearGradient.call(this,p*a+l,r*a+k,o*a,n*a+l,q*a+k,m*a);this.updatePrecisionCompensate();return s},fillText:function(o,m,p,n){h.setTransform.apply(this,i.elements);if(typeof n==="undefined"){h.fillText.call(this,o,m,p)}else{h.fillText.call(this,o,m,p,n)}this.updatePrecisionCompensate()},strokeText:function(o,m,p,n){h.setTransform.apply(this,i.elements);if(typeof n==="undefined"){h.strokeText.call(this,o,m,p)}else{h.strokeText.call(this,o,m,p,n)}this.updatePrecisionCompensate()},fill:function(){var m=this.fillGradient,n=this.bbox;this.updatePrecisionCompensateRect();if(m&&n){this.fillStyle=m.generateGradient(this,n)}h.fill.call(this);this.updatePrecisionCompensate()},stroke:function(){var m=this.strokeGradient,n=this.bbox;this.updatePrecisionCompensateRect();if(m&&n){this.strokeStyle=m.generateGradient(this,n)}h.stroke.call(this);this.updatePrecisionCompensate()},drawImage:function(u,s,r,q,p,o,n,m,t){switch(arguments.length){case 3:return h.drawImage.call(this,u,s*a+l,r*g+k);case 5:return h.drawImage.call(this,u,s*a+l,r*g+k,q*a,p*g);case 9:return h.drawImage.call(this,u,s,r,q,p,o*a+l,n*g*k,m*a,t*g)}}};Ext.apply(j,f);this.setDirty(true)},updateRect:function(a){this.callParent([a]);var C=this,p=Math.floor(a[0]),e=Math.floor(a[1]),g=Math.ceil(a[0]+a[2]),B=Math.ceil(a[1]+a[3]),u=C.devicePixelRatio,D=C.canvases,d=g-p,y=B-e,n=Math.round(C.splitThreshold/u),c=C.xSplits=Math.ceil(d/n),f=C.ySplits=Math.ceil(y/n),v,s,q,A,z,x,o,m;for(s=0,z=0;s<f;s++,z+=n){for(v=0,A=0;v<c;v++,A+=n){q=s*c+v;if(q>=D.length){C.createCanvas()}x=D[q].dom;x.style.left=A+"px";x.style.top=z+"px";m=Math.min(n,y-z);if(m*u!==x.height){x.height=m*u;x.style.height=m+"px"}o=Math.min(n,d-A);if(o*u!==x.width){x.width=o*u;x.style.width=o+"px"}C.applyDefaults(C.contexts[q])}}for(q+=1;q<D.length;q++){D[q].destroy()}C.activeCanvases=c*f;D.length=C.activeCanvases;C.clear()},clearTransform:function(){var f=this,a=f.xSplits,g=f.ySplits,d=f.contexts,h=f.splitThreshold,l=f.devicePixelRatio,e,c,b,m;for(e=0;e<a;e++){for(c=0;c<g;c++){b=c*a+e;m=d[b];m.translate(-h*e,-h*c);m.scale(l,l);f.matrix.toContext(m)}}},renderSprite:function(q){var C=this,b=C.getRect(),e=C.matrix,g=q.getParent(),v=Ext.draw.Matrix.fly([1,0,0,1,0,0]),p=C.splitThreshold/C.devicePixelRatio,c=C.xSplits,m=C.ySplits,A,z,s,a,r,o,d=0,B,n=0,f,l=b[2],y=b[3],x,u,t;while(g&&(g!==C)){v.prependMatrix(g.matrix||g.attr&&g.attr.matrix);g=g.getParent()}v.prependMatrix(e);a=q.getBBox();if(a){a=v.transformBBox(a)}q.preRender(C);if(q.attr.hidden||q.attr.globalAlpha===0){q.setDirty(false);return}for(u=0,z=0;u<m;u++,z+=p){for(x=0,A=0;x<c;x++,A+=p){t=u*c+x;s=C.contexts[t];r=Math.min(p,l-A);o=Math.min(p,y-z);d=A;B=d+r;n=z;f=n+o;if(a){if(a.x>B||a.x+a.width<d||a.y>f||a.y+a.height<n){continue}}s.save();q.useAttributes(s,b);if(false===q.render(C,s,[d,n,r,o],b)){return false}s.restore()}}q.setDirty(false)},flatten:function(n,a){var k=document.createElement("canvas"),f=Ext.getClassName(this),g=this.devicePixelRatio,l=k.getContext("2d"),b,c,h,e,d,m;k.width=Math.ceil(n.width*g);k.height=Math.ceil(n.height*g);for(e=0;e<a.length;e++){b=a[e];if(Ext.getClassName(b)!==f){continue}h=b.getRect();for(d=0;d<b.canvases.length;d++){c=b.canvases[d];m=c.getOffsetsTo(c.getParent());l.drawImage(c.dom,(h[0]+m[0])*g,(h[1]+m[1])*g)}}return{data:k.toDataURL(),type:"png"}},applyDefaults:function(a){var b=Ext.draw.Color.RGBA_NONE;a.strokeStyle=b;a.fillStyle=b;a.textAlign="start";a.textBaseline="alphabetic";a.miterLimit=1},clear:function(){var d=this,e=d.activeCanvases,c,b,a;for(c=0;c<e;c++){b=d.canvases[c].dom;a=d.contexts[c];a.setTransform(1,0,0,1,0,0);a.clearRect(0,0,b.width,b.height)}d.setDirty(true)},destroy:function(){var c=this,a,b=c.canvases.length;for(a=0;a<b;a++){c.contexts[a]=null;c.canvases[a].destroy();c.canvases[a]=null}delete c.contexts;delete c.canvases;c.callParent()},privates:{initElement:function(){var a=this;a.callParent();a.canvases=[];a.contexts=[];a.activeCanvases=(a.xSplits=0)*(a.ySplits=0)}}},function(){var c=this,b=c.prototype,a=10000000000;if(Ext.os.is.Android4&&Ext.browser.is.Chrome){a=3000}else{if(Ext.is.iOS){a=2200}}b.splitThreshold=a});Ext.define("Ext.draw.Container",{extend:"Ext.draw.ContainerBase",alternateClassName:"Ext.draw.Component",xtype:"draw",defaultType:"surface",isDrawContainer:true,requires:["Ext.draw.Surface","Ext.draw.engine.Svg","Ext.draw.engine.Canvas","Ext.draw.gradient.GradientDefinition"],engine:"Ext.draw.engine.Canvas",config:{cls:Ext.baseCSSPrefix+"draw-container",resizeHandler:null,sprites:null,gradients:[]},defaultDownloadServerUrl:"http://svg.sencha.io",supportedFormats:["png","pdf","jpeg","gif"],supportedOptions:{version:Ext.isNumber,data:Ext.isString,format:function(a){return Ext.Array.indexOf(this.supportedFormats,a)>=0},filename:Ext.isString,width:Ext.isNumber,height:Ext.isNumber,scale:Ext.isNumber,pdf:Ext.isObject,jpeg:Ext.isObject},initAnimator:function(){this.frameCallbackId=Ext.draw.Animator.addFrameCallback("renderFrame",this)},applyGradients:function(b){var a=[],c,f,d,e;if(!Ext.isArray(b)){return a}for(c=0,f=b.length;c<f;c++){d=b[c];if(!Ext.isObject(d)){continue}if(typeof d.type!=="string"){d.type="linear"}if(d.angle){d.degrees=d.angle;delete d.angle}if(Ext.isObject(d.stops)){d.stops=(function(i){var g=[],h;for(e in i){h=i[e];h.offset=e/100;g.push(h)}return g})(d.stops)}a.push(d)}Ext.draw.gradient.GradientDefinition.add(a);return a},applySprites:function(f){if(!f){return}f=Ext.Array.from(f);var e=f.length,b=[],d,a,c;for(d=0;d<e;d++){c=f[d];a=c.surface;if(!(a&&a.isSurface)){if(Ext.isString(a)){a=this.getSurface(a)}else{a=this.getSurface("main")}}c=a.add(c);b.push(c)}return b},onBodyResize:function(){var b=this.element,a;if(!b){return}a=b.getSize();if(a.width&&a.height){this.setBodySize(a)}},setBodySize:function(c){var d=this,b=d.getResizeHandler()||d.defaultResizeHandler,a;d.fireEvent("bodyresize",d,c);a=b.call(d,c);if(a!==false){d.renderFrame()}},defaultResizeHandler:function(a){this.getItems().each(function(b){b.setRect([0,0,a.width,a.height])})},getSurface:function(d){d=this.getId()+"-"+(d||"main");var c=this,b=c.getItems(),a=b.get(d);if(!a){a=c.add({xclass:c.engine,id:d});c.onBodyResize()}return a},renderFrame:function(){var e=this,a=e.getItems(),b,d,c;for(b=0,d=a.length;b<d;b++){c=a.items[b];if(c.isSurface){c.renderFrame()}}},getImage:function(k){var l=this.innerElement.getSize(),a=Array.prototype.slice.call(this.items.items),d,g,c=this.surfaceZIndexes,f,e,b,h;for(e=1;e<a.length;e++){b=a[e];h=c[b.type];f=e-1;while(f>=0&&c[a[f].type]>h){a[f+1]=a[f];f--}a[f+1]=b}d=a[0].flatten(l,a);if(k==="image"){g=new Image();g.src=d.data;d.data=g;return d}if(k==="stream"){d.data=d.data.replace(/^data:image\/[^;]+/,"data:application/octet-stream");return d}return d},download:function(d){var e=this,a=[],b,c,f;d=Ext.apply({version:2,data:e.getImage().data},d);for(c in d){if(d.hasOwnProperty(c)){f=d[c];if(c in e.supportedOptions){if(e.supportedOptions[c].call(e,f)){a.push({tag:"input",type:"hidden",name:c,value:Ext.String.htmlEncode(Ext.isObject(f)?Ext.JSON.encode(f):f)})}}}}b=Ext.dom.Helper.markup({tag:"html",children:[{tag:"head"},{tag:"body",children:[{tag:"form",method:"POST",action:d.url||e.defaultDownloadServerUrl,children:a},{tag:"script",type:"text/javascript",children:'document.getElementsByTagName("form")[0].submit();'}]}]});window.open("","ImageDownload_"+Date.now()).document.write(b)},destroy:function(){var a=this.frameCallbackId;if(a){Ext.draw.Animator.removeFrameCallback(a)}this.callParent()}},function(){if(location.search.match("svg")){Ext.draw.Container.prototype.engine="Ext.draw.engine.Svg"}else{if((Ext.os.is.BlackBerry&&Ext.os.version.getMajor()===10)||(Ext.browser.is.AndroidStock4&&(Ext.os.version.getMinor()===1||Ext.os.version.getMinor()===2||Ext.os.version.getMinor()===3))){Ext.draw.Container.prototype.engine="Ext.draw.engine.Svg"}}});Ext.define("Ext.chart.theme.Base",{mixins:{factoryable:"Ext.mixin.Factoryable"},requires:["Ext.draw.Color"],factoryConfig:{type:"chart.theme"},isTheme:true,config:{baseColor:null,colors:undefined,gradients:null,chart:{defaults:{background:"white"}},axis:{defaults:{label:{x:0,y:0,textBaseline:"middle",textAlign:"center",fontSize:"default",fontFamily:"default",fontWeight:"default",fillStyle:"black"},title:{fillStyle:"black",fontSize:"default*1.23",fontFamily:"default",fontWeight:"default"},style:{strokeStyle:"black"},grid:{strokeStyle:"rgb(221, 221, 221)"}},top:{style:{textPadding:5}},bottom:{style:{textPadding:5}}},series:{defaults:{label:{fillStyle:"black",strokeStyle:"none",fontFamily:"default",fontWeight:"default",fontSize:"default*1.077",textBaseline:"middle",textAlign:"center"},labelOverflowPadding:5}},sprites:{text:{fontSize:"default",fontWeight:"default",fontFamily:"default",fillStyle:"black"}},seriesThemes:undefined,markerThemes:{type:["circle","cross","plus","square","triangle","diamond"]},useGradients:false,background:null},colorDefaults:["#94ae0a","#115fa6","#a61120","#ff8809","#ffd13e","#a61187","#24ad9a","#7c7474","#a66111"],constructor:function(a){this.initConfig(a);this.resolveDefaults()},defaultRegEx:/^default([+\-/\*]\d+(?:\.\d+)?)?$/,defaultOperators:{"*":function(b,a){return b*a},"+":function(b,a){return b+a},"-":function(b,a){return b-a}},resolveDefaults:function(){var a=this;Ext.onReady(function(){var f=Ext.clone(a.getSprites()),e=Ext.clone(a.getAxis()),d=Ext.clone(a.getSeries()),g,c,b;if(!a.superclass.defaults){g=Ext.getBody().createChild({tag:"div",cls:"x-component"});a.superclass.defaults={fontFamily:g.getStyle("fontFamily"),fontWeight:g.getStyle("fontWeight"),fontSize:parseFloat(g.getStyle("fontSize")),fontVariant:g.getStyle("fontVariant"),fontStyle:g.getStyle("fontStyle")};g.destroy()}a.replaceDefaults(f.text);a.setSprites(f);for(c in e){b=e[c];a.replaceDefaults(b.label);a.replaceDefaults(b.title)}a.setAxis(e);for(c in d){b=d[c];a.replaceDefaults(b.label)}a.setSeries(d)})},replaceDefaults:function(h){var e=this,g=e.superclass.defaults,a=e.defaultRegEx,d,f,c,b;if(Ext.isObject(h)){for(d in g){c=a.exec(h[d]);if(c){f=g[d];c=c[1];if(c){b=e.defaultOperators[c.charAt(0)];f=Math.round(b(f,parseFloat(c.substr(1))))}h[d]=f}}}},applyBaseColor:function(c){var a,b;if(c){a=c.isColor?c:Ext.draw.Color.fromString(c);b=a.getHSL()[2];if(b<0.15){a=a.createLighter(0.3)}else{if(b<0.3){a=a.createLighter(0.15)}else{if(b>0.85){a=a.createDarker(0.3)}else{if(b>0.7){a=a.createDarker(0.15)}}}}this.setColors([a.createDarker(0.3).toString(),a.createDarker(0.15).toString(),a.toString(),a.createLighter(0.12).toString(),a.createLighter(0.24).toString(),a.createLighter(0.31).toString()])}return c},applyColors:function(a){return a||this.colorDefaults},updateUseGradients:function(a){if(a){this.updateGradients({type:"linear",degrees:90})}},updateBackground:function(a){if(a){var b=this.getChart();b.defaults.background=a;this.setChart(b)}},updateGradients:function(a){var c=this.getColors(),e=[],h,b,d,f,g;if(Ext.isObject(a)){for(f=0,g=c&&c.length||0;f<g;f++){b=Ext.draw.Color.fromString(c[f]);if(b){d=b.createLighter(0.15).toString();h=Ext.apply(Ext.Object.chain(a),{stops:[{offset:1,color:b.toString()},{offset:0,color:d.toString()}]});e.push(h)}}this.setColors(e)}},applySeriesThemes:function(a){this.getBaseColor();this.getUseGradients();this.getGradients();var b=this.getColors();if(!a){a={fillStyle:Ext.Array.clone(b),strokeStyle:Ext.Array.map(b,function(d){var c=Ext.draw.Color.fromString(d.stops?d.stops[0].color:d);return c.createDarker(0.15).toString()})}}return a}});Ext.define("Ext.chart.theme.Default",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.default","chart.theme.Base"]});Ext.define("Ext.chart.Markers",{extend:"Ext.draw.sprite.Instancing",isMarkers:true,defaultCategory:"default",constructor:function(){this.callParent(arguments);this.categories={};this.revisions={}},destroy:function(){this.categories=null;this.revisions=null;this.callParent()},getMarkerFor:function(b,a){if(b in this.categories){var c=this.categories[b];if(a in c){return this.get(c[a])}}},clear:function(a){a=a||this.defaultCategory;if(!(a in this.revisions)){this.revisions[a]=1}else{this.revisions[a]++}},putMarkerFor:function(e,b,c,h,f){e=e||this.defaultCategory;var d=this,g=d.categories[e]||(d.categories[e]={}),a;if(c in g){d.setAttributesFor(g[c],b,h)}else{g[c]=d.getCount();d.createInstance(b,h)}a=d.get(g[c]);if(a){a.category=e;if(!f){a.revision=d.revisions[e]||(d.revisions[e]=1)}}},getMarkerBBoxFor:function(c,a,b){if(c in this.categories){var d=this.categories[c];if(a in d){return this.getBBoxFor(d[a],b)}}},getBBox:function(){return null},render:function(a,l,b){var f=this,k=f.revisions,j=f.attr.matrix,h=f.getTemplate(),d=h.attr,g,c,e;j.toContext(l);h.preRender(a,l,b);h.useAttributes(l,b);for(c=0,e=f.instances.length;c<e;c++){g=f.get(c);if(g.hidden||g.revision!==k[g.category]){continue}l.save();h.attr=g;h.useAttributes(l,b);h.render(a,l,b);l.restore()}h.attr=d}});Ext.define("Ext.chart.label.Callout",{extend:"Ext.draw.modifier.Modifier",prepareAttributes:function(a){if(!a.hasOwnProperty("calloutOriginal")){a.calloutOriginal=Ext.Object.chain(a);a.calloutOriginal.prototype=a}if(this._previous){this._previous.prepareAttributes(a.calloutOriginal)}},setAttrs:function(e,h){var d=e.callout,i=e.calloutOriginal,l=e.bbox.plain,c=(l.width||0)+e.labelOverflowPadding,m=(l.height||0)+e.labelOverflowPadding,p,o;if("callout" in h){d=h.callout}if("callout" in h||"calloutPlaceX" in h||"calloutPlaceY" in h||"x" in h||"y" in h){var n="rotationRads" in h?i.rotationRads=h.rotationRads:i.rotationRads,g="x" in h?(i.x=h.x):i.x,f="y" in h?(i.y=h.y):i.y,b="calloutPlaceX" in h?h.calloutPlaceX:e.calloutPlaceX,a="calloutPlaceY" in h?h.calloutPlaceY:e.calloutPlaceY,k="calloutVertical" in h?h.calloutVertical:e.calloutVertical,j;n%=Math.PI*2;if(Math.cos(n)<0){n=(n+Math.PI)%(Math.PI*2)}if(n>Math.PI){n-=Math.PI*2}if(k){n=n*(1-d)-Math.PI/2*d;j=c;c=m;m=j}else{n=n*(1-d)}h.rotationRads=n;h.x=g*(1-d)+b*d;h.y=f*(1-d)+a*d;p=b-g;o=a-f;if(Math.abs(o*c)>Math.abs(p*m)){if(o>0){h.calloutEndX=h.x-(m/2)*(p/o)*d;h.calloutEndY=h.y-(m/2)*d}else{h.calloutEndX=h.x+(m/2)*(p/o)*d;h.calloutEndY=h.y+(m/2)*d}}else{if(p>0){h.calloutEndX=h.x-c/2;h.calloutEndY=h.y-(c/2)*(o/p)*d}else{h.calloutEndX=h.x+c/2;h.calloutEndY=h.y+(c/2)*(o/p)*d}}if(h.calloutStartX&&h.calloutStartY){h.calloutHasLine=(p>0&&h.calloutStartX<h.calloutEndX)||(p<=0&&h.calloutStartX>h.calloutEndX)||(o>0&&h.calloutStartY<h.calloutEndY)||(o<=0&&h.calloutStartY>h.calloutEndY)}else{h.calloutHasLine=true}}return h},pushDown:function(a,b){b=this.callParent([a.calloutOriginal,b]);return this.setAttrs(a,b)},popUp:function(a,b){a=a.prototype;b=this.setAttrs(a,b);if(this._next){return this._next.popUp(a,b)}else{return Ext.apply(a,b)}}});Ext.define("Ext.chart.label.Label",{extend:"Ext.draw.sprite.Text",requires:["Ext.chart.label.Callout"],inheritableStatics:{def:{processors:{callout:"limited01",calloutHasLine:"bool",calloutPlaceX:"number",calloutPlaceY:"number",calloutStartX:"number",calloutStartY:"number",calloutEndX:"number",calloutEndY:"number",calloutColor:"color",calloutWidth:"number",calloutVertical:"bool",labelOverflowPadding:"number",display:"enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",orientation:"enums(horizontal,vertical)",renderer:"default"},defaults:{callout:0,calloutHasLine:true,calloutPlaceX:0,calloutPlaceY:0,calloutStartX:0,calloutStartY:0,calloutEndX:0,calloutEndY:0,calloutWidth:1,calloutVertical:false,calloutColor:"black",labelOverflowPadding:5,display:"none",orientation:"",renderer:null},triggers:{callout:"transform",calloutPlaceX:"transform",calloutPlaceY:"transform",labelOverflowPadding:"transform",calloutRotation:"transform",display:"hidden"},updaters:{hidden:function(a){a.hidden=a.display==="none"}}}},config:{fx:{customDurations:{callout:200}},field:null,calloutLine:true},applyCalloutLine:function(a){if(a){return Ext.apply({},a)}},prepareModifiers:function(){this.callParent(arguments);this.calloutModifier=new Ext.chart.label.Callout({sprite:this});this.fx.setNext(this.calloutModifier);this.calloutModifier.setNext(this.topModifier)},render:function(b,c){var e=this,a=e.attr,d=a.calloutColor;c.save();c.globalAlpha*=a.callout;if(c.globalAlpha>0&&a.calloutHasLine){if(d&&d.isGradient){d=d.getStops()[0].color}c.strokeStyle=d;c.fillStyle=d;c.lineWidth=a.calloutWidth;c.beginPath();c.moveTo(e.attr.calloutStartX,e.attr.calloutStartY);c.lineTo(e.attr.calloutEndX,e.attr.calloutEndY);c.stroke();c.beginPath();c.arc(e.attr.calloutStartX,e.attr.calloutStartY,1*a.calloutWidth,0,2*Math.PI,true);c.fill();c.beginPath();c.arc(e.attr.calloutEndX,e.attr.calloutEndY,1*a.calloutWidth,0,2*Math.PI,true);c.fill()}c.restore();Ext.draw.sprite.Text.prototype.render.apply(e,arguments)}});Ext.define("Ext.chart.series.Series",{requires:["Ext.chart.Markers","Ext.chart.label.Label","Ext.tip.ToolTip"],mixins:["Ext.mixin.Observable","Ext.mixin.Bindable"],isSeries:true,defaultBindProperty:"store",type:null,seriesType:"sprite",identifiablePrefix:"ext-line-",observableType:"series",darkerStrokeRatio:0.15,config:{chart:null,title:null,renderer:null,showInLegend:true,triggerAfterDraw:false,style:{},subStyle:{},themeStyle:{},colors:null,useDarkerStrokeColor:true,store:null,label:{},labelOverflowPadding:null,showMarkers:true,marker:null,markerSubStyle:null,itemInstancing:null,background:null,highlightItem:null,surface:null,overlaySurface:null,hidden:false,highlight:false,highlightCfg:{merge:function(a){return a},$value:{fillStyle:"yellow",strokeStyle:"red"}},animation:null,tooltip:null},directions:[],sprites:null,themeColorCount:function(){return 1},isStoreDependantColorCount:false,themeMarkerCount:function(){return 0},getFields:function(f){var e=this,a=[],c,b,d;for(b=0,d=f.length;b<d;b++){c=e["get"+f[b]+"Field"]();if(Ext.isArray(c)){a.push.apply(a,c)}else{a.push(c)}}return a},applyAnimation:function(a,b){if(!a){a={duration:0}}else{if(a===true){a={easing:"easeInOut",duration:500}}}return b?Ext.apply({},a,b):a},getAnimation:function(){var a=this.getChart();if(a&&a.animationSuspendCount){return{duration:0}}else{return this.callParent()}},updateTitle:function(a){var j=this,g=j.getChart();if(!g||g.isInitializing){return}a=Ext.Array.from(a);var c=g.getSeries(),b=Ext.Array.indexOf(c,j),e=g.getLegendStore(),h=j.getYField(),d,l,k,f;if(e.getCount()&&b!==-1){f=h?Math.min(a.length,h.length):a.length;for(d=0;d<f;d++){k=a[d];l=e.getAt(b+d);if(k&&l){l.set("name",k)}}}},applyHighlight:function(a,b){if(Ext.isObject(a)){a=Ext.merge({},this.config.highlightCfg,a)}else{if(a===true){a=this.config.highlightCfg}}return Ext.apply(b||{},a)},updateHighlight:function(a){this.getStyle();if(!Ext.Object.isEmpty(a)){this.addItemHighlight()}},updateHighlightCfg:function(a){if(!Ext.Object.equals(a,this.defaultConfig.highlightCfg)){this.addItemHighlight()}},applyItemInstancing:function(a,b){return Ext.merge(b||{},a)},setAttributesForItem:function(c,d){var b=c&&c.sprite,a;if(b){if(b.itemsMarker&&c.category==="items"){b.putMarker(c.category,d,c.index,false,true)}if(b.isMarkerHolder&&c.category==="markers"){b.putMarker(c.category,d,c.index,false,true)}else{if(b.isInstancing){b.setAttributesFor(c.index,d)}else{if(Ext.isArray(b)){for(a=0;a<b.length;a++){b[a].setAttributes(d)}}else{b.setAttributes(d)}}}}},getBBoxForItem:function(a){if(a&&a.sprite){if(a.sprite.itemsMarker&&a.category==="items"){return a.sprite.getMarkerBBox(a.category,a.index)}else{if(a.sprite instanceof Ext.draw.sprite.Instancing){return a.sprite.getBBoxFor(a.index)}else{return a.sprite.getBBox()}}}return null},applyHighlightItem:function(d,a){if(d===a){return}if(Ext.isObject(d)&&Ext.isObject(a)){var c=d.sprite===a.sprite,b=d.index===a.index;if(c&&b){return}}return d},updateHighlightItem:function(b,a){this.setAttributesForItem(a,{highlighted:false});this.setAttributesForItem(b,{highlighted:true})},constructor:function(a){var b=this,c;a=a||{};if(a.tips){a=Ext.apply({tooltip:a.tips},a)}if(a.highlightCfg){a=Ext.apply({highlight:a.highlightCfg},a)}if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.sprites=[];b.dataRange=[];b.mixins.observable.constructor.call(b,a);b.initBindable()},lookupViewModel:function(a){var b=this.getChart();return b?b.lookupViewModel(a):null},applyTooltip:function(c,b){var a=Ext.apply({xtype:"tooltip",renderer:Ext.emptyFn,constrainPosition:true,shrinkWrapDock:true,autoHide:true,offsetX:10,offsetY:10},c);return Ext.create(a)},updateTooltip:function(){this.addItemHighlight()},addItemHighlight:function(){var d=this.getChart();if(!d){return}var e=d.getInteractions(),c,a,b;for(c=0;c<e.length;c++){a=e[c];if(a.isItemHighlight||a.isItemEdit){b=true;break}}if(!b){e.push("itemhighlight");d.setInteractions(e)}},showTooltip:function(l,m){var d=this,n=d.getTooltip(),j,a,i,f,h,k,g,e,b,c;if(!n){return}clearTimeout(d.tooltipTimeout);b=n.config;if(n.trackMouse){m[0]+=b.offsetX;m[1]+=b.offsetY}else{j=l.sprite;a=j.getSurface();i=Ext.get(a.getId());if(i){k=l.series.getBBoxForItem(l);g=k.x+k.width/2;e=k.y+k.height/2;h=a.matrix.transformPoint([g,e]);f=i.getXY();c=a.getInherited().rtl;g=c?f[0]+i.getWidth()-h[0]:f[0]+h[0];e=f[1]+h[1];m=[g,e]}}Ext.callback(n.renderer,n.scope,[n,l.record,l],0,d);n.show(m)},hideTooltip:function(b){var a=this,c=a.getTooltip();if(!c){return}clearTimeout(a.tooltipTimeout);a.tooltipTimeout=Ext.defer(function(){c.hide()},1)},applyStore:function(a){return a&&Ext.StoreManager.lookup(a)},getStore:function(){return this._store||this.getChart()&&this.getChart().getStore()},updateStore:function(b,a){var h=this,g=h.getChart(),c=g&&g.getStore(),f,j,e,d;a=a||c;if(a&&a!==b){a.un({datachanged:"onDataChanged",update:"onDataChanged",scope:h})}if(b){b.on({datachanged:"onDataChanged",update:"onDataChanged",scope:h});f=h.getSprites();for(d=0,e=f.length;d<e;d++){j=f[d];if(j.setStore){j.setStore(b)}}h.onDataChanged()}h.fireEvent("storechange",h,b,a)},onStoreChange:function(b,a,c){if(!this._store){this.updateStore(a,c)}},coordinate:function(o,m,e){var l=this,p=l.getStore(),h=l.getHidden(),k=p.getData().items,b=l["get"+o+"Axis"](),f={min:Infinity,max:-Infinity},q=l["fieldCategory"+o]||[o],g=l.getFields(q),d,n,c,a={},j=l.getSprites();if(j.length>0){if(!Ext.isBoolean(h)||!h){for(d=0;d<q.length;d++){n=g[d];c=l.coordinateData(k,n,b);l.getRangeOfData(c,f);a["data"+q[d]]=c}}l.dataRange[m]=f.min;l.dataRange[m+e]=f.max;a["dataMin"+o]=f.min;a["dataMax"+o]=f.max;if(b){b.range=null;a["range"+o]=b.getRange()}for(d=0;d<j.length;d++){j[d].setAttributes(a)}}},coordinateData:function(b,h,d){var g=[],f=b.length,e=d&&d.getLayout(),c,a;for(c=0;c<f;c++){a=b[c].data[h];if(!Ext.isEmpty(a,true)){if(e){g[c]=e.getCoordFor(a,h,c,b)}else{g[c]=+a}}else{g[c]=a}}return g},getRangeOfData:function(g,b){var e=g.length,d=b.min,a=b.max,c,f;for(c=0;c<e;c++){f=g[c];if(f<d){d=f}if(f>a){a=f}}b.min=d;b.max=a},updateLabelData:function(){var h=this,l=h.getStore(),g=l.getData().items,f=h.getSprites(),a=h.getLabel().getTemplate(),n=Ext.Array.from(a.getField()),c,b,e,d,m,k;if(!f.length||!n.length){return}for(c=0;c<f.length;c++){d=[];m=f[c];k=m.getField();if(Ext.Array.indexOf(n,k)<0){k=n[c]}for(b=0,e=g.length;b<e;b++){d.push(g[b].get(k))}m.setAttributes({labels:d})}},processData:function(){if(!this.getStore()){return}var d=this,f=this.directions,a,c=f.length,e,b;for(a=0;a<c;a++){e=f[a];b=d["get"+e+"Axis"]();if(b){b.processData(d);continue}if(d["coordinate"+e]){d["coordinate"+e]()}}d.updateLabelData()},applyBackground:function(a){if(this.getChart()){this.getSurface().setBackground(a);return this.getSurface().getBackground()}else{return a}},updateChart:function(d,a){var c=this,b=c._store;if(a){a.un("axeschange","onAxesChange",c);c.clearSprites();c.setSurface(null);c.setOverlaySurface(null);a.unregister(c);c.onChartDetached(a);if(!b){c.updateStore(null)}}if(d){c.setSurface(d.getSurface("series"));c.setOverlaySurface(d.getSurface("overlay"));d.on("axeschange","onAxesChange",c);if(d.getAxes()){c.onAxesChange(d)}c.onChartAttached(d);d.register(c);if(!b){c.updateStore(d.getStore())}}},onAxesChange:function(h){var k=this,g=h.getAxes(),c,a={},b={},e=false,j=this.directions,l,d,f;for(d=0,f=j.length;d<f;d++){l=j[d];b[l]=k.getFields(k["fieldCategory"+l])}for(d=0,f=g.length;d<f;d++){c=g[d];if(!a[c.getDirection()]){a[c.getDirection()]=[c]}else{a[c.getDirection()].push(c)}}for(d=0,f=j.length;d<f;d++){l=j[d];if(k["get"+l+"Axis"]()){continue}if(a[l]){c=k.findMatchingAxis(a[l],b[l]);if(c){k["set"+l+"Axis"](c);if(c.getNeedHighPrecision()){e=true}}}}this.getSurface().setHighPrecision(e)},findMatchingAxis:function(f,e){var d,c,b,a;for(b=0;b<f.length;b++){d=f[b];c=d.getFields();if(!c.length){return d}else{if(e){for(a=0;a<e.length;a++){if(Ext.Array.indexOf(c,e[a])>=0){return d}}}}}},onChartDetached:function(a){var b=this;b.fireEvent("chartdetached",a,b);a.un("storechange","onStoreChange",b)},onChartAttached:function(a){var b=this;b.setBackground(b.getBackground());b.fireEvent("chartattached",a,b);a.on("storechange","onStoreChange",b);b.processData()},updateOverlaySurface:function(a){var b=this;if(a){if(b.getLabel()){b.getOverlaySurface().add(b.getLabel())}}},applyLabel:function(a,b){if(!b){b=new Ext.chart.Markers({zIndex:10});b.setTemplate(new Ext.chart.label.Label(a))}else{b.getTemplate().setAttributes(a)}return b},createItemInstancingSprite:function(c,b){var e=this,f=new Ext.chart.Markers(),a,d;f.setAttributes({zIndex:Number.MAX_VALUE});a=Ext.apply({},b);if(e.getHighlight()){a.highlight=e.getHighlight();a.modifiers=["highlight"]}f.setTemplate(a);d=f.getTemplate();d.setAttributes(e.getStyle());d.fx.on("animationstart","onSpriteAnimationStart",this);d.fx.on("animationend","onSpriteAnimationEnd",this);c.bindMarker("items",f);e.getSurface().add(f);return f},getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer()}},updateRenderer:function(c){var b=this,a=b.getChart(),d;if(a&&a.isInitializing){return}d=b.getSprites();if(d.length){d[0].setAttributes({renderer:c||null});if(a&&!a.isInitializing){a.redraw()}}},updateShowMarkers:function(a){var d=this.getSprites(),b=d&&d[0],c=b&&b.getMarker("markers");if(c){c.getTemplate().setAttributes({hidden:!a})}},createSprite:function(){var f=this,a=f.getSurface(),e=f.getItemInstancing(),d=a.add(f.getDefaultSpriteConfig()),b=f.getMarker(),g,c;d.setAttributes(f.getStyle());d.setSeries(f);if(e){d.itemsMarker=f.createItemInstancingSprite(d,e)}if(d.bindMarker){if(b){g=new Ext.chart.Markers();c=Ext.Object.merge({},b);if(f.getHighlight()){c.highlight=f.getHighlight();c.modifiers=["highlight"]}g.setTemplate(c);g.getTemplate().fx.setCustomDurations({translationX:0,translationY:0});d.dataMarker=g;d.bindMarker("markers",g);f.getOverlaySurface().add(g)}if(f.getLabel().getTemplate().getField()){d.bindMarker("labels",f.getLabel())}}if(d.setStore){d.setStore(f.getStore())}d.fx.on("animationstart","onSpriteAnimationStart",f);d.fx.on("animationend","onSpriteAnimationEnd",f);f.sprites.push(d);return d},getSprites:Ext.emptyFn,onDataChanged:function(){var d=this,c=d.getChart(),b=c&&c.getStore(),a=d.getStore();if(a!==b){d.processData()}},isXType:function(a){return a==="series"},getItemId:function(){return this.getId()},applyThemeStyle:function(e,a){var b=this,d,c;d=e&&e.subStyle&&e.subStyle.fillStyle;c=d&&e.subStyle.strokeStyle;if(d&&!c){e.subStyle.strokeStyle=b.getStrokeColorsFromFillColors(d)}d=e&&e.markerSubStyle&&e.markerSubStyle.fillStyle;c=d&&e.markerSubStyle.strokeStyle;if(d&&!c){e.markerSubStyle.strokeStyle=b.getStrokeColorsFromFillColors(d)}return Ext.apply(a||{},e)},applyStyle:function(c,b){var a=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+this.seriesType));if(a&&a.def){c=a.def.normalize(c)}return Ext.apply({},c,b)},applySubStyle:function(b,c){var a=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+this.seriesType));if(a&&a.def){b=a.def.batchedNormalize(b,true)}return Ext.merge({},c,b)},applyMarker:function(c,a){var d=(c&&c.type)||(a&&a.type)||"circle",b=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+d));if(b&&b.def){c=b.def.normalize(Ext.isObject(c)?c:{},true);c.type=d}return Ext.merge(a||{},c)},applyMarkerSubStyle:function(c,a){var d=(c&&c.type)||(a&&a.type)||"circle",b=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+d));if(b&&b.def){c=b.def.batchedNormalize(c,true)}return Ext.merge(a||{},c)},updateHidden:function(b){var a=this;a.getColors();a.getSubStyle();a.setSubStyle({hidden:b});a.processData();a.doUpdateStyles();if(!Ext.isArray(b)){a.updateLegendStore(b)}},updateLegendStore:function(f,b){var e=this,d=e.getChart(),c=d.getLegendStore(),g=e.getId(),a;if(c){if(arguments.length>1){a=c.findBy(function(h){return h.get("series")===g&&h.get("index")===b});if(a!==-1){a=c.getAt(a)}}else{a=c.findRecord("series",g)}if(a&&a.get("disabled")!==f){a.set("disabled",f)}}},setHiddenByIndex:function(a,c){var b=this;if(Ext.isArray(b.getHidden())){b.getHidden()[a]=c;b.updateHidden(b.getHidden());b.updateLegendStore(c,a)}else{b.setHidden(c)}},getStrokeColorsFromFillColors:function(a){var c=this,e=c.getUseDarkerStrokeColor(),b=(Ext.isNumber(e)?e:c.darkerStrokeRatio),d;if(e){d=Ext.Array.map(a,function(f){f=Ext.isString(f)?f:f.stops[0].color;f=Ext.draw.Color.fromString(f);return f.createDarker(b).toString()})}else{d=Ext.Array.clone(a)}return d},updateThemeColors:function(b){var c=this,d=c.getThemeStyle(),a=Ext.Array.clone(b),f=c.getStrokeColorsFromFillColors(b),e={fillStyle:a,strokeStyle:f};d.subStyle=Ext.apply(d.subStyle||{},e);d.markerSubStyle=Ext.apply(d.markerSubStyle||{},e);c.doUpdateStyles()},themeOnlyIfConfigured:{},updateTheme:function(d){var h=this,a=d.getSeries(),n=h.getInitialConfig(),c=h.defaultConfig,f=h.getConfigurator().configs,j=a.defaults,k=a[h.type],g=h.themeOnlyIfConfigured,l,i,o,b,m,e;a=Ext.merge({},j,k);for(l in a){i=a[l];e=f[l];if(i!==null&&i!==undefined&&e){m=n[l];o=Ext.isObject(i);b=m===c[l];if(o){if(b&&g[l]){continue}i=Ext.merge({},i,m)}if(b||o){h[e.names.set](i)}}}},updateChartColors:function(a){var b=this;if(!b.getColors()){b.updateThemeColors(a)}},updateColors:function(a){this.updateThemeColors(a)},updateStyle:function(){this.doUpdateStyles()},updateSubStyle:function(){this.doUpdateStyles()},updateThemeStyle:function(){this.doUpdateStyles()},doUpdateStyles:function(){var g=this,h=g.sprites,d=g.getItemInstancing(),c=0,f=h&&h.length,a=g.getConfig("showMarkers",true),b=g.getMarker(),e;for(;c<f;c++){e=g.getStyleByIndex(c);if(d){h[c].itemsMarker.getTemplate().setAttributes(e)}h[c].setAttributes(e);if(b&&h[c].dataMarker){h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))}}},getStyleWithTheme:function(){var b=this,c=b.getThemeStyle(),d=(c&&c.style)||{},a=Ext.applyIf(Ext.apply({},b.getStyle()),d);return a},getSubStyleWithTheme:function(){var c=this,d=c.getThemeStyle(),a=(d&&d.subStyle)||{},b=Ext.applyIf(Ext.apply({},c.getSubStyle()),a);return b},getStyleByIndex:function(b){var e=this,h=e.getThemeStyle(),d,g,c,f,a={};d=e.getStyle();g=(h&&h.style)||{};c=e.styleDataForIndex(e.getSubStyle(),b);f=e.styleDataForIndex((h&&h.subStyle),b);Ext.apply(a,g);Ext.apply(a,f);Ext.apply(a,d);Ext.apply(a,c);return a},getMarkerStyleByIndex:function(d){var g=this,c=g.getThemeStyle(),a,e,k,j,b,l,h,f,m={};a=g.getStyle();e=(c&&c.style)||{};k=g.styleDataForIndex(g.getSubStyle(),d);if(k.hasOwnProperty("hidden")){k.hidden=k.hidden||!this.getConfig("showMarkers",true)}j=g.styleDataForIndex((c&&c.subStyle),d);b=g.getMarker();l=(c&&c.marker)||{};h=g.getMarkerSubStyle();f=g.styleDataForIndex((c&&c.markerSubStyle),d);Ext.apply(m,e);Ext.apply(m,j);Ext.apply(m,l);Ext.apply(m,f);Ext.apply(m,a);Ext.apply(m,k);Ext.apply(m,b);Ext.apply(m,h);return m},styleDataForIndex:function(d,c){var e,b,a={};if(d){for(b in d){e=d[b];if(Ext.isArray(e)){a[b]=e[c%e.length]}else{a[b]=e}}}return a},getItemForPoint:Ext.emptyFn,getItemByIndex:function(a,e){var d=this,f=d.getSprites(),b=f&&f[0],c;if(!b){return}if(e===undefined&&b.isMarkerHolder){e=d.getItemInstancing()?"items":"markers"}else{if(!e||e===""||e==="sprites"){b=f[a]}}if(b){c={series:d,category:e,index:a,record:d.getStore().getData().items[a],field:d.getYField(),sprite:b};return c}},onSpriteAnimationStart:function(a){this.fireEvent("animationstart",this,a)},onSpriteAnimationEnd:function(a){this.fireEvent("animationend",this,a)},resolveListenerScope:function(e){var d=this,a=Ext._namedScopes[e],c=d.getChart(),b;if(!a){b=c?c.resolveListenerScope(e,false):(e||d)}else{if(a.isThis){b=d}else{if(a.isController){b=c?c.resolveListenerScope(e,false):d}else{if(a.isSelf){b=c?c.resolveListenerScope(e,false):d;if(b===c&&!c.getInheritedConfig("defaultListenerScope")){b=d}}}}}return b},provideLegendInfo:function(a){a.push({name:this.getTitle()||this.getId(),mark:"black",disabled:this.getHidden(),series:this.getId(),index:0})},clearSprites:function(){var d=this.sprites,b,a,c;for(a=0,c=d.length;a<c;a++){b=d[a];if(b&&b.isSprite){b.destroy()}}this.sprites=[]},destroy:function(){var b=this,a=b._store,c=b.getConfig("tooltip",true);if(a&&a.getAutoDestroy()){Ext.destroy(a)}b.setChart(null);b.clearListeners();if(c){Ext.destroy(c);clearTimeout(b.tooltipTimeout)}b.callParent()}});Ext.define("Ext.chart.interactions.Abstract",{xtype:"interaction",mixins:{observable:"Ext.mixin.Observable"},config:{gestures:{tap:"onGesture"},chart:null,enabled:true},throttleGap:0,stopAnimationBeforeSync:false,constructor:function(a){var b=this,c;a=a||{};if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.mixins.observable.constructor.call(b,a)},initialize:Ext.emptyFn,updateChart:function(c,a){var b=this;if(a===c){return}if(a){a.unregister(b);b.removeChartListener(a)}if(c){c.register(b);b.addChartListener()}},updateEnabled:function(a){var c=this,b=c.getChart();if(b){if(a){c.addChartListener()}else{c.removeChartListener(b)}}},onGesture:Ext.emptyFn,getItemForEvent:function(d){var b=this,a=b.getChart(),c=a.getEventXY(d);return a.getItemForPoint(c[0],c[1])},getItemsForEvent:function(d){var b=this,a=b.getChart(),c=a.getEventXY(d);return a.getItemsForPoint(c[0],c[1])},addChartListener:function(){var c=this,b=c.getChart(),e=c.getGestures(),a;if(!c.getEnabled()){return}function d(f,g){b.addElementListener(f,c.listeners[f]=function(j){var i=c.getLocks(),h;if(c.getEnabled()&&(!(f in i)||i[f]===c)){h=(Ext.isFunction(g)?g:c[g]).apply(this,arguments);if(h===false&&j&&j.stopPropagation){j.stopPropagation()}return h}},c)}c.listeners=c.listeners||{};for(a in e){d(a,e[a])}},removeChartListener:function(c){var d=this,e=d.getGestures(),b;function a(f){var g=d.listeners[f];if(g){c.removeElementListener(f,g);delete d.listeners[f]}}if(d.listeners){for(b in e){a(b)}}},lockEvents:function(){var d=this,c=d.getLocks(),a=Array.prototype.slice.call(arguments),b=a.length;while(b--){c[a[b]]=d}},unlockEvents:function(){var c=this.getLocks(),a=Array.prototype.slice.call(arguments),b=a.length;while(b--){delete c[a[b]]}},getLocks:function(){var a=this.getChart();return a.lockedEvents||(a.lockedEvents={})},isMultiTouch:function(){if(Ext.browser.is.IE10){return true}return !Ext.os.is.Desktop},initializeDefaults:Ext.emptyFn,doSync:function(){var b=this,a=b.getChart();if(b.syncTimer){clearTimeout(b.syncTimer);b.syncTimer=null}if(b.stopAnimationBeforeSync){a.animationSuspendCount++}a.redraw();if(b.stopAnimationBeforeSync){a.animationSuspendCount--}b.syncThrottle=Date.now()+b.throttleGap},sync:function(){var a=this;if(a.throttleGap&&Ext.frameStartTime<a.syncThrottle){if(a.syncTimer){return}a.syncTimer=Ext.defer(function(){a.doSync()},a.throttleGap)}else{a.doSync()}},getItemId:function(){return this.getId()},isXType:function(a){return a==="interaction"},destroy:function(){var a=this;a.setChart(null);delete a.listeners;a.callParent()}},function(){if(Ext.os.is.Android4){this.prototype.throttleGap=40}});Ext.define("Ext.chart.MarkerHolder",{extend:"Ext.Mixin",mixinConfig:{id:"markerHolder",after:{constructor:"constructor",preRender:"preRender"},before:{destroy:"destroy"}},isMarkerHolder:true,surfaceMatrix:null,inverseSurfaceMatrix:null,deprecated:{6:{methods:{getBoundMarker:{message:"Please use the 'getMarker' method instead.",fn:function(b){var a=this.boundMarkers[b];return a?[a]:a}}}}},constructor:function(){this.boundMarkers={};this.cleanRedraw=false},bindMarker:function(b,a){var c=this,d=c.boundMarkers;if(a&&a.isMarkers){c.releaseMarker(b);d[b]=a;a.on("destroy",c.onMarkerDestroy,c)}},onMarkerDestroy:function(a){this.releaseMarker(a)},releaseMarker:function(a){var c=this.boundMarkers,b;if(a&&a.isMarkers){for(b in c){if(c[b]===a){delete c[b];break}}}else{b=a;a=c[b];delete c[b]}return a||null},getMarker:function(a){return this.boundMarkers[a]||null},preRender:function(){var f=this,g=f.getId(),d=f.boundMarkers,e=f.getParent(),c,a,b;if(f.surfaceMatrix){b=f.surfaceMatrix.set(1,0,0,1,0,0)}else{b=f.surfaceMatrix=new Ext.draw.Matrix()}f.cleanRedraw=!f.attr.dirty;if(!f.cleanRedraw){for(c in d){a=d[c];if(a){a.clear(g)}}}while(e&&e.attr&&e.attr.matrix){b.prependMatrix(e.attr.matrix);e=e.getParent()}b.prependMatrix(e.matrix);f.surfaceMatrix=b;f.inverseSurfaceMatrix=b.inverse(f.inverseSurfaceMatrix)},putMarker:function(d,a,c,g,e){var b=this.boundMarkers[d],f=this.getId();if(b){b.putMarkerFor(f,a,c,g,e)}},getMarkerBBox:function(c,b,d){var a=this.boundMarkers[c],e=this.getId();if(a){return a.getMarkerBBoxFor(e,b,d)}},destroy:function(){var c=this.boundMarkers,b,a;for(b in c){a=c[b];a.destroy()}}});Ext.define("Ext.chart.axis.sprite.Axis",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.axis",type:"axis",mixins:{markerHolder:"Ext.chart.MarkerHolder"},requires:["Ext.draw.sprite.Text"],inheritableStatics:{def:{processors:{grid:"bool",axisLine:"bool",minorTicks:"bool",minorTickSize:"number",majorTicks:"bool",majorTickSize:"number",length:"number",startGap:"number",endGap:"number",dataMin:"number",dataMax:"number",visibleMin:"number",visibleMax:"number",position:"enums(left,right,top,bottom,angular,radial,gauge)",minStepSize:"number",estStepSize:"number",titleOffset:"number",textPadding:"number",min:"number",max:"number",centerX:"number",centerY:"number",radius:"number",totalAngle:"number",baseRotation:"number",data:"default",enlargeEstStepSizeByText:"bool"},defaults:{grid:false,axisLine:true,minorTicks:false,minorTickSize:3,majorTicks:true,majorTickSize:5,length:0,startGap:0,endGap:0,visibleMin:0,visibleMax:1,dataMin:0,dataMax:1,position:"",minStepSize:0,estStepSize:20,min:0,max:1,centerX:0,centerY:0,radius:1,baseRotation:0,data:null,titleOffset:0,textPadding:0,scalingCenterY:0,scalingCenterX:0,strokeStyle:"black",enlargeEstStepSizeByText:false},triggers:{minorTickSize:"bbox",majorTickSize:"bbox",position:"bbox,layout",axisLine:"bbox,layout",min:"layout",max:"layout",length:"layout",minStepSize:"layout",estStepSize:"layout",data:"layout",dataMin:"layout",dataMax:"layout",visibleMin:"layout",visibleMax:"layout",enlargeEstStepSizeByText:"layout"},updaters:{layout:"layoutUpdater"}}},config:{label:null,layout:null,segmenter:null,renderer:null,layoutContext:null,axis:null},thickness:0,stepSize:0,getBBox:function(){return null},defaultRenderer:function(a){return this.segmenter.renderer(a,this)},layoutUpdater:function(){var h=this,f=h.getAxis().getChart();if(f.isInitializing){return}var e=h.attr,d=h.getLayout(),g=f.getInherited().rtl,b=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMin,i=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMax,c=e.position,a={attr:e,segmenter:h.getSegmenter(),renderer:h.defaultRenderer};if(c==="left"||c==="right"){e.translationX=0;e.translationY=i*e.length/(i-b);e.scalingX=1;e.scalingY=-e.length/(i-b);e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}else{if(c==="top"||c==="bottom"){if(g){e.translationX=e.length+b*e.length/(i-b)+1}else{e.translationX=-b*e.length/(i-b)}e.translationY=0;e.scalingX=(g?-1:1)*e.length/(i-b);e.scalingY=1;e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}}if(d){d.calculateLayout(a);h.setLayoutContext(a)}},iterate:function(e,j){var c,g,a,b,h,d,k=Ext.Array.some,m=Math.abs,f;if(e.getLabel){if(e.min<e.from){j.call(this,e.min,e.getLabel(e.min),-1,e)}for(c=0;c<=e.steps;c++){j.call(this,e.get(c),e.getLabel(c),c,e)}if(e.max>e.to){j.call(this,e.max,e.getLabel(e.max),e.steps+1,e)}}else{b=this.getAxis();h=b.floatingAxes;d=[];f=(e.to-e.from)/(e.steps+1);if(b.getFloating()){for(a in h){d.push(h[a])}}function l(i){return !d.length||k(d,function(n){return m(n-i)>f})}if(e.min<e.from&&l(e.min)){j.call(this,e.min,e.min,-1,e)}for(c=0;c<=e.steps;c++){g=e.get(c);if(l(g)){j.call(this,g,g,c,e)}}if(e.max>e.to&&l(e.max)){j.call(this,e.max,e.max,e.steps+1,e)}}},renderTicks:function(l,m,s,p){var v=this,k=v.attr,u=k.position,n=k.matrix,e=0.5*k.lineWidth,f=n.getXX(),i=n.getDX(),j=n.getYY(),h=n.getDY(),o=s.majorTicks,d=k.majorTickSize,a=s.minorTicks,r=k.minorTickSize;if(o){switch(u){case"right":function q(w){return function(x,z,y){x=l.roundPixel(x*j+h)+e;m.moveTo(0,x);m.lineTo(w,x)}}v.iterate(o,q(d));a&&v.iterate(a,q(r));break;case"left":function t(w){return function(x,z,y){x=l.roundPixel(x*j+h)+e;m.moveTo(p[2]-w,x);m.lineTo(p[2],x)}}v.iterate(o,t(d));a&&v.iterate(a,t(r));break;case"bottom":function c(w){return function(x,z,y){x=l.roundPixel(x*f+i)-e;m.moveTo(x,0);m.lineTo(x,w)}}v.iterate(o,c(d));a&&v.iterate(a,c(r));break;case"top":function b(w){return function(x,z,y){x=l.roundPixel(x*f+i)-e;m.moveTo(x,p[3]);m.lineTo(x,p[3]-w)}}v.iterate(o,b(d));a&&v.iterate(a,b(r));break;case"angular":v.iterate(o,function(w,y,x){w=w/(k.max+1)*Math.PI*2+k.baseRotation;m.moveTo(k.centerX+(k.length)*Math.cos(w),k.centerY+(k.length)*Math.sin(w));m.lineTo(k.centerX+(k.length+d)*Math.cos(w),k.centerY+(k.length+d)*Math.sin(w))});break;case"gauge":var g=v.getGaugeAngles();v.iterate(o,function(w,y,x){w=(w-k.min)/(k.max-k.min+1)*k.totalAngle-k.totalAngle+g.start;m.moveTo(k.centerX+(k.length)*Math.cos(w),k.centerY+(k.length)*Math.sin(w));m.lineTo(k.centerX+(k.length+d)*Math.cos(w),k.centerY+(k.length+d)*Math.sin(w))});break}}},renderLabels:function(E,q,D,K){var o=this,k=o.attr,i=0.5*k.lineWidth,u=k.position,y=k.matrix,A=k.textPadding,x=y.getXX(),d=y.getDX(),g=y.getYY(),c=y.getDY(),n=0,I=D.majorTicks,G=Math.max(k.majorTickSize,k.minorTickSize)+k.lineWidth,f=Ext.draw.Draw.isBBoxIntersect,F=o.getLabel(),J,s,r=null,w=0,b=0,m=D.segmenter,B=o.getRenderer(),t=o.getAxis(),z=t.getTitle(),a=z&&z.attr.text!==""&&z.getBBox(),l,h=null,p,C,v,e,H;if(I&&F&&!F.attr.hidden){J=F.attr.font;if(q.font!==J){q.font=J}F.setAttributes({translationX:0,translationY:0},true);F.applyTransformations();l=F.attr.inverseMatrix.elements.slice(0);switch(u){case"left":e=a?a.x+a.width:0;switch(F.attr.textAlign){case"start":H=E.roundPixel(e+d)-i;break;case"end":H=E.roundPixel(K[2]-G+d)-i;break;default:H=E.roundPixel(e+(K[2]-e-G)/2+d)-i}F.setAttributes({translationX:H},true);break;case"right":e=a?K[2]-a.x:0;switch(F.attr.textAlign){case"start":H=E.roundPixel(G+d)+i;break;case"end":H=E.roundPixel(K[2]-e+d)+i;break;default:H=E.roundPixel(G+(K[2]-G-e)/2+d)+i}F.setAttributes({translationX:H},true);break;case"top":e=a?a.y+a.height:0;F.setAttributes({translationY:E.roundPixel(e+(K[3]-e-G)/2)-i},true);break;case"bottom":e=a?K[3]-a.y:0;F.setAttributes({translationY:E.roundPixel(G+(K[3]-G-e)/2)+i},true);break;case"radial":F.setAttributes({translationX:k.centerX},true);break;case"angular":F.setAttributes({translationY:k.centerY},true);break;case"gauge":F.setAttributes({translationY:k.centerY},true);break}if(u==="left"||u==="right"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;F.setAttributes({text:String(v),translationY:E.roundPixel(L*g+c)},true);F.applyTransformations();n=Math.max(n,F.getBBox().width+G);if(n<=o.thickness){C=Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));p=C.prepend.apply(C,l).transformBBox(F.getBBox(true));if(h&&!f(p,h,A)){return}E.renderSprite(F);h=p;w+=p.height;b++}})}else{if(u==="top"||u==="bottom"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;F.setAttributes({text:String(v),translationX:E.roundPixel(L*x+d)},true);F.applyTransformations();n=Math.max(n,F.getBBox().height+G);if(n<=o.thickness){C=Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));p=C.prepend.apply(C,l).transformBBox(F.getBBox(true));if(h&&!f(p,h,A)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="radial"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;if(typeof v!=="undefined"){F.setAttributes({text:String(v),translationX:k.centerX-E.roundPixel(L)/k.max*k.length*Math.cos(k.baseRotation+Math.PI/2),translationY:k.centerY-E.roundPixel(L)/k.max*k.length*Math.sin(k.baseRotation+Math.PI/2)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="angular"){s=k.majorTickSize+k.lineWidth*0.5+(parseInt(F.attr.fontSize,10)||10)/2;o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;n=Math.max(n,Math.max(k.majorTickSize,k.minorTickSize)+(k.lineCap!=="butt"?k.lineWidth*0.5:0));if(typeof v!=="undefined"){var O=L/(k.max+1)*Math.PI*2+k.baseRotation;F.setAttributes({text:String(v),translationX:k.centerX+(k.length+s)*Math.cos(O),translationY:k.centerY+(k.length+s)*Math.sin(O)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="gauge"){var j=o.getGaugeAngles();o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;if(typeof v!=="undefined"){var O=(L-k.min)/(k.max-k.min+1)*k.totalAngle-k.totalAngle+j.start;F.setAttributes({text:String(v),translationX:k.centerX+(k.length+10)*Math.cos(O),translationY:k.centerY+(k.length+10)*Math.sin(O)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}}}}}if(k.enlargeEstStepSizeByText&&b){w/=b;w+=G;w*=2;if(k.estStepSize<w){k.estStepSize=w}}if(Math.abs(o.thickness-(n))>1){o.thickness=n;k.bbox.plain.dirty=true;k.bbox.transform.dirty=true;o.doThicknessChanged();return false}}},renderAxisLine:function(a,i,e,c){var h=this,g=h.attr,b=g.lineWidth*0.5,j=g.position,d,f;if(g.axisLine&&g.length){switch(j){case"left":d=a.roundPixel(c[2])-b;i.moveTo(d,-g.endGap);i.lineTo(d,g.length+g.startGap+1);break;case"right":i.moveTo(b,-g.endGap);i.lineTo(b,g.length+g.startGap+1);break;case"bottom":i.moveTo(-g.startGap,b);i.lineTo(g.length+g.endGap,b);break;case"top":d=a.roundPixel(c[3])-b;i.moveTo(-g.startGap,d);i.lineTo(g.length+g.endGap,d);break;case"angular":i.moveTo(g.centerX+g.length,g.centerY);i.arc(g.centerX,g.centerY,g.length,0,Math.PI*2,true);break;case"gauge":f=h.getGaugeAngles();i.moveTo(g.centerX+Math.cos(f.start)*g.length,g.centerY+Math.sin(f.start)*g.length);i.arc(g.centerX,g.centerY,g.length,f.start,f.end,true);break}}},getGaugeAngles:function(){var a=this,c=a.attr.totalAngle,b;if(c<=Math.PI){b=(Math.PI-c)*0.5}else{b=-(Math.PI*2-c)*0.5}b=Math.PI*2-b;return{start:b,end:b-c}},renderGridLines:function(m,n,s,r){var t=this,b=t.getAxis(),l=t.attr,p=l.matrix,d=l.startGap,a=l.endGap,c=p.getXX(),k=p.getYY(),h=p.getDX(),g=p.getDY(),u=l.position,f=b.getGridAlignment(),q=s.majorTicks,e,o,i;if(l.grid){if(q){if(u==="left"||u==="right"){i=l.min*k+g+a+d;t.iterate(q,function(j,w,v){e=j*k+g+a;t.putMarker(f+"-"+(v%2?"odd":"even"),{y:e,height:i-e},o=v,true);i=e});o++;e=0;t.putMarker(f+"-"+(o%2?"odd":"even"),{y:e,height:i-e},o,true)}else{if(u==="top"||u==="bottom"){i=l.min*c+h+d;if(d){t.putMarker(f+"-even",{x:0,width:i},-1,true)}t.iterate(q,function(j,w,v){e=j*c+h+d;t.putMarker(f+"-"+(v%2?"odd":"even"),{x:e,width:i-e},o=v,true);i=e});o++;e=l.length+l.startGap+l.endGap;t.putMarker(f+"-"+(o%2?"odd":"even"),{x:e,width:i-e},o,true)}else{if(u==="radial"){t.iterate(q,function(j,w,v){if(!j){return}e=j/l.max*l.length;t.putMarker(f+"-"+(v%2?"odd":"even"),{scalingX:e,scalingY:e},v,true);i=e})}else{if(u==="angular"){t.iterate(q,function(j,w,v){if(!l.length){return}e=j/(l.max+1)*Math.PI*2+l.baseRotation;t.putMarker(f+"-"+(v%2?"odd":"even"),{rotationRads:e,rotationCenterX:0,rotationCenterY:0,scalingX:l.length,scalingY:l.length},v,true);i=e})}}}}}}},renderLimits:function(o){var t=this,a=t.getAxis(),h=a.getChart(),p=h.getInnerPadding(),d=Ext.Array.from(a.getLimits());if(!d.length){return}var r=a.limits.surface.getRect(),m=t.attr,n=m.matrix,u=m.position,k=Ext.Object.chain,v=a.limits.titles,c,j,b,s,l,q,f,g,e;v.instances=[];v.position=0;if(u==="left"||u==="right"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l*n.getYY()+n.getDY();s.line.y=l+p.top;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("horizontal-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);j=s.line.title.position||(u==="left"?"start":"end");switch(j){case"start":g=10;break;case"end":g=r[2]-10;break;case"middle":g=r[2]/2;break}v.setAttributesFor(v.position-1,{x:g,y:s.line.y-c.height/2,textAlign:j,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="top"||u==="bottom"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l*n.getXX()+n.getDX();s.line.x=l+p.left;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("vertical-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);j=s.line.title.position||(u==="top"?"end":"start");switch(j){case"start":e=r[3]-c.width/2-10;break;case"end":e=c.width/2+10;break;case"middle":e=r[3]/2;break}v.setAttributesFor(v.position-1,{x:s.line.x+c.height/2,y:e,fillStyle:s.line.title.fillStyle||s.line.strokeStyle,rotationRads:Math.PI/2})}}}else{if(u==="radial"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;if(l>m.max){continue}l=l/m.max*m.length;s.line.cx=m.centerX;s.line.cy=m.centerY;s.line.scalingX=l;s.line.scalingY=l;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("circular-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);v.setAttributesFor(v.position-1,{x:m.centerX,y:m.centerY-l-c.height/2,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="angular"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l/(m.max+1)*Math.PI*2+m.baseRotation;s.line.translationX=m.centerX;s.line.translationY=m.centerY;s.line.rotationRads=l;s.line.rotationCenterX=0;s.line.rotationCenterY=0;s.line.scalingX=m.length;s.line.scalingY=m.length;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("radial-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);b=((l>-0.5*Math.PI&&l<0.5*Math.PI)||(l>1.5*Math.PI&&l<2*Math.PI))?1:-1;v.setAttributesFor(v.position-1,{x:m.centerX+0.5*m.length*Math.cos(l)+b*c.height/2*Math.sin(l),y:m.centerY+0.5*m.length*Math.sin(l)-b*c.height/2*Math.cos(l),rotationRads:b===1?l:l-Math.PI,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="gauge"){}}}}}},doThicknessChanged:function(){var a=this.getAxis();if(a){a.onThicknessChanged()}},render:function(a,c,d){var e=this,b=e.getLayoutContext();if(b){if(false===e.renderLabels(a,c,b,d)){return false}c.beginPath();e.renderTicks(a,c,b,d);e.renderAxisLine(a,c,b,d);e.renderGridLines(a,c,b,d);e.renderLimits(d);c.stroke()}}});Ext.define("Ext.chart.axis.segmenter.Segmenter",{config:{axis:null},constructor:function(a){this.initConfig(a)},renderer:function(b,a){return String(b)},from:function(a){return a},diff:Ext.emptyFn,align:Ext.emptyFn,add:Ext.emptyFn,preferredStep:Ext.emptyFn});Ext.define("Ext.chart.axis.segmenter.Names",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.names",renderer:function(b,a){return b},diff:function(b,a,c){return Math.floor(a-b)},align:function(c,b,a){return Math.floor(c)},add:function(c,b,a){return c+b},preferredStep:function(c,a,b,d){return{unit:1,step:1}}});Ext.define("Ext.chart.axis.segmenter.Numeric",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.numeric",isNumeric:true,renderer:function(b,a){return b.toFixed(Math.max(0,a.majorTicks.unit.fixes))},diff:function(b,a,c){return Math.floor((a-b)/c.scale)},align:function(c,b,a){return Math.floor(c/(a.scale*b))*a.scale*b},add:function(c,b,a){return c+b*a.scale},preferredStep:function(c,b){var a=Math.floor(Math.log(b)*Math.LOG10E),d=Math.pow(10,a);b/=d;if(b<2){b=2}else{if(b<5){b=5}else{if(b<10){b=10;a++}}}return{unit:{fixes:-a,scale:d},step:b}},exactStep:function(c,b){var a=Math.floor(Math.log(b)*Math.LOG10E),d=Math.pow(10,a);return{unit:{fixes:-a+(b%d===0?0:1),scale:1},step:b}},adjustByMajorUnit:function(e,g,c){var d=c[0],b=c[1],a=e*g,f=d%a;if(f!==0){c[0]=d-f+(d<0?-a:0)}f=b%a;if(f!==0){c[1]=b-f+(b>0?a:0)}}});Ext.define("Ext.chart.axis.segmenter.Time",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.time",config:{step:null},renderer:function(c,b){var a=Ext.Date;switch(b.majorTicks.unit){case"y":return a.format(c,"Y");case"mo":return a.format(c,"Y-m");case"d":return a.format(c,"Y-m-d")}return a.format(c,"Y-m-d\nH:i:s")},from:function(a){return new Date(a)},diff:function(b,a,c){if(isFinite(b)){b=new Date(b)}if(isFinite(a)){a=new Date(a)}return Ext.Date.diff(b,a,c)},align:function(a,c,b){if(b==="d"&&c>=7){a=Ext.Date.align(a,"d",c);a.setDate(a.getDate()-a.getDay()+1);return a}else{return Ext.Date.align(a,b,c)}},add:function(c,b,a){return Ext.Date.add(new Date(c),a,b)},stepUnits:[[Ext.Date.YEAR,1,2,5,10,20,50,100,200,500],[Ext.Date.MONTH,1,3,6],[Ext.Date.DAY,1,7,14],[Ext.Date.HOUR,1,6,12],[Ext.Date.MINUTE,1,5,15,30],[Ext.Date.SECOND,1,5,15,30],[Ext.Date.MILLI,1,2,5,10,20,50,100,200,500]],preferredStep:function(b,e){if(this.getStep()){return this.getStep()}var f=new Date(+b),g=new Date(+b+Math.ceil(e)),d=this.stepUnits,l,k,h,c,a;for(c=0;c<d.length;c++){k=d[c][0];h=this.diff(f,g,k);if(h>0){for(a=1;a<d[c].length;a++){if(h<=d[c][a]){l={unit:k,step:d[c][a]};break}}if(!l){c--;l={unit:d[c][0],step:1}}break}}if(!l){l={unit:Ext.Date.DAY,step:1}}return l}});Ext.define("Ext.chart.axis.layout.Layout",{mixins:{observable:"Ext.mixin.Observable"},config:{axis:null},constructor:function(a){this.mixins.observable.constructor.call(this,a)},processData:function(b){var e=this,c=e.getAxis(),f=c.getDirection(),g=c.boundSeries,a,d;if(b){b["coordinate"+f]()}else{for(a=0,d=g.length;a<d;a++){g[a]["coordinate"+f]()}}},calculateMajorTicks:function(a){var f=this,e=a.attr,d=e.max-e.min,i=d/Math.max(1,e.length)*(e.visibleMax-e.visibleMin),h=e.min+d*e.visibleMin,b=e.min+d*e.visibleMax,g=e.estStepSize*i,c=f.snapEnds(a,e.min,e.max,g);if(c){f.trimByRange(a,c,h,b);a.majorTicks=c}},calculateMinorTicks:function(a){if(this.snapMinorEnds){a.minorTicks=this.snapMinorEnds(a)}},calculateLayout:function(b){var c=this,a=b.attr;if(a.length===0){return null}if(a.majorTicks){c.calculateMajorTicks(b);if(a.minorTicks){c.calculateMinorTicks(b)}}},snapEnds:Ext.emptyFn,trimByRange:function(b,f,i,a){var g=b.segmenter,j=f.unit,h=g.diff(f.from,i,j),d=g.diff(f.from,a,j),c=Math.max(0,Math.ceil(h/f.step)),e=Math.min(f.steps,Math.floor(d/f.step));if(e<f.steps){f.to=g.add(f.from,e*f.step,j)}if(f.max>a){f.max=f.to}if(f.from<i){f.from=g.add(f.from,c*f.step,j);while(f.from<i){c++;f.from=g.add(f.from,f.step,j)}}if(f.min<i){f.min=f.from}f.steps=e-c}});Ext.define("Ext.chart.axis.layout.Discrete",{extend:"Ext.chart.axis.layout.Layout",alias:"axisLayout.discrete",isDiscrete:true,processData:function(){var f=this,d=f.getAxis(),c=d.boundSeries,g=d.getDirection(),b,e,a;f.labels=[];f.labelMap={};for(b=0,e=c.length;b<e;b++){a=c[b];if(a["get"+g+"Axis"]()===d){a["coordinate"+g]()}}d.getSprites()[0].setAttributes({data:f.labels});f.fireEvent("datachange",f.labels)},calculateLayout:function(a){a.data=this.labels;this.callParent([a])},calculateMajorTicks:function(a){var g=this,f=a.attr,d=a.data,e=f.max-f.min,j=e/Math.max(1,f.length)*(f.visibleMax-f.visibleMin),i=f.min+e*f.visibleMin,b=f.min+e*f.visibleMax,h=f.estStepSize*j;var c=g.snapEnds(a,Math.max(0,f.min),Math.min(f.max,d.length-1),h);if(c){g.trimByRange(a,c,i,b);a.majorTicks=c}},snapEnds:function(e,d,a,b){b=Math.ceil(b);var c=Math.floor((a-d)/b),f=e.data;return{min:d,max:a,from:d,to:c*b+d,step:b,steps:c,unit:1,getLabel:function(g){return f[this.from+this.step*g]},get:function(g){return this.from+this.step*g}}},trimByRange:function(b,f,h,a){var i=f.unit,g=Math.ceil((h-f.from)/i)*i,d=Math.floor((a-f.from)/i)*i,c=Math.max(0,Math.ceil(g/f.step)),e=Math.min(f.steps,Math.floor(d/f.step));if(e<f.steps){f.to=e}if(f.max>a){f.max=f.to}if(f.from<h&&f.step>0){f.from=f.from+c*f.step*i;while(f.from<h){c++;f.from+=f.step*i}}if(f.min<h){f.min=f.from}f.steps=e-c},getCoordFor:function(c,d,a,b){this.labels.push(c);return this.labels.length-1}});Ext.define("Ext.chart.axis.layout.CombineDuplicate",{extend:"Ext.chart.axis.layout.Discrete",alias:"axisLayout.combineDuplicate",getCoordFor:function(d,e,b,c){if(!(d in this.labelMap)){var a=this.labelMap[d]=this.labels.length;this.labels.push(d);return a}return this.labelMap[d]}});Ext.define("Ext.chart.axis.layout.Continuous",{extend:"Ext.chart.axis.layout.Layout",alias:"axisLayout.continuous",isContinuous:true,config:{adjustMinimumByMajorUnit:false,adjustMaximumByMajorUnit:false},getCoordFor:function(c,d,a,b){return +c},snapEnds:function(a,d,i,h){var f=a.segmenter,c=this.getAxis(),l=c.getMajorTickSteps(),e=l&&f.exactStep?f.exactStep(d,(i-d)/l):f.preferredStep(d,h),k=e.unit,b=e.step,j=f.align(d,b,k),g=(l||f.diff(d,i,k))+1;return{min:f.from(d),max:f.from(i),from:j,to:f.add(j,g*b,k),step:b,steps:g,unit:k,get:function(m){return f.add(this.from,this.step*m,k)}}},snapMinorEnds:function(a){var e=a.majorTicks,m=this.getAxis().getMinorTickSteps(),f=a.segmenter,d=e.min,i=e.max,k=e.from,l=e.unit,b=e.step/m,n=b*l.scale,j=k-d,c=Math.floor(j/n),h=c+Math.floor((i-e.to)/n)+1,g=e.steps*m+h;return{min:d,max:i,from:d+j%n,to:f.add(k,g*b,l),step:b,steps:g,unit:l,get:function(o){return(o%m+c+1!==0)?f.add(this.from,this.step*o,l):null}}}});Ext.define("Ext.chart.axis.Axis",{xtype:"axis",mixins:{observable:"Ext.mixin.Observable"},requires:["Ext.chart.axis.sprite.Axis","Ext.chart.axis.segmenter.*","Ext.chart.axis.layout.*"],isAxis:true,config:{position:"bottom",fields:[],label:undefined,grid:false,limits:null,renderer:null,chart:null,style:null,margin:0,titleMargin:4,background:null,minimum:NaN,maximum:NaN,reconcileRange:false,minZoom:1,maxZoom:10000,layout:"continuous",segmenter:"numeric",hidden:false,majorTickSteps:0,minorTickSteps:0,adjustByMajorUnit:true,title:null,increment:0.5,length:0,center:null,radius:null,totalAngle:Math.PI,rotation:null,labelInSpan:null,visibleRange:[0,1],needHighPrecision:false,linkedTo:null,floating:null},titleOffset:0,spriteAnimationCount:0,prevMin:0,prevMax:1,boundSeries:[],sprites:null,surface:null,range:null,xValues:[],yValues:[],masterAxis:null,applyRotation:function(b){var a=Math.PI*2;return(b%a+Math.PI)%a-Math.PI},updateRotation:function(b){var c=this.getSprites(),a=this.getPosition();if(!this.getHidden()&&a==="angular"&&c[0]){c[0].setAttributes({baseRotation:b})}},applyTitle:function(c,b){var a;if(Ext.isString(c)){c={text:c}}if(!b){b=Ext.create("sprite.text",c);if((a=this.getSurface())){a.add(b)}}else{b.setAttributes(c)}return b},applyFloating:function(b,a){if(b===null){b={value:null,alongAxis:null}}else{if(Ext.isNumber(b)){b={value:b,alongAxis:null}}}if(Ext.isObject(b)){if(a&&a.alongAxis){delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]}return b}return a},constructor:function(a){var b=this,c;b.sprites=[];b.labels=[];b.floatingAxes={};a=a||{};if(a.position==="angular"){a.style=a.style||{};a.style.estStepSize=1}if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.mixins.observable.constructor.apply(b,arguments)},getAlignment:function(){switch(this.getPosition()){case"left":case"right":return"vertical";case"top":case"bottom":return"horizontal";case"radial":return"radial";case"angular":return"angular"}},getGridAlignment:function(){switch(this.getPosition()){case"left":case"right":return"horizontal";case"top":case"bottom":return"vertical";case"radial":return"circular";case"angular":return"radial"}},getSurface:function(){var e=this,d=e.getChart();if(d&&!e.surface){var b=e.surface=d.getSurface(e.getId(),"axis"),c=e.gridSurface=d.getSurface("main"),a=e.getSprites()[0],f=e.getGridAlignment();c.waitFor(b);e.getGrid();if(e.getLimits()&&f){f=f.replace("3d","");e.limits={surface:d.getSurface("overlay"),lines:new Ext.chart.Markers(),titles:new Ext.draw.sprite.Instancing()};e.limits.lines.setTemplate({xclass:"grid."+f});e.limits.lines.getTemplate().setAttributes({strokeStyle:"black"},true);e.limits.surface.add(e.limits.lines);a.bindMarker(f+"-limit-lines",e.limits.lines);e.limitTitleTpl=new Ext.draw.sprite.Text();e.limits.titles.setTemplate(e.limitTitleTpl);e.limits.surface.add(e.limits.titles);d.on("redraw",e.renderLimits,e)}}return e.surface},applyGrid:function(a){if(a===true){return{}}return a},updateGrid:function(b){var e=this,d=e.getChart();if(!d){e.on({chartattached:Ext.bind(e.updateGrid,e,[b]),single:true});return}var c=e.gridSurface,a=e.getSprites()[0],f=e.getGridAlignment(),g;if(b){g=e.gridSpriteEven;if(!g){g=e.gridSpriteEven=new Ext.chart.Markers();g.setTemplate({xclass:"grid."+f});c.add(g);a.bindMarker(f+"-even",g)}if(Ext.isObject(b)){g.getTemplate().setAttributes(b);if(Ext.isObject(b.even)){g.getTemplate().setAttributes(b.even)}}g=e.gridSpriteOdd;if(!g){g=e.gridSpriteOdd=new Ext.chart.Markers();g.setTemplate({xclass:"grid."+f});c.add(g);a.bindMarker(f+"-odd",g)}if(Ext.isObject(b)){g.getTemplate().setAttributes(b);if(Ext.isObject(b.odd)){g.getTemplate().setAttributes(b.odd)}}}},renderLimits:function(){this.getSprites()[0].renderLimits()},getCoordFor:function(c,d,a,b){return this.getLayout().getCoordFor(c,d,a,b)},applyPosition:function(a){return a.toLowerCase()},applyLength:function(b,a){return b>0?b:a},applyLabel:function(b,a){if(!a){a=new Ext.draw.sprite.Text({})}if(this.limitTitleTpl){this.limitTitleTpl.setAttributes(b)}a.setAttributes(b);return a},applyLayout:function(b,a){b=Ext.factory(b,null,a,"axisLayout");b.setAxis(this);return b},applySegmenter:function(a,b){a=Ext.factory(a,null,b,"segmenter");a.setAxis(this);return a},updateMinimum:function(){this.range=null},updateMaximum:function(){this.range=null},hideLabels:function(){this.getSprites()[0].setDirty(true);this.setLabel({hidden:true})},showLabels:function(){this.getSprites()[0].setDirty(true);this.setLabel({hidden:false})},renderFrame:function(){this.getSurface().renderFrame()},updateChart:function(d,b){var c=this,a;if(b){b.unregister(c);b.un("serieschange",c.onSeriesChange,c);b.un("redraw",c.renderLimits,c);c.linkAxis();c.fireEvent("chartdetached",b,c)}if(d){d.on("serieschange",c.onSeriesChange,c);c.surface=null;a=c.getSurface();c.getLabel().setSurface(a);a.add(c.getSprites());a.add(c.getTitle());d.register(c);c.fireEvent("chartattached",d,c)}},applyBackground:function(a){var b=Ext.ClassManager.getByAlias("sprite.rect");return b.def.normalize(a)},processData:function(){this.getLayout().processData();this.range=null},getDirection:function(){return this.getChart().getDirectionForAxis(this.getPosition())},isSide:function(){var a=this.getPosition();return a==="left"||a==="right"},applyFields:function(a){return Ext.Array.from(a)},applyVisibleRange:function(a,c){this.getChart();if(a[0]>a[1]){var b=a[0];a[0]=a[1];a[0]=b}if(a[1]===a[0]){a[1]+=1/this.getMaxZoom()}if(a[1]>a[0]+1){a[0]=0;a[1]=1}else{if(a[0]<0){a[1]-=a[0];a[0]=0}else{if(a[1]>1){a[0]-=a[1]-1;a[1]=1}}}if(c&&a[0]===c[0]&&a[1]===c[1]){return undefined}return a},updateVisibleRange:function(a){this.fireEvent("visiblerangechange",this,a)},onSeriesChange:function(e){var f=this,b=e.getSeries(),j="get"+f.getDirection()+"Axis",g=[],c,d=b.length,a,h;for(c=0;c<d;c++){if(this===b[c][j]()){g.push(b[c])}}f.boundSeries=g;a=f.getLinkedTo();h=!Ext.isEmpty(a)&&e.getAxis(a);if(h){f.linkAxis(h)}else{f.getLayout().processData()}},linkAxis:function(a){var c=this;function b(f,d,e){e.getLayout()[f]("datachange","onDataChange",d);e[f]("rangechange","onMasterAxisRangeChange",d)}if(c.masterAxis){b("un",c,c.masterAxis);c.masterAxis=null}if(a){if(a.type!==this.type){Ext.Error.raise("Linked axes must be of the same type.")}b("on",c,a);c.onDataChange(a.getLayout().labels);c.onMasterAxisRangeChange(a,a.range);c.setStyle(Ext.apply({},c.config.style,a.config.style));c.setTitle(Ext.apply({},c.config.title,a.config.title));c.setLabel(Ext.apply({},c.config.label,a.config.label));c.masterAxis=a}},onDataChange:function(a){this.getLayout().labels=a},onMasterAxisRangeChange:function(b,a){this.range=a},applyRange:function(a){if(!a){return this.dataRange.slice(0)}else{return[a[0]===null?this.dataRange[0]:a[0],a[1]===null?this.dataRange[1]:a[1]]}},getRange:function(){var m=this;if(m.range){return m.range}else{if(m.masterAxis){return m.masterAxis.range}}if(Ext.isNumber(m.getMinimum()+m.getMaximum())){return m.range=[m.getMinimum(),m.getMaximum()]}var d=Infinity,n=-Infinity,o=m.boundSeries,h=m.getLayout(),l=m.getSegmenter(),p=m.getVisibleRange(),b="get"+m.getDirection()+"Range",a,j,g,f,e,k;for(e=0,k=o.length;e<k;e++){f=o[e];var c=f[b]();if(c){if(c[0]<d){d=c[0]}if(c[1]>n){n=c[1]}}}if(!isFinite(n)){n=m.prevMax}if(!isFinite(d)){d=m.prevMin}if(m.getLabelInSpan()||d===n){n+=m.getIncrement();d-=m.getIncrement()}if(Ext.isNumber(m.getMinimum())){d=m.getMinimum()}else{m.prevMin=d}if(Ext.isNumber(m.getMaximum())){n=m.getMaximum()}else{m.prevMax=n}m.range=[Ext.Number.correctFloat(d),Ext.Number.correctFloat(n)];if(m.getReconcileRange()){m.reconcileRange()}if(m.getAdjustByMajorUnit()&&l.adjustByMajorUnit&&!m.getMajorTickSteps()){j=Ext.Object.chain(m.getSprites()[0].attr);j.min=m.range[0];j.max=m.range[1];j.visibleMin=p[0];j.visibleMax=p[1];a={attr:j,segmenter:l};h.calculateLayout(a);g=a.majorTicks;if(g){l.adjustByMajorUnit(g.step,g.unit.scale,m.range);j.min=m.range[0];j.max=m.range[1];delete a.majorTicks;h.calculateLayout(a);g=a.majorTicks;l.adjustByMajorUnit(g.step,g.unit.scale,m.range)}else{if(!m.hasClearRangePending){m.hasClearRangePending=true;m.getChart().on("layout","clearRange",m)}}}if(!Ext.Array.equals(m.range,m.oldRange||[])){m.fireEvent("rangechange",m,m.range);m.oldRange=m.range}return m.range},clearRange:function(){delete this.hasClearRangePending;this.range=null},reconcileRange:function(){var e=this,g=e.getChart().getAxes(),f=e.getDirection(),b,d,c,a;if(!g){return}for(b=0,d=g.length;b<d;b++){c=g[b];a=c.getRange();if(c===e||c.getDirection()!==f||!a||!c.getReconcileRange()){continue}if(a[0]<e.range[0]){e.range[0]=a[0]}if(a[1]>e.range[1]){e.range[1]=a[1]}}},applyStyle:function(c,b){var a=Ext.ClassManager.getByAlias("sprite."+this.seriesType);if(a&&a.def){c=a.def.normalize(c)}b=Ext.apply(b||{},c);return b},themeOnlyIfConfigured:{grid:true},updateTheme:function(d){var i=this,k=d.getAxis(),e=i.getPosition(),o=i.getInitialConfig(),c=i.defaultConfig,g=i.getConfigurator().configs,a=k.defaults,n=k[e],h=i.themeOnlyIfConfigured,l,j,p,b,m,f;k=Ext.merge({},a,n);for(l in k){j=k[l];f=g[l];if(j!==null&&j!==undefined&&f){m=o[l];p=Ext.isObject(j);b=m===c[l];if(p){if(b&&h[l]){continue}j=Ext.merge({},j,m)}if(b||p){i[f.names.set](j)}}}},updateCenter:function(b){var e=this.getSprites(),a=e[0],d=b[0],c=b[1];if(a){a.setAttributes({centerX:d,centerY:c})}if(this.gridSpriteEven){this.gridSpriteEven.getTemplate().setAttributes({translationX:d,translationY:c,rotationCenterX:d,rotationCenterY:c})}if(this.gridSpriteOdd){this.gridSpriteOdd.getTemplate().setAttributes({translationX:d,translationY:c,rotationCenterX:d,rotationCenterY:c})}},getSprites:function(){if(!this.getChart()){return}var i=this,e=i.getRange(),f=i.getPosition(),g=i.getChart(),c=g.getAnimation(),d,a,b=i.getLength(),h=i.superclass;if(c===false){c={duration:0}}if(e){a=Ext.applyIf({position:f,axis:i,min:e[0],max:e[1],length:b,grid:i.getGrid(),hidden:i.getHidden(),titleOffset:i.titleOffset,layout:i.getLayout(),segmenter:i.getSegmenter(),totalAngle:i.getTotalAngle(),label:i.getLabel()},i.getStyle());if(!i.sprites.length){while(!h.xtype){h=h.superclass}d=Ext.create("sprite."+h.xtype,a);d.fx.setCustomDurations({baseRotation:0});d.fx.on("animationstart","onAnimationStart",i);d.fx.on("animationend","onAnimationEnd",i);d.setLayout(i.getLayout());d.setSegmenter(i.getSegmenter());d.setLabel(i.getLabel());i.sprites.push(d);i.updateTitleSprite()}else{d=i.sprites[0];d.setAnimation(c);d.setAttributes(a)}if(i.getRenderer()){d.setRenderer(i.getRenderer())}}return i.sprites},updateTitleSprite:function(){var f=this,b=f.getLength();if(!f.sprites[0]||!Ext.isNumber(b)){return}var h=this.sprites[0].thickness,a=f.getSurface(),g=f.getTitle(),e=f.getPosition(),c=f.getMargin(),i=f.getTitleMargin(),d=a.roundPixel(b/2);if(g){switch(e){case"top":g.setAttributes({x:d,y:c+i/2,textBaseline:"top",textAlign:"center"},true);g.applyTransformations();f.titleOffset=g.getBBox().height+i;break;case"bottom":g.setAttributes({x:d,y:h+i/2,textBaseline:"top",textAlign:"center"},true);g.applyTransformations();f.titleOffset=g.getBBox().height+i;break;case"left":g.setAttributes({x:c+i/2,y:d,textBaseline:"top",textAlign:"center",rotationCenterX:c+i/2,rotationCenterY:d,rotationRads:-Math.PI/2},true);g.applyTransformations();f.titleOffset=g.getBBox().width+i;break;case"right":g.setAttributes({x:h-c+i/2,y:d,textBaseline:"bottom",textAlign:"center",rotationCenterX:h+i/2,rotationCenterY:d,rotationRads:Math.PI/2},true);g.applyTransformations();f.titleOffset=g.getBBox().width+i;break}}},onThicknessChanged:function(){this.getChart().onThicknessChanged()},getThickness:function(){if(this.getHidden()){return 0}return(this.sprites[0]&&this.sprites[0].thickness||1)+this.titleOffset+this.getMargin()},onAnimationStart:function(){this.spriteAnimationCount++;if(this.spriteAnimationCount===1){this.fireEvent("animationstart",this)}},onAnimationEnd:function(){this.spriteAnimationCount--;if(this.spriteAnimationCount===0){this.fireEvent("animationend",this)}},getItemId:function(){return this.getId()},getAncestorIds:function(){return[this.getChart().getId()]},isXType:function(a){return a==="axis"},resolveListenerScope:function(e){var d=this,a=Ext._namedScopes[e],c=d.getChart(),b;if(!a){b=c?c.resolveListenerScope(e,false):(e||d)}else{if(a.isThis){b=d}else{if(a.isController){b=c?c.resolveListenerScope(e,false):d}else{if(a.isSelf){b=c?c.resolveListenerScope(e,false):d;if(b===c&&!c.getInheritedConfig("defaultListenerScope")){b=d}}}}}return b},destroy:function(){var a=this;a.setChart(null);a.surface.destroy();a.surface=null;a.callParent()}});Ext.define("Ext.chart.LegendBase",{extend:"Ext.view.View",config:{tpl:['<div class="',Ext.baseCSSPrefix,'legend-container">','<tpl for=".">','<div class="',Ext.baseCSSPrefix,'legend-item">',"<span ",'class="',Ext.baseCSSPrefix,"legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ",'style="background:{mark};">',"</span>{name}","</div>","</tpl>","</div>"],nodeContainerSelector:"div."+Ext.baseCSSPrefix+"legend-container",itemSelector:"div."+Ext.baseCSSPrefix+"legend-item",docked:"bottom"},setDocked:function(d){var c=this,a=c.ownerCt,b;c.docked=d;switch(d){case"top":case"bottom":c.addCls(Ext.baseCSSPrefix+"horizontal");b="hbox";break;case"left":case"right":c.removeCls(Ext.baseCSSPrefix+"horizontal");b="vbox";break}if(a){a.setDocked(d)}},setStore:function(a){this.bindStore(a)},clearViewEl:function(){this.callParent(arguments);Ext.removeNode(this.getNodeContainer())},onItemClick:function(a,c,b,d){this.callParent(arguments);this.toggleItem(b)}});Ext.define("Ext.chart.Legend",{xtype:"legend",extend:"Ext.chart.LegendBase",config:{baseCls:Ext.baseCSSPrefix+"legend",padding:5,rect:null,disableSelection:true,toggleable:true},toggleItem:function(c){if(!this.getToggleable()){return}var b=this.getStore(),h=0,e,g=true,d,f,a;if(b){f=b.getCount();for(d=0;d<f;d++){a=b.getAt(d);if(a.get("disabled")){h++}}g=f-h>1;a=b.getAt(c);if(a){e=a.get("disabled");if(e||g){a.set("disabled",!e)}}}}});Ext.define("Ext.chart.AbstractChart",{extend:"Ext.draw.Container",requires:["Ext.chart.theme.Default","Ext.chart.series.Series","Ext.chart.interactions.Abstract","Ext.chart.axis.Axis","Ext.data.StoreManager","Ext.chart.Legend","Ext.data.Store"],isChart:true,defaultBindProperty:"store",config:{store:"ext-empty-store",theme:"default",style:null,animation:!Ext.isIE8,series:[],axes:[],legend:null,colors:null,insetPadding:{top:10,left:10,right:10,bottom:10},background:null,interactions:[],mainRect:null,resizeHandler:null,highlightItem:null},animationSuspendCount:0,chartLayoutSuspendCount:0,axisThicknessSuspendCount:0,isThicknessChanged:false,surfaceZIndexes:{background:0,main:1,grid:2,series:3,axis:4,chart:5,overlay:6,events:7},constructor:function(a){var b=this;b.itemListeners={};b.surfaceMap={};b.chartComponents={};b.isInitializing=true;b.suspendChartLayout();b.animationSuspendCount++;b.callParent(arguments);delete b.isInitializing;b.getSurface("main");b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);b.getSurface("overlay").waitFor(b.getSurface("series"));b.animationSuspendCount--;b.resumeChartLayout()},applyAnimation:function(a,b){if(!a){a={duration:0}}else{if(a===true){a={easing:"easeInOut",duration:500}}}return b?Ext.apply({},a,b):a},getAnimation:function(){if(this.animationSuspendCount){return{duration:0}}else{return this.callParent()}},applyInsetPadding:function(b,a){if(!Ext.isObject(b)){return Ext.util.Format.parseBox(b)}else{if(!a){return b}else{return Ext.apply(a,b)}}},suspendAnimation:function(){var d=this,c=d.getSeries(),e=c.length,b=-1,a;d.animationSuspendCount++;if(d.animationSuspendCount===1){while(++b<e){a=c[b];a.setAnimation(a.getAnimation())}}},resumeAnimation:function(){var d=this,c=d.getSeries(),f=c.length,b=-1,a,e;d.animationSuspendCount--;if(d.animationSuspendCount===0){while(++b<f){a=c[b];e=a.getAnimation();a.setAnimation(e.duration&&e||d.getAnimation())}}},suspendChartLayout:function(){this.chartLayoutSuspendCount++;if(this.chartLayoutSuspendCount===1){if(this.scheduledLayoutId){this.layoutInSuspension=true;this.cancelChartLayout()}else{this.layoutInSuspension=false}}},resumeChartLayout:function(){this.chartLayoutSuspendCount--;if(this.chartLayoutSuspendCount===0){if(this.layoutInSuspension){this.scheduleLayout()}}},cancelChartLayout:function(){if(this.scheduledLayoutId){Ext.draw.Animator.cancel(this.scheduledLayoutId);this.scheduledLayoutId=null}},scheduleLayout:function(){var a=this;if(a.allowSchedule()&&!a.scheduledLayoutId){a.scheduledLayoutId=Ext.draw.Animator.schedule("doScheduleLayout",a)}},allowSchedule:function(){return true},doScheduleLayout:function(){if(this.chartLayoutSuspendCount){this.layoutInSuspension=true}else{this.performLayout()}},suspendThicknessChanged:function(){this.axisThicknessSuspendCount++},resumeThicknessChanged:function(){if(this.axisThicknessSuspendCount>0){this.axisThicknessSuspendCount--;if(this.axisThicknessSuspendCount===0&&this.isThicknessChanged){this.onThicknessChanged()}}},onThicknessChanged:function(){if(this.axisThicknessSuspendCount===0){this.isThicknessChanged=false;this.performLayout()}else{this.isThicknessChanged=true}},applySprites:function(b){var a=this.getSurface("chart");b=Ext.Array.from(b);a.removeAll(true);a.add(b);return b},initItems:function(){var a=this.items,b,d,c;if(a&&!a.isMixedCollection){this.items=[];a=Ext.Array.from(a);for(b=0,d=a.length;b<d;b++){c=a[b];if(c.type){Ext.raise("To add custom sprites to the chart use the 'sprites' config.")}else{this.items.push(c)}}}this.callParent()},applyBackground:function(c,e){var b=this.getSurface("background"),d,a,f;if(c){if(e){d=e.attr.width;a=e.attr.height;f=e.type===(c.type||"rect")}if(c.isSprite){e=c}else{if(c.type==="image"&&Ext.isString(c.src)){if(f){e.setAttributes({src:c.src})}else{b.remove(e,true);e=b.add(c)}}else{if(f){e.setAttributes({fillStyle:c})}else{b.remove(e,true);e=b.add({type:"rect",fillStyle:c,fx:{customDurations:{x:0,y:0,width:0,height:0}}})}}}}if(d&&a){e.setAttributes({width:d,height:a})}e.setAnimation(this.getAnimation());return e},getLegendStore:function(){return this.legendStore},refreshLegendStore:function(){if(this.getLegendStore()){var d,e,c=this.getSeries(),b,a=[];if(c){for(d=0,e=c.length;d<e;d++){b=c[d];if(b.getShowInLegend()){b.provideLegendInfo(a)}}}this.getLegendStore().setData(a)}},resetLegendStore:function(){var c=this.getLegendStore(),e,d,a,b;if(c){e=this.getLegendStore().getData().items;for(d=0,a=e.length;d<a;d++){b=e[d];b.beginEdit();b.set("disabled",false);b.commit()}}},onUpdateLegendStore:function(b,a){var d=this.getSeries(),c;if(a&&d){c=d.map[a.get("series")];if(c){c.setHiddenByIndex(a.get("index"),a.get("disabled"));this.redraw()}}},defaultResizeHandler:function(a){this.scheduleLayout();return false},applyMainRect:function(a,b){if(!b){return a}this.getSeries();this.getAxes();if(a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]){return b}else{return a}},register:function(a){var b=this.chartComponents,c=a.getId();b[c]=a},unregister:function(a){var b=this.chartComponents,c=a.getId();delete b[c]},get:function(a){return this.chartComponents[a]},getAxis:function(a){if(a instanceof Ext.chart.axis.Axis){return a}else{if(Ext.isNumber(a)){return this.getAxes()[a]}else{if(Ext.isString(a)){return this.get(a)}}}},getSurface:function(b,c){b=b||"main";c=c||b;var d=this,a=this.callParent([b]),f=d.surfaceZIndexes,e=d.surfaceMap;if(c in f){a.element.setStyle("zIndex",f[c])}if(!e[c]){e[c]=[]}if(Ext.Array.indexOf(e[c],a)<0){a.type=c;e[c].push(a);a.on("destroy",d.forgetSurface,d)}return a},forgetSurface:function(a){var d=this.surfaceMap;if(!d||this.isDestroying){return}var c=d[a.type],b=c?Ext.Array.indexOf(c,a):-1;if(b>=0){c.splice(b,1)}},applyAxes:function(b,k){var l=this,g={left:"right",right:"left"},m=[],c,d,e,a,f,h,j;l.animationSuspendCount++;l.getStore();if(!k){k=[];k.map={}}j=k.map;m.map={};b=Ext.Array.from(b,true);for(f=0,h=b.length;f<h;f++){c=b[f];if(!c){continue}if(c instanceof Ext.chart.axis.Axis){d=j[c.getId()];c.setChart(l)}else{c=Ext.Object.chain(c);e=c.linkedTo;a=c.id;if(Ext.isNumber(e)){c=Ext.merge({},b[e],c)}else{if(Ext.isString(e)){Ext.Array.each(b,function(i){if(i.id===c.linkedTo){c=Ext.merge({},i,c);return false}})}}c.id=a;c.chart=l;if(l.getInherited().rtl){c.position=g[c.position]||c.position}a=c.getId&&c.getId()||c.id;c=Ext.factory(c,null,d=j[a],"axis")}if(c){m.push(c);m.map[c.getId()]=c;if(!d){c.on("animationstart","onAnimationStart",l);c.on("animationend","onAnimationEnd",l)}}}for(f in j){if(!m.map[f]){j[f].destroy()}}l.animationSuspendCount--;return m},updateAxes:function(){if(!this.isDestroying){this.scheduleLayout()}},circularCopyArray:function(e,f,d){var c=[],b,a=e&&e.length;if(a){for(b=0;b<d;b++){c.push(e[(f+b)%a])}}return c},circularCopyObject:function(f,g,d){var c=this,b,e,a={};if(d){for(b in f){if(f.hasOwnProperty(b)){e=f[b];if(Ext.isArray(e)){a[b]=c.circularCopyArray(e,g,d)}else{a[b]=e}}}}return a},getColors:function(){var b=this,a=b.config.colors,c=b.getTheme();if(Ext.isArray(a)&&a.length>0){a=b.applyColors(a)}return a||(c&&c.getColors())},applyColors:function(a){a=Ext.Array.map(a,function(b){if(Ext.isString(b)){return b}else{return b.toString()}});return a},updateColors:function(c){var k=this,e=k.getTheme(),a=c||(e&&e.getColors()),l=0,f=k.getSeries(),d=f&&f.length,g,j,b,h;if(a.length){for(g=0;g<d;g++){j=f[g];h=j.themeColorCount();b=k.circularCopyArray(a,l,h);l+=h;j.updateChartColors(b)}}k.refreshLegendStore()},applyTheme:function(a){if(a&&a.isTheme){return a}return Ext.Factory.chartTheme(a)},updateTheme:function(g){var e=this,f=e.getAxes(),d=e.getSeries(),a=e.getColors(),c,b;e.updateChartTheme(g);for(b=0;b<f.length;b++){f[b].updateTheme(g)}for(b=0;b<d.length;b++){c=d[b];c.updateTheme(g)}e.updateSpriteTheme(g);e.updateColors(a);e.redraw()},themeOnlyIfConfigured:{},updateChartTheme:function(c){var i=this,k=c.getChart(),n=i.getInitialConfig(),b=i.defaultConfig,e=i.getConfigurator().configs,f=k.defaults,g=k[i.xtype],h=i.themeOnlyIfConfigured,l,j,o,a,m,d;k=Ext.merge({},f,g);for(l in k){j=k[l];d=e[l];if(j!==null&&j!==undefined&&d){m=n[l];o=Ext.isObject(j);a=m===b[l];if(o){if(a&&h[l]){continue}j=Ext.merge({},j,m)}if(a||o){i[d.names.set](j)}}}},updateSpriteTheme:function(c){this.getSprites();var j=this,e=j.getSurface("chart"),h=e.getItems(),m=c.getSprites(),k,a,l,f,d,b,g;for(b=0,g=h.length;b<g;b++){k=h[b];a=m[k.type];if(a){f={};d=k.type==="text";for(l in a){if(!(l in k.config)){if(!(d&&l.indexOf("font")===0&&k.config.font)){f[l]=a[l]}}}k.setAttributes(f)}}},addSeries:function(b){var a=this.getSeries();Ext.Array.push(a,b);this.setSeries(a)},removeSeries:function(d){d=Ext.Array.from(d);var b=this.getSeries(),f=[],a=d.length,g={},c,e;for(c=0;c<a;c++){e=d[c];if(typeof e!=="string"){e=e.getId()}g[e]=true}for(c=0,a=b.length;c<a;c++){if(!g[b[c].getId()]){f.push(b[c])}}this.setSeries(f)},applySeries:function(e,d){var g=this,j=[],h,a,c,f,b;g.animationSuspendCount++;g.getAxes();if(d){h=d.map}else{d=[];h=d.map={}}j.map={};e=Ext.Array.from(e,true);for(c=0,f=e.length;c<f;c++){b=e[c];if(!b){continue}a=h[b.getId&&b.getId()||b.id];if(b instanceof Ext.chart.series.Series){if(a&&a!==b){a.destroy()}b.setChart(g)}else{if(Ext.isObject(b)){if(a){a.setConfig(b);b=a}else{if(Ext.isString(b)){b={type:b}}b.chart=g;b=Ext.create(b.xclass||("series."+b.type),b);b.on("animationstart","onAnimationStart",g);b.on("animationend","onAnimationEnd",g)}}}j.push(b);j.map[b.getId()]=b}for(c in h){if(!j.map[h[c].getId()]){h[c].destroy()}}g.animationSuspendCount--;return j},applyLegend:function(b,a){return Ext.factory(b,Ext.chart.Legend,a)},updateLegend:function(b,a){if(a){a.destroy()}if(b){this.getItems();this.legendStore=new Ext.data.Store({autoDestroy:true,fields:["id","name","mark","disabled","series","index"]});b.setStore(this.legendStore);this.refreshLegendStore();this.legendStore.on("update","onUpdateLegendStore",this)}},updateSeries:function(b,a){var c=this;if(c.isDestroying){return}c.animationSuspendCount++;c.fireEvent("serieschange",c,b,a);c.refreshLegendStore();if(!Ext.isEmpty(b)){c.updateTheme(c.getTheme())}c.scheduleLayout();c.animationSuspendCount--},applyInteractions:function(h,d){if(!d){d=[];d.map={}}var g=this,a=[],c=d.map,e,f,b;a.map={};h=Ext.Array.from(h,true);for(e=0,f=h.length;e<f;e++){b=h[e];if(!b){continue}b=Ext.factory(b,null,c[b.getId&&b.getId()||b.id],"interaction");if(b){b.setChart(g);a.push(b);a.map[b.getId()]=b}}for(e in c){if(!a.map[e]){c[e].destroy()}}return a},getInteraction:function(e){var f=this.getInteractions(),a=f&&f.length,c=null,b,d;if(a){for(d=0;d<a;++d){b=f[d];if(b.type===e){c=b;break}}}return c},applyStore:function(a){return a&&Ext.StoreManager.lookup(a)},updateStore:function(a,c){var b=this;if(c){c.un({datachanged:"onDataChanged",update:"onDataChanged",scope:b,order:"after"});if(c.autoDestroy){c.destroy()}}if(a){a.on({datachanged:"onDataChanged",update:"onDataChanged",scope:b,order:"after"})}b.fireEvent("storechange",b,a,c);b.onDataChanged()},redraw:function(){this.fireEvent("redraw",this)},performLayout:function(){var d=this,b=d.getChartSize(true),c=[0,0,b.width,b.height],a=d.getBackground();d.hasFirstLayout=true;d.fireEvent("layout",d);d.cancelChartLayout();d.getSurface("background").setRect(c);d.getSurface("chart").setRect(c);a.setAttributes({width:b.width,height:b.height})},getChartSize:function(b){var a=this;if(b){a.chartSize=null}return a.chartSize||(a.chartSize=a.innerElement.getSize())},getEventXY:function(a){return this.getSurface().getEventXY(a)},getItemForPoint:function(h,g){var f=this,a=f.getSeries(),e=f.getMainRect(),d=a.length,b=f.hasFirstLayout?d-1:-1,c,j;if(!(e&&h>=0&&h<=e[2]&&g>=0&&g<=e[3])){return null}for(;b>=0;b--){c=a[b];j=c.getItemForPoint(h,g);if(j){return j}}return null},getItemsForPoint:function(h,g){var f=this,a=f.getSeries(),d=a.length,b=f.hasFirstLayout?d-1:-1,e=[],c,j;for(;b>=0;b--){c=a[b];j=c.getItemForPoint(h,g);if(j){e.push(j)}}return e},onAnimationStart:function(){this.fireEvent("animationstart",this)},onAnimationEnd:function(){this.fireEvent("animationend",this)},onDataChanged:function(){var d=this;if(d.isInitializing){return}var c=d.getMainRect(),a=d.getStore(),b=d.getSeries(),e=d.getAxes();if(!a||!e||!b){return}if(!c){d.on({redraw:d.onDataChanged,scope:d,single:true});return}d.processData();d.redraw()},recordCount:0,processData:function(){var g=this,e=g.getStore().getCount(),c=g.getSeries(),f=c.length,d=false,b=0,a;for(;b<f;b++){a=c[b];a.processData();if(!d&&a.isStoreDependantColorCount){d=true}}if(d&&e>g.recordCount){g.updateColors(g.getColors());g.recordCount=e}},bindStore:function(a){this.setStore(a)},applyHighlightItem:function(f,a){if(f===a){return}if(Ext.isObject(f)&&Ext.isObject(a)){var e=f,d=a,c=e.sprite&&(e.sprite[0]||e.sprite),b=d.sprite&&(d.sprite[0]||d.sprite);if(c===b&&e.index===d.index){return}}return f},updateHighlightItem:function(b,a){if(a){a.series.setAttributesForItem(a,{highlighted:false})}if(b){b.series.setAttributesForItem(b,{highlighted:true});this.fireEvent("itemhighlight",this,b,a)}this.fireEvent("itemhighlightchange",this,b,a)},destroyChart:function(){var f=this,d=f.getLegend(),g=f.getAxes(),c=f.getSeries(),h=f.getInteractions(),b=[],a,e;f.surfaceMap=null;for(a=0,e=h.length;a<e;a++){h[a].destroy()}for(a=0,e=g.length;a<e;a++){g[a].destroy()}for(a=0,e=c.length;a<e;a++){c[a].destroy()}f.setInteractions(b);f.setAxes(b);f.setSeries(b);if(d){d.destroy();f.setLegend(null)}f.legendStore=null;f.setStore(null);f.cancelChartLayout()},getRefItems:function(b){var g=this,e=g.getSeries(),h=g.getAxes(),a=g.getInteractions(),c=[],d,f;for(d=0,f=e.length;d<f;d++){c.push(e[d]);if(e[d].getRefItems){c.push.apply(c,e[d].getRefItems(b))}}for(d=0,f=h.length;d<f;d++){c.push(h[d]);if(h[d].getRefItems){c.push.apply(c,h[d].getRefItems(b))}}for(d=0,f=a.length;d<f;d++){c.push(a[d]);if(a[d].getRefItems){c.push.apply(c,a[d].getRefItems(b))}}return c}});Ext.define("Ext.chart.overrides.AbstractChart",{override:"Ext.chart.AbstractChart",updateLegend:function(b,a){var c;this.callParent([b,a]);if(b){c=b.docked;this.addDocked({dock:c,xtype:"panel",shrinkWrap:true,scrollable:true,layout:{type:c==="top"||c==="bottom"?"hbox":"vbox",pack:"center"},items:b,cls:Ext.baseCSSPrefix+"legend-panel"})}},performLayout:function(){if(this.isVisible(true)){return this.callParent()}this.cancelChartLayout();return false},afterComponentLayout:function(c,a,b,d){this.callParent([c,a,b,d]);this.scheduleLayout()},allowSchedule:function(){return this.rendered},onDestroy:function(){this.destroyChart();this.callParent(arguments)}});Ext.define("Ext.chart.grid.HorizontalGrid",{extend:"Ext.draw.sprite.Sprite",alias:"grid.horizontal",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number"},defaults:{x:0,y:0,width:1,height:1,strokeStyle:"#DDD"}}},render:function(b,c,e){var a=this.attr,f=b.roundPixel(a.y),d=c.lineWidth*0.5;c.beginPath();c.rect(e[0]-b.matrix.getDX(),f+d,+e[2],a.height);c.fill();c.beginPath();c.moveTo(e[0]-b.matrix.getDX(),f+d);c.lineTo(e[0]+e[2]-b.matrix.getDX(),f+d);c.stroke()}});Ext.define("Ext.chart.grid.VerticalGrid",{extend:"Ext.draw.sprite.Sprite",alias:"grid.vertical",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number"},defaults:{x:0,y:0,width:1,height:1,strokeStyle:"#DDD"}}},render:function(c,d,f){var b=this.attr,a=c.roundPixel(b.x),e=d.lineWidth*0.5;d.beginPath();d.rect(a-e,f[1]-c.matrix.getDY(),b.width,f[3]);d.fill();d.beginPath();d.moveTo(a-e,f[1]-c.matrix.getDY());d.lineTo(a-e,f[1]+f[3]-c.matrix.getDY());d.stroke()}});Ext.define("Ext.chart.CartesianChart",{extend:"Ext.chart.AbstractChart",alternateClassName:"Ext.chart.Chart",requires:["Ext.chart.grid.HorizontalGrid","Ext.chart.grid.VerticalGrid"],xtype:["cartesian","chart"],isCartesian:true,config:{flipXY:false,innerRect:[0,0,1,1],innerPadding:{top:0,left:0,right:0,bottom:0}},applyInnerPadding:function(b,a){if(!Ext.isObject(b)){return Ext.util.Format.parseBox(b)}else{if(!a){return b}else{return Ext.apply(a,b)}}},getDirectionForAxis:function(a){var b=this.getFlipXY();if(a==="left"||a==="right"){if(b){return"X"}else{return"Y"}}else{if(b){return"Y"}else{return"X"}}},performLayout:function(){var A=this;A.animationSuspendCount++;if(A.callParent()===false){--A.animationSuspendCount;return}A.suspendThicknessChanged();var d=A.getSurface("chart").getRect(),o=d[2],n=d[3],z=A.getAxes(),b,q=A.getSeries(),h,l,a,f=A.getInsetPadding(),v=A.getInnerPadding(),r,c,e=Ext.apply({},f),u,p,s,k,m,y,t,x,g,j=A.getInherited().rtl,w=A.getFlipXY();if(o<=0||n<=0){return}for(x=0;x<z.length;x++){b=z[x];l=b.getSurface();m=b.getFloating();y=m?m.value:null;a=b.getThickness();switch(b.getPosition()){case"top":l.setRect([0,e.top+1,o,a]);break;case"bottom":l.setRect([0,n-(e.bottom+a),o,a]);break;case"left":l.setRect([e.left,0,a,n]);break;case"right":l.setRect([o-(e.right+a),0,a,n]);break}if(y===null){e[b.getPosition()]+=a}}o-=e.left+e.right;n-=e.top+e.bottom;u=[e.left,e.top,o,n];e.left+=v.left;e.top+=v.top;e.right+=v.right;e.bottom+=v.bottom;p=o-v.left-v.right;s=n-v.top-v.bottom;A.setInnerRect([e.left,e.top,p,s]);if(p<=0||s<=0){return}A.setMainRect(u);A.getSurface().setRect(u);for(x=0,g=A.surfaceMap.grid&&A.surfaceMap.grid.length;x<g;x++){c=A.surfaceMap.grid[x];c.setRect(u);c.matrix.set(1,0,0,1,v.left,v.top);c.matrix.inverse(c.inverseMatrix)}for(x=0;x<z.length;x++){b=z[x];l=b.getSurface();t=l.matrix;k=t.elements;switch(b.getPosition()){case"top":case"bottom":k[4]=e.left;b.setLength(p);break;case"left":case"right":k[5]=e.top;b.setLength(s);break}b.updateTitleSprite();t.inverse(l.inverseMatrix)}for(x=0,g=q.length;x<g;x++){h=q[x];r=h.getSurface();r.setRect(u);if(w){if(j){r.matrix.set(0,-1,-1,0,v.left+p,v.top+s)}else{r.matrix.set(0,-1,1,0,v.left,v.top+s)}}else{r.matrix.set(1,0,0,-1,v.left,v.top+s)}r.matrix.inverse(r.inverseMatrix);h.getOverlaySurface().setRect(u)}A.redraw();A.animationSuspendCount--;A.resumeThicknessChanged()},refloatAxes:function(){var h=this,g=h.getAxes(),o=(g&&g.length)||0,c,d,n,f,l,b,k,r=h.getChartSize(),q=h.getInsetPadding(),p=h.getInnerPadding(),a=r.width-q.left-q.right,m=r.height-q.top-q.bottom,j,e;for(e=0;e<o;e++){c=g[e];f=c.getFloating();l=f?f.value:null;if(l===null){delete c.floatingAtCoord;continue}d=c.getSurface();n=d.getRect();if(!n){continue}n=n.slice();b=h.getAxis(f.alongAxis);if(b){j=b.getAlignment()==="horizontal";if(Ext.isString(l)){l=b.getCoordFor(l)}b.floatingAxes[c.getId()]=l;k=b.getSprites()[0].attr.matrix;if(j){l=l*k.getXX()+k.getDX();c.floatingAtCoord=l+p.left+p.right}else{l=l*k.getYY()+k.getDY();c.floatingAtCoord=l+p.top+p.bottom}}else{j=c.getAlignment()==="horizontal";if(j){c.floatingAtCoord=l+p.top+p.bottom}else{c.floatingAtCoord=l+p.left+p.right}l=d.roundPixel(0.01*l*(j?m:a))}switch(c.getPosition()){case"top":n[1]=q.top+p.top+l-n[3]+1;break;case"bottom":n[1]=q.top+p.top+(b?l:m-l);break;case"left":n[0]=q.left+p.left+l-n[2];break;case"right":n[0]=q.left+p.left+(b?l:a-l)-1;break}d.setRect(n)}},redraw:function(){var C=this,r=C.getSeries(),z=C.getAxes(),b=C.getMainRect(),p,t,w=C.getInnerPadding(),f,l,s,e,q,A,v,g,d,c,a,k,n,y=C.getFlipXY(),x=1000,m,u,h,o,B;if(!b){return}p=b[2]-w.left-w.right;t=b[3]-w.top-w.bottom;for(A=0;A<r.length;A++){h=r[A];if((c=h.getXAxis())){n=c.getVisibleRange();l=c.getRange();l=[l[0]+(l[1]-l[0])*n[0],l[0]+(l[1]-l[0])*n[1]]}else{l=h.getXRange()}if((a=h.getYAxis())){n=a.getVisibleRange();s=a.getRange();s=[s[0]+(s[1]-s[0])*n[0],s[0]+(s[1]-s[0])*n[1]]}else{s=h.getYRange()}q={visibleMinX:l[0],visibleMaxX:l[1],visibleMinY:s[0],visibleMaxY:s[1],innerWidth:p,innerHeight:t,flipXY:y};f=h.getSprites();for(v=0,g=f.length;v<g;v++){o=f[v];m=o.attr.zIndex;if(m<x){m+=(A+1)*100+x;o.attr.zIndex=m;B=o.getMarker("items");if(B){u=B.attr.zIndex;if(u===Number.MAX_VALUE){B.attr.zIndex=m}else{if(u<x){B.attr.zIndex=m+u}}}}o.setAttributes(q,true)}}for(A=0;A<z.length;A++){d=z[A];e=d.isSide();f=d.getSprites();k=d.getRange();n=d.getVisibleRange();q={dataMin:k[0],dataMax:k[1],visibleMin:n[0],visibleMax:n[1]};if(e){q.length=t;q.startGap=w.bottom;q.endGap=w.top}else{q.length=p;q.startGap=w.left;q.endGap=w.right}for(v=0,g=f.length;v<g;v++){f[v].setAttributes(q,true)}}C.renderFrame();C.callParent(arguments)},renderFrame:function(){this.refloatAxes();this.callParent()}});Ext.define("Ext.chart.grid.CircularGrid",{extend:"Ext.draw.sprite.Circle",alias:"grid.circular",inheritableStatics:{def:{defaults:{r:1,strokeStyle:"#DDD"}}}});Ext.define("Ext.chart.grid.RadialGrid",{extend:"Ext.draw.sprite.Path",alias:"grid.radial",inheritableStatics:{def:{processors:{startRadius:"number",endRadius:"number"},defaults:{startRadius:0,endRadius:1,scalingCenterX:0,scalingCenterY:0,strokeStyle:"#DDD"},triggers:{startRadius:"path,bbox",endRadius:"path,bbox"}}},render:function(){this.callParent(arguments)},updatePath:function(d,a){var b=a.startRadius,c=a.endRadius;d.moveTo(b,0);d.lineTo(c,0)}});Ext.define("Ext.chart.PolarChart",{extend:"Ext.chart.AbstractChart",requires:["Ext.chart.grid.CircularGrid","Ext.chart.grid.RadialGrid"],xtype:"polar",isPolar:true,config:{center:[0,0],radius:0,innerPadding:0},getDirectionForAxis:function(a){return a==="radial"?"Y":"X"},applyCenter:function(a,b){if(b&&a[0]===b[0]&&a[1]===b[1]){return}return[+a[0],+a[1]]},updateCenter:function(a){var g=this,h=g.getAxes(),d=g.getSeries(),c,f,e,b;for(c=0,f=h.length;c<f;c++){e=h[c];e.setCenter(a)}for(c=0,f=d.length;c<f;c++){b=d[c];b.setCenter(a)}},applyInnerPadding:function(b,a){return Ext.isNumber(b)?b:a},doSetSurfaceRect:function(b,c){var a=this.getMainRect();b.setRect(c);b.matrix.set(1,0,0,1,a[0]-c[0],a[1]-c[1]);b.inverseMatrix.set(1,0,0,1,c[0]-a[0],c[1]-a[1])},applyAxes:function(f,h){var e=this,g=Ext.Array.from(e.config.series)[0],b,d,c,a;if(g.type==="radar"&&f&&f.length){for(b=0,d=f.length;b<d;b++){c=f[b];if(c.position==="angular"){a=true;break}}if(!a){f.push({type:"category",position:"angular",fields:g.xField||g.angleField,style:{estStepSize:1},grid:true})}}return this.callParent(arguments)},performLayout:function(){var F=this,g=true;try{F.animationSuspendCount++;if(this.callParent()===false){g=false;return}F.suspendThicknessChanged();var h=F.getSurface("chart").getRect(),v=F.getInsetPadding(),G=F.getInnerPadding(),l=Ext.apply({},v),d,s=h[2]-v.left-v.right,r=h[3]-v.top-v.bottom,x=[v.left,v.top,s,r],u=F.getSeries(),p,t=s-G*2,w=r-G*2,D=[t*0.5+G,w*0.5+G],j=Math.min(t,w)*0.5,A=F.getAxes(),f,a,k,m=[],o=[],E=j-G,z,n,b,q,y,c,C;F.setMainRect(x);F.doSetSurfaceRect(F.getSurface(),x);for(z=0,n=F.surfaceMap.grid&&F.surfaceMap.grid.length;z<n;z++){F.doSetSurfaceRect(F.surfaceMap.grid[z],h)}for(z=0,n=A.length;z<n;z++){f=A[z];switch(f.getPosition()){case"angular":m.push(f);break;case"radial":o.push(f);break}}for(z=0,n=m.length;z<n;z++){f=m[z];q=f.getFloating();y=q?q.value:null;F.doSetSurfaceRect(f.getSurface(),h);a=f.getThickness();for(d in l){l[d]+=a}s=h[2]-l.left-l.right;r=h[3]-l.top-l.bottom;b=Math.min(s,r)*0.5;if(z===0){E=b-G}f.setMinimum(0);f.setLength(b);f.getSprites();k=f.sprites[0].attr.lineWidth*0.5;for(d in l){l[d]+=k}}for(z=0,n=o.length;z<n;z++){f=o[z];F.doSetSurfaceRect(f.getSurface(),h);f.setMinimum(0);f.setLength(E);f.getSprites()}for(z=0,n=u.length;z<n;z++){p=u[z];if(p.type==="gauge"&&!c){c=p}else{p.setRadius(E)}F.doSetSurfaceRect(p.getSurface(),x)}F.doSetSurfaceRect(F.getSurface("overlay"),h);if(c){c.setRect(x);C=c.getRadius()-G;F.setRadius(C);F.setCenter(c.getCenter());c.setRadius(C);if(A.length&&A[0].getPosition()==="gauge"){f=A[0];F.doSetSurfaceRect(f.getSurface(),h);f.setTotalAngle(c.getTotalAngle());f.setLength(C)}}else{F.setRadius(j);F.setCenter(D)}F.redraw()}catch(B){throw B}finally{F.animationSuspendCount--;if(g){F.resumeThicknessChanged()}}},refloatAxes:function(){var j=this,g=j.getAxes(),h=j.getMainRect(),f,k,b,d,a,c,e;if(!h){return}e=0.5*Math.min(h[2],h[3]);for(d=0,a=g.length;d<a;d++){c=g[d];f=c.getFloating();k=f?f.value:null;if(k!==null){b=j.getAxis(f.alongAxis);if(c.getPosition()==="angular"){if(b){k=b.getLength()*k/b.getRange()[1]}else{k=0.01*k*e}c.sprites[0].setAttributes({length:k},true)}else{if(b){if(Ext.isString(k)){k=b.getCoordFor(k)}k=k/(b.getRange()[1]+1)*Math.PI*2-Math.PI*1.5+c.getRotation()}else{k=Ext.draw.Draw.rad(k)}c.sprites[0].setAttributes({baseRotation:k},true)}}}},redraw:function(){var f=this,g=f.getAxes(),d,c=f.getSeries(),b,a,e;for(a=0,e=g.length;a<e;a++){d=g[a];d.getSprites()}for(a=0,e=c.length;a<e;a++){b=c[a];b.getSprites()}f.renderFrame();f.callParent(arguments)},renderFrame:function(){this.refloatAxes();this.callParent()}});Ext.define("Ext.chart.SpaceFillingChart",{extend:"Ext.chart.AbstractChart",xtype:"spacefilling",config:{},performLayout:function(){var j=this;try{j.animationSuspendCount++;if(j.callParent()===false){return}var k=j.getSurface("chart").getRect(),l=j.getInsetPadding(),a=k[2]-l.left-l.right,m=k[3]-l.top-l.bottom,h=[l.left,l.top,a,m],b=j.getSeries(),d,c,g;j.getSurface().setRect(h);j.setMainRect(h);for(c=0,g=b.length;c<g;c++){d=b[c];d.getSurface().setRect(h);if(d.setRect){d.setRect(h)}d.getOverlaySurface().setRect(k)}j.redraw()}catch(f){throw f}finally{j.animationSuspendCount--}},redraw:function(){var e=this,c=e.getSeries(),b,a,d;for(a=0,d=c.length;a<d;a++){b=c[a];b.getSprites()}e.renderFrame();e.callParent(arguments)}});Ext.define("Ext.chart.axis.sprite.Axis3D",{extend:"Ext.chart.axis.sprite.Axis",alias:"sprite.axis3d",type:"axis3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0},triggers:{depth:"layout"}}},config:{fx:{customDurations:{depth:0}}},layoutUpdater:function(){var h=this,f=h.getAxis().getChart();if(f.isInitializing){return}var e=h.attr,d=h.getLayout(),c=d.isDiscrete?0:e.depth,g=f.getInherited().rtl,b=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMin,i=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMax,a={attr:e,segmenter:h.getSegmenter(),renderer:h.defaultRenderer};if(e.position==="left"||e.position==="right"){e.translationX=0;e.translationY=i*(e.length-c)/(i-b)+c;e.scalingX=1;e.scalingY=(-e.length+c)/(i-b);e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}else{if(e.position==="top"||e.position==="bottom"){if(g){e.translationX=e.length+b*e.length/(i-b)+1}else{e.translationX=-b*e.length/(i-b)}e.translationY=0;e.scalingX=(g?-1:1)*(e.length-c)/(i-b);e.scalingY=1;e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}}if(d){d.calculateLayout(a);h.setLayoutContext(a)}},renderAxisLine:function(a,j,f,c){var i=this,h=i.attr,b=h.lineWidth*0.5,f=i.getLayout(),d=f.isDiscrete?0:h.depth,k=h.position,e,g;if(h.axisLine&&h.length){switch(k){case"left":e=a.roundPixel(c[2])-b;j.moveTo(e,-h.endGap+d);j.lineTo(e,h.length+h.startGap);break;case"right":j.moveTo(b,-h.endGap);j.lineTo(b,h.length+h.startGap);break;case"bottom":j.moveTo(-h.startGap,b);j.lineTo(h.length-d+h.endGap,b);break;case"top":e=a.roundPixel(c[3])-b;j.moveTo(-h.startGap,e);j.lineTo(h.length+h.endGap,e);break;case"angular":j.moveTo(h.centerX+h.length,h.centerY);j.arc(h.centerX,h.centerY,h.length,0,Math.PI*2,true);break;case"gauge":g=i.getGaugeAngles();j.moveTo(h.centerX+Math.cos(g.start)*h.length,h.centerY+Math.sin(g.start)*h.length);j.arc(h.centerX,h.centerY,h.length,g.start,g.end,true);break}}}});Ext.define("Ext.chart.axis.Axis3D",{extend:"Ext.chart.axis.Axis",xtype:"axis3d",requires:["Ext.chart.axis.sprite.Axis3D"],config:{depth:0},onSeriesChange:function(e){var g=this,b="depthchange",f="onSeriesDepthChange",d,c;function a(h){var i=g.boundSeries;for(d=0;d<i.length;d++){c=i[d];c[h](b,f,g)}}a("un");g.callParent(arguments);a("on")},onSeriesDepthChange:function(b,f){var d=this,g=f,e=d.boundSeries,a,c;if(f>d.getDepth()){g=f}else{for(a=0;a<e.length;a++){c=e[a];if(c!==b&&c.getDepth){f=c.getDepth();if(f>g){g=f}}}}d.setDepth(g)},updateDepth:function(d){var b=this,c=b.getSprites(),a={depth:d};if(c&&c.length){c[0].setAttributes(a)}if(b.gridSpriteEven&&b.gridSpriteOdd){b.gridSpriteEven.getTemplate().setAttributes(a);b.gridSpriteOdd.getTemplate().setAttributes(a)}},getGridAlignment:function(){switch(this.getPosition()){case"left":case"right":return"horizontal3d";case"top":case"bottom":return"vertical3d"}}});Ext.define("Ext.chart.axis.Category",{requires:["Ext.chart.axis.layout.CombineDuplicate","Ext.chart.axis.segmenter.Names"],extend:"Ext.chart.axis.Axis",alias:"axis.category",type:"category",config:{layout:"combineDuplicate",segmenter:"names"}});Ext.define("Ext.chart.axis.Category3D",{requires:["Ext.chart.axis.layout.CombineDuplicate","Ext.chart.axis.segmenter.Names"],extend:"Ext.chart.axis.Axis3D",alias:"axis.category3d",type:"category3d",config:{layout:"combineDuplicate",segmenter:"names"}});Ext.define("Ext.chart.axis.Numeric",{extend:"Ext.chart.axis.Axis",type:"numeric",alias:["axis.numeric","axis.radial"],requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Numeric"],config:{layout:"continuous",segmenter:"numeric",aggregator:"double"}});Ext.define("Ext.chart.axis.Numeric3D",{extend:"Ext.chart.axis.Axis3D",alias:["axis.numeric3d"],type:"numeric3d",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Numeric"],config:{layout:"continuous",segmenter:"numeric",aggregator:"double"}});Ext.define("Ext.chart.axis.Time",{extend:"Ext.chart.axis.Numeric",alias:"axis.time",type:"time",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Time"],config:{calculateByLabelSize:true,dateFormat:null,fromDate:null,toDate:null,step:[Ext.Date.DAY,1],layout:"continuous",segmenter:"time",aggregator:"time"},updateDateFormat:function(a){this.setRenderer(function(c,b){return Ext.Date.format(new Date(b),a)})},updateFromDate:function(a){this.setMinimum(+a)},updateToDate:function(a){this.setMaximum(+a)},getCoordFor:function(a){if(Ext.isString(a)){a=new Date(a)}return +a}});Ext.define("Ext.chart.axis.Time3D",{extend:"Ext.chart.axis.Numeric3D",alias:"axis.time3d",type:"time3d",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Time"],config:{calculateByLabelSize:true,dateFormat:null,fromDate:null,toDate:null,step:[Ext.Date.DAY,1],layout:"continuous",segmenter:"time",aggregator:"time"},updateDateFormat:function(a){this.setRenderer(function(c,b){return Ext.Date.format(new Date(b),a)})},updateFromDate:function(a){this.setMinimum(+a)},updateToDate:function(a){this.setMaximum(+a)},getCoordFor:function(a){if(Ext.isString(a)){a=new Date(a)}return +a}});Ext.define("Ext.chart.grid.HorizontalGrid3D",{extend:"Ext.chart.grid.HorizontalGrid",alias:"grid.horizontal3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0}}},render:function(a,k,d){var f=this.attr,i=a.roundPixel(f.x),h=a.roundPixel(f.y),l=a.matrix.getDX(),c=k.lineWidth*0.5,j=f.height,e=f.depth,b,g;if(h<=d[1]){return}b=d[0]+e-l;g=h+c-e;k.beginPath();k.rect(b,g,d[2],j);k.fill();k.beginPath();k.moveTo(b,g);k.lineTo(b+d[2],g);k.stroke();b=d[0]+i-l;g=h+c;k.beginPath();k.moveTo(b,g);k.lineTo(b+e,g-e);k.lineTo(b+e,g-e+j);k.lineTo(b,g+j);k.closePath();k.fill();k.beginPath();k.moveTo(b,g);k.lineTo(b+e,g-e);k.stroke()}});Ext.define("Ext.chart.grid.VerticalGrid3D",{extend:"Ext.chart.grid.VerticalGrid",alias:"grid.vertical3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0}}},render_:function(c,d,f){var b=this.attr,a=c.roundPixel(b.x),e=d.lineWidth*0.5;d.beginPath();d.rect(a-e,f[1]-c.matrix.getDY(),b.width,f[3]);d.fill();d.beginPath();d.moveTo(a-e,f[1]-c.matrix.getDY());d.lineTo(a-e,f[1]+f[3]-c.matrix.getDY());d.stroke()},render:function(b,j,e){var g=this.attr,i=b.roundPixel(g.x),k=b.matrix.getDY(),d=j.lineWidth*0.5,a=g.width,f=g.depth,c,h;if(i>=e[2]){return}c=i-d+f;h=e[1]-f-k;j.beginPath();j.rect(c,h,a,e[3]);j.fill();j.beginPath();j.moveTo(c,h);j.lineTo(c,h+e[3]);j.stroke();c=i-d;h=e[3];j.beginPath();j.moveTo(c,h);j.lineTo(c+f,h-f);j.lineTo(c+f+a,h-f);j.lineTo(c+a,h);j.closePath();j.fill();c=i-d;h=e[3];j.beginPath();j.moveTo(c,h);j.lineTo(c+f,h-f);j.stroke()}});Ext.define("Ext.chart.interactions.CrossZoom",{extend:"Ext.chart.interactions.Abstract",type:"crosszoom",alias:"interaction.crosszoom",isCrossZoom:true,config:{axes:true,gestures:{dragstart:"onGestureStart",drag:"onGesture",dragend:"onGestureEnd",dblclick:"onDoubleTap"},undoButton:{}},stopAnimationBeforeSync:false,zoomAnimationInProgress:false,constructor:function(){this.callParent(arguments);this.zoomHistory=[]},applyAxes:function(b){var a={};if(b===true){return{top:{},right:{},bottom:{},left:{}}}else{if(Ext.isArray(b)){a={};Ext.each(b,function(c){a[c]={}})}else{if(Ext.isObject(b)){Ext.iterate(b,function(c,d){if(d===true){a[c]={}}else{if(d!==false){a[c]=d}}})}}}return a},applyUndoButton:function(b,a){var c=this;if(a){a.destroy()}if(b){return Ext.create("Ext.Button",Ext.apply({cls:[],text:"Undo Zoom",disabled:true,handler:function(){c.undoZoom()}},b))}},getSurface:function(){return this.getChart()&&this.getChart().getSurface("main")},setSeriesOpacity:function(b){var a=this.getChart()&&this.getChart().getSurface("series");if(a){a.element.setStyle("opacity",b)}},onGestureStart:function(h){var j=this,i=j.getChart(),d=j.getSurface(),l=i.getInnerRect(),c=i.getInnerPadding(),g=c.left,b=g+l[2],f=c.top,a=f+l[3],n=i.getEventXY(h),m=n[0],k=n[1];if(j.zoomAnimationInProgress){return}if(m>g&&m<b&&k>f&&k<a){j.gestureEvent="drag";j.lockEvents(j.gestureEvent);j.startX=m;j.startY=k;j.selectionRect=d.add({type:"rect",globalAlpha:0.5,fillStyle:"rgba(80,80,140,0.5)",strokeStyle:"rgba(80,80,140,1)",lineWidth:2,x:m,y:k,width:0,height:0,zIndex:10000});j.setSeriesOpacity(0.8);return false}},onGesture:function(h){var j=this;if(j.zoomAnimationInProgress){return}if(j.getLocks()[j.gestureEvent]===j){var i=j.getChart(),d=j.getSurface(),l=i.getInnerRect(),c=i.getInnerPadding(),g=c.left,b=g+l[2],f=c.top,a=f+l[3],n=i.getEventXY(h),m=n[0],k=n[1];if(m<g){m=g}else{if(m>b){m=b}}if(k<f){k=f}else{if(k>a){k=a}}j.selectionRect.setAttributes({width:m-j.startX,height:k-j.startY});if(Math.abs(j.startX-m)<11||Math.abs(j.startY-k)<11){j.selectionRect.setAttributes({globalAlpha:0.5})}else{j.selectionRect.setAttributes({globalAlpha:1})}d.renderFrame();return false}},onGestureEnd:function(i){var l=this;if(l.zoomAnimationInProgress){return}if(l.getLocks()[l.gestureEvent]===l){var k=l.getChart(),d=l.getSurface(),n=k.getInnerRect(),c=k.getInnerPadding(),g=c.left,b=g+n[2],f=c.top,a=f+n[3],h=n[2],j=n[3],p=k.getEventXY(i),o=p[0],m=p[1];if(o<g){o=g}else{if(o>b){o=b}}if(m<f){m=f}else{if(m>a){m=a}}if(Math.abs(l.startX-o)<11||Math.abs(l.startY-m)<11){d.remove(l.selectionRect)}else{l.zoomBy([Math.min(l.startX,o)/h,1-Math.max(l.startY,m)/j,Math.max(l.startX,o)/h,1-Math.min(l.startY,m)/j]);l.selectionRect.setAttributes({x:Math.min(l.startX,o),y:Math.min(l.startY,m),width:Math.abs(l.startX-o),height:Math.abs(l.startY-m)});l.selectionRect.setAnimation(k.getAnimation()||{duration:0});l.selectionRect.setAttributes({globalAlpha:0,x:0,y:0,width:h,height:j});l.zoomAnimationInProgress=true;k.suspendThicknessChanged();l.selectionRect.fx.on("animationend",function(){k.resumeThicknessChanged();d.remove(l.selectionRect);l.selectionRect=null;l.zoomAnimationInProgress=false})}d.renderFrame();l.sync();l.unlockEvents(l.gestureEvent);l.setSeriesOpacity(1);if(!l.zoomAnimationInProgress){d.remove(l.selectionRect);l.selectionRect=null}}},zoomBy:function(o){var n=this,a=n.getAxes(),k=n.getChart(),j=k.getAxes(),l=k.getInherited().rtl,f,d={},c,b;if(l){o=o.slice();c=1-o[0];b=1-o[2];o[0]=Math.min(c,b);o[2]=Math.max(c,b)}for(var h=0;h<j.length;h++){var g=j[h];f=a[g.getPosition()];if(f&&f.allowZoom!==false){var e=g.isSide(),m=g.getVisibleRange();d[g.getId()]=m.slice(0);if(!e){g.setVisibleRange([(m[1]-m[0])*o[0]+m[0],(m[1]-m[0])*o[2]+m[0]])}else{g.setVisibleRange([(m[1]-m[0])*o[1]+m[0],(m[1]-m[0])*o[3]+m[0]])}}}n.zoomHistory.push(d);n.getUndoButton().setDisabled(false)},undoZoom:function(){var c=this.zoomHistory.pop(),d=this.getChart().getAxes();if(c){for(var a=0;a<d.length;a++){var b=d[a];if(c[b.getId()]){b.setVisibleRange(c[b.getId()])}}}this.getUndoButton().setDisabled(this.zoomHistory.length===0);this.sync()},onDoubleTap:function(a){this.undoZoom()},destroy:function(){this.setUndoButton(null);this.callParent(arguments)}});Ext.define("Ext.chart.interactions.Crosshair",{extend:"Ext.chart.interactions.Abstract",requires:["Ext.chart.grid.HorizontalGrid","Ext.chart.grid.VerticalGrid","Ext.chart.CartesianChart","Ext.chart.axis.layout.Discrete"],type:"crosshair",alias:"interaction.crosshair",config:{axes:{top:{label:{},rect:{}},right:{label:{},rect:{}},bottom:{label:{},rect:{}},left:{label:{},rect:{}}},lines:{horizontal:{strokeStyle:"black",lineDash:[5,5]},vertical:{strokeStyle:"black",lineDash:[5,5]}},gesture:"drag"},applyAxes:function(b,a){return Ext.merge(a||{},b)},applyLines:function(a,b){return Ext.merge(b||{},a)},updateChart:function(a){if(a&&!a.isCartesian){Ext.raise("Crosshair interaction can only be used on cartesian charts.")}this.callParent(arguments)},getGestures:function(){var a=this,b={};b[a.getGesture()]="onGesture";b[a.getGesture()+"start"]="onGestureStart";b[a.getGesture()+"end"]="onGestureEnd";return b},onGestureStart:function(N){var m=this,O=m.getChart(),B=O.getTheme().getAxis(),A,F=O.getSurface("overlay"),s=O.getInnerRect(),n=s[2],M=s[3],r=O.getEventXY(N),D=r[0],C=r[1],E=O.getAxes(),u=m.getAxes(),h=m.getLines(),q,v,b,d,k,z,G,L,J,o,I,w,l,f,p,j,t,a,g,H,c,K;if(D>0&&D<n&&C>0&&C<M){m.lockEvents(m.getGesture());H=Ext.apply({xclass:"Ext.chart.grid.HorizontalGrid",x:0,y:C,width:n},h.horizontal);c=Ext.apply({xclass:"Ext.chart.grid.VerticalGrid",x:D,y:0,height:M},h.vertical);m.axesLabels=m.axesLabels||{};for(K=0;K<E.length;K++){q=E[K];v=q.getSurface();b=v.getRect();w=q.getSprites()[0];d=b[2];k=b[3];z=q.getPosition();G=q.getAlignment();t=q.getTitle();a=t&&t.attr.text!==""&&t.getBBox();l=w.attr;f=w.thickness;p=l.axisLine?l.lineWidth:0;j=p/2;I=Math.max(l.majorTickSize,l.minorTickSize)+p;L=m.axesLabels[z]=v.add({type:"composite"});L.labelRect=L.add(Ext.apply({type:"rect",fillStyle:"white",x:z==="right"?p:0,y:z==="bottom"?p:0,width:d-p-(G==="vertical"&&a?a.width:0),height:k-p-(G==="horizontal"&&a?a.height:0),translationX:z==="left"&&a?a.width:0,translationY:z==="top"&&a?a.height:0},u.rect||u[z].rect));if(G==="vertical"&&!c.strokeStyle){c.strokeStyle=l.strokeStyle}if(G==="horizontal"&&!H.strokeStyle){H.strokeStyle=l.strokeStyle}A=Ext.merge({},B.defaults,B[z]);J=Ext.apply({},q.config.label,A.label);o=u.label||u[z].label;L.labelText=L.add(Ext.apply(J,o,{type:"text",x:(function(){switch(z){case"left":g=a?a.x+a.width:0;return g+(d-g-I)/2-j;case"right":g=a?d-a.x:0;return I+(d-I-g)/2+j;default:return 0}})(),y:(function(){switch(z){case"top":g=a?a.y+a.height:0;return g+(k-g-I)/2-j;case"bottom":g=a?k-a.y:0;return I+(k-I-g)/2+j;default:return 0}})()}))}m.horizontalLine=F.add(H);m.verticalLine=F.add(c);return false}},onGesture:function(G){var K=this;if(K.getLocks()[K.getGesture()]!==K){return}var u=K.getChart(),z=u.getSurface("overlay"),a=Ext.Array.slice(u.getInnerRect()),r=u.getInnerPadding(),t=r.left,q=r.top,E=a[2],f=a[3],d=u.getEventXY(G),k=d[0],j=d[1],D=u.getAxes(),c,h,m,p,J,w,I,H,s,b,C,g,v,n,l,A,F,o,B;if(k<0){k=0}else{if(k>E){k=E}}if(j<0){j=0}else{if(j>f){j=f}}k+=t;j+=q;for(B=0;B<D.length;B++){c=D[B];h=c.getPosition();m=c.getAlignment();p=c.getSurface();J=c.getSprites()[0];w=J.attr.matrix;C=J.attr.textPadding*2;s=K.axesLabels[h];I=J.getLayoutContext();H=c.getSegmenter();if(s){if(m==="vertical"){v=w.getYY();l=w.getDY();F=(j-l-q)/v;if(c.getLayout() instanceof Ext.chart.axis.layout.Discrete){j=Math.round(F)*v+l+q;F=H.from(Math.round(F));F=J.attr.data[F]}else{F=H.from(F)}o=H.renderer(F,I);s.setAttributes({translationY:j-q});s.labelText.setAttributes({text:o});b=s.labelText.getBBox();s.labelRect.setAttributes({height:b.height+C,y:-(b.height+C)/2});p.renderFrame()}else{g=w.getXX();n=w.getDX();A=(k-n-t)/g;if(c.getLayout() instanceof Ext.chart.axis.layout.Discrete){k=Math.round(A)*g+n+t;A=H.from(Math.round(A));A=J.attr.data[A]}else{A=H.from(A)}o=H.renderer(A,I);s.setAttributes({translationX:k-t});s.labelText.setAttributes({text:o});b=s.labelText.getBBox();s.labelRect.setAttributes({width:b.width+C,x:-(b.width+C)/2});p.renderFrame()}}}K.horizontalLine.setAttributes({y:j,strokeStyle:J.attr.strokeStyle});K.verticalLine.setAttributes({x:k,strokeStyle:J.attr.strokeStyle});z.renderFrame();return false},onGestureEnd:function(h){var l=this,k=l.getChart(),a=k.getSurface("overlay"),j=k.getAxes(),c,g,d,b,f;a.remove(l.verticalLine);a.remove(l.horizontalLine);for(f=0;f<j.length;f++){c=j[f];g=c.getPosition();d=c.getSurface();b=l.axesLabels[g];if(b){delete l.axesLabels[g];d.remove(b)}d.renderFrame()}a.renderFrame();l.unlockEvents(l.getGesture())}});Ext.define("Ext.chart.interactions.ItemHighlight",{extend:"Ext.chart.interactions.Abstract",type:"itemhighlight",alias:"interaction.itemhighlight",isItemHighlight:true,config:{gestures:{tap:"onTapGesture",mousemove:"onMouseMoveGesture",mousedown:"onMouseDownGesture",mouseup:"onMouseUpGesture",mouseleave:"onMouseUpGesture"},sticky:false},stickyHighlightItem:null,onMouseMoveGesture:function(g){var d=this,h=d.tipItem,a=g.pointerType==="mouse",c,f,b;if(d.getSticky()){return true}if(d.isDragging){if(h&&a){h.series.hideTooltip(h);d.tipItem=null}}else{if(!d.stickyHighlightItem){c=d.getItemForEvent(g);b=d.getChart();if(c!==b.getHighlightItem()){d.highlight(c);d.sync()}if(a){if(h&&(!c||h.field!==c.field||h.record!==c.record)){h.series.hideTooltip(h);d.tipItem=h=null}if(c&&(f=c.series.getTooltip())){if(f.trackMouse||!h){c.series.showTooltip(c,g.getXY())}d.tipItem=c}}return false}}},highlight:function(a){this.getChart().setHighlightItem(a)},showTooltip:function(b,a){a.series.showTooltip(a,b.getXY());this.tipItem=a},onMouseDownGesture:function(){this.isDragging=true},onMouseUpGesture:function(){this.isDragging=false},onTapGesture:function(c){var b=this;if(c.pointerType==="mouse"&&!b.getSticky()){return}var a=b.getItemForEvent(c);if(b.stickyHighlightItem&&a&&(b.stickyHighlightItem.index===a.index)){a=null}b.stickyHighlightItem=a;b.highlight(a)}});Ext.define("Ext.chart.interactions.ItemEdit",{extend:"Ext.chart.interactions.ItemHighlight",requires:["Ext.tip.ToolTip"],type:"itemedit",alias:"interaction.itemedit",isItemEdit:true,config:{style:null,renderer:null,tooltip:true,gestures:{dragstart:"onDragStart",drag:"onDrag",dragend:"onDragEnd"},cursors:{ewResize:"ew-resize",nsResize:"ns-resize",move:"move"}},item:null,applyTooltip:function(b){if(b){var a=Ext.apply({},b,{renderer:this.defaultTooltipRenderer,constrainPosition:true,shrinkWrapDock:true,autoHide:true,offsetX:10,offsetY:10});b=new Ext.tip.ToolTip(a)}return b},defaultTooltipRenderer:function(b,a,f,d){var c=[];if(f.xField){c.push(f.xField+": "+f.xValue)}if(f.yField){c.push(f.yField+": "+f.yValue)}b.setHtml(c.join("<br>"))},onDragStart:function(d){var c=this,a=c.getChart(),b=a.getHighlightItem();if(b){a.fireEvent("beginitemedit",a,c,c.item=b);return false}},onDrag:function(f){var d=this,b=d.getChart(),c=b.getHighlightItem(),a=c&&c.sprite.type;if(c){switch(a){case"barSeries":return d.onDragBar(f);break;case"scatterSeries":return d.onDragScatter(f);break}}},highlight:function(f){var e=this,d=e.getChart(),a=d.getFlipXY(),g=e.getCursors(),c=f&&f.sprite.type,b=d.el.dom.style;e.callParent([f]);if(f){switch(c){case"barSeries":if(a){b.cursor=g.ewResize}else{b.cursor=g.nsResize}break;case"scatterSeries":b.cursor=g.move;break}}else{d.el.dom.style.cursor="default"}},onDragBar:function(i){var m=this,k=m.getChart(),l=k.getInherited().rtl,f=k.isCartesian&&k.getFlipXY(),q=k.getHighlightItem(),g=q.sprite.getMarker("items"),p=g.getMarkerFor(q.sprite.getId(),q.index),b=q.sprite.getSurface(),c=b.getRect(),r=b.getEventXY(i),o=q.sprite.attr.matrix,j=m.getRenderer(),a,n,d,h;if(f){h=l?c[2]-r[0]:r[0]}else{h=c[3]-r[1]}a={x:p.x,y:h,width:p.width,height:p.height+(p.y-h),radius:p.radius,fillStyle:"none",lineDash:[4,4],zIndex:100};Ext.apply(a,m.getStyle());if(Ext.isArray(q.series.getYField())){h=h-p.y-p.height}m.target={index:q.index,yField:q.field,yValue:(h-o.getDY())/o.getYY()};d=[k,{target:m.target,style:a,item:q}];n=Ext.callback(j,null,d,0,k);if(n){Ext.apply(a,n)}q.sprite.putMarker("items",a,"itemedit");m.showTooltip(i,m.target,q);b.renderFrame()},onDragScatter:function(n){var t=this,g=t.getChart(),d=g.getInherited().rtl,l=g.isCartesian&&g.getFlipXY(),o=g.getHighlightItem(),b=o.sprite.getMarker("items"),p=b.getMarkerFor(o.sprite.getId(),o.index),j=o.sprite.getSurface(),h=j.getRect(),a=j.getEventXY(n),k=o.sprite.attr.matrix,c=o.series.getXAxis(),f=c&&c.getLayout().isContinuous,i=t.getRenderer(),m,u,q,s,r;if(l){r=d?h[2]-a[0]:a[0]}else{r=h[3]-a[1]}if(f){if(l){s=h[3]-a[1]}else{s=a[0]}}else{s=p.translationX}m={translationX:s,translationY:r,scalingX:p.scalingX,scalingY:p.scalingY,r:p.r,fillStyle:"none",lineDash:[4,4],zIndex:100};Ext.apply(m,t.getStyle());t.target={index:o.index,yField:o.field,yValue:(r-k.getDY())/k.getYY()};if(f){Ext.apply(t.target,{xField:o.series.getXField(),xValue:(s-k.getDX())/k.getXX()})}q=[g,{target:t.target,style:m,item:o}];u=Ext.callback(i,null,q,0,g);if(u){Ext.apply(m,u)}o.sprite.putMarker("items",m,"itemedit");t.showTooltip(n,t.target,o);j.renderFrame()},showTooltip:function(g,f,c){var d=this.getTooltip(),a,b;if(d&&Ext.toolkit!=="modern"){a=d.config;b=this.getChart();Ext.callback(a.renderer,null,[d,c,f,g],0,b);d.show([g.x+a.offsetX,g.y+a.offsetY])}},hideTooltip:function(){var a=this.getTooltip();if(a&&Ext.toolkit!=="modern"){a.hide()}},onDragEnd:function(g){var d=this,f=d.target,c=d.getChart(),b=c.getStore(),a;if(f){a=b.getAt(f.index);if(f.yField){a.set(f.yField,f.yValue,{convert:false})}if(f.xField){a.set(f.xField,f.xValue,{convert:false})}if(f.yField||f.xField){d.getChart().onDataChanged()}d.target=null}d.hideTooltip();if(d.item){c.fireEvent("enditemedit",c,d,d.item,f)}d.highlight(d.item=null)},destroy:function(){var a=this.getConfig("tooltip",true);Ext.destroy(a);this.callParent()}});Ext.define("Ext.chart.interactions.PanZoom",{extend:"Ext.chart.interactions.Abstract",type:"panzoom",alias:"interaction.panzoom",requires:["Ext.draw.Animator"],config:{axes:{top:{},right:{},bottom:{},left:{}},minZoom:null,maxZoom:null,showOverflowArrows:true,panGesture:"drag",zoomGesture:"pinch",zoomOnPanGesture:false,modeToggleButton:{xtype:"segmentedbutton",width:200,defaults:{ui:"default-toolbar"},cls:Ext.baseCSSPrefix+"panzoom-toggle",items:[{text:"Pan"},{text:"Zoom"}]},hideLabelInGesture:false},stopAnimationBeforeSync:true,applyAxes:function(b,a){return Ext.merge(a||{},b)},applyZoomOnPanGesture:function(a){this.getChart();if(this.isMultiTouch()){return false}return a},updateZoomOnPanGesture:function(b){var a=this.getModeToggleButton();if(!this.isMultiTouch()){a.show();a.setValue(b?1:0)}else{a.hide()}},toggleMode:function(){var a=this;if(!a.isMultiTouch()){a.setZoomOnPanGesture(!a.getZoomOnPanGesture())}},applyModeToggleButton:function(c,b){var d=this,a=Ext.factory(c,"Ext.button.Segmented",b);if(!a&&b){b.destroy()}if(a&&!b){a.addListener("toggle",function(e){d.setZoomOnPanGesture(e.getValue()===1)})}return a},getGestures:function(){var c=this,e={},d=c.getPanGesture(),b=c.getZoomGesture(),a=Ext.supports.Touch;e[b]="onZoomGestureMove";e[b+"start"]="onZoomGestureStart";e[b+"end"]="onZoomGestureEnd";e[d]="onPanGestureMove";e[d+"start"]="onPanGestureStart";e[d+"end"]="onPanGestureEnd";e.doubletap="onDoubleTap";return e},onDoubleTap:function(h){var f=this,c=f.getChart(),g=c.getAxes(),b,a,d;for(a=0,d=g.length;a<d;a++){b=g[a];b.setVisibleRange([0,1])}c.redraw()},onPanGestureStart:function(d){if(!d||!d.touches||d.touches.length<2){var b=this,a=b.getChart().getInnerRect(),c=b.getChart().element.getXY();b.startX=d.getX()-c[0]-a[0];b.startY=d.getY()-c[1]-a[1];b.oldVisibleRanges=null;b.hideLabels();b.getChart().suspendThicknessChanged();b.lockEvents(b.getPanGesture());return false}},onPanGestureMove:function(d){var b=this;if(b.getLocks()[b.getPanGesture()]===b){var a=b.getChart().getInnerRect(),c=b.getChart().element.getXY();if(b.getZoomOnPanGesture()){b.transformAxesBy(b.getZoomableAxes(d),0,0,(d.getX()-c[0]-a[0])/b.startX,b.startY/(d.getY()-c[1]-a[1]))}else{b.transformAxesBy(b.getPannableAxes(d),d.getX()-c[0]-a[0]-b.startX,d.getY()-c[1]-a[1]-b.startY,1,1)}b.sync();return false}},onPanGestureEnd:function(b){var a=this,c=a.getPanGesture();if(a.getLocks()[c]===a){a.getChart().resumeThicknessChanged();a.showLabels();a.sync();a.unlockEvents(c);return false}},onZoomGestureStart:function(b){if(b.touches&&b.touches.length===2){var c=this,i=c.getChart().element.getXY(),f=c.getChart().getInnerRect(),h=i[0]+f[0],d=i[1]+f[1],j=[b.touches[0].point.x-h,b.touches[0].point.y-d,b.touches[1].point.x-h,b.touches[1].point.y-d],g=Math.max(44,Math.abs(j[2]-j[0])),a=Math.max(44,Math.abs(j[3]-j[1]));c.getChart().suspendThicknessChanged();c.lastZoomDistances=[g,a];c.lastPoints=j;c.oldVisibleRanges=null;c.hideLabels();c.lockEvents(c.getZoomGesture());return false}},onZoomGestureMove:function(d){var f=this;if(f.getLocks()[f.getZoomGesture()]===f){var i=f.getChart().getInnerRect(),n=f.getChart().element.getXY(),k=n[0]+i[0],h=n[1]+i[1],o=Math.abs,c=f.lastPoints,m=[d.touches[0].point.x-k,d.touches[0].point.y-h,d.touches[1].point.x-k,d.touches[1].point.y-h],g=Math.max(44,o(m[2]-m[0])),b=Math.max(44,o(m[3]-m[1])),a=this.lastZoomDistances||[g,b],l=g/a[0],j=b/a[1];f.transformAxesBy(f.getZoomableAxes(d),i[2]*(l-1)/2+m[2]-c[2]*l,i[3]*(j-1)/2+m[3]-c[3]*j,l,j);f.sync();return false}},onZoomGestureEnd:function(c){var b=this,a=b.getZoomGesture();if(b.getLocks()[a]===b){b.getChart().resumeThicknessChanged();b.showLabels();b.sync();b.unlockEvents(a);return false}},hideLabels:function(){if(this.getHideLabelInGesture()){this.eachInteractiveAxes(function(a){a.hideLabels()})}},showLabels:function(){if(this.getHideLabelInGesture()){this.eachInteractiveAxes(function(a){a.showLabels()})}},isEventOnAxis:function(c,a){var b=a.getSurface().getRect();return b[0]<=c.getX()&&c.getX()<=b[0]+b[2]&&b[1]<=c.getY()&&c.getY()<=b[1]+b[3]},getPannableAxes:function(d){var h=this,a=h.getAxes(),f=h.getChart().getAxes(),c,g=f.length,k=[],j=false,b;if(d){for(c=0;c<g;c++){if(this.isEventOnAxis(d,f[c])){j=true;break}}}for(c=0;c<g;c++){b=a[f[c].getPosition()];if(b&&b.allowPan!==false&&(!j||this.isEventOnAxis(d,f[c]))){k.push(f[c])}}return k},getZoomableAxes:function(f){var j=this,a=j.getAxes(),g=j.getChart().getAxes(),l=[],d,h=g.length,c,k=false,b;if(f){for(d=0;d<h;d++){if(this.isEventOnAxis(f,g[d])){k=true;break}}}for(d=0;d<h;d++){c=g[d];b=a[c.getPosition()];if(b&&b.allowZoom!==false&&(!k||this.isEventOnAxis(f,c))){l.push(c)}}return l},eachInteractiveAxes:function(c){var d=this,b=d.getAxes(),e=d.getChart().getAxes();for(var a=0;a<e.length;a++){if(b[e[a].getPosition()]){if(false===c.call(this,e[a])){return}}}},transformAxesBy:function(d,j,g,h,e){var f=this.getChart().getInnerRect(),a=this.getAxes(),k,b=this.oldVisibleRanges,l=false;if(!b){this.oldVisibleRanges=b={};this.eachInteractiveAxes(function(i){b[i.getId()]=i.getVisibleRange()})}if(!f){return}for(var c=0;c<d.length;c++){k=a[d[c].getPosition()];l=this.transformAxisBy(d[c],b[d[c].getId()],j,g,h,e,this.minZoom||k.minZoom,this.maxZoom||k.maxZoom)||l}return l},transformAxisBy:function(c,o,r,q,k,i,h,m){var s=this,b=o[1]-o[0],l=c.getVisibleRange(),g=h||s.getMinZoom()||c.config.minZoom,j=m||s.getMaxZoom()||c.config.maxZoom,a=s.getChart().getInnerRect(),f,p;if(!a){return}var d=c.isSide(),e=d?a[3]:a[2],n=d?-q:r;b/=d?i:k;if(b<0){b=-b}if(b*g>1){b=1}if(b*j<1){b=1/j}f=o[0];p=o[1];l=l[1]-l[0];if(b===l&&l===1){return}c.setVisibleRange([(o[0]+o[1]-b)*0.5-n/e*b,(o[0]+o[1]+b)*0.5-n/e*b]);return(Math.abs(f-c.getVisibleRange()[0])>1e-10||Math.abs(p-c.getVisibleRange()[1])>1e-10)},destroy:function(){this.setModeToggleButton(null);this.callParent()}});Ext.define("Ext.chart.interactions.Rotate",{extend:"Ext.chart.interactions.Abstract",type:"rotate",alias:"interaction.rotate",config:{gesture:"rotate",gestures:{rotate:"onRotate",rotateend:"onRotate",dragstart:"onGestureStart",drag:"onGesture",dragend:"onGestureEnd"},rotation:0},oldRotations:null,getAngle:function(f){var c=this,b=c.getChart(),d=b.getEventXY(f),a=b.getCenter();return Math.atan2(d[1]-a[1],d[0]-a[0])},getRadius:function(a){return this.getChart().getRadius()},getEventRadius:function(h){var f=this,d=f.getChart(),g=d.getEventXY(h),a=d.getCenter(),c=g[0]-a[0],b=g[1]-a[1];return Math.sqrt(c*c+b*b)},onGestureStart:function(d){var c=this,b=c.getRadius(d),a=c.getEventRadius(d);if(b>=a){c.lockEvents("drag");c.angle=c.getAngle(d);c.oldRotations={};return false}},onGesture:function(b){var a=this,c=a.getAngle(b)-a.angle;if(a.getLocks().drag===a){a.doRotateTo(c,true);return false}},doRotateTo:function(d,a,b){var n=this,l=n.getChart(),k=l.getAxes(),f=l.getSeries(),m=n.oldRotations,c,j,g,e,h;if(!b){l.suspendAnimation()}for(e=0,h=k.length;e<h;e++){c=k[e];g=m[c.getId()]||(m[c.getId()]=c.getRotation());c.setRotation(d+(a?g:0))}for(e=0,h=f.length;e<h;e++){j=f[e];g=m[j.getId()]||(m[j.getId()]=j.getRotation());j.setRotation(d+(a?g:0))}n.setRotation(d+(a?g:0));n.fireEvent("rotate",n,n.getRotation());n.sync();if(!b){l.resumeAnimation()}},rotateTo:function(c,b,a){this.doRotateTo(c,b,a);this.oldRotations={}},onGestureEnd:function(b){var a=this;if(a.getLocks().drag===a){a.onGesture(b);a.unlockEvents("drag");a.fireEvent("rotationEnd",a,a.getRotation());return false}},onRotate:function(a){}});Ext.define("Ext.chart.interactions.RotatePie3D",{extend:"Ext.chart.interactions.Rotate",type:"rotatePie3d",alias:"interaction.rotatePie3d",getAngle:function(g){var a=this.getChart(),f=a.getInherited().rtl,d=f?-1:1,h=g.getXY(),c=a.element.getXY(),b=a.getMainRect();return d*Math.atan2(h[1]-c[1]-b[3]*0.5,h[0]-c[0]-b[2]*0.5)},getRadius:function(j){var f=this.getChart(),a=f.getRadius(),d=f.getSeries(),h=d.length,c=0,b,g;for(;c<h;c++){b=d[c];if(b.isPie3D){g=b.getRadius();if(g>a){a=g}}}return a}});Ext.define("Ext.chart.plugin.ItemEvents",{extend:"Ext.plugin.Abstract",alias:"plugin.chartitemevents",moveEvents:false,mouseMoveEvents:{mousemove:true,mouseover:true,mouseout:true},itemMouseMoveEvents:{itemmousemove:true,itemmouseover:true,itemmouseout:true},init:function(b){var a="handleEvent";this.chart=b;b.addElementListener({click:a,dblclick:a,mousedown:a,mousemove:a,mouseup:a,mouseover:a,mouseout:a,priority:1001,scope:this})},hasItemMouseMoveListeners:function(){var b=this.chart.hasListeners,a;for(a in this.itemMouseMoveEvents){if(a in b){return true}}return false},handleEvent:function(g){var d=this,a=d.chart,h=g.type in d.mouseMoveEvents,c=d.lastItem,f,b;if(h&&!d.hasItemMouseMoveListeners()&&!d.moveEvents){return}f=a.getEventXY(g);b=a.getItemForPoint(f[0],f[1]);if(h&&!Ext.Object.equals(b,c)){if(c){a.fireEvent("itemmouseout",a,c,g);c.series.fireEvent("itemmouseout",c.series,c,g)}if(b){a.fireEvent("itemmouseover",a,b,g);b.series.fireEvent("itemmouseover",b.series,b,g)}}if(b){a.fireEvent("item"+g.type,a,b,g);b.series.fireEvent("item"+g.type,b.series,b,g)}d.lastItem=b}});Ext.define("Ext.chart.series.Cartesian",{extend:"Ext.chart.series.Series",config:{xField:null,yField:null,xAxis:null,yAxis:null},directions:["X","Y"],fieldCategoryX:["X"],fieldCategoryY:["Y"],applyXAxis:function(a,b){return this.getChart().getAxis(a)||b},applyYAxis:function(a,b){return this.getChart().getAxis(a)||b},updateXAxis:function(a){a.processData(this)},updateYAxis:function(a){a.processData(this)},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},getItemForPoint:function(a,g){if(this.getSprites()){var f=this,d=f.getSprites()[0],b=f.getStore(),e,c;if(f.getHidden()){return null}if(d){c=d.getIndexNearPoint(a,g);if(c!==-1){e={series:f,category:f.getItemInstancing()?"items":"markers",index:c,record:b.getData().items[c],field:f.getYField(),sprite:d};return e}}}},createSprite:function(){var c=this,a=c.callParent(),b=c.getChart(),d=c.getXAxis();a.setAttributes({flipXY:b.getFlipXY(),xAxis:d});if(a.setAggregator&&d&&d.getAggregator){if(d.getAggregator){a.setAggregator({strategy:d.getAggregator()})}else{a.setAggregator({})}}return a},getSprites:function(){var d=this,c=this.getChart(),e=d.getAnimation()||c&&c.getAnimation(),b=d.getItemInstancing(),f=d.sprites,a;if(!c){return[]}if(!f.length){a=d.createSprite()}else{a=f[0]}if(e){if(b){a.itemsMarker.getTemplate().setAnimation(e)}a.setAnimation(e)}return f},provideLegendInfo:function(d){var b=this,a=b.getSubStyleWithTheme(),c=a.fillStyle;if(Ext.isArray(c)){c=c[0]}d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})},getXRange:function(){return[this.dataRange[0],this.dataRange[2]]},getYRange:function(){return[this.dataRange[1],this.dataRange[3]]}});Ext.define("Ext.chart.series.StackedCartesian",{extend:"Ext.chart.series.Cartesian",config:{stacked:true,splitStacks:true,fullStack:false,fullStackTotal:100,hidden:[]},spriteAnimationCount:0,themeColorCount:function(){var b=this,a=b.getYField();return Ext.isArray(a)?a.length:1},updateStacked:function(){this.processData()},updateSplitStacks:function(){this.processData()},coordinateY:function(){return this.coordinateStacked("Y",1,2)},coordinateStacked:function(D,e,m){var F=this,f=F.getStore(),r=f.getData().items,B=r.length,c=F["get"+D+"Axis"](),x=F.getHidden(),a=F.getSplitStacks(),z=F.getFullStack(),l=F.getFullStackTotal(),p={min:0,max:0},n=F["fieldCategory"+D],C=[],o=[],E=[],h,A=F.getStacked(),g=F.getSprites(),q=[],w,v,u,s,H,y,b,d,G,t;if(!g.length){return}for(w=0;w<n.length;w++){d=n[w];s=F.getFields([d]);H=s.length;for(v=0;v<B;v++){C[v]=0;o[v]=0;E[v]=0}for(v=0;v<H;v++){if(!x[v]){q[v]=F.coordinateData(r,s[v],c)}}if(A&&z){y=[];if(a){b=[]}for(v=0;v<B;v++){y[v]=0;if(a){b[v]=0}for(u=0;u<H;u++){G=q[u];if(!G){continue}G=G[v];if(G>=0||!a){y[v]+=G}else{if(G<0){b[v]+=G}}}}}for(v=0;v<H;v++){t={};if(x[v]){t["dataStart"+d]=C;t["data"+d]=C;g[v].setAttributes(t);continue}G=q[v];if(A){h=[];for(u=0;u<B;u++){if(!G[u]){G[u]=0}if(G[u]>=0||!a){if(z&&y[u]){G[u]*=l/y[u]}C[u]=o[u];o[u]+=G[u];h[u]=o[u]}else{if(z&&b[u]){G[u]*=l/b[u]}C[u]=E[u];E[u]+=G[u];h[u]=E[u]}}t["dataStart"+d]=C;t["data"+d]=h;F.getRangeOfData(C,p);F.getRangeOfData(h,p)}else{t["dataStart"+d]=C;t["data"+d]=G;F.getRangeOfData(G,p)}g[v].setAttributes(t)}}F.dataRange[e]=p.min;F.dataRange[e+m]=p.max;t={};t["dataMin"+D]=p.min;t["dataMax"+D]=p.max;for(w=0;w<g.length;w++){g[w].setAttributes(t)}},getFields:function(f){var e=this,a=[],c,b,d;for(b=0,d=f.length;b<d;b++){c=e["get"+f[b]+"Field"]();if(Ext.isArray(c)){a.push.apply(a,c)}else{a.push(c)}}return a},updateLabelOverflowPadding:function(a){this.getLabel().setAttributes({labelOverflowPadding:a})},getSprites:function(){var k=this,j=k.getChart(),c=k.getAnimation()||j&&j.getAnimation(),f=k.getFields(k.fieldCategoryY),b=k.getItemInstancing(),h=k.sprites,l,e=k.getHidden(),g=false,d,a=f.length;if(!j){return[]}for(d=0;d<a;d++){l=h[d];if(!l){l=k.createSprite();l.setAttributes({zIndex:-d});l.setField(f[d]);g=true;e.push(false);if(b){l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))}else{l.setAttributes(k.getStyleByIndex(d))}}if(c){if(b){l.itemsMarker.getTemplate().setAnimation(c)}l.setAnimation(c)}}if(g){k.updateHidden(e)}return h},getItemForPoint:function(k,j){if(this.getSprites()){var h=this,b,g,m,a=h.getItemInstancing(),f=h.getSprites(),l=h.getStore(),c=h.getHidden(),n,d,e;for(b=0,g=f.length;b<g;b++){if(!c[b]){m=f[b];d=m.getIndexNearPoint(k,j);if(d!==-1){e=h.getYField();n={series:h,index:d,category:a?"items":"markers",record:l.getData().items[d],field:typeof e==="string"?e:e[b],sprite:m};return n}}}return null}},provideLegendInfo:function(e){var g=this,f=g.getSprites(),h=g.getTitle(),j=g.getYField(),d=g.getHidden(),k=f.length===1,b,l,c,a;for(c=0;c<f.length;c++){b=g.getStyleByIndex(c);l=b.fillStyle;if(h){if(Ext.isArray(h)){a=h[c]}else{if(k){a=h}}}else{if(Ext.isArray(j)){a=j[c]}else{a=g.getId()}}e.push({name:a,mark:(Ext.isObject(l)?l.stops&&l.stops[0].color:l)||b.strokeStyle||"black",disabled:d[c],series:g.getId(),index:c})}},onSpriteAnimationStart:function(a){this.spriteAnimationCount++;if(this.spriteAnimationCount===1){this.fireEvent("animationstart")}},onSpriteAnimationEnd:function(a){this.spriteAnimationCount--;if(this.spriteAnimationCount===0){this.fireEvent("animationend")}}});Ext.define("Ext.chart.series.sprite.Series",{extend:"Ext.draw.sprite.Sprite",mixins:{markerHolder:"Ext.chart.MarkerHolder"},inheritableStatics:{def:{processors:{dataMinX:"number",dataMaxX:"number",dataMinY:"number",dataMaxY:"number",rangeX:"data",rangeY:"data",dataX:"data",dataY:"data"},defaults:{dataMinX:0,dataMaxX:1,dataMinY:0,dataMaxY:1,rangeX:null,rangeY:null,dataX:null,dataY:null},triggers:{dataX:"bbox",dataY:"bbox",dataMinX:"bbox",dataMaxX:"bbox",dataMinY:"bbox",dataMaxY:"bbox"}}},config:{store:null,series:null,field:null}});Ext.define("Ext.chart.series.sprite.Cartesian",{extend:"Ext.chart.series.sprite.Series",inheritableStatics:{def:{processors:{labels:"default",labelOverflowPadding:"number",selectionTolerance:"number",flipXY:"bool",renderer:"default",visibleMinX:"number",visibleMinY:"number",visibleMaxX:"number",visibleMaxY:"number",innerWidth:"number",innerHeight:"number"},defaults:{labels:null,labelOverflowPadding:10,selectionTolerance:20,flipXY:false,renderer:null,transformFillStroke:false,visibleMinX:0,visibleMinY:0,visibleMaxX:1,visibleMaxY:1,innerWidth:1,innerHeight:1},triggers:{dataX:"dataX,bbox",dataY:"dataY,bbox",visibleMinX:"panzoom",visibleMinY:"panzoom",visibleMaxX:"panzoom",visibleMaxY:"panzoom",innerWidth:"panzoom",innerHeight:"panzoom"},updaters:{dataX:function(a){this.processDataX();this.scheduleUpdater(a,"dataY",["dataY"])},dataY:function(){this.processDataY()},panzoom:function(c){var e=c.visibleMaxX-c.visibleMinX,d=c.visibleMaxY-c.visibleMinY,b=c.flipXY?c.innerHeight:c.innerWidth,g=!c.flipXY?c.innerHeight:c.innerWidth,a=this.getSurface(),f=a?a.getInherited().rtl:false;if(f&&!c.flipXY){c.translationX=b+c.visibleMinX*b/e}else{c.translationX=-c.visibleMinX*b/e}c.translationY=-c.visibleMinY*g/d;c.scalingX=(f&&!c.flipXY?-1:1)*b/e;c.scalingY=g/d;c.scalingCenterX=0;c.scalingCenterY=0;this.applyTransformations(true)}}}},processDataY:Ext.emptyFn,processDataX:Ext.emptyFn,updatePlainBBox:function(b){var a=this.attr;b.x=a.dataMinX;b.y=a.dataMinY;b.width=a.dataMaxX-a.dataMinX;b.height=a.dataMaxY-a.dataMinY},binarySearch:function(d){var b=this.attr.dataX,f=0,a=b.length;if(d<=b[0]){return f}if(d>=b[a-1]){return a-1}while(f+1<a){var c=(f+a)>>1,e=b[c];if(e===d){return c}else{if(e<d){f=c}else{a=c}}}return f},render:function(b,c,g){var f=this,a=f.attr,e=a.inverseMatrix.clone();e.appendMatrix(b.inverseMatrix);if(a.dataX===null||a.dataX===undefined){return}if(a.dataY===null||a.dataY===undefined){return}if(e.getXX()*e.getYX()||e.getXY()*e.getYY()){console.log("Cartesian Series sprite does not support rotation/sheering");return}var d=e.transformList([[g[0]-1,g[3]+1],[g[0]+g[2]+1,-1]]);d=d[0].concat(d[1]);f.renderClipped(b,c,d,g)},renderClipped:Ext.emptyFn,getIndexNearPoint:function(f,e){var w=this,q=w.attr.matrix,h=w.attr.dataX,g=w.attr.dataY,k=w.attr.selectionTolerance,t,r,c=-1,j=q.clone().prependMatrix(w.surfaceMatrix).inverse(),u=j.transformPoint([f,e]),b=j.transformPoint([f-k,e-k]),n=j.transformPoint([f+k,e+k]),a=Math.min(b[0],n[0]),s=Math.max(b[0],n[0]),l=Math.min(b[1],n[1]),d=Math.max(b[1],n[1]),m,v,o,p;for(o=0,p=h.length;o<p;o++){m=h[o];v=g[o];if(m>a&&m<s&&v>l&&v<d){if(c===-1||(Math.abs(m-u[0])<t)&&(Math.abs(v-u[1])<r)){t=Math.abs(m-u[0]);r=Math.abs(v-u[1]);c=o}}}return c}});Ext.define("Ext.chart.series.sprite.StackedCartesian",{extend:"Ext.chart.series.sprite.Cartesian",inheritableStatics:{def:{processors:{groupCount:"number",groupOffset:"number",dataStartY:"data"},defaults:{selectionTolerance:20,groupCount:1,groupOffset:0,dataStartY:null},triggers:{dataStartY:"dataY,bbox"}}},getIndexNearPoint:function(e,d){var o=this,q=o.attr.matrix,h=o.attr.dataX,f=o.attr.dataY,u=o.attr.dataStartY,l=o.attr.selectionTolerance,s=0.5,r=Infinity,b=-1,k=q.clone().prependMatrix(this.surfaceMatrix).inverse(),t=k.transformPoint([e,d]),a=k.transformPoint([e-l,d-l]),n=k.transformPoint([e+l,d+l]),m=Math.min(a[1],n[1]),c=Math.max(a[1],n[1]),j,g;for(var p=0;p<h.length;p++){if(Math.min(u[p],f[p])<=c&&m<=Math.max(u[p],f[p])){j=Math.abs(h[p]-t[0]);g=Math.max(-Math.min(f[p]-t[1],t[1]-u[p]),0);if(j<s&&g<=r){s=j;r=g;b=p}}}return b}});Ext.define("Ext.chart.series.sprite.Area",{alias:"sprite.areaSeries",extend:"Ext.chart.series.sprite.StackedCartesian",inheritableStatics:{def:{processors:{step:"bool"},defaults:{step:false}}},renderClipped:function(q,s,A){var B=this,p=B.attr,l=p.dataX,j=p.dataY,C=p.dataStartY,t=p.matrix,h,g,v,f,d,z,w,e=t.elements[0],m=t.elements[4],o=t.elements[3],k=t.elements[5],c=B.surfaceMatrix,n={},r=Math.min(A[0],A[2]),u=Math.max(A[0],A[2]),b=Math.max(0,this.binarySearch(r)),a=Math.min(l.length-1,this.binarySearch(u)+1);s.beginPath();z=l[b]*e+m;w=j[b]*o+k;s.moveTo(z,w);if(p.step){d=w;for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,d);s.lineTo(h,d=g)}}else{for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,g)}}if(C){if(p.step){f=l[a]*e+m;for(v=a;v>=b;v--){h=l[v]*e+m;g=C[v]*o+k;s.lineTo(f,g);s.lineTo(f=h,g)}}else{for(v=a;v>=b;v--){h=l[v]*e+m;g=C[v]*o+k;s.lineTo(h,g)}}}else{s.lineTo(l[a]*e+m,g);s.lineTo(l[a]*e+m,k);s.lineTo(z,k);s.lineTo(z,j[v]*o+k)}if(p.transformFillStroke){p.matrix.toContext(s)}s.fill();if(p.transformFillStroke){p.inverseMatrix.toContext(s)}s.beginPath();s.moveTo(z,w);if(p.step){for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,d);s.lineTo(h,d=g);n.translationX=c.x(h,g);n.translationY=c.y(h,g);B.putMarker("markers",n,v,!p.renderer)}}else{for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,g);n.translationX=c.x(h,g);n.translationY=c.y(h,g);B.putMarker("markers",n,v,!p.renderer)}}if(p.transformFillStroke){p.matrix.toContext(s)}s.stroke()}});Ext.define("Ext.chart.series.Area",{extend:"Ext.chart.series.StackedCartesian",alias:"series.area",type:"area",seriesType:"areaSeries",requires:["Ext.chart.series.sprite.Area"],config:{splitStacks:false}});Ext.define("Ext.chart.series.sprite.Bar",{alias:"sprite.barSeries",extend:"Ext.chart.series.sprite.StackedCartesian",inheritableStatics:{def:{processors:{minBarWidth:"number",maxBarWidth:"number",minGapWidth:"number",radius:"number",inGroupGapWidth:"number"},defaults:{minBarWidth:2,maxBarWidth:100,minGapWidth:5,inGroupGapWidth:3,radius:0}}},drawLabel:function(k,i,s,h,o){var q=this,n=q.attr,f=q.getMarker("labels"),d=f.getTemplate(),l=q.labelCfg||(q.labelCfg={}),c=q.surfaceMatrix,j=n.labelOverflowPadding,b=d.attr.display,m=d.attr.orientation,g,e,a,r,t,p;l.x=c.x(i,h);l.y=c.y(i,h);if(!n.flipXY){l.rotationRads=-Math.PI*0.5}else{l.rotationRads=0}l.calloutVertical=!n.flipXY;switch(m){case"horizontal":l.rotationRads=0;l.calloutVertical=false;break;case"vertical":l.rotationRads=-Math.PI*0.5;l.calloutVertical=true;break}l.text=k;if(d.attr.renderer){p=[k,f,l,{store:q.getStore()},o];r=Ext.callback(d.attr.renderer,null,p,0,q.getSeries());if(typeof r==="string"){l.text=r}else{if(typeof r==="object"){if("text" in r){l.text=r.text}t=true}}}a=q.getMarkerBBox("labels",o,true);if(!a){q.putMarker("labels",l,o);a=q.getMarkerBBox("labels",o,true)}e=(a.width/2+j);if(s>h){e=-e}if((m==="horizontal"&&n.flipXY)||(m==="vertical"&&!n.flipXY)||!m){g=(b==="insideStart")?s+e:h-e}else{g=(b==="insideStart")?s+j*2:h-j*2}l.x=c.x(i,g);l.y=c.y(i,g);g=(b==="insideStart")?s-e:h+e;l.calloutPlaceX=c.x(i,g);l.calloutPlaceY=c.y(i,g);g=(b==="insideStart")?s:h;l.calloutStartX=c.x(i,g);l.calloutStartY=c.y(i,g);if(s>h){e=-e}if(Math.abs(h-s)<=e*2||b==="outside"){l.callout=1}else{l.callout=0}if(t){Ext.apply(l,r)}q.putMarker("labels",l,o)},drawBar:function(l,b,d,c,h,k,a,e){var g=this,j={},f=g.attr.renderer,i;j.x=c;j.y=h;j.width=k-c;j.height=a-h;j.radius=g.attr.radius;if(f){i=Ext.callback(f,null,[g,j,{store:g.getStore()},e],0,g.getSeries());Ext.apply(j,i)}g.putMarker("items",j,e,!f)},renderClipped:function(G,u,F,C){if(this.cleanRedraw){return}var q=this,o=q.attr,w=o.dataX,v=o.dataY,H=o.labels,n=o.dataStartY,m=o.groupCount,E=o.groupOffset-(m-1)*0.5,z=o.inGroupGapWidth,t=u.lineWidth,D=o.matrix,B=D.elements[0],j=D.elements[3],e=D.elements[4],d=G.roundPixel(D.elements[5])-1,J=(B<0?-1:1)*B-o.minGapWidth,k=(Math.min(J,o.maxBarWidth)-z*(m-1))/m,A=G.roundPixel(Math.max(o.minBarWidth,k)),c=q.surfaceMatrix,g,I,b,h,K,a,l=0.5*o.lineWidth,L=Math.min(F[0],F[2]),x=Math.max(F[0],F[2]),y=Math.max(0,Math.floor(L)),p=Math.min(w.length-1,Math.ceil(x)),f=H&&q.getMarker("labels"),s,r;for(K=y;K<=p;K++){s=n?n[K]:0;r=v[K];a=w[K]*B+e+E*(A+z);g=G.roundPixel(a-A/2)+l;h=G.roundPixel(r*j+d+t);I=G.roundPixel(a+A/2)-l;b=G.roundPixel(s*j+d+t);q.drawBar(u,G,F,g,h-l,I,b-l,K);if(f&&H[K]!=null){q.drawLabel(H[K],a,b,h,K)}q.putMarker("markers",{translationX:c.x(a,h),translationY:c.y(a,h)},K,true)}},getIndexNearPoint:function(l,k){var m=this,g=m.attr,h=g.dataX,a=m.getSurface(),b=a.getRect()||[0,0,0,0],j=b[3],e,d,c,n,f=-1;if(g.flipXY){e=j-k;if(a.getInherited().rtl){d=b[2]-l}else{d=l}}else{e=l;d=j-k}for(c=0;c<h.length;c++){n=m.getMarkerBBox("items",c);if(Ext.draw.Draw.isPointInBBox(e,d,n)){f=c;break}}return f}});Ext.define("Ext.chart.series.Bar",{extend:"Ext.chart.series.StackedCartesian",alias:"series.bar",type:"bar",seriesType:"barSeries",requires:["Ext.chart.series.sprite.Bar","Ext.draw.sprite.Rect"],config:{itemInstancing:{type:"rect",fx:{customDurations:{x:0,y:0,width:0,height:0,radius:0}}}},getItemForPoint:function(a,f){if(this.getSprites()){var d=this,c=d.getChart(),e=c.getInnerPadding(),b=c.getInherited().rtl;arguments[0]=a+(b?e.right:-e.left);arguments[1]=f+e.bottom;return d.callParent(arguments)}},updateXAxis:function(a){a.setLabelInSpan(true);this.callParent(arguments)},updateHidden:function(a){this.callParent(arguments);this.updateStacked()},updateStacked:function(c){var e=this,g=e.getSprites(),d=g.length,f=[],a={},b;for(b=0;b<d;b++){if(!g[b].attr.hidden){f.push(g[b])}}d=f.length;if(e.getStacked()){a.groupCount=1;a.groupOffset=0;for(b=0;b<d;b++){f[b].setAttributes(a)}}else{a.groupCount=f.length;for(b=0;b<d;b++){a.groupOffset=b;f[b].setAttributes(a)}}e.callParent(arguments)}});Ext.define("Ext.chart.series.sprite.Bar3D",{extend:"Ext.chart.series.sprite.Bar",alias:"sprite.bar3dSeries",requires:["Ext.draw.gradient.Linear"],inheritableStatics:{def:{processors:{depthWidthRatio:"number",saturationFactor:"number",brightnessFactor:"number",colorSpread:"number"},defaults:{depthWidthRatio:1/3,saturationFactor:1,brightnessFactor:1,colorSpread:1,transformFillStroke:true},triggers:{groupCount:"panzoom"},updaters:{panzoom:function(c){var g=this,e=c.visibleMaxX-c.visibleMinX,d=c.visibleMaxY-c.visibleMinY,b=c.flipXY?c.innerHeight:c.innerWidth,h=!c.flipXY?c.innerHeight:c.innerWidth,a=g.getSurface(),f=a?a.getInherited().rtl:false;if(f&&!c.flipXY){c.translationX=b+c.visibleMinX*b/e}else{c.translationX=-c.visibleMinX*b/e}c.translationY=-c.visibleMinY*(h-g.depth)/d;c.scalingX=(f&&!c.flipXY?-1:1)*b/e;c.scalingY=(h-g.depth)/d;c.scalingCenterX=0;c.scalingCenterY=0;g.applyTransformations(true)}}}},config:{showStroke:false},depth:0,drawBar:function(p,b,d,c,l,o,a,h){var k=this,i=k.attr,n={},j=i.renderer,m,g,f,e;n.x=(c+o)*0.5;n.y=l;n.width=(o-c)*0.75;n.height=a-l;n.depth=g=n.width*i.depthWidthRatio;n.orientation=i.flipXY?"horizontal":"vertical";n.saturationFactor=i.saturationFactor;n.brightnessFactor=i.brightnessFactor;n.colorSpread=i.colorSpread;if(g!==k.depth){k.depth=g;f=k.getSeries();f.fireEvent("depthchange",f,g)}if(j){e=[k,n,{store:k.getStore()},h];m=Ext.callback(j,null,e,0,k.getSeries());Ext.apply(n,m)}k.putMarker("items",n,h,!j)}});Ext.define("Ext.chart.series.sprite.Box",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.box",type:"box",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number",depth:"number",orientation:"enums(vertical,horizontal)",showStroke:"bool",saturationFactor:"number",brightnessFactor:"number",colorSpread:"number"},triggers:{x:"bbox",y:"bbox",width:"bbox",height:"bbox",depth:"bbox",orientation:"bbox"},defaults:{x:0,y:0,width:8,height:8,depth:8,orientation:"vertical",showStroke:false,saturationFactor:1,brightnessFactor:1,colorSpread:1,lineJoin:"bevel"}}},constructor:function(a){this.callParent([a]);this.topGradient=new Ext.draw.gradient.Linear({});this.rightGradient=new Ext.draw.gradient.Linear({});this.frontGradient=new Ext.draw.gradient.Linear({})},updatePlainBBox:function(d){var c=this.attr,b=c.x,g=c.y,e=c.width,a=c.height,f=c.depth;d.x=b-e*0.5;d.width=e+f;if(a>0){d.y=g;d.height=a+f}else{d.y=g+f;d.height=a-f}},render:function(l,m){var u=this,k=u.attr,r=k.x,j=k.y,f=j+k.height,i=j<f,e=k.width*0.5,v=k.depth,d=k.orientation==="horizontal",g=k.globalAlpha<1,c=k.fillStyle,n=Ext.draw.Color.create(c.isGradient?c.getStops()[0].color:c),h=k.saturationFactor,o=k.brightnessFactor,t=k.colorSpread,b=n.getHSV(),a={},s,q,p;if(!k.showStroke){m.strokeStyle=Ext.draw.Color.RGBA_NONE}if(i){p=j;j=f;f=p}u.topGradient.setDegrees(d?0:80);u.topGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5+t*0.1)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5-t*0.11)*o,0,1))}]);u.rightGradient.setDegrees(d?45:90);u.rightGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5-t*0.14)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1+t*0.4)*h,0,1),Ext.Number.constrain((0.5-t*0.32)*o,0,1))}]);if(d){u.frontGradient.setDegrees(0)}else{u.frontGradient.setRadians(Math.atan2(j-f,e*2))}u.frontGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1-t*0.1)*h,0,1),Ext.Number.constrain((0.5+t*0.1)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1+t*0.1)*h,0,1),Ext.Number.constrain((0.5-t*0.23)*o,0,1))}]);if(g||i){m.beginPath();m.moveTo(r-e,f);m.lineTo(r-e+v,f+v);m.lineTo(r+e+v,f+v);m.lineTo(r+e,f);m.closePath();a.x=r-e;a.y=j;a.width=e+v;a.height=v;m.fillStyle=(d?u.rightGradient:u.topGradient).generateGradient(m,a);m.fillStroke(k)}if(g){m.beginPath();m.moveTo(r-e,j);m.lineTo(r-e+v,j+v);m.lineTo(r-e+v,f+v);m.lineTo(r-e,f);m.closePath();a.x=r+e;a.y=f;a.width=v;a.height=j+v-f;m.fillStyle=(d?u.topGradient:u.rightGradient).generateGradient(m,a);m.fillStroke(k)}q=l.roundPixel(j);m.beginPath();m.moveTo(r-e,q);m.lineTo(r-e+v,j+v);m.lineTo(r+e+v,j+v);m.lineTo(r+e,q);m.closePath();a.x=r-e;a.y=j;a.width=e+v;a.height=v;m.fillStyle=(d?u.rightGradient:u.topGradient).generateGradient(m,a);m.fillStroke(k);s=l.roundPixel(r+e);m.beginPath();m.moveTo(s,l.roundPixel(j));m.lineTo(r+e+v,j+v);m.lineTo(r+e+v,f+v);m.lineTo(s,f);m.closePath();a.x=r+e;a.y=f;a.width=v;a.height=j+v-f;m.fillStyle=(d?u.topGradient:u.rightGradient).generateGradient(m,a);m.fillStroke(k);s=l.roundPixel(r+e);q=l.roundPixel(j);m.beginPath();m.moveTo(r-e,f);m.lineTo(r-e,q);m.lineTo(s,q);m.lineTo(s,f);m.closePath();a.x=r-e;a.y=f;a.width=e*2;a.height=j-f;m.fillStyle=u.frontGradient.generateGradient(m,a);m.fillStroke(k)}});Ext.define("Ext.chart.series.Bar3D",{extend:"Ext.chart.series.Bar",requires:["Ext.chart.series.sprite.Bar3D","Ext.chart.series.sprite.Box"],alias:"series.bar3d",type:"bar3d",seriesType:"bar3dSeries",config:{itemInstancing:{type:"box",fx:{customDurations:{x:0,y:0,width:0,height:0,depth:0}}},highlightCfg:{opacity:0.8}},getSprites:function(){var c=this.callParent(arguments),b,d,a;for(a=0;a<c.length;a++){b=c[a];d=b.attr.zIndex;if(d<0){b.setAttributes({zIndex:-d})}if(b.setSeries){b.setSeries(this)}}return c},getDepth:function(){var a=this.getSprites()[0];return a?(a.depth||0):0},getItemForPoint:function(m,k){if(this.getSprites()){var j=this,b,o,a=j.getItemInstancing(),h=j.getSprites(),n=j.getStore(),c=j.getHidden(),g=j.getChart(),l=g.getInnerPadding(),f=g.getInherited().rtl,p,d,e;m=m+(f?l.right:-l.left);k=k+l.bottom;for(b=h.length-1;b>=0;b--){if(!c[b]){o=h[b];d=o.getIndexNearPoint(m,k);if(d!==-1){e=j.getYField();p={series:j,index:d,category:a?"items":"markers",record:n.getData().items[d],field:typeof e==="string"?e:e[b],sprite:o};return p}}}return null}}});Ext.define("Ext.draw.LimitedCache",{config:{limit:40,feeder:function(){return 0},scope:null},cache:null,constructor:function(a){this.cache={};this.cache.list=[];this.cache.tail=0;this.initConfig(a)},get:function(e){var c=this.cache,b=this.getLimit(),a=this.getFeeder(),d=this.getScope()||this;if(c[e]){return c[e].value}if(c.list[c.tail]){delete c[c.list[c.tail].cacheId]}c[e]=c.list[c.tail]={value:a.apply(d,Array.prototype.slice.call(arguments,1)),cacheId:e};c.tail++;if(c.tail===b){c.tail=0}return c[e].value},clear:function(){this.cache={};this.cache.list=[];this.cache.tail=0}});Ext.define("Ext.draw.SegmentTree",{config:{strategy:"double"},time:function(m,l,n,c,E,d,e){var f=0,o,A,s=new Date(n[m.startIdx[0]]),x=new Date(n[m.endIdx[l-1]]),D=Ext.Date,u=[[D.MILLI,1,"ms1",null],[D.MILLI,2,"ms2","ms1"],[D.MILLI,5,"ms5","ms1"],[D.MILLI,10,"ms10","ms5"],[D.MILLI,50,"ms50","ms10"],[D.MILLI,100,"ms100","ms50"],[D.MILLI,500,"ms500","ms100"],[D.SECOND,1,"s1","ms500"],[D.SECOND,10,"s10","s1"],[D.SECOND,30,"s30","s10"],[D.MINUTE,1,"mi1","s10"],[D.MINUTE,5,"mi5","mi1"],[D.MINUTE,10,"mi10","mi5"],[D.MINUTE,30,"mi30","mi10"],[D.HOUR,1,"h1","mi30"],[D.HOUR,6,"h6","h1"],[D.HOUR,12,"h12","h6"],[D.DAY,1,"d1","h12"],[D.DAY,7,"d7","d1"],[D.MONTH,1,"mo1","d1"],[D.MONTH,3,"mo3","mo1"],[D.MONTH,6,"mo6","mo3"],[D.YEAR,1,"y1","mo3"],[D.YEAR,5,"y5","y1"],[D.YEAR,10,"y10","y5"],[D.YEAR,100,"y100","y10"]],z,b,k=f,F=l,j=false,r=m.startIdx,h=m.endIdx,w=m.minIdx,C=m.maxIdx,a=m.open,y=m.close,g=m.minX,q=m.minY,p=m.maxX,B=m.maxY,v,t;for(z=0;l>f+1&&z<u.length;z++){s=new Date(n[r[0]]);b=u[z];s=D.align(s,b[0],b[1]);if(D.diff(s,x,b[0])>n.length*2*b[1]){continue}if(b[3]&&m.map["time_"+b[3]]){o=m.map["time_"+b[3]][0];A=m.map["time_"+b[3]][1]}else{o=k;A=F}f=l;t=s;j=true;r[l]=r[o];h[l]=h[o];w[l]=w[o];C[l]=C[o];a[l]=a[o];y[l]=y[o];g[l]=g[o];q[l]=q[o];p[l]=p[o];B[l]=B[o];t=Ext.Date.add(t,b[0],b[1]);for(v=o+1;v<A;v++){if(n[h[v]]<+t){h[l]=h[v];y[l]=y[v];if(B[v]>B[l]){B[l]=B[v];p[l]=p[v];C[l]=C[v]}if(q[v]<q[l]){q[l]=q[v];g[l]=g[v];w[l]=w[v]}}else{l++;r[l]=r[v];h[l]=h[v];w[l]=w[v];C[l]=C[v];a[l]=a[v];y[l]=y[v];g[l]=g[v];q[l]=q[v];p[l]=p[v];B[l]=B[v];t=Ext.Date.add(t,b[0],b[1])}}if(l>f){m.map["time_"+b[2]]=[f,l]}}},"double":function(h,u,j,a,t,b,c){var e=0,k,f=1,n,d,v,g,s,l,m,r,q,p,o;while(u>e+1){k=e;e=u;f+=f;for(n=k;n<e;n+=2){if(n===e-1){d=h.startIdx[n];v=h.endIdx[n];g=h.minIdx[n];s=h.maxIdx[n];l=h.open[n];m=h.close[n];r=h.minX[n];q=h.minY[n];p=h.maxX[n];o=h.maxY[n]}else{d=h.startIdx[n];v=h.endIdx[n+1];l=h.open[n];m=h.close[n];if(h.minY[n]<=h.minY[n+1]){g=h.minIdx[n];r=h.minX[n];q=h.minY[n]}else{g=h.minIdx[n+1];r=h.minX[n+1];q=h.minY[n+1]}if(h.maxY[n]>=h.maxY[n+1]){s=h.maxIdx[n];p=h.maxX[n];o=h.maxY[n]}else{s=h.maxIdx[n+1];p=h.maxX[n+1];o=h.maxY[n+1]}}h.startIdx[u]=d;h.endIdx[u]=v;h.minIdx[u]=g;h.maxIdx[u]=s;h.open[u]=l;h.close[u]=m;h.minX[u]=r;h.minY[u]=q;h.maxX[u]=p;h.maxY[u]=o;u++}h.map["double_"+f]=[e,u]}},none:Ext.emptyFn,aggregateData:function(h,a,r,c,d){var b=h.length,e=[],s=[],f=[],q=[],j=[],p=[],n=[],o=[],m=[],k=[],g={startIdx:e,endIdx:s,minIdx:f,maxIdx:q,open:j,minX:p,minY:n,maxX:o,maxY:m,close:k},l;for(l=0;l<b;l++){e[l]=l;s[l]=l;f[l]=l;q[l]=l;j[l]=a[l];p[l]=h[l];n[l]=c[l];o[l]=h[l];m[l]=r[l];k[l]=d[l]}g.map={original:[0,b]};if(b){this[this.getStrategy()](g,b,h,a,r,c,d)}return g},binarySearchMin:function(c,g,a,e){var b=this.dataX;if(e<=b[c.startIdx[0]]){return g}if(e>=b[c.startIdx[a-1]]){return a-1}while(g+1<a){var d=(g+a)>>1,f=b[c.startIdx[d]];if(f===e){return d}else{if(f<e){g=d}else{a=d}}}return g},binarySearchMax:function(c,g,a,e){var b=this.dataX;if(e<=b[c.endIdx[0]]){return g}if(e>=b[c.endIdx[a-1]]){return a-1}while(g+1<a){var d=(g+a)>>1,f=b[c.endIdx[d]];if(f===e){return d}else{if(f<e){g=d}else{a=d}}}return a},constructor:function(a){this.initConfig(a)},setData:function(d,a,b,c,e){if(!b){e=c=b=a}this.dataX=d;this.dataOpen=a;this.dataHigh=b;this.dataLow=c;this.dataClose=e;if(d.length===b.length&&d.length===c.length){this.cache=this.aggregateData(d,a,b,c,e)}},getAggregation:function(d,k,i){if(!this.cache){return null}var c=Infinity,g=this.dataX[this.dataX.length-1]-this.dataX[0],l=this.cache.map,m=l.original,a,e,j,b,f,h;for(a in l){e=l[a];j=e[1]-e[0]-1;b=g/j;if(i<=b&&b<c){m=e;c=b}}f=Math.max(this.binarySearchMin(this.cache,m[0],m[1],d),m[0]);h=Math.min(this.binarySearchMax(this.cache,m[0],m[1],k)+1,m[1]);return{data:this.cache,start:f,end:h}}});Ext.define("Ext.chart.series.sprite.Aggregative",{extend:"Ext.chart.series.sprite.Cartesian",requires:["Ext.draw.LimitedCache","Ext.draw.SegmentTree"],inheritableStatics:{def:{processors:{dataHigh:"data",dataLow:"data",dataClose:"data"},aliases:{dataOpen:"dataY"},defaults:{dataHigh:null,dataLow:null,dataClose:null}}},config:{aggregator:{}},applyAggregator:function(b,a){return Ext.factory(b,Ext.draw.SegmentTree,a)},constructor:function(){this.callParent(arguments)},processDataY:function(){var d=this,b=d.attr,e=b.dataHigh,a=b.dataLow,f=b.dataClose,c=b.dataY;d.callParent(arguments);if(b.dataX&&c&&c.length>0){if(e){d.getAggregator().setData(b.dataX,b.dataY,e,a,f)}else{d.getAggregator().setData(b.dataX,b.dataY)}}},getGapWidth:function(){return 1},renderClipped:function(b,c,g,f){var e=this,d=Math.min(g[0],g[2]),a=Math.max(g[0],g[2]),h=e.getAggregator()&&e.getAggregator().getAggregation(d,a,(a-d)/f[2]*e.getGapWidth());if(h){e.dataStart=h.data.startIdx[h.start];e.dataEnd=h.data.endIdx[h.end-1];e.renderAggregates(h.data,h.start,h.end,b,c,g,f)}}});Ext.define("Ext.chart.series.sprite.CandleStick",{alias:"sprite.candlestickSeries",extend:"Ext.chart.series.sprite.Aggregative",inheritableStatics:{def:{processors:{raiseStyle:function(b,a){return Ext.merge({},a||{},b)},dropStyle:function(b,a){return Ext.merge({},a||{},b)},barWidth:"number",padding:"number",ohlcType:"enums(candlestick,ohlc)"},defaults:{raiseStyle:{strokeStyle:"green",fillStyle:"green"},dropStyle:{strokeStyle:"red",fillStyle:"red"},planar:false,barWidth:15,padding:3,lineJoin:"miter",miterLimit:5,ohlcType:"candlestick"},triggers:{raiseStyle:"raiseStyle",dropStyle:"dropStyle"},updaters:{raiseStyle:function(){this.raiseTemplate&&this.raiseTemplate.setAttributes(this.attr.raiseStyle)},dropStyle:function(){this.dropTemplate&&this.dropTemplate.setAttributes(this.attr.dropStyle)}}}},candlestick:function(i,c,a,e,h,f,b){var d=Math.min(c,h),g=Math.max(c,h);i.moveTo(f,e);i.lineTo(f,g);i.moveTo(f+b,g);i.lineTo(f+b,d);i.lineTo(f-b,d);i.lineTo(f-b,g);i.closePath();i.moveTo(f,a);i.lineTo(f,d)},ohlc:function(b,d,e,a,f,c,g){b.moveTo(c,e);b.lineTo(c,a);b.moveTo(c,d);b.lineTo(c-g,d);b.moveTo(c,f);b.lineTo(c+g,f)},constructor:function(){this.callParent(arguments);this.raiseTemplate=new Ext.draw.sprite.Rect({parent:this});this.dropTemplate=new Ext.draw.sprite.Rect({parent:this})},getGapWidth:function(){var a=this.attr,b=a.barWidth,c=a.padding;return b+c},renderAggregates:function(d,c,b,t,u,z){var D=this,s=this.attr,j=s.dataX,v=s.matrix,e=v.getXX(),r=v.getYY(),l=v.getDX(),h=v.getDY(),o=s.barWidth/e,C,k=s.ohlcType,f=Math.round(o*0.5*e),a=d.open,y=d.close,B=d.maxY,p=d.minY,q=d.startIdx,m,g,E,n,A,x,w=s.lineWidth*t.devicePixelRatio/2;w-=Math.floor(w);u.save();C=this.raiseTemplate;C.useAttributes(u,z);u.beginPath();for(x=c;x<b;x++){if(a[x]<=y[x]){m=Math.round(a[x]*r+h)+w;g=Math.round(B[x]*r+h)+w;E=Math.round(p[x]*r+h)+w;n=Math.round(y[x]*r+h)+w;A=Math.round(j[q[x]]*e+l)+w;D[k](u,m,g,E,n,A,f)}}u.fillStroke(C.attr);u.restore();u.save();C=this.dropTemplate;C.useAttributes(u,z);u.beginPath();for(x=c;x<b;x++){if(a[x]>y[x]){m=Math.round(a[x]*r+h)+w;g=Math.round(B[x]*r+h)+w;E=Math.round(p[x]*r+h)+w;n=Math.round(y[x]*r+h)+w;A=Math.round(j[q[x]]*e+l)+w;D[k](u,m,g,E,n,A,f)}}u.fillStroke(C.attr);u.restore()}});Ext.define("Ext.chart.series.CandleStick",{extend:"Ext.chart.series.Cartesian",requires:["Ext.chart.series.sprite.CandleStick"],alias:"series.candlestick",type:"candlestick",seriesType:"candlestickSeries",config:{openField:null,highField:null,lowField:null,closeField:null},fieldCategoryY:["Open","High","Low","Close"],themeColorCount:function(){return 2}});Ext.define("Ext.chart.series.Polar",{extend:"Ext.chart.series.Series",config:{rotation:0,radius:null,center:[0,0],offsetX:0,offsetY:0,showInLegend:true,xField:null,yField:null,angleField:null,radiusField:null,xAxis:null,yAxis:null},directions:["X","Y"],fieldCategoryX:["X"],fieldCategoryY:["Y"],deprecatedConfigs:{field:"angleField",lengthField:"radiusField"},constructor:function(b){var c=this,a=c.getConfigurator(),e=a.configs,d;if(b){for(d in c.deprecatedConfigs){if(d in b&&!(b in e)){Ext.raise("'"+d+"' config has been deprecated. Please use the '"+c.deprecatedConfigs[d]+"' config instead.")}}}c.callParent([b])},getXField:function(){return this.getAngleField()},updateXField:function(a){this.setAngleField(a)},getYField:function(){return this.getRadiusField()},updateYField:function(a){this.setRadiusField(a)},applyXAxis:function(a,b){return this.getChart().getAxis(a)||b},applyYAxis:function(a,b){return this.getChart().getAxis(a)||b},getXRange:function(){return[this.dataRange[0],this.dataRange[2]]},getYRange:function(){return[this.dataRange[1],this.dataRange[3]]},themeColorCount:function(){var c=this,a=c.getStore(),b=a&&a.getCount()||0;return b},isStoreDependantColorCount:true,getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer(),centerX:0,centerY:0,rotationCenterX:0,rotationCenterY:0}},applyRotation:function(a){return Ext.draw.sprite.AttributeParser.angle(a)},updateRotation:function(a){var b=this.getSprites();if(b&&b[0]){b[0].setAttributes({baseRotation:a})}}});Ext.define("Ext.chart.series.Gauge",{alias:"series.gauge",extend:"Ext.chart.series.Polar",type:"gauge",seriesType:"pieslice",requires:["Ext.draw.sprite.Sector"],config:{needle:false,needleLength:90,needleWidth:4,donut:30,showInLegend:false,value:null,colors:null,sectors:null,minimum:0,maximum:100,rotation:0,totalAngle:Math.PI/2,rect:[0,0,1,1],center:[0.5,0.75],radius:0.5,wholeDisk:false},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},updateNeedle:function(b){var a=this,d=a.getSprites(),c=a.valueToAngle(a.getValue());if(d&&d.length){d[0].setAttributes({startAngle:(b?c:0),endAngle:c,strokeOpacity:(b?1:0),lineWidth:(b?a.getNeedleWidth():0)});a.doUpdateStyles()}},themeColorCount:function(){var c=this,a=c.getStore(),b=a&&a.getCount()||0;return b+(c.getNeedle()?0:1)},updateColors:function(a,b){var f=this,h=f.getSectors(),j=h&&h.length,e=f.getSprites(),c=Ext.Array.clone(a),g=a&&a.length,d;if(!g||!a[0]){return}for(d=0;d<j;d++){c[d+1]=h[d].color||c[d+1]||a[d%g]}if(e.length){e[0].setAttributes({strokeStyle:c[0]})}this.setSubStyle({fillStyle:c,strokeStyle:c});this.doUpdateStyles()},updateRect:function(f){var d=this.getWholeDisk(),c=d?Math.PI:this.getTotalAngle()/2,g=this.getDonut()/100,e,b,a;if(c<=Math.PI/2){e=2*Math.sin(c);b=1-g*Math.cos(c)}else{e=2;b=1-Math.cos(c)}a=Math.min(f[2]/e,f[3]/b);this.setRadius(a);this.setCenter([f[2]/2,a+(f[3]-b*a)/2])},updateCenter:function(a){this.setStyle({centerX:a[0],centerY:a[1],rotationCenterX:a[0],rotationCenterY:a[1]});this.doUpdateStyles()},updateRotation:function(a){this.setStyle({rotationRads:a-(this.getTotalAngle()+Math.PI)/2});this.doUpdateStyles()},doUpdateShape:function(b,f){var a,d=this.getSectors(),c=(d&&d.length)||0,e=this.getNeedleLength()/100;a=[b*e,b];while(c--){a.push(b)}this.setSubStyle({endRho:a,startRho:b/100*f});this.doUpdateStyles()},updateRadius:function(a){var b=this.getDonut();this.doUpdateShape(a,b)},updateDonut:function(b){var a=this.getRadius();this.doUpdateShape(a,b)},valueToAngle:function(a){a=this.applyValue(a);return this.getTotalAngle()*(a-this.getMinimum())/(this.getMaximum()-this.getMinimum())},applyValue:function(a){return Math.min(this.getMaximum(),Math.max(a,this.getMinimum()))},updateValue:function(b){var a=this,c=a.getNeedle(),e=a.valueToAngle(b),d=a.getSprites();d[0].rendererData.value=b;d[0].setAttributes({startAngle:(c?e:0),endAngle:e});a.doUpdateStyles()},processData:function(){var f=this,j=f.getStore(),a,d,h,b,g,e=j&&j.first(),c,i;if(e){c=f.getXField();if(c){i=e.get(c)}}if(a=f.getXAxis()){d=a.getMinimum();h=a.getMaximum();b=a.getSprites()[0].fx;g=b.getDuration();b.setDuration(0);if(Ext.isNumber(d)){f.setMinimum(d)}else{a.setMinimum(f.getMinimum())}if(Ext.isNumber(h)){f.setMaximum(h)}else{a.setMaximum(f.getMaximum())}b.setDuration(g)}if(!Ext.isNumber(i)){i=f.getMinimum()}f.setValue(i)},getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer(),fx:{customDurations:{translationX:0,translationY:0,rotationCenterX:0,rotationCenterY:0,centerX:0,centerY:0,startRho:0,endRho:0,baseRotation:0}}}},normalizeSectors:function(f){var d=this,c=(f&&f.length)||0,b,e,g,a;if(c){for(b=0;b<c;b++){e=f[b];if(typeof e==="number"){f[b]={start:(b>0?f[b-1].end:d.getMinimum()),end:Math.min(e,d.getMaximum())};if(b==(c-1)&&f[b].end<d.getMaximum()){f[b+1]={start:f[b].end,end:d.getMaximum()}}}else{if(typeof e.start==="number"){g=Math.max(e.start,d.getMinimum())}else{g=(b>0?f[b-1].end:d.getMinimum())}if(typeof e.end==="number"){a=Math.min(e.end,d.getMaximum())}else{a=d.getMaximum()}f[b].start=g;f[b].end=a}}}else{f=[{start:d.getMinimum(),end:d.getMaximum()}]}return f},getSprites:function(){var j=this,m=j.getStore(),l=j.getValue(),c,g;if(!m&&!Ext.isNumber(l)){return[]}var h=j.getChart(),b=j.getAnimation()||h&&h.getAnimation(),f=j.sprites,k=0,o,n,e,d,a=[];if(f&&f.length){f[0].setAnimation(b);return f}d={store:m,field:j.getXField(),angleField:j.getXField(),value:l,series:j};o=j.createSprite();o.setAttributes({zIndex:10},true);o.rendererData=d;o.rendererIndex=k++;a.push(j.getNeedleWidth());j.getLabel().getTemplate().setField(true);n=j.normalizeSectors(j.getSectors());for(c=0,g=n.length;c<g;c++){e={startAngle:j.valueToAngle(n[c].start),endAngle:j.valueToAngle(n[c].end),label:n[c].label,fillStyle:n[c].color,strokeOpacity:0,doCallout:false,labelOverflowPadding:-1};Ext.apply(e,n[c].style);o=j.createSprite();o.rendererData=d;o.rendererIndex=k++;o.setAttributes(e,true);a.push(e.lineWidth)}j.setSubStyle({lineWidth:a});j.doUpdateStyles();return f}});Ext.define("Ext.chart.series.sprite.Line",{alias:"sprite.lineSeries",extend:"Ext.chart.series.sprite.Aggregative",inheritableStatics:{def:{processors:{smooth:"bool",fillArea:"bool",step:"bool",preciseStroke:"bool",xAxis:"default",yCap:"default"},defaults:{smooth:false,fillArea:false,step:false,preciseStroke:true,xAxis:null,yCap:Math.pow(2,20),yJump:50},triggers:{dataX:"dataX,bbox,smooth",dataY:"dataY,bbox,smooth",smooth:"smooth"},updaters:{smooth:function(a){var c=a.dataX,b=a.dataY;if(a.smooth&&c&&b&&c.length>2&&b.length>2){this.smoothX=Ext.draw.Draw.spline(c);this.smoothY=Ext.draw.Draw.spline(b)}else{delete this.smoothX;delete this.smoothY}}}}},list:null,updatePlainBBox:function(d){var b=this.attr,c=Math.min(0,b.dataMinY),a=Math.max(0,b.dataMaxY);d.x=b.dataMinX;d.y=c;d.width=b.dataMaxX-b.dataMinX;d.height=a-c},drawStrip:function(a,c){a.moveTo(c[0],c[1]);for(var b=2,d=c.length;b<d;b+=2){a.lineTo(c[b],c[b+1])}},drawStraightStroke:function(p,q,e,d,u,h){var w=this,o=w.attr,n=o.renderer,g=o.step,a=true,l={type:"line",smooth:false,step:g},m=[],l,z,v,f,k,j,t,c,s,b,r;for(r=3;r<u.length;r+=3){t=u[r-3];c=u[r-2];k=u[r];j=u[r+1];s=u[r+3];b=u[r+4];if(n){l.x=k;l.y=j;l.x0=t;l.y0=c;v=[w,l,w.rendererData,e+r/3];z=Ext.callback(n,null,v,0,w.getSeries())}if(Ext.isNumber(k+j+t+c)){if(a){q.beginPath();q.moveTo(t,c);m.push(t,c);f=t;a=false}}else{continue}if(g){q.lineTo(k,c);m.push(k,c)}q.lineTo(k,j);m.push(k,j);if(z||!(Ext.isNumber(s+b))){q.save();Ext.apply(q,z);if(o.fillArea){q.lineTo(k,h);q.lineTo(f,h);q.closePath();q.fill()}q.beginPath();w.drawStrip(q,m);m=[];q.stroke();q.restore();q.beginPath();a=true}}},calculateScale:function(c,a){var b=0,d=c;while(d<a&&c>0){b++;d+=c>>b}return Math.pow(2,b>0?b-1:b)},drawSmoothStroke:function(u,v,c,b,C,f){var G=this,t=G.attr,d=t.step,z=t.matrix,s=t.renderer,e=z.getXX(),p=z.getYY(),m=z.getDX(),k=z.getDY(),r=G.smoothX,q=G.smoothY,I=G.calculateScale(t.dataX.length,b),o,F,n,E,h,g,B,a,A,w,H,D,l={type:"line",smooth:true,step:d};v.beginPath();v.moveTo(r[c*3]*e+m,q[c*3]*p+k);for(A=0,w=c*3+1;A<C.length-3;A+=3,w+=3*I){o=r[w]*e+m;F=q[w]*p+k;n=r[w+1]*e+m;E=q[w+1]*p+k;h=u.roundPixel(C[A+3]);g=C[A+4];B=u.roundPixel(C[A]);a=C[A+1];if(s){l.x0=B;l.y0=a;l.cx1=o;l.cy1=F;l.cx2=n;l.cy2=E;l.x=h;l.y=g;D=[G,l,G.rendererData,c+A/3+1];H=Ext.callback(s,null,D,0,G.getSeries());v.save();Ext.apply(v,H)}if(t.fillArea){v.moveTo(B,a);v.bezierCurveTo(o,F,n,E,h,g);v.lineTo(h,f);v.lineTo(B,f);v.lineTo(B,a);v.closePath();v.fill();v.beginPath()}v.moveTo(B,a);v.bezierCurveTo(o,F,n,E,h,g);v.stroke();v.moveTo(B,a);v.closePath();if(s){v.restore()}v.beginPath();v.moveTo(h,g)}v.beginPath()},drawLabel:function(k,i,h,o,a){var q=this,n=q.attr,e=q.getMarker("labels"),d=e.getTemplate(),m=q.labelCfg||(q.labelCfg={}),c=q.surfaceMatrix,g,f,j=n.labelOverflowPadding,l,b,r,p,s;m.x=c.x(i,h);m.y=c.y(i,h);if(n.flipXY){m.rotationRads=Math.PI*0.5}else{m.rotationRads=0}m.text=k;if(d.attr.renderer){p=[k,e,m,q.rendererData,o];r=Ext.callback(d.attr.renderer,null,p,0,q.getSeries());if(typeof r==="string"){m.text=r}else{if(typeof r==="object"){if("text" in r){m.text=r.text}s=true}}}b=q.getMarkerBBox("labels",o,true);if(!b){q.putMarker("labels",m,o);b=q.getMarkerBBox("labels",o,true)}l=b.height/2;g=i;switch(d.attr.display){case"under":f=h-l-j;break;case"rotate":g+=j;f=h-j;m.rotationRads=-Math.PI/4;break;default:f=h+l+j}m.x=c.x(g,f);m.y=c.y(g,f);if(s){Ext.apply(m,r)}q.putMarker("labels",m,o)},drawMarker:function(j,h,d){var g=this,e=g.attr,f=e.renderer,c=g.surfaceMatrix,b={},i,a;if(f&&g.getMarker("markers")){b.type="marker";b.x=j;b.y=h;a=[g,b,g.rendererData,d];i=Ext.callback(f,null,a,0,g.getSeries());if(i){Ext.apply(b,i)}}b.translationX=c.x(j,h);b.translationY=c.y(j,h);delete b.x;delete b.y;g.putMarker("markers",b,d,!f)},drawStroke:function(a,c,h,b,f,e){var d=this,g=d.attr.smooth&&d.smoothX&&d.smoothY;if(g){d.drawSmoothStroke(a,c,h,b,f,e)}else{d.drawStraightStroke(a,c,h,b,f,e)}},renderAggregates:function(B,w,l,N,o,I,D){var m=this,k=m.attr,s=k.dataX,r=k.dataY,h=k.labels,v=k.xAxis,a=k.yCap,g=k.smooth&&m.smoothX&&m.smoothY,d=h&&m.getMarker("labels"),t=m.getMarker("markers"),E=k.matrix,u=N.devicePixelRatio,C=E.getXX(),f=E.getYY(),c=E.getDX(),b=E.getDY(),q=m.list||(m.list=[]),F=B.minX,e=B.maxX,j=B.minY,P=B.maxY,U=B.startIdx,S=true,Q,T,L,K,R,G;m.rendererData={store:m.getStore()};q.length=0;for(R=w;R<l;R++){var O=F[R],p=e[R],M=j[R],n=P[R];if(O<p){q.push(O*C+c,M*f+b,U[R]);q.push(p*C+c,n*f+b,U[R])}else{if(O>p){q.push(p*C+c,n*f+b,U[R]);q.push(O*C+c,M*f+b,U[R])}else{q.push(p*C+c,n*f+b,U[R])}}}if(q.length){for(R=0;R<q.length;R+=3){L=q[R];K=q[R+1];if(Ext.isNumber(L+K)){if(K>a){K=a}else{if(K<-a){K=-a}}q[R+1]=K}else{S=false;continue}G=q[R+2];if(t){m.drawMarker(L,K,G)}if(d&&h[G]){m.drawLabel(h[G],L,K,G,D)}}m.isContinuousLine=S;if(g&&!S){Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")}if(v){T=v.getAlignment()==="vertical";if(Ext.isNumber(v.floatingAtCoord)){Q=(T?D[2]:D[3])-v.floatingAtCoord}else{Q=T?D[0]:D[1]}}else{Q=k.flipXY?D[0]:D[1]}if(k.preciseStroke){if(k.fillArea){o.fill()}if(k.transformFillStroke){k.inverseMatrix.toContext(o)}m.drawStroke(N,o,w,l,q,Q);if(k.transformFillStroke){k.matrix.toContext(o)}o.stroke()}else{m.drawStroke(N,o,w,l,q,Q);if(S&&g&&k.fillArea&&!k.renderer){var A=s[s.length-1]*C+c+u,z=r[r.length-1]*f+b,J=s[0]*C+c-u,H=r[0]*f+b;o.lineTo(A,z);o.lineTo(A,Q-k.lineWidth);o.lineTo(J,Q-k.lineWidth);o.lineTo(J,H)}if(k.transformFillStroke){k.matrix.toContext(o)}if(k.fillArea){o.fillStroke(k,true)}else{o.stroke(true)}}}}});Ext.define("Ext.chart.series.Line",{extend:"Ext.chart.series.Cartesian",alias:"series.line",type:"line",seriesType:"lineSeries",requires:["Ext.chart.series.sprite.Line"],config:{selectionTolerance:20,smooth:false,step:false,fill:undefined,aggregator:{strategy:"double"}},defaultSmoothness:3,overflowBuffer:1,themeMarkerCount:function(){return 1},getDefaultSpriteConfig:function(){var d=this,e=d.callParent(arguments),c=Ext.apply({},d.getStyle()),b,a=false;if(typeof d.config.fill!="undefined"){if(d.config.fill){a=true;if(typeof c.fillStyle=="undefined"){if(typeof c.strokeStyle=="undefined"){b=d.getStyleWithTheme();c.fillStyle=b.fillStyle;c.strokeStyle=b.strokeStyle}else{c.fillStyle=c.strokeStyle}}}}else{if(c.fillStyle){a=true}}if(!a){delete c.fillStyle}c=Ext.apply(e||{},c);return Ext.apply(c,{fillArea:a,step:d.config.step,smooth:d.config.smooth,selectionTolerance:d.config.selectionTolerance})},updateStep:function(b){var a=this.getSprites()[0];if(a&&a.attr.step!==b){a.setAttributes({step:b})}},updateFill:function(b){var a=this.getSprites()[0];if(a&&a.attr.fillArea!==b){a.setAttributes({fillArea:b})}},updateSmooth:function(a){var b=this.getSprites()[0];if(b&&b.attr.smooth!==a){b.setAttributes({smooth:a})}}});Ext.define("Ext.chart.series.sprite.PieSlice",{extend:"Ext.draw.sprite.Sector",mixins:{markerHolder:"Ext.chart.MarkerHolder"},alias:"sprite.pieslice",inheritableStatics:{def:{processors:{doCallout:"bool",label:"string",rotateLabels:"bool",labelOverflowPadding:"number",renderer:"default"},defaults:{doCallout:true,rotateLabels:true,label:"",labelOverflowPadding:10,renderer:null}}},config:{rendererData:null,rendererIndex:0,series:null},setGradientBBox:function(q,k){var j=this,i=j.attr,g=(i.fillStyle&&i.fillStyle.isGradient)||(i.strokeStyle&&i.strokeStyle.isGradient);if(g&&!i.constrainGradients){var b=j.getMidAngle(),d=i.margin,e=i.centerX,c=i.centerY,a=i.endRho,l=i.matrix,o=l.getScaleX(),n=l.getScaleY(),m=o*a,f=n*a,p={width:m+m,height:f+f};if(d){e+=d*Math.cos(b);c+=d*Math.sin(b)}p.x=l.x(e,c)-m;p.y=l.y(e,c)-f;q.setGradientBBox(p)}else{j.callParent([q,k])}},render:function(b,c,g,f){var e=this,a=e.attr,h={},d;if(a.renderer){h={type:"sector",text:a.text,centerX:a.centerX,centerY:a.centerY,margin:a.margin,startAngle:Math.min(a.startAngle,a.endAngle),endAngle:Math.max(a.startAngle,a.endAngle),startRho:Math.min(a.startRho,a.endRho),endRho:Math.max(a.startRho,a.endRho)};d=Ext.callback(a.renderer,null,[e,h,e.rendererData,e.rendererIndex],0,e.getSeries());e.setAttributes(d);e.useAttributes(c,g)}e.callParent([b,c,g,f]);if(a.label&&e.getMarker("labels")){e.placeLabel()}},placeLabel:function(){var z=this,s=z.attr,r=s.attributeId,t=Math.min(s.startAngle,s.endAngle),p=Math.max(s.startAngle,s.endAngle),k=(t+p)*0.5,n=s.margin,h=s.centerX,g=s.centerY,f=Math.sin(k),c=Math.cos(k),v=Math.min(s.startRho,s.endRho)+n,m=Math.max(s.startRho,s.endRho)+n,l=(v+m)*0.5,b=z.surfaceMatrix,o=z.labelCfg||(z.labelCfg={}),e=z.getMarker("labels"),d=e.getTemplate(),a=d.getCalloutLine(),q=a&&a.length||40,u,j,i,A,w;b.appendMatrix(s.matrix);o.text=s.label;j=h+c*l;i=g+f*l;o.x=b.x(j,i);o.y=b.y(j,i);j=h+c*m;i=g+f*m;o.calloutStartX=b.x(j,i);o.calloutStartY=b.y(j,i);j=h+c*(m+q);i=g+f*(m+q);o.calloutPlaceX=b.x(j,i);o.calloutPlaceY=b.y(j,i);if(!s.rotateLabels){o.rotationRads=0}else{switch(d.attr.orientation){case"horizontal":o.rotationRads=k+Math.atan2(b.y(1,0)-b.y(0,0),b.x(1,0)-b.x(0,0))+Math.PI/2;break;case"vertical":o.rotationRads=k+Math.atan2(b.y(1,0)-b.y(0,0),b.x(1,0)-b.x(0,0));break}}o.calloutColor=(a&&a.color)||z.attr.fillStyle;if(a){if(a.width){o.calloutWidth=a.width}}else{o.calloutHasLine=false}o.globalAlpha=s.globalAlpha*s.fillOpacity;o.hidden=(s.startAngle==s.endAngle);if(d.attr.renderer){w=[z.attr.label,e,o,z.rendererData,z.rendererIndex];A=Ext.callback(d.attr.renderer,null,w,0,z.getSeries());if(typeof A==="string"){o.text=A}else{Ext.apply(o,A)}}z.putMarker("labels",o,r);u=z.getMarkerBBox("labels",r,true);if(u){if(s.doCallout){if(d.attr.display==="outside"){z.putMarker("labels",{callout:1},r)}else{if(d.attr.display==="inside"){z.putMarker("labels",{callout:0},r)}else{z.putMarker("labels",{callout:1-z.sliceContainsLabel(s,u)},r)}}}else{z.putMarker("labels",{globalAlpha:z.sliceContainsLabel(s,u)},r)}}},sliceContainsLabel:function(d,f){var e=d.labelOverflowPadding,h=(d.endRho+d.startRho)/2,g=h+(f.width+e)/2,i=h-(f.width+e)/2,j,c,b,a;if(e<0){return 1}if(f.width+e*2>(d.endRho-d.startRho)){return 0}c=Math.sqrt(d.endRho*d.endRho-g*g);b=Math.sqrt(d.endRho*d.endRho-i*i);j=Math.abs(d.endAngle-d.startAngle);a=(j>Math.PI/2?i:Math.abs(Math.tan(j/2))*i);if(f.height+e*2>Math.min(c,b,a)*2){return 0}return 1}});Ext.define("Ext.chart.series.Pie",{extend:"Ext.chart.series.Polar",requires:["Ext.chart.series.sprite.PieSlice"],type:"pie",alias:"series.pie",seriesType:"pieslice",config:{donut:0,rotation:0,clockwise:true,totalAngle:2*Math.PI,hidden:[],radiusFactor:100,highlightCfg:{margin:20},style:{}},directions:["X"],applyLabel:function(a,b){if(Ext.isObject(a)&&!Ext.isString(a.orientation)){Ext.apply(a=Ext.Object.chain(a),{orientation:"vertical"})}return this.callParent([a,b])},updateLabelData:function(){var h=this,j=h.getStore(),g=j.getData().items,e=h.getSprites(),a=h.getLabel().getTemplate().getField(),d=h.getHidden(),b,f,c,k;if(e.length&&a){c=[];for(b=0,f=g.length;b<f;b++){c.push(g[b].get(a))}for(b=0,f=e.length;b<f;b++){k=e[b];k.setAttributes({label:c[b]});k.putMarker("labels",{hidden:d[b]},k.attr.attributeId)}}},coordinateX:function(){var t=this,f=t.getStore(),q=f.getData().items,c=q.length,b=t.getXField(),e=t.getYField(),l,a=0,m,k,s=0,o=t.getHidden(),d=[],p,g=0,h=t.getTotalAngle(),r=t.getClockwise()?1:-1,j=t.getSprites(),n;if(!j){return}for(p=0;p<c;p++){l=Math.abs(Number(q[p].get(b)))||0;k=e&&Math.abs(Number(q[p].get(e)))||0;if(!o[p]){a+=l;if(k>s){s=k}}d[p]=a;if(p>=o.length){o[p]=false}}o.length=c;t.maxY=s;if(a!==0){m=h/a}for(p=0;p<c;p++){j[p].setAttributes({startAngle:g,endAngle:g=(m?r*d[p]*m:0),globalAlpha:1})}if(c<t.sprites.length){for(p=c;p<t.sprites.length;p++){n=t.sprites[p];n.getMarker("labels").clear(n.getId());n.releaseMarker("labels");n.destroy()}t.sprites.length=c}for(p=c;p<t.sprites.length;p++){j[p].setAttributes({startAngle:h,endAngle:h,globalAlpha:0})}t.getChart().refreshLegendStore()},updateCenter:function(a){this.setStyle({translationX:a[0]+this.getOffsetX(),translationY:a[1]+this.getOffsetY()});this.doUpdateStyles()},updateRadius:function(a){this.setStyle({startRho:a*this.getDonut()*0.01,endRho:a*this.getRadiusFactor()*0.01});this.doUpdateStyles()},getStyleByIndex:function(c){var g=this,j=g.getStore(),k=j.getAt(c),f=g.getYField(),d=g.getRadius(),a={},e,b,h;if(k){h=f&&Math.abs(Number(k.get(f)))||0;e=d*g.getDonut()*0.01;b=d*g.getRadiusFactor()*0.01;a=g.callParent([c]);a.startRho=e;a.endRho=g.maxY?(e+(b-e)*h/g.maxY):b}return a},updateDonut:function(b){var a=this.getRadius();this.setStyle({startRho:a*b*0.01,endRho:a*this.getRadiusFactor()*0.01});this.doUpdateStyles()},rotationOffset:-Math.PI/2,updateRotation:function(a){this.setStyle({rotationRads:a+this.rotationOffset});this.doUpdateStyles()},updateTotalAngle:function(a){this.processData()},getSprites:function(){var k=this,h=k.getChart(),n=k.getStore();if(!h||!n){return[]}k.getColors();k.getSubStyle();var j=n.getData().items,b=j.length,d=k.getAnimation()||h&&h.getAnimation(),g=k.sprites,o,l=0,f,e,c=false,m=k.getLabel(),a=m.getTemplate();f={store:n,field:k.getXField(),angleField:k.getXField(),radiusField:k.getYField(),series:k};for(e=0;e<b;e++){o=g[e];if(!o){o=k.createSprite();if(k.getHighlight()){o.config.highlight=k.getHighlight();o.addModifier("highlight",true)}if(a.getField()){a.setAttributes({labelOverflowPadding:k.getLabelOverflowPadding()});a.fx.setCustomDurations({callout:200})}o.setAttributes(k.getStyleByIndex(e));o.rendererData=f;o.rendererIndex=l++;c=true}o.setAnimation(d)}if(c){k.doUpdateStyles()}return k.sprites},betweenAngle:function(d,f,c){var e=Math.PI*2,g=this.rotationOffset;if(!this.getClockwise()){d*=-1;f*=-1;c*=-1;f-=g;c-=g}else{f+=g;c+=g}d-=f;c-=f;d%=e;c%=e;d+=e;c+=e;d%=e;c%=e;return d<c||c===0},getItemForAngle:function(a){var h=this,f=h.getSprites(),d;a%=Math.PI*2;while(a<0){a+=Math.PI*2}if(f){var j=h.getStore(),g=j.getData().items,c=h.getHidden(),b=0,e=j.getCount();for(;b<e;b++){if(!c[b]){d=f[b].attr;if(d.startAngle<=a&&d.endAngle>=a){return{series:h,sprite:f[b],index:b,record:g[b],field:h.getXField()}}}}}return null},getItemForPoint:function(f,e){var t=this,c=t.getSprites();if(c){var s=t.getCenter(),q=t.getOffsetX(),p=t.getOffsetY(),j=f-s[0]+q,h=e-s[1]+p,b=t.getStore(),g=t.getDonut(),o=b.getData().items,r=Math.atan2(h,j)-t.getRotation(),a=Math.sqrt(j*j+h*h),l=t.getRadius()*g*0.01,m=t.getHidden(),n,d,k;for(n=0,d=o.length;n<d;n++){if(!m[n]){k=c[n].attr;if(a>=l+k.margin&&a<=k.endRho+k.margin){if(t.betweenAngle(r,k.startAngle,k.endAngle)){return{series:t,sprite:c[n],index:n,record:o[n],field:t.getXField()}}}}}return null}},provideLegendInfo:function(f){var h=this,j=h.getStore();if(j){var g=j.getData().items,b=h.getLabel().getTemplate().getField(),c=h.getXField(),e=h.getHidden(),d,a,k;for(d=0;d<g.length;d++){a=h.getStyleByIndex(d);k=a.fillStyle;if(Ext.isObject(k)){k=k.stops&&k.stops[0].color}f.push({name:b?String(g[d].get(b)):c+" "+d,mark:k||a.strokeStyle||"black",disabled:e[d],series:h.getId(),index:d})}}}});Ext.define("Ext.chart.series.sprite.Pie3DPart",{extend:"Ext.draw.sprite.Path",mixins:{markerHolder:"Ext.chart.MarkerHolder"},alias:"sprite.pie3dPart",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",margin:"number",thickness:"number",bevelWidth:"number",distortion:"number",baseColor:"color",colorSpread:"number",baseRotation:"number",part:"enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",label:"string"},aliases:{rho:"endRho"},triggers:{centerX:"path,bbox",centerY:"path,bbox",startAngle:"path,partZIndex",endAngle:"path,partZIndex",startRho:"path",endRho:"path,bbox",margin:"path,bbox",thickness:"path",distortion:"path",baseRotation:"path,partZIndex",baseColor:"partZIndex,partColor",colorSpread:"partColor",part:"path,partZIndex",globalAlpha:"canvas,alpha"},defaults:{centerX:0,centerY:0,startAngle:Math.PI*2,endAngle:Math.PI*2,startRho:0,endRho:150,margin:0,thickness:35,distortion:0.5,baseRotation:0,baseColor:"white",colorSpread:1,miterLimit:1,bevelWidth:5,strokeOpacity:0,part:"top",label:""},updaters:{alpha:"alphaUpdater",partColor:"partColorUpdater",partZIndex:"partZIndexUpdater"}}},bevelParams:[],constructor:function(a){this.callParent([a]);this.bevelGradient=new Ext.draw.gradient.Linear({stops:[{offset:0,color:"rgba(255,255,255,0)"},{offset:0.7,color:"rgba(255,255,255,0.6)"},{offset:1,color:"rgba(255,255,255,0)"}]})},alphaUpdater:function(a){var d=this,c=a.globalAlpha,b=d.oldOpacity;if(c!==b&&(c===1||b===1)){d.scheduleUpdater(a,"path",["globalAlpha"]);d.oldOpacity=c}},partColorUpdater:function(a){var d=Ext.draw.Color.fly(a.baseColor),b=d.toString(),e=a.colorSpread,c;switch(a.part){case"top":c=new Ext.draw.gradient.Radial({start:{x:0,y:0,r:0},end:{x:0,y:0,r:1},stops:[{offset:0,color:d.createLighter(0.1*e)},{offset:1,color:d.createDarker(0.1*e)}]});break;case"bottom":c=new Ext.draw.gradient.Radial({start:{x:0,y:0,r:0},end:{x:0,y:0,r:1},stops:[{offset:0,color:d.createDarker(0.2*e)},{offset:1,color:d.toString()}]});break;case"outerFront":case"outerBack":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.15*e).toString()},{offset:0.3,color:b},{offset:0.8,color:d.createLighter(0.2*e).toString()},{offset:1,color:d.createDarker(0.25*e).toString()}]});break;case"start":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:1,color:d.createLighter(0.2*e).toString()}]});break;case"end":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:1,color:d.createLighter(0.2*e).toString()}]});break;case"innerFront":case"innerBack":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:0.2,color:d.createLighter(0.2*e).toString()},{offset:0.7,color:b},{offset:1,color:d.createDarker(0.1*e).toString()}]});break}a.fillStyle=c;a.canvasAttributes.fillStyle=c},partZIndexUpdater:function(a){var c=Ext.draw.sprite.AttributeParser.angle,e=a.baseRotation,d=a.startAngle,b=a.endAngle,f;switch(a.part){case"top":a.zIndex=5;break;case"outerFront":d=c(d+e);b=c(b+e);if(d>=0&&b<0){f=Math.sin(d)}else{if(d<=0&&b>0){f=Math.sin(b)}else{if(d>=0&&b>0){if(d>b){f=0}else{f=Math.max(Math.sin(d),Math.sin(b))}}else{f=1}}}a.zIndex=4+f;break;case"outerBack":a.zIndex=1;break;case"start":a.zIndex=4+Math.sin(c(d+e));break;case"end":a.zIndex=4+Math.sin(c(b+e));break;case"innerFront":a.zIndex=2;break;case"innerBack":a.zIndex=4+Math.sin(c((d+b)/2+e));break;case"bottom":a.zIndex=0;break}a.dirtyZIndex=true},updatePlainBBox:function(k){var f=this.attr,a=f.part,b=f.baseRotation,e=f.centerX,d=f.centerY,j,c,i,h,g,l;if(a==="start"){c=f.startAngle+b}else{if(a==="end"){c=f.endAngle+b}}if(Ext.isNumber(c)){g=Math.sin(c);l=Math.cos(c);i=Math.min(e+l*f.startRho,e+l*f.endRho);h=d+g*f.startRho*f.distortion;k.x=i;k.y=h;k.width=l*(f.endRho-f.startRho);k.height=f.thickness+g*(f.endRho-f.startRho)*2;return}if(a==="innerFront"||a==="innerBack"){j=f.startRho}else{j=f.endRho}k.width=j*2;k.height=j*f.distortion*2+f.thickness;k.x=f.centerX-j;k.y=f.centerY-j*f.distortion},updateTransformedBBox:function(a){if(this.attr.part==="start"||this.attr.part==="end"){return this.callParent(arguments)}return this.updatePlainBBox(a)},updatePath:function(a){if(!this.attr.globalAlpha){return}if(this.attr.endAngle<this.attr.startAngle){return}this[this.attr.part+"Renderer"](a)},render:function(b,c){var d=this,a=d.attr;if(!a.globalAlpha){return}d.callParent([b,c]);d.bevelRenderer(b,c);if(a.label&&d.getMarker("labels")){d.placeLabel()}},placeLabel:function(){var z=this,u=z.attr,t=u.attributeId,p=u.margin,c=u.distortion,i=u.centerX,h=u.centerY,j=u.baseRotation,v=u.startAngle+j,r=u.endAngle+j,m=(v+r)/2,w=u.startRho+p,o=u.endRho+p,n=(w+o)/2,a=Math.sin(m),b=Math.cos(m),e=z.surfaceMatrix,g=z.getMarker("labels"),f=g.getTemplate(),d=f.getCalloutLine(),s=d&&d.length||40,q={},l,k;e.appendMatrix(u.matrix);q.text=u.label;l=i+b*n;k=h+a*n*c;q.x=e.x(l,k);q.y=e.y(l,k);l=i+b*o;k=h+a*o*c;q.calloutStartX=e.x(l,k);q.calloutStartY=e.y(l,k);l=i+b*(o+s);k=h+a*(o+s)*c;q.calloutPlaceX=e.x(l,k);q.calloutPlaceY=e.y(l,k);q.calloutWidth=2;z.putMarker("labels",q,t);z.putMarker("labels",{callout:1},t)},bevelRenderer:function(b,c){var f=this,a=f.attr,e=a.bevelWidth,g=f.bevelParams,d;for(d=0;d<g.length;d++){c.beginPath();c.ellipse.apply(c,g[d]);c.save();c.lineWidth=e;c.strokeOpacity=e?1:0;c.strokeGradient=f.bevelGradient;c.stroke(a);c.restore()}},lidRenderer:function(o,m){var k=this.attr,g=k.margin,c=k.distortion,i=k.centerX,h=k.centerY,f=k.baseRotation,j=k.startAngle+f,e=k.endAngle+f,d=(j+e)/2,l=k.startRho,b=k.endRho,n=Math.sin(e),a=Math.cos(e);i+=Math.cos(d)*g;h+=Math.sin(d)*g*c;o.ellipse(i,h+m,l,l*c,0,j,e,false);o.lineTo(i+a*b,h+m+n*b*c);o.ellipse(i,h+m,b,b*c,0,e,j,true);o.closePath()},topRenderer:function(a){this.lidRenderer(a,0)},bottomRenderer:function(b){var a=this.attr;if(a.globalAlpha<1||a.shadowColor!==Ext.draw.Color.RGBA_NONE){this.lidRenderer(b,a.thickness)}},sideRenderer:function(l,s){var o=this.attr,k=o.margin,g=o.centerX,f=o.centerY,e=o.distortion,h=o.baseRotation,p=o.startAngle+h,m=o.endAngle+h,a=o.thickness,q=o.startRho,j=o.endRho,r=(s==="start"&&p)||(s==="end"&&m),b=Math.sin(r),d=Math.cos(r),c=o.globalAlpha<1,n=s==="start"&&d<0||s==="end"&&d>0||c,i;if(n){i=(p+m)/2;g+=Math.cos(i)*k;f+=Math.sin(i)*k*e;l.moveTo(g+d*q,f+b*q*e);l.lineTo(g+d*j,f+b*j*e);l.lineTo(g+d*j,f+b*j*e+a);l.lineTo(g+d*q,f+b*q*e+a);l.closePath()}},startRenderer:function(a){this.sideRenderer(a,"start")},endRenderer:function(a){this.sideRenderer(a,"end")},rimRenderer:function(q,e,o,j){var w=this,s=w.attr,p=s.margin,h=s.centerX,g=s.centerY,d=s.distortion,i=s.baseRotation,t=Ext.draw.sprite.AttributeParser.angle,u=s.startAngle+i,r=s.endAngle+i,k=t((u+r)/2),a=s.thickness,b=s.globalAlpha<1,c,n,v;w.bevelParams=[];u=t(u);r=t(r);h+=Math.cos(k)*p;g+=Math.sin(k)*p*d;c=u>=0&&r>=0;n=u<=0&&r<=0;function l(){q.ellipse(h,g+a,e,e*d,0,Math.PI,u,true);q.lineTo(h+Math.cos(u)*e,g+Math.sin(u)*e*d);v=[h,g,e,e*d,0,u,Math.PI,false];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function f(){q.ellipse(h,g+a,e,e*d,0,0,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,0,true];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function x(){q.ellipse(h,g+a,e,e*d,0,Math.PI,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,Math.PI,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function m(){q.ellipse(h,g+a,e,e*d,0,u,0,false);q.lineTo(h+e,g);v=[h,g,e,e*d,0,0,u,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}if(j){if(!o||b){if(u>=0&&r<0){l()}else{if(u<=0&&r>0){f()}else{if(u<=0&&r<0){if(u>r){q.ellipse(h,g+a,e,e*d,0,0,Math.PI,false);q.lineTo(h-e,g);v=[h,g,e,e*d,0,Math.PI,0,true];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}else{if(u>r){l();f()}else{v=[h,g,e,e*d,0,u,r,false];if(c&&!o||n&&o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d+a);q.ellipse(h,g+a,e,e*d,0,r,u,true);q.closePath()}}}}}}else{if(o||b){if(u>=0&&r<0){x()}else{if(u<=0&&r>0){m()}else{if(u<=0&&r<0){if(u>r){x();m()}else{q.ellipse(h,g+a,e,e*d,0,u,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,u,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}else{if(u>r){q.ellipse(h,g+a,e,e*d,0,-Math.PI,0,false);q.lineTo(h+e,g);v=[h,g,e,e*d,0,0,-Math.PI,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}}}}}},innerFrontRenderer:function(a){this.rimRenderer(a,this.attr.startRho,true,true)},innerBackRenderer:function(a){this.rimRenderer(a,this.attr.startRho,true,false)},outerFrontRenderer:function(a){this.rimRenderer(a,this.attr.endRho,false,true)},outerBackRenderer:function(a){this.rimRenderer(a,this.attr.endRho,false,false)}});Ext.define("Ext.draw.PathUtil",function(){var a=Math.abs,c=Math.pow,e=Math.cos,b=Math.acos,d=Math.sqrt,f=Math.PI;return{singleton:true,requires:["Ext.draw.overrides.Path","Ext.draw.overrides.sprite.Path","Ext.draw.overrides.sprite.Instancing","Ext.draw.overrides.Surface"],cubicRoots:function(m){var z=m[0],x=m[1],w=m[2],v=m[3];if(z===0){return this.quadraticRoots(x,w,v)}var s=x/z,r=w/z,q=v/z,k=(3*r-c(s,2))/9,j=(9*s*r-27*q-2*c(s,3))/54,p=c(k,3)+c(j,2),n=[],h,g,o,l,u,y=Ext.Number.sign;if(p>=0){h=y(j+d(p))*c(a(j+d(p)),1/3);g=y(j-d(p))*c(a(j-d(p)),1/3);n[0]=-s/3+(h+g);n[1]=-s/3-(h+g)/2;n[2]=n[1];o=a(d(3)*(h-g)/2);if(o!==0){n[1]=-1;n[2]=-1}}else{l=b(j/d(-c(k,3)));n[0]=2*d(-k)*e(l/3)-s/3;n[1]=2*d(-k)*e((l+2*f)/3)-s/3;n[2]=2*d(-k)*e((l+4*f)/3)-s/3}for(u=0;u<3;u++){if(n[u]<0||n[u]>1){n[u]=-1}}return n},quadraticRoots:function(h,g,n){var m,l,k,j;if(h===0){return this.linearRoot(g,n)}m=g*g-4*h*n;if(m===0){k=[-g/(2*h)]}else{if(m>0){l=d(m);k=[(-g-l)/(2*h),(-g+l)/(2*h)]}else{return[]}}for(j=0;j<k.length;j++){if(k[j]<0||k[j]>1){k[j]=-1}}return k},linearRoot:function(h,g){var i=-g/h;if(h===0||i<0||i>1){return[]}return[i]},bezierCoeffs:function(h,g,k,j){var i=[];i[0]=-h+3*g-3*k+j;i[1]=3*h-6*g+3*k;i[2]=-3*h+3*g;i[3]=h;return i},cubicLineIntersections:function(I,G,F,E,l,k,j,h,M,p,K,n){var u=[],N=[],D=p-n,z=K-M,y=M*(n-p)-p*(K-M),L=this.bezierCoeffs(I,G,F,E),J=this.bezierCoeffs(l,k,j,h),H,x,w,v,g,q,o,m;u[0]=D*L[0]+z*J[0];u[1]=D*L[1]+z*J[1];u[2]=D*L[2]+z*J[2];u[3]=D*L[3]+z*J[3]+y;x=this.cubicRoots(u);for(H=0;H<x.length;H++){v=x[H];if(v<0||v>1){continue}g=v*v;q=g*v;o=L[0]*q+L[1]*g+L[2]*v+L[3];m=J[0]*q+J[1]*g+J[2]*v+J[3];if((K-M)!==0){w=(o-M)/(K-M)}else{w=(m-p)/(n-p)}if(!(w<0||w>1)){N.push([o,m])}}return N},splitCubic:function(g,q,p,o,m){var j=m*m,n=m*j,i=m-1,h=i*i,k=i*h,l=n*o-3*j*i*p+3*m*h*q-k*g;return[[g,m*q-i*g,j*p-2*m*i*q+h*g,l],[l,j*o-2*m*i*p+h*q,m*o-i*p,o]]},cubicDimension:function(p,o,l,k){var j=3*(-p+3*(o-l)+k),i=6*(p-2*o+l),h=-3*(p-o),q,n,g=Math.min(p,k),m=Math.max(p,k),r;if(j===0){if(i===0){return[g,m]}else{q=-h/i;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}}}else{r=i*i-4*j*h;if(r>=0){r=d(r);q=(r-i)/2/j;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}if(r>0){q-=r/j;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}}}}return[g,m]},interpolateCubic:function(h,g,l,k,i){if(i===0){return h}if(i===1){return k}var j=(1-i)/i;return i*i*i*(k+j*(3*l+j*(3*g+j*h)))},cubicsIntersections:function(r,q,p,o,A,z,y,v,g,F,E,D,m,l,k,i){var C=this,x=C.cubicDimension(r,q,p,o),B=C.cubicDimension(A,z,y,v),n=C.cubicDimension(g,F,E,D),s=C.cubicDimension(m,l,k,i),j,h,u,t,w=[];if(x[0]>n[1]||x[1]<n[0]||B[0]>s[1]||B[1]<s[0]){return[]}if(a(A-z)<1&&a(y-v)<1&&a(r-o)<1&&a(q-p)<1&&a(m-l)<1&&a(k-i)<1&&a(g-D)<1&&a(F-E)<1){return[[(r+o)*0.5,(A+z)*0.5]]}j=C.splitCubic(r,q,p,o,0.5);h=C.splitCubic(A,z,y,v,0.5);u=C.splitCubic(g,F,E,D,0.5);t=C.splitCubic(m,l,k,i,0.5);w.push.apply(w,C.cubicsIntersections.apply(C,j[0].concat(h[0],u[0],t[0])));w.push.apply(w,C.cubicsIntersections.apply(C,j[0].concat(h[0],u[1],t[1])));w.push.apply(w,C.cubicsIntersections.apply(C,j[1].concat(h[1],u[0],t[0])));w.push.apply(w,C.cubicsIntersections.apply(C,j[1].concat(h[1],u[1],t[1])));return w},linesIntersection:function(k,p,j,o,h,n,q,m){var l=(j-k)*(m-n)-(o-p)*(q-h),i,g;if(l===0){return null}i=((q-h)*(p-n)-(k-h)*(m-n))/l;g=((j-k)*(p-n)-(o-p)*(k-h))/l;if(i>=0&&i<=1&&g>=0&&g<=1){return[k+i*(j-k),p+i*(o-p)]}return null},pointOnLine:function(j,m,h,l,g,n){var k,i;if(a(h-j)<a(l-m)){i=j;j=m;m=i;i=h;h=l;l=i;i=g;g=n;n=i}k=(g-j)/(h-j);if(k<0||k>1){return false}return a(m+k*(l-m)-n)<4},pointOnCubic:function(w,u,s,r,l,k,h,g,p,o){var C=this,B=C.bezierCoeffs(w,u,s,r),A=C.bezierCoeffs(l,k,h,g),z,v,n,m,q;B[3]-=p;A[3]-=o;n=C.cubicRoots(B);m=C.cubicRoots(A);for(z=0;z<n.length;z++){q=n[z];for(v=0;v<m.length;v++){if(q>=0&&q<=1&&a(q-m[v])<0.05){return true}}}return false}}});Ext.define("Ext.chart.series.Pie3D",{extend:"Ext.chart.series.Polar",requires:["Ext.chart.series.sprite.Pie3DPart","Ext.draw.PathUtil"],type:"pie3d",seriesType:"pie3d",alias:"series.pie3d",isPie3D:true,config:{rect:[0,0,0,0],thickness:35,distortion:0.5,donut:false,hidden:[],highlightCfg:{margin:20},shadow:false},rotationOffset:-Math.PI/2,setField:function(a){return this.setXField(a)},getField:function(){return this.getXField()},updateRotation:function(a){this.setStyle({baseRotation:a+this.rotationOffset});this.doUpdateStyles()},updateDistortion:function(){this.setRadius()},updateThickness:function(){this.setRadius()},updateColors:function(a){this.setSubStyle({baseColor:a})},applyShadow:function(a){if(a===true){a={shadowColor:"rgba(0,0,0,0.8)",shadowBlur:30}}else{if(!Ext.isObject(a)){a={shadowColor:Ext.draw.Color.RGBA_NONE}}}return a},updateShadow:function(g){var e=this,f=e.getSprites(),d=e.spritesPerSlice,c=f&&f.length,b,a;for(b=1;b<c;b+=d){a=f[b];if(a.attr.part="bottom"){a.setAttributes(g)}}},getStyleByIndex:function(b){var d=this.callParent([b]),c=this.getStyle(),a=d.fillStyle||d.fill||d.color,e=c.strokeStyle||c.stroke;if(a){d.baseColor=a;delete d.fillStyle;delete d.fill;delete d.color}if(e){d.strokeStyle=e}return d},doUpdateStyles:function(){var g=this,h=g.getSprites(),f=g.spritesPerSlice,e=h&&h.length,c=0,b=0,a,d;for(;c<e;c+=f,b++){d=g.getStyleByIndex(b);for(a=0;a<f;a++){h[c+a].setAttributes(d)}}},coordinateX:function(){var w=this,m=w.getChart(),u=m&&m.getAnimation(),f=w.getStore(),t=f.getData().items,d=t.length,b=w.getXField(),p=w.getRotation(),s=w.getHidden(),n,c=0,h,e=[],k=w.getSprites(),a=k.length,l=w.spritesPerSlice,g=0,o=Math.PI*2,v=1e-10,r,q;for(r=0;r<d;r++){n=Math.abs(Number(t[r].get(b)))||0;if(!s[r]){c+=n}e[r]=c;if(r>=s.length){s[r]=false}}s.length=d;if(c===0){return}h=2*Math.PI/c;for(r=0;r<d;r++){e[r]*=h}for(r=0;r<a;r++){k[r].setAnimation(u)}for(r=0;r<d;r++){for(q=0;q<l;q++){k[r*l+q].setAttributes({startAngle:g,endAngle:e[r]-v,globalAlpha:1,baseRotation:p})}g=e[r]}for(r*=l;r<a;r++){k[r].setAnimation(u);k[r].setAttributes({startAngle:o,endAngle:o,globalAlpha:0,baseRotation:p})}},updateLabelData:function(){var l=this,m=l.getStore(),k=m.getData().items,h=l.getSprites(),b=l.getLabel().getTemplate().getField(),f=l.getHidden(),a=l.spritesPerSlice,d,c,g,e,n;if(h.length&&b){e=[];for(d=0,g=k.length;d<g;d++){e.push(k[d].get(b))}for(d=0,c=0,g=h.length;d<g;d+=a,c++){n=h[d];n.setAttributes({label:e[c]});n.putMarker("labels",{hidden:f[c]},n.attr.attributeId)}}},applyRadius:function(){var f=this,d=f.getChart(),h=d.getInnerPadding(),e=d.getMainRect()||[0,0,1,1],c=e[2]-h*2,a=e[3]-h*2-f.getThickness(),g=c/2,b=g*f.getDistortion();if(b>a/2){return a/(f.getDistortion()*2)}else{return g}},getSprites:function(){var y=this,e=y.getStore();if(!e){return[]}var n=y.getChart(),p=y.getSurface(),t=e.getData().items,l=y.spritesPerSlice,a=t.length,v=y.getAnimation()||n&&n.getAnimation(),x=y.getCenter(),w=y.getOffsetX(),u=y.getOffsetY(),b=y.getRadius(),q=y.getRotation(),d=y.getHighlight(),c={centerX:x[0]+w,centerY:x[1]+u-y.getThickness()/2,endRho:b,startRho:b*y.getDonut()/100,thickness:y.getThickness(),distortion:y.getDistortion()},k=y.sprites,h=y.getLabel(),f=h.getTemplate(),m,g,o,s,r;for(s=0;s<a;s++){g=Ext.apply({},this.getStyleByIndex(s),c);if(!k[s*l]){for(r=0;r<y.partNames.length;r++){o=p.add({type:"pie3dPart",part:y.partNames[r]});if(r===0&&f.getField()){o.bindMarker("labels",h)}o.fx.setDurationOn("baseRotation",q);if(d){o.config.highlight=d;o.addModifier("highlight",true)}o.setAttributes(g);k.push(o)}}else{m=k.slice(s*l,(s+1)*l);for(r=0;r<m.length;r++){o=m[r];if(v){o.setAnimation(v)}o.setAttributes(g)}}}return k},betweenAngle:function(d,f,c){var e=Math.PI*2,g=this.rotationOffset;f+=g;c+=g;d-=f;c-=f;d%=e;c%=e;d+=e;c+=e;d%=e;c%=e;return d<c||c===0},getItemForPoint:function(k,j){var h=this,g=h.getSprites();if(g){var l=h.getStore(),b=l.getData().items,a=h.spritesPerSlice,e=h.getHidden(),c,f,m,d;for(c=0,f=b.length;c<f;c++){if(!e[c]){d=c*a;m=g[d];if(m.hitTest([k,j])){return{series:h,sprite:g.slice(d,d+a),index:c,record:b[c],category:"sprites",field:h.getXField()}}}}return null}},provideLegendInfo:function(f){var h=this,k=h.getStore();if(k){var g=k.getData().items,b=h.getLabel().getTemplate().getField(),j=h.getField(),e=h.getHidden(),d,a,c;for(d=0;d<g.length;d++){a=h.getStyleByIndex(d);c=a.baseColor;f.push({name:b?String(g[d].get(b)):j+" "+d,mark:c||"black",disabled:e[d],series:h.getId(),index:d})}}}},function(){var b=this.prototype,a=Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;b.partNames=a.replace(/^enums\(|\)/g,"").split(",");b.spritesPerSlice=b.partNames.length});Ext.define("Ext.chart.series.sprite.Polar",{extend:"Ext.chart.series.sprite.Series",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",baseRotation:"number",labels:"default",labelOverflowPadding:"number"},defaults:{centerX:0,centerY:0,startAngle:0,endAngle:Math.PI,startRho:0,endRho:150,baseRotation:0,labels:null,labelOverflowPadding:10},triggers:{centerX:"bbox",centerY:"bbox",startAngle:"bbox",endAngle:"bbox",startRho:"bbox",endRho:"bbox",baseRotation:"bbox"}}},updatePlainBBox:function(b){var a=this.attr;b.x=a.centerX-a.endRho;b.y=a.centerY+a.endRho;b.width=a.endRho*2;b.height=a.endRho*2}});Ext.define("Ext.chart.series.sprite.Radar",{alias:"sprite.radar",extend:"Ext.chart.series.sprite.Polar",getDataPointXY:function(d){var u=this,n=u.attr,f=n.centerX,e=n.centerY,o=n.matrix,t=n.dataMinX,s=n.dataMaxX,k=n.dataX,j=n.dataY,l=n.endRho,p=n.startRho,g=n.baseRotation,i,h,m,c,b,a,q;if(n.rangeY){q=n.rangeY[1]}else{q=n.dataMaxY}c=(k[d]-t)/(s-t+1)*2*Math.PI+g;m=j[d]/q*(l-p)+p;b=f+Math.cos(c)*m;a=e+Math.sin(c)*m;i=o.x(b,a);h=o.y(b,a);return[i,h]},render:function(a,l){var h=this,f=h.attr,g=f.dataX,b=g.length,e=h.surfaceMatrix,d={},c,k,j,m;l.beginPath();for(c=0;c<b;c++){m=h.getDataPointXY(c);k=m[0];j=m[1];if(c===0){l.moveTo(k,j)}l.lineTo(k,j);d.translationX=e.x(k,j);d.translationY=e.y(k,j);h.putMarker("markers",d,c,true)}l.closePath();l.fillStroke(f)}});Ext.define("Ext.chart.series.Radar",{extend:"Ext.chart.series.Polar",type:"radar",seriesType:"radar",alias:"series.radar",requires:["Ext.chart.series.sprite.Radar"],themeColorCount:function(){return 1},isStoreDependantColorCount:false,themeMarkerCount:function(){return 1},updateAngularAxis:function(a){a.processData(this)},updateRadialAxis:function(a){a.processData(this)},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},updateCenter:function(a){this.setStyle({translationX:a[0]+this.getOffsetX(),translationY:a[1]+this.getOffsetY()});this.doUpdateStyles()},updateRadius:function(a){this.setStyle({endRho:a});this.doUpdateStyles()},updateRotation:function(a){this.setStyle({rotationRads:a});this.doUpdateStyles()},updateTotalAngle:function(a){this.processData()},getItemForPoint:function(k,j){var h=this,m=h.sprites&&h.sprites[0],f=m.attr,g=f.dataX,a=g.length,l=h.getStore(),e=h.getMarker(),b,o,p,d,n,c;if(h.getHidden()){return null}if(m&&e){c=m.getMarker("markers");for(d=0;d<a;d++){n=c.getBBoxFor(d);b=(n.width+n.height)*0.25;p=m.getDataPointXY(d);if(Math.abs(p[0]-k)<b&&Math.abs(p[1]-j)<b){o={series:h,sprite:m,index:d,category:"markers",record:l.getData().items[d],field:h.getYField()};return o}}}return h.callParent(arguments)},getDefaultSpriteConfig:function(){var a=this.callParent(),b={customDurations:{translationX:0,translationY:0,rotationRads:0,dataMinX:0,dataMaxX:0}};if(a.fx){Ext.apply(a.fx,b)}else{a.fx=b}return a},getSprites:function(){var d=this,c=d.getChart(),e=d.getAnimation()||c&&c.getAnimation(),b=d.sprites[0],a;if(!c){return[]}if(!b){b=d.createSprite()}if(e){a=b.getMarker("markers");if(a){a.getTemplate().setAnimation(e)}b.setAnimation(e)}return d.sprites},provideLegendInfo:function(d){var b=this,a=b.getSubStyleWithTheme(),c=a.fillStyle;if(Ext.isArray(c)){c=c[0]}d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})}});Ext.define("Ext.chart.series.sprite.Scatter",{alias:"sprite.scatterSeries",extend:"Ext.chart.series.sprite.Cartesian",renderClipped:function(r,s,w,u){if(this.cleanRedraw){return}var C=this,q=C.attr,l=q.dataX,h=q.dataY,z=q.labels,j=C.getSeries(),b=z&&C.getMarker("labels"),t=C.attr.matrix,c=t.getXX(),p=t.getYY(),m=t.getDX(),k=t.getDY(),n={},D,B,d=r.getInherited().rtl&&!q.flipXY?-1:1,a,A,o,e,g,f,v;if(q.flipXY){a=u[1]-c*d;A=u[1]+u[3]+c*d;o=u[0]-p;e=u[0]+u[2]+p}else{a=u[0]-c*d;A=u[0]+u[2]+c*d;o=u[1]-p;e=u[1]+u[3]+p}for(v=0;v<l.length;v++){g=l[v];f=h[v];g=g*c+m;f=f*p+k;if(a<=g&&g<=A&&o<=f&&f<=e){if(q.renderer){n={type:"items",translationX:g,translationY:f};B=[C,n,{store:C.getStore()},v];D=Ext.callback(q.renderer,null,B,0,j);n=Ext.apply(n,D)}else{n.translationX=g;n.translationY=f}C.putMarker("items",n,v,!q.renderer);if(b&&z[v]){C.drawLabel(z[v],g,f,v,u)}}}},drawLabel:function(j,h,g,p,a){var r=this,m=r.attr,d=r.getMarker("labels"),c=d.getTemplate(),l=r.labelCfg||(r.labelCfg={}),b=r.surfaceMatrix,f,e,i=m.labelOverflowPadding,o=m.flipXY,k,n,s,q;l.text=j;n=r.getMarkerBBox("labels",p,true);if(!n){r.putMarker("labels",l,p);n=r.getMarkerBBox("labels",p,true)}if(o){l.rotationRads=Math.PI*0.5}else{l.rotationRads=0}k=n.height/2;f=h;switch(c.attr.display){case"under":e=g-k-i;break;case"rotate":f+=i;e=g-i;l.rotationRads=-Math.PI/4;break;default:e=g+k+i}l.x=b.x(f,e);l.y=b.y(f,e);if(c.attr.renderer){q=[j,d,l,{store:r.getStore()},p];s=Ext.callback(c.attr.renderer,null,q,0,r.getSeries());if(typeof s==="string"){l.text=s}else{Ext.apply(l,s)}}r.putMarker("labels",l,p)}});Ext.define("Ext.chart.series.Scatter",{extend:"Ext.chart.series.Cartesian",alias:"series.scatter",type:"scatter",seriesType:"scatterSeries",requires:["Ext.chart.series.sprite.Scatter"],config:{itemInstancing:{fx:{customDurations:{translationX:0,translationY:0}}}},themeMarkerCount:function(){return 1},applyMarker:function(b,a){this.getItemInstancing();this.setItemInstancing(b);return this.callParent(arguments)},provideLegendInfo:function(d){var b=this,a=b.getMarkerStyleByIndex(0),c=a.fillStyle;d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})}});Ext.define("Ext.chart.theme.Blue",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.blue","chart.theme.Blue"],config:{baseColor:"#4d7fe6"}});Ext.define("Ext.chart.theme.BlueGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.blue-gradients","chart.theme.Blue:gradients"],config:{baseColor:"#4d7fe6",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category1",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category1","chart.theme.Category1"],config:{colors:["#f0a50a","#c20024","#2044ba","#810065","#7eae29"]}});Ext.define("Ext.chart.theme.Category1Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category1-gradients","chart.theme.Category1:gradients"],config:{colors:["#f0a50a","#c20024","#2044ba","#810065","#7eae29"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category2",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category2","chart.theme.Category2"],config:{colors:["#6d9824","#87146e","#2a9196","#d39006","#1e40ac"]}});Ext.define("Ext.chart.theme.Category2Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category2-gradients","chart.theme.Category2:gradients"],config:{colors:["#6d9824","#87146e","#2a9196","#d39006","#1e40ac"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category3",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category3","chart.theme.Category3"],config:{colors:["#fbbc29","#ce2e4e","#7e0062","#158b90","#57880e"]}});Ext.define("Ext.chart.theme.Category3Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category3-gradients","chart.theme.Category3:gradients"],config:{colors:["#fbbc29","#ce2e4e","#7e0062","#158b90","#57880e"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category4",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category4","chart.theme.Category4"],config:{colors:["#ef5773","#fcbd2a","#4f770d","#1d3eaa","#9b001f"]}});Ext.define("Ext.chart.theme.Category4Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category4-gradients","chart.theme.Category4:gradients"],config:{colors:["#ef5773","#fcbd2a","#4f770d","#1d3eaa","#9b001f"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category5",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category5","chart.theme.Category5"],config:{colors:["#7eae29","#fdbe2a","#910019","#27b4bc","#d74dbc"]}});Ext.define("Ext.chart.theme.Category5Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category5-gradients","chart.theme.Category5:gradients"],config:{colors:["#7eae29","#fdbe2a","#910019","#27b4bc","#d74dbc"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category6",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category6","chart.theme.Category6"],config:{colors:["#44dce1","#0b2592","#996e05","#7fb325","#b821a1"]}});Ext.define("Ext.chart.theme.Category6Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category6-gradients","chart.theme.Category6:gradients"],config:{colors:["#44dce1","#0b2592","#996e05","#7fb325","#b821a1"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.DefaultGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.default-gradients","chart.theme.Base:gradients"],config:{gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Green",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.green","chart.theme.Green"],config:{baseColor:"#b1da5a"}});Ext.define("Ext.chart.theme.GreenGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.green-gradients","chart.theme.Green:gradients"],config:{baseColor:"#b1da5a",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Midnight",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.midnight","chart.theme.Midnight"],config:{colors:["#A837FF","#4AC0F2","#FF4D35","#FF8809","#61C102","#FF37EA"],chart:{defaults:{background:"rgb(52, 52, 53)"}},axis:{defaults:{style:{strokeStyle:"rgb(224, 224, 227)"},label:{fillStyle:"rgb(224, 224, 227)"},title:{fillStyle:"rgb(224, 224, 227)"},grid:{strokeStyle:"rgb(112, 112, 115)"}}},series:{defaults:{label:{fillStyle:"rgb(224, 224, 227)"}}},sprites:{text:{fillStyle:"rgb(224, 224, 227)"}}}});Ext.define("Ext.chart.theme.Muted",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.muted","chart.theme.Muted"],config:{colors:["#8ca640","#974144","#4091ba","#8e658e","#3b8d8b","#b86465","#d2af69","#6e8852","#3dcc7e","#a6bed1","#cbaa4b","#998baa"]}});Ext.define("Ext.chart.theme.Purple",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.purple","chart.theme.Purple"],config:{baseColor:"#da5abd"}});Ext.define("Ext.chart.theme.PurpleGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.purple-gradients","chart.theme.Purple:gradients"],config:{baseColor:"#da5abd",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Red",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.red","chart.theme.Red"],config:{baseColor:"#e84b67"}});Ext.define("Ext.chart.theme.RedGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.red-gradients","chart.theme.Red:gradients"],config:{baseColor:"#e84b67",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Sky",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.sky","chart.theme.Sky"],config:{baseColor:"#4ce0e7"}});Ext.define("Ext.chart.theme.SkyGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.sky-gradients","chart.theme.Sky:gradients"],config:{baseColor:"#4ce0e7",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Yellow",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.yellow","chart.theme.Yellow"],config:{baseColor:"#fec935"}});Ext.define("Ext.chart.theme.YellowGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.yellow-gradients","chart.theme.Yellow:gradients"],config:{baseColor:"#fec935",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.draw.Point",{requires:["Ext.draw.Draw","Ext.draw.Matrix"],isPoint:true,x:0,y:0,length:0,angle:0,angleUnits:"degrees",statics:{fly:(function(){var a=null;return function(b,c){if(!a){a=new Ext.draw.Point()}a.constructor(b,c);return a}})()},constructor:function(a,c){var b=this;if(typeof a==="number"){b.x=a;if(typeof c==="number"){b.y=c}else{b.y=a}}else{if(Ext.isArray(a)){b.x=a[0];b.y=a[1]}else{if(a){b.x=a.x;b.y=a.y}}}b.calculatePolar()},calculateCartesian:function(){var b=this,a=b.length,c=b.angle;if(b.angleUnits==="degrees"){c=Ext.draw.Draw.rad(c)}b.x=Math.cos(c)*a;b.y=Math.sin(c)*a},calculatePolar:function(){var b=this,a=b.x,c=b.y;b.length=Math.sqrt(a*a+c*c);b.angle=Math.atan2(c,a);if(b.angleUnits==="degrees"){b.angle=Ext.draw.Draw.degrees(b.angle)}},setX:function(a){this.x=a;this.calculatePolar()},setY:function(a){this.y=a;this.calculatePolar()},set:function(a,b){this.constructor(a,b)},setAngle:function(a){this.angle=a;this.calculateCartesian()},setLength:function(a){this.length=a;this.calculateCartesian()},setPolar:function(b,a){this.angle=b;this.length=a;this.calculateCartesian()},clone:function(){return new Ext.draw.Point(this.x,this.y)},add:function(a,c){var b=Ext.draw.Point.fly(a,c);return new Ext.draw.Point(this.x+b.x,this.y+b.y)},sub:function(a,c){var b=Ext.draw.Point.fly(a,c);return new Ext.draw.Point(this.x-b.x,this.y-b.y)},mul:function(a){return new Ext.draw.Point(this.x*a,this.y*a)},div:function(a){return new Ext.draw.Point(this.x/a,this.y/a)},dot:function(a,c){var b=Ext.draw.Point.fly(a,c);return this.x*b.x+this.y*b.y},equals:function(a,c){var b=Ext.draw.Point.fly(a,c);return this.x===b.x&&this.y===b.y},rotate:function(f,c){var d,e,b,g,a;if(this.angleUnits==="degrees"){f=Ext.draw.Draw.rad(f);d=Math.sin(f);e=Math.cos(f)}if(c){b=c.x;g=c.y}else{b=0;g=0}a=Ext.draw.Matrix.fly([e,d,-d,e,b-e*b+g*d,g-e*g+b*-d]).transformPoint(this);return new Ext.draw.Point(a)},transform:function(a){if(a&&a.isMatrix){return new Ext.draw.Point(a.transformPoint(this))}else{if(arguments.length===6){return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))}else{Ext.raise("Invalid parameters.")}}},round:function(){return new Ext.draw.Point(Math.round(this.x),Math.round(this.y))},ceil:function(){return new Ext.draw.Point(Math.ceil(this.x),Math.ceil(this.y))},floor:function(){return new Ext.draw.Point(Math.floor(this.x),Math.floor(this.y))},abs:function(a,b){return new Ext.draw.Point(Math.abs(this.x),Math.abs(this.y))},normalize:function(c){var b=this.x,f=this.y,a,e,d;c=c||1;if(b===0){a=0;e=c*Ext.Number.sign(f)}else{d=f/b;a=c/Math.sqrt(1+d*d);e=a*d}return new Ext.draw.Point(a,e)},getDistanceToLine:function(c,b){if(arguments.length===4){c=new Ext.draw.Point(arguments[0],arguments[1]);b=new Ext.draw.Point(arguments[2],arguments[3])}var d=b.sub(c).normalize(),a=c.sub(this);return a.sub(d.mul(a.dot(d)))},isZero:function(){return this.x===0&&this.y===0},isNumber:function(){return Ext.isNumber(this.x+this.y)}});Ext.define("Ext.draw.plugin.SpriteEvents",{extend:"Ext.plugin.Abstract",alias:"plugin.spriteevents",requires:["Ext.draw.PathUtil"],mouseMoveEvents:{mousemove:true,mouseover:true,mouseout:true},spriteMouseMoveEvents:{spritemousemove:true,spritemouseover:true,spritemouseout:true},init:function(a){var b="handleEvent";this.drawContainer=a;a.addElementListener({click:b,dblclick:b,mousedown:b,mousemove:b,mouseup:b,mouseover:b,mouseout:b,priority:1001,scope:this})},hasSpriteMouseMoveListeners:function(){var b=this.drawContainer.hasListeners,a;for(a in this.spriteMouseMoveEvents){if(a in b){return true}}return false},hitTestEvent:function(f){var b=this.drawContainer.getItems(),a,d,c;for(c=b.length-1;c>=0;c--){a=b.get(c);d=a.hitTestEvent(f);if(d){return d}}return null},handleEvent:function(f){var d=this,b=d.drawContainer,g=f.type in d.mouseMoveEvents,a=d.lastSprite,c;if(g&&!d.hasSpriteMouseMoveListeners()){return}c=d.hitTestEvent(f);if(g&&!Ext.Object.equals(c,a)){if(a){b.fireEvent("spritemouseout",a,f)}if(c){b.fireEvent("spritemouseover",c,f)}}if(c){b.fireEvent("sprite"+f.type,c,f)}d.lastSprite=c}});Ext.define("Ext.chart.TipSurface",{extend:"Ext.draw.Container",spriteArray:false,renderFirst:true,constructor:function(a){this.callParent([a]);if(a.sprites){this.spriteArray=[].concat(a.sprites);delete a.sprites}},onRender:function(){var c=this,b=0,a=0,d,e;this.callParent(arguments);e=c.spriteArray;if(c.renderFirst&&e){c.renderFirst=false;for(a=e.length;b<a;b++){d=c.surface.add(e[b]);d.setAttributes({hidden:false},true)}}}});Ext.define("Ext.chart.interactions.ItemInfo",{extend:"Ext.chart.interactions.Abstract",type:"iteminfo",alias:"interaction.iteminfo",config:{extjsGestures:{start:{event:"click",handler:"onInfoGesture"},move:{event:"mousemove",handler:"onInfoGesture"},end:{event:"mouseleave",handler:"onInfoGesture"}}},item:null,onInfoGesture:function(f,a){var c=this,b=c.getItemForEvent(f),d=b&&b.series.tooltip;if(d){d.onMouseMove.call(d,f)}if(b!==c.item){if(b){b.series.showTip(b)}else{c.item.series.hideTip(c.item)}c.item=b}return false}});
\ No newline at end of file
diff --git a/serverside/jsmod/6.0-4/proxmoxlib.js b/serverside/jsmod/6.0-4/proxmoxlib.js
deleted file mode 100644
index cb8b6d158dc5b54c0891b2e552fca9ffce3a7285..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/proxmoxlib.js
+++ /dev/null
@@ -1,7357 +0,0 @@
-// 2.0-5
-Ext.ns('Proxmox');
-Ext.ns('Proxmox.Setup');
-
-if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
-    throw "Proxmox library not initialized";
-}
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	dir: function() {},
-	log: function() {}
-    };
-}
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (Proxmox.CSRFPreventionToken) {
-	if (!options.headers) {
-	    options.headers = {};
-	}
-	options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-    }
-});
-
-Ext.define('Proxmox.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    enabledText: gettext('Enabled'),
-    disabledText: gettext('Disabled'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    stateText: gettext('State'),
-    groupText: gettext('Group'),
-
-    language_map: {
-	zh_CN: 'Chinese (Simplified)',
-	zh_TW: 'Chinese (Traditional)',
-	ca: 'Catalan',
-	da: 'Danish',
-	en: 'English',
-	eu: 'Euskera (Basque)',
-	fr: 'French',
-	de: 'German',
-	it: 'Italian',
-	es: 'Spanish',
-	ja: 'Japanese',
-	nb: 'Norwegian (Bokmal)',
-	nn: 'Norwegian (Nynorsk)',
-	fa: 'Persian (Farsi)',
-	pl: 'Polish',
-	pt_BR: 'Portuguese (Brazil)',
-	ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	tr: 'Turkish'
-    },
-
-    render_language: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (English)';
-	}
-	var text = Proxmox.Utils.language_map[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    language_array: function() {
-	var data = [['__default__', Proxmox.Utils.render_language('')]];
-	Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
-	    data.push([key, Proxmox.Utils.render_language(value)]);
-	});
-
-	return data;
-    },
-
-    bond_mode_gettext_map: {
-	'802.3ad': 'LACP (802.3ad)',
-	'lacp-balance-slb': 'LACP (balance-slb)',
-	'lacp-balance-tcp': 'LACP (balance-tcp)',
-    },
-
-    render_bond_mode: value => Proxmox.Utils.bond_mode_gettext_map[value] || value || '',
-
-    bond_mode_array: function(modes) {
-	return modes.map(mode => [mode, Proxmox.Utils.render_bond_mode(mode)]);
-    },
-
-    getNoSubKeyHtml: function(url) {
-	// url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
-	return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'https://www.proxmox.com');
-    },
-
-    format_boolean_with_default: function(value) {
-	if (Ext.isDefined(value) && value !== '__default__') {
-	    return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-	}
-	return Proxmox.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-	return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-	return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_enabled_toggle: function(value) {
-	return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
-    },
-
-    format_expire: function(date) {
-	if (!date) {
-	    return Proxmox.Utils.neverText;
-	}
-	return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_duration_long: function(ut) {
-
-	var days = Math.floor(ut / 86400);
-	ut -= days*86400;
-	var hours = Math.floor(ut / 3600);
-	ut -= hours*3600;
-	var mins = Math.floor(ut / 60);
-	ut -= mins*60;
-
-	var hours_str = '00' + hours.toString();
-	hours_str = hours_str.substr(hours_str.length - 2);
-	var mins_str = "00" + mins.toString();
-	mins_str = mins_str.substr(mins_str.length - 2);
-	var ut_str = "00" + ut.toString();
-	ut_str = ut_str.substr(ut_str.length - 2);
-
-	if (days) {
-	    var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
-	    return days.toString() + ' ' + ds + ' ' +
-		hours_str + ':' + mins_str + ':' + ut_str;
-	} else {
-	    return hours_str + ':' + mins_str + ':' + ut_str;
-	}
-    },
-
-    format_subscription_level: function(level) {
-	if (level === 'c') {
-	    return 'Community';
-	} else if (level === 'b') {
-	    return 'Basic';
-	} else if (level === 's') {
-	    return 'Standard';
-	} else if (level === 'p') {
-	    return 'Premium';
-	} else {
-	    return Proxmox.Utils.noneText;
-	}
-    },
-
-    compute_min_label_width: function(text, width) {
-
-	if (width === undefined) { width = 100; }
-
-	var tm = new Ext.util.TextMetrics();
-	var min = tm.getWidth(text + ':');
-
-	return min < width ? width : min;
-    },
-
-    setAuthData: function(data) {
-	Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
-	Proxmox.UserName = data.username;
-	Proxmox.LoggedOut = data.LoggedOut;
-	// creates a session cookie (expire = null)
-	// that way the cookie gets deleted after the browser window is closed
-	Ext.util.Cookies.set(Proxmox.Setup.auth_cookie_name, data.ticket, null, '/', null, true);
-    },
-
-    authOK: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
-    },
-
-    authClear: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-	var el = comp.el;
-	if (!el) {
-	    return;
-	}
-	if (!msg) {
-	    el.unmask();
-	} else {
-	    if (msg === true) {
-		el.mask(gettext("Loading..."));
-	    } else {
-		el.mask(msg);
-	    }
-	}
-    },
-
-    monStoreErrors: function(me, store, clearMaskBeforeLoad) {
-	if (clearMaskBeforeLoad) {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		Proxmox.Utils.setErrorMask(me, false);
-	    });
-	} else {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		if (!me.loadCount) {
-		    me.loadCount = 0; // make sure it is numeric
-		    Proxmox.Utils.setErrorMask(me, true);
-		}
-	    });
-	}
-
-	// only works with 'proxmox' proxy
-	me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-	    me.loadCount++;
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-
-	    var msg;
-	    /*jslint nomen: true */
-	    var operation = request._operation;
-	    var error = operation.getError();
-	    if (error.statusText) {
-		msg = error.statusText + ' (' + error.status + ')';
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    extractRequestError: function(result, verbose) {
-	var msg = gettext('Successful');
-
-	if (!result.success) {
-	    msg = gettext("Unknown error");
-	    if (result.message) {
-		msg = result.message;
-		if (result.status) {
-		    msg += ' (' + result.status + ')';
-		}
-	    }
-	    if (verbose && Ext.isObject(result.errors)) {
-		msg += "<br>";
-		Ext.Object.each(result.errors, function(prop, desc) {
-		    msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
-			Ext.htmlEncode(desc);
-		});
-	    }
-	}
-
-	return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-	var newopts = Ext.apply({
-	    waitMsg: gettext('Please wait...')
-	}, reqOpts);
-
-	if (!newopts.url.match(/^\/api2/)) {
-	    newopts.url = '/api2/extjs' + newopts.url;
-	}
-	delete newopts.callback;
-
-	var createWrapper = function(successFn, callbackFn, failureFn) {
-	    Ext.apply(newopts, {
-		success: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    var result = Ext.decode(response.responseText);
-		    response.result = result;
-		    if (!result.success) {
-			response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.callback(callbackFn, options.scope, [options, false, response]);
-			Ext.callback(failureFn, options.scope, [response, options]);
-			return;
-		    }
-		    Ext.callback(callbackFn, options.scope, [options, true, response]);
-		    Ext.callback(successFn, options.scope, [response, options]);
-		},
-		failure: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    response.result = {};
-		    try {
-			response.result = Ext.decode(response.responseText);
-		    } catch(e) {}
-		    var msg = gettext('Connection error') + ' - server offline?';
-		    if (response.aborted) {
-			msg = gettext('Connection error') + ' - aborted.';
-		    } else if (response.timedout) {
-			msg = gettext('Connection error') + ' - Timeout.';
-		    } else if (response.status && response.statusText) {
-			msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-		    }
-		    response.htmlStatus = msg;
-		    Ext.callback(callbackFn, options.scope, [options, false, response]);
-		    Ext.callback(failureFn, options.scope, [response, options]);
-		}
-	    });
-	};
-
-	createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-	var target = newopts.waitMsgTarget;
-	if (target) {
-	    if (Proxmox.Utils.toolkit === 'touch') {
-		target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-	    } else {
-		// Note: ExtJS bug - this does not work when component is not rendered
-		target.setLoading(newopts.waitMsg);
-	    }
-	}
-	Ext.Ajax.request(newopts);
-    },
-
-    checked_command: function(orig_cmd) {
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/localhost/subscription',
-	    method: 'GET',
-	    //waitMsgTarget: me,
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-
-		if (data.status !== 'Active') {
-		    Ext.Msg.show({
-			title: gettext('No valid subscription'),
-			icon: Ext.Msg.WARNING,
-			msg: Proxmox.Utils.getNoSubKeyHtml(data.url),
-			buttons: Ext.Msg.OK,
-			callback: function(btn) {
-			    if (btn !== 'ok') {
-				return;
-			    }
-			    orig_cmd();
-			}
-		    });
-		} else {
-		    orig_cmd();
-		}
-	    }
-	});
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-	    Ext.Object.each(data, function(name, val) {
-		if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-		    values[name] = val;
-                }
-            });
-	}
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-	if (create) {
-	    if (isAdd) {
-		return gettext('Add') + ': ' + subject;
-	    } else {
-		return gettext('Create') + ': ' + subject;
-	    }
-	} else {
-	    return gettext('Edit') + ': ' + subject;
-	}
-    },
-
-    network_iface_types: {
-	eth: gettext("Network Device"),
-	bridge: 'Linux Bridge',
-	bond: 'Linux Bond',
-	vlan: 'Linux VLAN',
-	OVSBridge: 'OVS Bridge',
-	OVSBond: 'OVS Bond',
-	OVSPort: 'OVS Port',
-	OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-	return Proxmox.Utils.network_iface_types[value] ||
-	    Proxmox.Utils.unknownText;
-    },
-
-    task_desc_table: {
-	acmenewcert: [ 'SRV', gettext('Order Certificate') ],
-	acmeregister: [ 'ACME Account', gettext('Register') ],
-	acmedeactivate: [ 'ACME Account', gettext('Deactivate') ],
-	acmeupdate: [ 'ACME Account', gettext('Update') ],
-	acmerefresh: [ 'ACME Account', gettext('Refresh') ],
-	acmerenew: [ 'SRV', gettext('Renew Certificate') ],
-	acmerevoke: [ 'SRV', gettext('Revoke Certificate') ],
-	'move_volume': [ 'CT', gettext('Move Volume') ],
-	clustercreate: [ '', gettext('Create Cluster') ],
-	clusterjoin: [ '', gettext('Join Cluster') ],
-	diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ],
-	vncproxy: [ 'VM/CT', gettext('Console') ],
-	spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-	vncshell: [ '', gettext('Shell') ],
-	spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-	qmsnapshot: [ 'VM', gettext('Snapshot') ],
-	qmrollback: [ 'VM', gettext('Rollback') ],
-	qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-	qmcreate: [ 'VM', gettext('Create') ],
-	qmrestore: [ 'VM', gettext('Restore') ],
-	qmdestroy: [ 'VM', gettext('Destroy') ],
-	qmigrate: [ 'VM', gettext('Migrate') ],
-	qmclone: [ 'VM', gettext('Clone') ],
-	qmmove: [ 'VM', gettext('Move disk') ],
-	qmtemplate: [ 'VM', gettext('Convert to template') ],
-	qmstart: [ 'VM', gettext('Start') ],
-	qmstop: [ 'VM', gettext('Stop') ],
-	qmreset: [ 'VM', gettext('Reset') ],
-	qmshutdown: [ 'VM', gettext('Shutdown') ],
-	qmsuspend: [ 'VM', gettext('Hibernate') ],
-	qmpause: [ 'VM', gettext('Pause') ],
-	qmresume: [ 'VM', gettext('Resume') ],
-	qmconfig: [ 'VM', gettext('Configure') ],
-	vzsnapshot: [ 'CT', gettext('Snapshot') ],
-	vzrollback: [ 'CT', gettext('Rollback') ],
-	vzdelsnapshot: [ 'CT', gettext('Delete Snapshot') ],
-	vzcreate: ['CT', gettext('Create') ],
-	vzrestore: ['CT', gettext('Restore') ],
-	vzdestroy: ['CT', gettext('Destroy') ],
-	vzmigrate: [ 'CT', gettext('Migrate') ],
-	vzclone: [ 'CT', gettext('Clone') ],
-	vztemplate: [ 'CT', gettext('Convert to template') ],
-	vzstart: ['CT', gettext('Start') ],
-	vzstop: ['CT', gettext('Stop') ],
-	vzmount: ['CT', gettext('Mount') ],
-	vzumount: ['CT', gettext('Unmount') ],
-	vzshutdown: ['CT', gettext('Shutdown') ],
-	vzsuspend: [ 'CT', gettext('Suspend') ],
-	vzresume: [ 'CT', gettext('Resume') ],
-	hamigrate: [ 'HA', gettext('Migrate') ],
-	hastart: [ 'HA', gettext('Start') ],
-	hastop: [ 'HA', gettext('Stop') ],
-	srvstart: ['SRV', gettext('Start') ],
-	srvstop: ['SRV', gettext('Stop') ],
-	srvrestart: ['SRV', gettext('Restart') ],
-	srvreload: ['SRV', gettext('Reload') ],
-	cephcreatemgr: ['Ceph Manager', gettext('Create') ],
-	cephdestroymgr: ['Ceph Manager', gettext('Destroy') ],
-	cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-	cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-	cephcreateosd: ['Ceph OSD', gettext('Create') ],
-	cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-	cephcreatepool: ['Ceph Pool', gettext('Create') ],
-	cephdestroypool: ['Ceph Pool', gettext('Destroy') ],
-	cephfscreate: ['CephFS', gettext('Create') ],
-	cephcreatemds: ['Ceph Metadata Server', gettext('Create') ],
-	cephdestroymds: ['Ceph Metadata Server', gettext('Destroy') ],
-	imgcopy: ['', gettext('Copy data') ],
-	imgdel: ['', gettext('Erase data') ],
-	unknownimgdel: ['', gettext('Destroy image from unknown guest') ],
-	download: ['', gettext('Download') ],
-	vzdump: ['VM/CT', gettext('Backup') ],
-	aptupdate: ['', gettext('Update package database') ],
-	startall: [ '', gettext('Start all VMs and Containers') ],
-	stopall: [ '', gettext('Stop all VMs and Containers') ],
-	migrateall: [ '', gettext('Migrate all VMs and Containers') ],
-	dircreate: [ gettext('Directory Storage'), gettext('Create') ],
-	lvmcreate: [ gettext('LVM Storage'), gettext('Create') ],
-	lvmthincreate: [ gettext('LVM-Thin Storage'), gettext('Create') ],
-	zfscreate: [ gettext('ZFS Storage'), gettext('Create') ]
-    },
-
-    format_task_description: function(type, id) {
-	var farray = Proxmox.Utils.task_desc_table[type];
-	var text;
-	if (!farray) {
-	    text = type;
-	    if (id) {
-		type += ' ' + id;
-	    }
-	    return text;
-	}
-	var prefix = farray[0];
-	text = farray[1];
-	if (prefix) {
-	    return prefix + ' ' + id + ' - ' + text;
-	}
-	return text;
-    },
-
-    format_size: function(size) {
-	/*jslint confusion: true */
-
-	var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
-	var num = 0;
-
-	while (size >= 1024 && ((num++)+1) < units.length) {
-	    size = size / 1024;
-	}
-
-	return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    render_uptime: function(value) {
-
-	var uptime = value;
-
-	if (uptime === undefined) {
-	    return '';
-	}
-
-	if (uptime <= 0) {
-	    return '-';
-	}
-
-	return Proxmox.Utils.format_duration_long(uptime);
-    },
-
-    parse_task_upid: function(upid) {
-	var task = {};
-
-	var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-	if (!res) {
-	    throw "unable to parse upid '" + upid + "'";
-	}
-	task.node = res[1];
-	task.pid = parseInt(res[2], 16);
-	task.pstart = parseInt(res[3], 16);
-	task.starttime = parseInt(res[4], 16);
-	task.type = res[5];
-	task.id = res[6];
-	task.user = res[7];
-
-	task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	return task;
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-	var servertime = new Date(value * 1000);
-	return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    get_help_info: function(section) {
-	var helpMap;
-	if (typeof proxmoxOnlineHelpInfo !== 'undefined') {
-	    helpMap = proxmoxOnlineHelpInfo;
-	} else if (typeof pveOnlineHelpInfo !== 'undefined') {
-	    // be backward compatible with older pve-doc-generators
-	    helpMap = pveOnlineHelpInfo;
-	} else {
-	    throw "no global OnlineHelpInfo map declared";
-	}
-
-	return helpMap[section];
-    },
-
-    get_help_link: function(section) {
-	var info = Proxmox.Utils.get_help_info(section);
-	if (!info) {
-	    return;
-	}
-
-	return window.location.origin + info.link;
-    },
-
-    openXtermJsViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    xtermjs: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    cmd: cmd,
-
-	});
-	var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
-	if (nw) {
-	    nw.focus();
-	}
-    }
-
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-
-	var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-	var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-	var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-	var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-	var IPV4_CIDR_MASK = "([0-9]{1,2})";
-	var IPV6_CIDR_MASK = "([0-9]{1,3})";
-
-
-	me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-	me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/" + IPV4_CIDR_MASK + "$");
-
-	var IPV6_REGEXP = "(?:" +
-	    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-	    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-	    ")";
-
-	me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-	me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/" + IPV6_CIDR_MASK + "$");
-	me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-	me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-	me.IP64_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + "\/" + IPV6_CIDR_MASK + ")|(?:" + IPV4_REGEXP + "\/" + IPV4_CIDR_MASK + ")$");
-
-	var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
-	me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
-
-	me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
-	me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
-	me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
-    }
-});
-// ExtJS related things
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-	return Proxmox.Utils.IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP4_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 32);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24' + "<br>" + gettext('Valid CIDR Range') + ': 8-32',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return Proxmox.Utils.IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP6_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 128);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64' + "<br>" + gettext('Valid CIDR Range') + ': 8-128',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-	return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-
-    IP64Address:  function(v) {
-        return Proxmox.Utils.IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    IP64CIDRAddress: function(v) {
-	var result = Proxmox.Utils.IP64_cidr_match.exec(v);
-	if (result === null) {
-	    return false;
-	}
-	if (result[1] !== undefined) {
-	    return result[1] >= 8 && result[1] <= 128;
-	} else if (result[2] !== undefined) {
-	    return result[2] >= 8 && result[2] <= 32;
-	} else {
-	    return false;
-	}
-    },
-    IP64CIDRAddressText: gettext('Example') + ': 192.168.1.1/24 2001:DB8::42/64',
-    IP64CIDRAddressMask: /[A-Fa-f0-9\.:\/]/,
-
-    MacAddress: function(v) {
-	return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    MacPrefix:  function(v) {
-	return (/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i).test(v);
-    },
-    MacPrefixMask: /[a-fA-F0-9:]/,
-    MacPrefixText: gettext('Example') + ': 02:8f - ' + gettext('only unicast addresses are allowed'),
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext("Allowed characters") + ": 'a-z', '0-9', '_'" + "<br />" +
-		       gettext("Minimum characters") + ": 2" + "<br />" +
-		       gettext("Maximum characters") + ": 21" + "<br />" +
-		       gettext("Must start with") + ": 'a-z'",
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'" + "<br />" +
-		   gettext("Minimum characters") + ": 2" + "<br />" +
-		   gettext("Must start with") + ": 'A-Z', 'a-z'<br />" +
-		   gettext("Must end with") + ": 'A-Z', 'a-z', '0-9'<br />",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'" + "<br />" +
-		  gettext("Minimum characters") + ": 2" + "<br />" +
-		  gettext("Must start with") + ": " + gettext("letter"),
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-	return Proxmox.Utils.DnsName_match.test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name'),
-
-    // workaround for https://www.sencha.com/forum/showthread.php?302150
-    proxmoxMail: function(v) {
-        return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
-    },
-    proxmoxMailText: gettext('Example') + ": user@example.com",
-
-    DnsOrIp: function(v) {
-	if (!Proxmox.Utils.DnsName_match.test(v) &&
-	    !Proxmox.Utils.IP64_match.test(v)) {
-	    return false;
-	}
-
-	return true;
-    },
-    DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
-
-    HostList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == "") {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
-		!Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
-		!Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    HostListText: gettext('Not a valid list of hosts'),
-
-    password: function(val, field) {
-        if (field.initialPassField) {
-            var pwd = field.up('form').down(
-		'[name=' + field.initialPassField + ']');
-            return (val == pwd.getValue());
-        }
-        return true;
-    },
-
-    passwordText: gettext('Passwords do not match')
-});
-
-// Firefox 52+ Touchscreen bug
-// see https://www.sencha.com/forum/showthread.php?336762-Examples-don-t-work-in-Firefox-52-touchscreen/page2
-// and https://bugzilla.proxmox.com/show_bug.cgi?id=1223
-Ext.define('EXTJS_23846.Element', {
-    override: 'Ext.dom.Element'
-}, function(Element) {
-    var supports = Ext.supports,
-        proto = Element.prototype,
-        eventMap = proto.eventMap,
-        additiveEvents = proto.additiveEvents;
-
-    if (Ext.os.is.Desktop && supports.TouchEvents && !supports.PointerEvents) {
-        eventMap.touchstart = 'mousedown';
-        eventMap.touchmove = 'mousemove';
-        eventMap.touchend = 'mouseup';
-        eventMap.touchcancel = 'mouseup';
-
-        additiveEvents.mousedown = 'mousedown';
-        additiveEvents.mousemove = 'mousemove';
-        additiveEvents.mouseup = 'mouseup';
-        additiveEvents.touchstart = 'touchstart';
-        additiveEvents.touchmove = 'touchmove';
-        additiveEvents.touchend = 'touchend';
-        additiveEvents.touchcancel = 'touchcancel';
-
-        additiveEvents.pointerdown = 'mousedown';
-        additiveEvents.pointermove = 'mousemove';
-        additiveEvents.pointerup = 'mouseup';
-        additiveEvents.pointercancel = 'mouseup';
-    }
-});
-
-Ext.define('EXTJS_23846.Gesture', {
-    override: 'Ext.event.publisher.Gesture'
-}, function(Gesture) {
-    var me = Gesture.instance;
-
-    if (Ext.supports.TouchEvents && !Ext.isWebKit && Ext.os.is.Desktop) {
-        me.handledDomEvents.push('mousedown', 'mousemove', 'mouseup');
-        me.registerEvents();
-    }
-});
-
-Ext.define('EXTJS_18900.Pie', {
-    override: 'Ext.chart.series.Pie',
-
-    // from 6.0.2
-    betweenAngle: function (x, a, b) {
-        var pp = Math.PI * 2,
-            offset = this.rotationOffset;
-
-        if (a === b) {
-            return false;
-        }
-
-        if (!this.getClockwise()) {
-            x *= -1;
-            a *= -1;
-            b *= -1;
-            a -= offset;
-            b -= offset;
-        } else {
-            a += offset;
-            b += offset;
-        }
-
-        x -= a;
-        b -= a;
-
-        // Normalize, so that both x and b are in the [0,360) interval.
-        x %= pp;
-        b %= pp;
-        x += pp;
-        b += pp;
-        x %= pp;
-        b %= pp;
-
-        // Because 360 * n angles will be normalized to 0,
-        // we need to treat b === 0 as a special case.
-        return x < b || b === 0;
-    },
-});
-
-// we always want the number in x.y format and never in, e.g., x,y
-Ext.define('PVE.form.field.Number', {
-    override: 'Ext.form.field.Number',
-    submitLocaleSeparator: false
-});
-
-// ExtJs 5-6 has an issue with caching
-// see https://www.sencha.com/forum/showthread.php?308989
-Ext.define('Proxmox.UnderlayPool', {
-    override: 'Ext.dom.UnderlayPool',
-
-    checkOut: function () {
-        var cache = this.cache,
-            len = cache.length,
-            el;
-
-        // do cleanup because some of the objects might have been destroyed
-	while (len--) {
-            if (cache[len].destroyed) {
-                cache.splice(len, 1);
-            }
-        }
-        // end do cleanup
-
-	el = cache.shift();
-
-        if (!el) {
-            el = Ext.Element.create(this.elementConfig);
-            el.setVisibilityMode(2);
-            //<debug>
-            // tell the spec runner to ignore this element when checking if the dom is clean
-	    el.dom.setAttribute('data-sticky', true);
-            //</debug>
-	}
-
-        return el;
-    }
-});
-
-// 'Enter' in Textareas and aria multiline fields should not activate the
-// defaultbutton, fixed in extjs 6.0.2
-Ext.define('PVE.panel.Panel', {
-    override: 'Ext.panel.Panel',
-
-    fireDefaultButton: function(e) {
-	if (e.target.getAttribute('aria-multiline') === 'true' ||
-	    e.target.tagName === "TEXTAREA") {
-	    return true;
-	}
-	return this.callParent(arguments);
-    }
-});
-
-// if the order of the values are not the same in originalValue and value
-// extjs will not overwrite value, but marks the field dirty and thus
-// the reset button will be enabled (but clicking it changes nothing)
-// so if the arrays are not the same after resetting, we
-// clear and set it
-Ext.define('Proxmox.form.ComboBox', {
-    override: 'Ext.form.field.ComboBox',
-
-    reset: function() {
-	// copied from combobox
-	var me = this;
-	me.callParent();
-
-	// clear and set when not the same
-	var value = me.getValue();
-	if (Ext.isArray(me.originalValue) && Ext.isArray(value) && !Ext.Array.equals(value, me.originalValue)) {
-	    me.clearValue();
-	    me.setValue(me.originalValue);
-	}
-    }
-});
-
-// when refreshing a grid/tree view, restoring the focus moves the view back to
-// the previously focused item. Save scroll position before refocusing.
-Ext.define(null, {
-    override: 'Ext.view.Table',
-
-    jumpToFocus: false,
-
-    saveFocusState: function() {
-        var me = this,
-            store = me.dataSource,
-            actionableMode = me.actionableMode,
-            navModel = me.getNavigationModel(),
-            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
-            refocusRow, refocusCol;
-
-        if (focusPosition) {
-            // Separate this from the instance that the nav model is using.
-            focusPosition = focusPosition.clone();
-
-            // Exit actionable mode.
-            // We must inform any Actionables that they must relinquish control.
-            // Tabbability must be reset.
-            if (actionableMode) {
-                me.ownerGrid.setActionableMode(false);
-            }
-
-            // Blur the focused descendant, but do not trigger focusLeave.
-            me.el.dom.focus();
-
-            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
-            // clear the navigation position
-            navModel.setPosition();
-
-            // The following function will attempt to refocus back in the same mode to the same cell
-            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
-            return function() {
-                // If we still have data, attempt to refocus in the same mode.
-                if (store.getCount()) {
-
-                    // Adjust expectations of where we are able to refocus according to what kind of destruction
-                    // might have been wrought on this view's DOM during focus save.
-                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
-                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
-                    focusPosition = new Ext.grid.CellContext(me).setPosition(
-                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
-
-                    if (actionableMode) {
-                        me.ownerGrid.setActionableMode(true, focusPosition);
-                    } else {
-                        me.cellFocused = true;
-
-			// we sometimes want to scroll back to where we were
-			var x = me.getScrollX();
-			var y = me.getScrollY();
-
-                        // Pass "preventNavigation" as true so that that does not cause selection.
-                        navModel.setPosition(focusPosition, null, null, null, true);
-
-			if (!me.jumpToFocus) {
-			    me.scrollTo(x,y);
-			}
-                    }
-                }
-                // No rows - focus associated column header
-                else {
-                    focusPosition.column.focus();
-                }
-            };
-        }
-        return Ext.emptyFn;
-    }
-});
-
-// should be fixed with ExtJS 6.0.2, see:
-// https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
-Ext.define('Proxmox.Datepicker', {
-    override: 'Ext.picker.Date',
-    hideMode: 'visibility'
-});
-
-// ExtJS 6.0.1 has no setSubmitValue() (although you find it in the docs).
-// Note: this.submitValue is a boolean flag, whereas getSubmitValue() returns
-// data to be submitted.
-Ext.define('Proxmox.form.field.Text', {
-    override: 'Ext.form.field.Text',
-
-    setSubmitValue: function(v) {
-	this.submitValue = v;
-    },
-});
-
-// this should be fixed with ExtJS 6.0.2
-// make mousescrolling work in firefox in the containers overflowhandler
-Ext.define(null, {
-    override: 'Ext.layout.container.boxOverflow.Scroller',
-
-    createWheelListener: function() {
-	var me = this;
-	if (Ext.isFirefox) {
-	    me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
-	} else {
-	    me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
-	}
-    },
-
-    // special wheel handler for firefox. differs from the default onMouseWheel
-    // handler by using deltaY instead of wheelDeltaY and no normalizing,
-    // because it is already
-    onMouseWheelFirefox: function(e) {
-	e.stopEvent();
-	var delta = e.browserEvent.deltaY || 0;
-	this.scrollBy(delta * this.wheelIncrement, false);
-    }
-
-});
-
-// add '@' to the valid id
-Ext.define('Proxmox.validIdReOverride', {
-    override: 'Ext.Component',
-    validIdRe: /^[a-z_][a-z0-9\-_\@]*$/i,
-});
-
-// force alert boxes to be rendered with an Error Icon
-// since Ext.Msg is an object and not a prototype, we need to override it
-// after the framework has been initiated
-Ext.onReady(function() {
-/*jslint confusion: true */
-    Ext.override(Ext.Msg, {
-	alert: function(title, message, fn, scope) {
-	    if (Ext.isString(title)) {
-		var config = {
-		    title: title,
-		    message: message,
-		    icon: this.ERROR,
-		    buttons: this.OK,
-		    fn: fn,
-		    scope : scope,
-		    minWidth: this.minWidth
-		};
-	    return this.show(config);
-	    }
-	}
-    });
-/*jslint confusion: false */
-});
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" id="{id}-iframeEl" data-ref="iframeEl" name="{frameName}" width="100%" height="100%" frameborder="0" allowfullscreen="true"></iframe>'
-    ],
-    childEls: ['iframeEl'],
-
-    initComponent: function () {
-        this.callParent();
-
-        this.frameName = this.frameName || this.id + '-frame';
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-                doc = this.getDoc();
-                if (doc) {
-		    /*jslint nomen: true*/
-                    Ext.get(doc).un(this._docListeners);
-		    /*jslint nomen: false*/
-                    if (destroying && doc.hasOwnProperty) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-		/*jslint nomen: true*/
-                Ext.get(doc).on(
-                    me._docListeners = {
-                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                        mousemove: fn, // window resize drag detection
-                        mouseup: fn,   // window resize termination
-                        click: fn,     // not sure, but just to be safe
-                        dblclick: fn,  // not sure again
-                        scope: me
-                    }
-                );
-		/*jslint nomen: false*/
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.get(this.getWin()).on('beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if (me.src) {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    onRelayedEvent: function (event) {
-        // relay event from the iframe's document to the document that owns the iframe...
-
-        var iframeEl = this.iframeEl,
-
-            // Get the left-based iframe position
-            iframeXY = iframeEl.getTrueXY(),
-            originalEventXY = event.getXY(),
-
-            // Get the left-based XY position.
-            // This is because the consumer of the injected event will
-            // perform its own RTL normalization.
-            eventXY = event.getTrueXY();
-
-        // the event from the inner document has XY relative to that document's origin,
-        // so adjust it to use the origin of the iframe in the outer document:
-        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
-
-        event.injectEvent(iframeEl); // blame the iframe for the event...
-
-        event.xy = originalEventXY; // restore the original XY (just for safety)
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
-Ext.define('Proxmox.Mixin.CBind', {
-    extend: 'Ext.Mixin',
-
-    mixinConfig: {
-        before: {
-            initComponent: 'cloneTemplates'
-        }
-    },
-
-    cloneTemplates: function() {
-	var me = this;
-	
- 	if (typeof(me.cbindData) == "function") {
-	    me.cbindData = me.cbindData(me.initialConfig) || {};
-	}
-	
-	var getConfigValue = function(cname) {
-
-	    if (cname in me.initialConfig) {
-		return me.initialConfig[cname];
-	    }
-	    if (cname in me.cbindData) {
-		return me.cbindData[cname];
-	    }	    
-	    if (cname in me) {
-		return me[cname];
-	    }
-	    throw "unable to get cbind data for '" + cname + "'";
-	};
-	
-	var applyCBind = function(obj) {
-	    var cbind = obj.cbind, prop, cdata, cvalue, match, found;
-	    if (!cbind) return;
-
-	    for (prop in cbind) {
-		cdata = cbind[prop];
-
-		found = false;
-		if (match = /^\{(!)?([a-z_][a-z0-9_]*)\}$/i.exec(cdata)) {
-		    var cvalue = getConfigValue(match[2]);
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)+)\}$/i.exec(cdata)) {
-		    var keys = match[2].split('.');
-		    var cvalue = getConfigValue(keys.shift());
-		    keys.forEach(function(k) {
-			if (k in cvalue) {
-			    cvalue = cvalue[k];
-			} else {
-			    throw "unable to get cbind data for '" + match[2] + "'";
-			}
-		    });
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else {
-		    obj[prop] = cdata.replace(/{([a-z_][a-z0-9_]*)\}/ig, function(match, cname) {
-			var cvalue = getConfigValue(cname);
-			found = true;
-			return cvalue;
-		    });
-		}
-		if (!found) {
-		    throw "unable to parse cbind template '" + cdata + "'";
-		}
-
-	    }
-	};
-
-	if (me.cbind) {
-	    applyCBind(me);
-	}
-	
-	var cloneTemplateArray = function(org) {
-	    var copy, i, found, el, elcopy, arrayLength;
-
-	    arrayLength = org.length;
-	    found = false;
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    found = true;
-		    break;
-		}
-	    }
-
-	    if (!found) return org; // no need to copy
-
-	    copy = [];
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    elcopy = cloneTemplateObject(el);
-		    if (elcopy.cbind) {
-			applyCBind(elcopy);
-		    }
-		    copy.push(elcopy);
-		} else if (el.constructor == Array) {
-		    elcopy = cloneTemplateArray(el);
-		    copy.push(elcopy);
-		} else {
-		    copy.push(el);
-		}
-	    }
-	    return copy;
-	};
-	
-	var cloneTemplateObject = function(org) {
-	    var res = {}, prop, el, copy;
-	    for (prop in org) {
-		el = org[prop];
-		if (el.constructor == Object && el.xtype) {
-		    copy = cloneTemplateObject(el);
-		    if (copy.cbind) {
-			applyCBind(copy);
-		    }
-		    res[prop] = copy;
-		} else if (el.constructor == Array) {
-		    copy = cloneTemplateArray(el);
-		    res[prop] = copy;
-		} else {
-		    res[prop] = el;
-		}
-	    }
-	    return res;
-	};
-
-	var condCloneProperties = function() {
-	    var prop, el, i, tmp;
-	
-	    for (prop in me) {
-		el = me[prop];
-		if (el === undefined || el === null) continue;
-		if (typeof(el) === 'object' && el.constructor == Object) {
-		    if (el.xtype && prop != 'config') {
-			me[prop] = cloneTemplateObject(el);
-		    }
-		} else if (el.constructor == Array) {
-		    tmp = cloneTemplateArray(el);
-		    me[prop] = tmp;
-		}
-	    }
-	};
-
-	condCloneProperties();
-    }
-});
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash. 
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"} 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ] 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('Proxmox.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-    
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-	me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-	var me = this;
-
-	var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-	    if (me.readArray) {
-
-		var rec_hash = {};
-		Ext.Array.each(root, function(rec) {
-		    if (Ext.isDefined(rec.key)) {
-			rec_hash[rec.key] = rec;
-		    }
-		});
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			var rec = rec_hash[key];
-			if (Ext.isDefined(rec)) {
-			    if (!Ext.isDefined(rec.value)) {
-				rec.value = rowdef.defaultValue;
-			    }
-			    data.push(rec);
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue} );
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined });
-			}
-		    });
-		} else {
-		    Ext.Array.each(root, function(rec) {
-			if (Ext.isDefined(rec.key)) {
-			    data.push(rec);
-			}
-		    });
-		}
-		
-	    } else { 
-		
-		var org_root = root;
-
-		if (Ext.isArray(org_root)) {
-		    if (root.length == 1) {
-			root = org_root[0];
-		    } else {
-			root = {};
-		    }
-		}
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			if (Ext.isDefined(root[key])) {
-			    data.push({key: key, value: root[key]});
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue});
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined});
-			}
-		    });
-		} else {
-		    Ext.Object.each(root, function(key, value) {
-			data.push({key: key, value: value });
-		    });
-		}
-	    }
-	}
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-	return data;
-    }
-});
-
-Ext.define('Proxmox.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.proxmox',
-
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-
-    afterRequest: function(request, success) {
-	this.fireEvent('afterload', this, request, success);
-	return;
-    },
-
-    constructor: function(config) {
-
-	Ext.applyIf(config, {
-	    reader: {
-		type: 'json',
-		rootProperty: config.root || 'data'
-	    }
-	});
-
-	this.callParent([config]);
-    }
-}, function() {
-
-    Ext.define('KeyValue', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value', 'pending', 'delete' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('proxmox-tasks', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'starttime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'endtime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'upid', 'user', 'status', 'type', 'id'
-	],
-	idProperty: 'upid'
-    });
-
-    Ext.define('proxmox-cluster-log', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'uid' , type: 'int' },
-	    { name: 'time', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pri', type: 'int' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'user', 'tag', 'msg',
-	    {
-		name: 'id',
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-		    // compute unique ID
-		    return info.uid + ':' + info.node;
-		}
-	    }
-	],
-	idProperty: 'id'
-    });
-
-});
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- *
- * Note that you have to call yourself startUpdate() for the background load
- * to begin
- */
-Ext.define('Proxmox.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.update',
-
-    isStopped: true,
-
-    autoStart: false,
-
-    destroy: function() {
-	var me = this;
-	me.stopUpdate();
-	me.callParent();
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.interval) {
-	    config.interval = 3000;
-	}
-
-	if (!config.storeid) {
-	    throw "no storeid specified";
-	}
-
-	var load_task = new Ext.util.DelayedTask();
-
-	var run_load_task = function() {
-	    if (me.isStopped) {
-		return;
-	    }
-
-	    if (Proxmox.Utils.authOK()) {
-		var start = new Date();
-		me.load(function() {
-		    var runtime = (new Date()) - start;
-		    var interval = config.interval + runtime*2;
-		    load_task.delay(interval, run_load_task);
-		});
-	    } else {
-		load_task.delay(200, run_load_task);
-	    }
-	};
-
-	Ext.apply(config, {
-	    startUpdate: function() {
-		me.isStopped = false;
-		// run_load_task(); this makes problems with chrome
-		load_task.delay(1, run_load_task);
-	    },
-	    stopUpdate: function() {
-		me.isStopped = true;
-		load_task.cancel();
-	    }
-	});
-
-	me.callParent([config]);
-
-	me.load_task = load_task;
-
-	if (me.autoStart) {
-	    me.startUpdate();
-	}
-    }
-});
-/*
- * The DiffStore is a in-memory store acting as proxy between a real store
- * instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the real store, to avoid the annoying visual flickering of using
- * the real store directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the real store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: the realstore which will autorefresh its content from the API
- * Only works if rstore has a model and use 'idProperty'
- * sortAfterUpdate: sort the diffstore before rendering the view
- */
-Ext.define('Proxmox.data.DiffStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.diff',
-
-    sortAfterUpdate: false,
-    
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.rstore) {
-	    throw "no rstore specified";
-	}
-
-	if (!config.rstore.model) {
-	    throw "no rstore model specified";
-	}
-
-	var rstore = config.rstore;
-
-	Ext.apply(config, {
-	    model: rstore.model,
-	    proxy: { type: 'memory' }
-	});
-
-	me.callParent([config]);
-
-	var first_load = true;
-
-	var cond_add_item = function(data, id) {
-	    var olditem = me.getById(id);
-	    if (olditem) {
-		olditem.beginEdit();
-		Ext.Array.each(me.model.prototype.fields, function(field) {
-		    if (olditem.data[field.name] !== data[field.name]) {
-			olditem.set(field.name, data[field.name]);
-		    }
-		});
-		olditem.endEdit(true);
-		olditem.commit(); 
-	    } else {
-		var newrec = Ext.create(me.model, data);
-		var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-		me.insert(pos, newrec);
-	    }
-	};
-
-	var loadFn = function(s, records, success) {
-
-	    if (!success) {
-		return;
-	    }
-
-	    me.suspendEvents();
-
-	    // getSource returns null if data is not filtered
-	    // if it is filtered it returns all records
-	    var allItems = me.getData().getSource() || me.getData();
-
-	    // remove vanished items
-	    allItems.each(function(olditem) {
-		var item = rstore.getById(olditem.getId());
-		if (!item) {
-		    me.remove(olditem);
-		}
-	    });
-
-	    rstore.each(function(item) {
-		cond_add_item(item.data, item.getId());
-	    });
-
-	    me.filter();
-
-	    if (me.sortAfterUpdate) {
-		me.sort();
-	    }
-
-	    first_load = false;
-
-	    me.resumeEvents();
-	    me.fireEvent('refresh', me);
-	    me.fireEvent('datachanged', me);
-	};
-
-	if (rstore.isLoaded()) {
-	    // if store is already loaded,
-	    // insert items instantly
-	    loadFn(rstore, [], true);
-	}
-
-	me.mon(rstore, 'load', loadFn);
-    }
-});
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('Proxmox.data.ObjectStore',  {
-    extend: 'Proxmox.data.UpdateStore',
-
-    getRecord: function() {
-	var me = this;
-	var record = Ext.create('Ext.data.Model');
-	me.getData().each(function(item) {
-	    record.set(item.data.key, item.data.value);
-	});
-	record.commit(true);
-	return record;
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-        config = config || {};
-
-	if (!config.storeid) {
-	    config.storeid =  'proxmox-store-' + (++Ext.idSeed);
-	}
-
-        Ext.applyIf(config, {
-	    model: 'KeyValue',
-            proxy: {
-                type: 'proxmox',
-		url: config.url,
-		extraParams: config.extraParams,
-                reader: {
-		    type: 'jsonobject',
-		    rows: config.rows,
-		    readArray: config.readArray,
-		    rootProperty: config.root || 'data'
-		}
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
-/* Extends the Proxmox.data.UpdateStore type
- *
- *
- */
-Ext.define('Proxmox.data.RRDStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    alias: 'store.proxmoxRRDStore',
-
-    setRRDUrl: function(timeframe, cf) {
-	var me = this;
-	if (!timeframe) {
-	    timeframe = me.timeframe;
-	}
-
-	if (!cf) {
-	    cf = me.cf;
-	}
-
-	me.proxy.url = me.rrdurl + "?timeframe=" + timeframe + "&cf=" + cf;
-    },
-
-    proxy: {
-	type: 'proxmox'
-    },
-
-    timeframe: 'hour',
-
-    cf: 'AVERAGE',
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	// set default interval to 30seconds
-	if (!config.interval) {
-	    config.interval = 30000;
-	}
-
-	// set a new storeid
-	if (!config.storeid) {
-	    config.storeid = 'rrdstore-' + (++Ext.idSeed);
-	}
-
-	// rrdurl is required
-	if (!config.rrdurl) {
-	    throw "no rrdurl specified";
-	}
-
-	var stateid = 'proxmoxRRDTypeSelection';
-	var sp = Ext.state.Manager.getProvider();
-	var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-	    if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-		me.timeframe = stateinit.timeframe;
-		me.rrdcffn = stateinit.cf;
-	    }
-	}
-
-	me.callParent([config]);
-
-	me.setRRDUrl();
-	me.mon(sp, 'statechange', function(prov, key, state){
-	    if (key === stateid) {
-		if (state && state.id) {
-		    if (state.timeframe !== me.timeframe || state.cf !== me.cf) {
-		        me.timeframe = state.timeframe;
-		        me.cf = state.cf;
-			me.setRRDUrl();
-			me.reload();
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Timezone', {
-    extend: 'Ext.data.Model',
-    fields: ['zone']
-});
-
-Ext.define('Proxmox.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-    model: 'Timezone',
-    data: [
-	    ['Africa/Abidjan'],
-	    ['Africa/Accra'],
-	    ['Africa/Addis_Ababa'],
-	    ['Africa/Algiers'],
-	    ['Africa/Asmara'],
-	    ['Africa/Bamako'],
-	    ['Africa/Bangui'],
-	    ['Africa/Banjul'],
-	    ['Africa/Bissau'],
-	    ['Africa/Blantyre'],
-	    ['Africa/Brazzaville'],
-	    ['Africa/Bujumbura'],
-	    ['Africa/Cairo'],
-	    ['Africa/Casablanca'],
-	    ['Africa/Ceuta'],
-	    ['Africa/Conakry'],
-	    ['Africa/Dakar'],
-	    ['Africa/Dar_es_Salaam'],
-	    ['Africa/Djibouti'],
-	    ['Africa/Douala'],
-	    ['Africa/El_Aaiun'],
-	    ['Africa/Freetown'],
-	    ['Africa/Gaborone'],
-	    ['Africa/Harare'],
-	    ['Africa/Johannesburg'],
-	    ['Africa/Kampala'],
-	    ['Africa/Khartoum'],
-	    ['Africa/Kigali'],
-	    ['Africa/Kinshasa'],
-	    ['Africa/Lagos'],
-	    ['Africa/Libreville'],
-	    ['Africa/Lome'],
-	    ['Africa/Luanda'],
-	    ['Africa/Lubumbashi'],
-	    ['Africa/Lusaka'],
-	    ['Africa/Malabo'],
-	    ['Africa/Maputo'],
-	    ['Africa/Maseru'],
-	    ['Africa/Mbabane'],
-	    ['Africa/Mogadishu'],
-	    ['Africa/Monrovia'],
-	    ['Africa/Nairobi'],
-	    ['Africa/Ndjamena'],
-	    ['Africa/Niamey'],
-	    ['Africa/Nouakchott'],
-	    ['Africa/Ouagadougou'],
-	    ['Africa/Porto-Novo'],
-	    ['Africa/Sao_Tome'],
-	    ['Africa/Tripoli'],
-	    ['Africa/Tunis'],
-	    ['Africa/Windhoek'],
-	    ['America/Adak'],
-	    ['America/Anchorage'],
-	    ['America/Anguilla'],
-	    ['America/Antigua'],
-	    ['America/Araguaina'],
-	    ['America/Argentina/Buenos_Aires'],
-	    ['America/Argentina/Catamarca'],
-	    ['America/Argentina/Cordoba'],
-	    ['America/Argentina/Jujuy'],
-	    ['America/Argentina/La_Rioja'],
-	    ['America/Argentina/Mendoza'],
-	    ['America/Argentina/Rio_Gallegos'],
-	    ['America/Argentina/Salta'],
-	    ['America/Argentina/San_Juan'],
-	    ['America/Argentina/San_Luis'],
-	    ['America/Argentina/Tucuman'],
-	    ['America/Argentina/Ushuaia'],
-	    ['America/Aruba'],
-	    ['America/Asuncion'],
-	    ['America/Atikokan'],
-	    ['America/Bahia'],
-	    ['America/Bahia_Banderas'],
-	    ['America/Barbados'],
-	    ['America/Belem'],
-	    ['America/Belize'],
-	    ['America/Blanc-Sablon'],
-	    ['America/Boa_Vista'],
-	    ['America/Bogota'],
-	    ['America/Boise'],
-	    ['America/Cambridge_Bay'],
-	    ['America/Campo_Grande'],
-	    ['America/Cancun'],
-	    ['America/Caracas'],
-	    ['America/Cayenne'],
-	    ['America/Cayman'],
-	    ['America/Chicago'],
-	    ['America/Chihuahua'],
-	    ['America/Costa_Rica'],
-	    ['America/Cuiaba'],
-	    ['America/Curacao'],
-	    ['America/Danmarkshavn'],
-	    ['America/Dawson'],
-	    ['America/Dawson_Creek'],
-	    ['America/Denver'],
-	    ['America/Detroit'],
-	    ['America/Dominica'],
-	    ['America/Edmonton'],
-	    ['America/Eirunepe'],
-	    ['America/El_Salvador'],
-	    ['America/Fortaleza'],
-	    ['America/Glace_Bay'],
-	    ['America/Godthab'],
-	    ['America/Goose_Bay'],
-	    ['America/Grand_Turk'],
-	    ['America/Grenada'],
-	    ['America/Guadeloupe'],
-	    ['America/Guatemala'],
-	    ['America/Guayaquil'],
-	    ['America/Guyana'],
-	    ['America/Halifax'],
-	    ['America/Havana'],
-	    ['America/Hermosillo'],
-	    ['America/Indiana/Indianapolis'],
-	    ['America/Indiana/Knox'],
-	    ['America/Indiana/Marengo'],
-	    ['America/Indiana/Petersburg'],
-	    ['America/Indiana/Tell_City'],
-	    ['America/Indiana/Vevay'],
-	    ['America/Indiana/Vincennes'],
-	    ['America/Indiana/Winamac'],
-	    ['America/Inuvik'],
-	    ['America/Iqaluit'],
-	    ['America/Jamaica'],
-	    ['America/Juneau'],
-	    ['America/Kentucky/Louisville'],
-	    ['America/Kentucky/Monticello'],
-	    ['America/La_Paz'],
-	    ['America/Lima'],
-	    ['America/Los_Angeles'],
-	    ['America/Maceio'],
-	    ['America/Managua'],
-	    ['America/Manaus'],
-	    ['America/Marigot'],
-	    ['America/Martinique'],
-	    ['America/Matamoros'],
-	    ['America/Mazatlan'],
-	    ['America/Menominee'],
-	    ['America/Merida'],
-	    ['America/Mexico_City'],
-	    ['America/Miquelon'],
-	    ['America/Moncton'],
-	    ['America/Monterrey'],
-	    ['America/Montevideo'],
-	    ['America/Montreal'],
-	    ['America/Montserrat'],
-	    ['America/Nassau'],
-	    ['America/New_York'],
-	    ['America/Nipigon'],
-	    ['America/Nome'],
-	    ['America/Noronha'],
-	    ['America/North_Dakota/Center'],
-	    ['America/North_Dakota/New_Salem'],
-	    ['America/Ojinaga'],
-	    ['America/Panama'],
-	    ['America/Pangnirtung'],
-	    ['America/Paramaribo'],
-	    ['America/Phoenix'],
-	    ['America/Port-au-Prince'],
-	    ['America/Port_of_Spain'],
-	    ['America/Porto_Velho'],
-	    ['America/Puerto_Rico'],
-	    ['America/Rainy_River'],
-	    ['America/Rankin_Inlet'],
-	    ['America/Recife'],
-	    ['America/Regina'],
-	    ['America/Resolute'],
-	    ['America/Rio_Branco'],
-	    ['America/Santa_Isabel'],
-	    ['America/Santarem'],
-	    ['America/Santiago'],
-	    ['America/Santo_Domingo'],
-	    ['America/Sao_Paulo'],
-	    ['America/Scoresbysund'],
-	    ['America/Shiprock'],
-	    ['America/St_Barthelemy'],
-	    ['America/St_Johns'],
-	    ['America/St_Kitts'],
-	    ['America/St_Lucia'],
-	    ['America/St_Thomas'],
-	    ['America/St_Vincent'],
-	    ['America/Swift_Current'],
-	    ['America/Tegucigalpa'],
-	    ['America/Thule'],
-	    ['America/Thunder_Bay'],
-	    ['America/Tijuana'],
-	    ['America/Toronto'],
-	    ['America/Tortola'],
-	    ['America/Vancouver'],
-	    ['America/Whitehorse'],
-	    ['America/Winnipeg'],
-	    ['America/Yakutat'],
-	    ['America/Yellowknife'],
-	    ['Antarctica/Casey'],
-	    ['Antarctica/Davis'],
-	    ['Antarctica/DumontDUrville'],
-	    ['Antarctica/Macquarie'],
-	    ['Antarctica/Mawson'],
-	    ['Antarctica/McMurdo'],
-	    ['Antarctica/Palmer'],
-	    ['Antarctica/Rothera'],
-	    ['Antarctica/South_Pole'],
-	    ['Antarctica/Syowa'],
-	    ['Antarctica/Vostok'],
-	    ['Arctic/Longyearbyen'],
-	    ['Asia/Aden'],
-	    ['Asia/Almaty'],
-	    ['Asia/Amman'],
-	    ['Asia/Anadyr'],
-	    ['Asia/Aqtau'],
-	    ['Asia/Aqtobe'],
-	    ['Asia/Ashgabat'],
-	    ['Asia/Baghdad'],
-	    ['Asia/Bahrain'],
-	    ['Asia/Baku'],
-	    ['Asia/Bangkok'],
-	    ['Asia/Beirut'],
-	    ['Asia/Bishkek'],
-	    ['Asia/Brunei'],
-	    ['Asia/Choibalsan'],
-	    ['Asia/Chongqing'],
-	    ['Asia/Colombo'],
-	    ['Asia/Damascus'],
-	    ['Asia/Dhaka'],
-	    ['Asia/Dili'],
-	    ['Asia/Dubai'],
-	    ['Asia/Dushanbe'],
-	    ['Asia/Gaza'],
-	    ['Asia/Harbin'],
-	    ['Asia/Ho_Chi_Minh'],
-	    ['Asia/Hong_Kong'],
-	    ['Asia/Hovd'],
-	    ['Asia/Irkutsk'],
-	    ['Asia/Jakarta'],
-	    ['Asia/Jayapura'],
-	    ['Asia/Jerusalem'],
-	    ['Asia/Kabul'],
-	    ['Asia/Kamchatka'],
-	    ['Asia/Karachi'],
-	    ['Asia/Kashgar'],
-	    ['Asia/Kathmandu'],
-	    ['Asia/Kolkata'],
-	    ['Asia/Krasnoyarsk'],
-	    ['Asia/Kuala_Lumpur'],
-	    ['Asia/Kuching'],
-	    ['Asia/Kuwait'],
-	    ['Asia/Macau'],
-	    ['Asia/Magadan'],
-	    ['Asia/Makassar'],
-	    ['Asia/Manila'],
-	    ['Asia/Muscat'],
-	    ['Asia/Nicosia'],
-	    ['Asia/Novokuznetsk'],
-	    ['Asia/Novosibirsk'],
-	    ['Asia/Omsk'],
-	    ['Asia/Oral'],
-	    ['Asia/Phnom_Penh'],
-	    ['Asia/Pontianak'],
-	    ['Asia/Pyongyang'],
-	    ['Asia/Qatar'],
-	    ['Asia/Qyzylorda'],
-	    ['Asia/Rangoon'],
-	    ['Asia/Riyadh'],
-	    ['Asia/Sakhalin'],
-	    ['Asia/Samarkand'],
-	    ['Asia/Seoul'],
-	    ['Asia/Shanghai'],
-	    ['Asia/Singapore'],
-	    ['Asia/Taipei'],
-	    ['Asia/Tashkent'],
-	    ['Asia/Tbilisi'],
-	    ['Asia/Tehran'],
-	    ['Asia/Thimphu'],
-	    ['Asia/Tokyo'],
-	    ['Asia/Ulaanbaatar'],
-	    ['Asia/Urumqi'],
-	    ['Asia/Vientiane'],
-	    ['Asia/Vladivostok'],
-	    ['Asia/Yakutsk'],
-	    ['Asia/Yekaterinburg'],
-	    ['Asia/Yerevan'],
-	    ['Atlantic/Azores'],
-	    ['Atlantic/Bermuda'],
-	    ['Atlantic/Canary'],
-	    ['Atlantic/Cape_Verde'],
-	    ['Atlantic/Faroe'],
-	    ['Atlantic/Madeira'],
-	    ['Atlantic/Reykjavik'],
-	    ['Atlantic/South_Georgia'],
-	    ['Atlantic/St_Helena'],
-	    ['Atlantic/Stanley'],
-	    ['Australia/Adelaide'],
-	    ['Australia/Brisbane'],
-	    ['Australia/Broken_Hill'],
-	    ['Australia/Currie'],
-	    ['Australia/Darwin'],
-	    ['Australia/Eucla'],
-	    ['Australia/Hobart'],
-	    ['Australia/Lindeman'],
-	    ['Australia/Lord_Howe'],
-	    ['Australia/Melbourne'],
-	    ['Australia/Perth'],
-	    ['Australia/Sydney'],
-	    ['Europe/Amsterdam'],
-	    ['Europe/Andorra'],
-	    ['Europe/Athens'],
-	    ['Europe/Belgrade'],
-	    ['Europe/Berlin'],
-	    ['Europe/Bratislava'],
-	    ['Europe/Brussels'],
-	    ['Europe/Bucharest'],
-	    ['Europe/Budapest'],
-	    ['Europe/Chisinau'],
-	    ['Europe/Copenhagen'],
-	    ['Europe/Dublin'],
-	    ['Europe/Gibraltar'],
-	    ['Europe/Guernsey'],
-	    ['Europe/Helsinki'],
-	    ['Europe/Isle_of_Man'],
-	    ['Europe/Istanbul'],
-	    ['Europe/Jersey'],
-	    ['Europe/Kaliningrad'],
-	    ['Europe/Kiev'],
-	    ['Europe/Lisbon'],
-	    ['Europe/Ljubljana'],
-	    ['Europe/London'],
-	    ['Europe/Luxembourg'],
-	    ['Europe/Madrid'],
-	    ['Europe/Malta'],
-	    ['Europe/Mariehamn'],
-	    ['Europe/Minsk'],
-	    ['Europe/Monaco'],
-	    ['Europe/Moscow'],
-	    ['Europe/Oslo'],
-	    ['Europe/Paris'],
-	    ['Europe/Podgorica'],
-	    ['Europe/Prague'],
-	    ['Europe/Riga'],
-	    ['Europe/Rome'],
-	    ['Europe/Samara'],
-	    ['Europe/San_Marino'],
-	    ['Europe/Sarajevo'],
-	    ['Europe/Simferopol'],
-	    ['Europe/Skopje'],
-	    ['Europe/Sofia'],
-	    ['Europe/Stockholm'],
-	    ['Europe/Tallinn'],
-	    ['Europe/Tirane'],
-	    ['Europe/Uzhgorod'],
-	    ['Europe/Vaduz'],
-	    ['Europe/Vatican'],
-	    ['Europe/Vienna'],
-	    ['Europe/Vilnius'],
-	    ['Europe/Volgograd'],
-	    ['Europe/Warsaw'],
-	    ['Europe/Zagreb'],
-	    ['Europe/Zaporozhye'],
-	    ['Europe/Zurich'],
-	    ['Indian/Antananarivo'],
-	    ['Indian/Chagos'],
-	    ['Indian/Christmas'],
-	    ['Indian/Cocos'],
-	    ['Indian/Comoro'],
-	    ['Indian/Kerguelen'],
-	    ['Indian/Mahe'],
-	    ['Indian/Maldives'],
-	    ['Indian/Mauritius'],
-	    ['Indian/Mayotte'],
-	    ['Indian/Reunion'],
-	    ['Pacific/Apia'],
-	    ['Pacific/Auckland'],
-	    ['Pacific/Chatham'],
-	    ['Pacific/Chuuk'],
-	    ['Pacific/Easter'],
-	    ['Pacific/Efate'],
-	    ['Pacific/Enderbury'],
-	    ['Pacific/Fakaofo'],
-	    ['Pacific/Fiji'],
-	    ['Pacific/Funafuti'],
-	    ['Pacific/Galapagos'],
-	    ['Pacific/Gambier'],
-	    ['Pacific/Guadalcanal'],
-	    ['Pacific/Guam'],
-	    ['Pacific/Honolulu'],
-	    ['Pacific/Johnston'],
-	    ['Pacific/Kiritimati'],
-	    ['Pacific/Kosrae'],
-	    ['Pacific/Kwajalein'],
-	    ['Pacific/Majuro'],
-	    ['Pacific/Marquesas'],
-	    ['Pacific/Midway'],
-	    ['Pacific/Nauru'],
-	    ['Pacific/Niue'],
-	    ['Pacific/Norfolk'],
-	    ['Pacific/Noumea'],
-	    ['Pacific/Pago_Pago'],
-	    ['Pacific/Palau'],
-	    ['Pacific/Pitcairn'],
-	    ['Pacific/Pohnpei'],
-	    ['Pacific/Port_Moresby'],
-	    ['Pacific/Rarotonga'],
-	    ['Pacific/Saipan'],
-	    ['Pacific/Tahiti'],
-	    ['Pacific/Tarawa'],
-	    ['Pacific/Tongatapu'],
-	    ['Pacific/Wake'],
-	    ['Pacific/Wallis'],
-	    ['UTC']
-	]
-});
-Ext.define('Proxmox.form.field.Integer',{
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.proxmoxintegerfield',
-
-    config: {
-	deleteEmpty: false
-    },
-
-    allowDecimals: false,
-    allowExponential: false,
-    step: 1,
-
-   getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== undefined && val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    }
-
-});
-Ext.define('Proxmox.form.field.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.proxmoxtextfield'],
-
-    config: {
-	skipEmptyText: true,
-
-	deleteEmpty: false,
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-	var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    }
-});
-Ext.define('Proxmox.DateTimeField', {
-    extend: 'Ext.form.FieldContainer',
-    xtype: 'promxoxDateTimeField',
-
-    layout: 'hbox',
-
-    referenceHolder: true,
-
-    submitFormat: 'U',
-
-    getValue: function() {
-	var me = this;
-	var d = me.lookupReference('dateentry').getValue();
-
-	if (d === undefined || d === null) { return null; }
-
-	var t = me.lookupReference('timeentry').getValue();
-
-	if (t === undefined || t === null) { return null; }
-
-	var offset = (t.getHours()*3600+t.getMinutes()*60)*1000;
-
-	return new Date(d.getTime() + offset);
-    },
-
-    getSubmitValue: function() {
-        var me = this;
-        var format = me.submitFormat;
-        var value = me.getValue();
-
-        return value ? Ext.Date.format(value, format) : null;
-    },
-
-    items: [
-	{
-	    xtype: 'datefield',
-	    editable: false,
-	    reference: 'dateentry',
-	    flex: 1,
-	    format: 'Y-m-d'
-	},
-	{
-	    xtype: 'timefield',
-	    reference: 'timeentry',
-	    format: 'H:i',
-	    width: 80,
-	    value: '00:00',
-	    increment: 60
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	var value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    }
-});
-Ext.define('Proxmox.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.proxmoxcheckbox'],
-
-    config: {
-	defaultValue: undefined,
-	deleteDefaultValue: false,
-	deleteEmpty: false
-    },
-
-    inputValue: '1',
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-		if ((val == me.getDefaultValue()) && me.getDeleteDefaultValue()) {
-		    data['delete'] = me.getName();
-		} else {
-                    data[me.getName()] = val;
-		}
-            } else if (me.getDeleteEmpty()) {
-               data = {};
-               data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-	var me = this;
-
-	if (value === 1) {
-            me.callParent([true]);
-	} else {
-            me.callParent([value]);
-	}
-    }
-
-});
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('Proxmox.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.proxmoxKVComboBox',
-
-    config: {
-	deleteEmpty: true
-    },
-
-    comboItems: undefined,
-    displayField: 'value',
-    valueField: 'key',
-    queryMode: 'local',
-
-    // overide framework function to implement deleteEmpty behaviour
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '' && val !== '__default__') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    validator: function(val) {
-	var me = this;
-
-	if (me.editable || val === null || val === '') {
-	    return true;
-	}
-
-	if (me.store.getCount() > 0) {
-	    var values = me.multiSelect ? val.split(me.delimiter) : [val];
-	    var items = me.store.getData().collect('value', 'data');
-	    if (Ext.Array.every(values, function(value) {
-		return Ext.Array.contains(items, value);
-	    })) {
-		return true;
-	    }
-	}
-
-	// returns a boolean or string
-	/*jslint confusion: true */
-	return "value '" + val + "' not allowed!";
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.store = Ext.create('Ext.data.ArrayStore', {
-	    model: 'KeyValue',
-	    data : me.comboItems
-	});
-
-	if (me.initialConfig.editable === undefined) {
-	    me.editable = false;
-	}
-
-	me.callParent();
-    },
-
-    setComboItems: function(items) {
-	var me = this;
-
-	me.getStore().setData(items);
-    }
-
-});
-Ext.define('Proxmox.form.LanguageSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'proxmoxLanguageSelector',
-
-    comboItems: Proxmox.Utils.language_array()
-});
-/*
- * ComboGrid component: a ComboBox where the dropdown menu (the
- * "Picker") is a Grid with Rows and Columns expects a listConfig
- * object with a columns property roughly based on the GridPicker from
- * https://www.sencha.com/forum/showthread.php?299909
- *
-*/
-
-Ext.define('Proxmox.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-	    (key == e.BACKSPACE || key == e.DELETE)) {
-	    me.setValue('');
-	}
-
-        me.callParent(arguments);
-    },
-
-    config: {
-	skipEmptyText: false,
-	deleteEmpty: false,
-    },
-
-    // needed to trigger onKeyUp etc.
-    enableKeyEvents: true,
-
-    editable: false,
-
-    // override ExtJS method
-    // if the field has multiSelect enabled, the store is not loaded, and
-    // the displayfield == valuefield, it saves the rawvalue as an array
-    // but the getRawValue method is only defined in the textfield class
-    // (which has not to deal with arrays) an returns the string in the
-    // field (not an array)
-    //
-    // so if we have multiselect enabled, return the rawValue (which
-    // should be an array) and else we do callParent so
-    // it should not impact any other use of the class
-    getRawValue: function() {
-	var me = this;
-	if (me.multiSelect) {
-	    return me.rawValue;
-	} else {
-	    return me.callParent();
-	}
-    },
-
-    getSubmitData: function() {
-	var me = this;
-
-	let data = null;
-	if (!me.disabled && me.submitValue) {
-	    let val = me.getSubmitValue();
-	    if (val !== null) {
-		data = {};
-		data[me.getName()] = val;
-	    } else if (me.getDeleteEmpty()) {
-		data = {};
-		data['delete'] = me.getName();
-	    }
-	}
-	return data;
-   },
-
-    getSubmitValue: function() {
-	var me = this;
-
-	var value = me.callParent();
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    },
-
-// override ExtJS protected method
-    onBindStore: function(store, initial) {
-        var me = this,
-            picker = me.picker,
-            extraKeySpec,
-            valueCollectionConfig;
-
-        // We're being bound, not unbound...
-        if (store) {
-            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2'
-            if (store.autoCreated) {
-                me.queryMode = 'local';
-                me.valueField = me.displayField = 'field1';
-                if (!store.expanded) {
-                    me.displayField = 'field2';
-                }
-
-                // displayTpl config will need regenerating with the autogenerated displayField name 'field1'
-                me.setDisplayTpl(null);
-            }
-            if (!Ext.isDefined(me.valueField)) {
-                me.valueField = me.displayField;
-            }
-
-            // Add a byValue index to the store so that we can efficiently look up records by the value field
-            // when setValue passes string value(s).
-            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys
-            // are found, they are all returned by the get call.
-            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default,
-            // if unique is true, CollectionKey keeps the *last* matching value.
-            extraKeySpec = {
-                byValue: {
-                    rootProperty: 'data',
-                    unique: false
-                }
-            };
-            extraKeySpec.byValue.property = me.valueField;
-            store.setExtraKeys(extraKeySpec);
-
-            if (me.displayField === me.valueField) {
-                store.byText = store.byValue;
-            } else {
-                extraKeySpec.byText = {
-                    rootProperty: 'data',
-                    unique: false
-                };
-                extraKeySpec.byText.property = me.displayField;
-                store.setExtraKeys(extraKeySpec);
-            }
-
-            // We hold a collection of the values which have been selected, keyed by this field's valueField.
-            // This collection also functions as the selected items collection for the BoundList's selection model
-            valueCollectionConfig = {
-                rootProperty: 'data',
-                extraKeys: {
-                    byInternalId: {
-                        property: 'internalId'
-                    },
-                    byValue: {
-                        property: me.valueField,
-                        rootProperty: 'data'
-                    }
-                },
-                // Whenever this collection is changed by anyone, whether by this field adding to it,
-                // or the BoundList operating, we must refresh our value.
-                listeners: {
-                    beginupdate: me.onValueCollectionBeginUpdate,
-                    endupdate: me.onValueCollectionEndUpdate,
-                    scope: me
-                }
-            };
-
-            // This becomes our collection of selected records for the Field.
-            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);
-
-            // We use the selected Collection as our value collection and the basis
-            // for rendering the tag list.
-
-            //proxmox override: since the picker is represented by a grid panel,
-            // we changed here the selection to RowModel
-            me.pickerSelectionModel = new Ext.selection.RowModel({
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
-                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row
-                // and released.  In these situations, the event target for the click event won't be the row where the mouse
-                // was released but the boundview.  The view will then determine that it should fire a container click, and
-                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will
-                // prevent the model from deselecting.
-                deselectOnContainerClick: false,
-                enableInitialSelection: false,
-                pruneRemoved: false,
-                selected: me.valueCollection,
-                store: store,
-                listeners: {
-                    scope: me,
-                    lastselectedchanged: me.updateBindSelection
-                }
-            });
-
-            if (!initial) {
-                me.resetToDefault();
-            }
-
-            if (picker) {
-                picker.setSelectionModel(me.pickerSelectionModel);
-                if (picker.getStore() !== store) {
-                    picker.bindStore(store);
-                }
-            }
-        }
-    },
-
-    // copied from ComboBox
-    createPicker: function() {
-        var me = this;
-        var picker;
-
-        var pickerCfg = Ext.apply({
-                // proxmox overrides: display a grid for selection
-                xtype: 'gridpanel',
-                id: me.pickerId,
-                pickerField: me,
-                floating: true,
-                hidden: true,
-                store: me.store,
-                displayField: me.displayField,
-                preserveScrollOnRefresh: true,
-                pageSize: me.pageSize,
-                tpl: me.tpl,
-                selModel: me.pickerSelectionModel,
-                focusOnToFront: false
-            }, me.listConfig, me.defaultListConfig);
-
-        picker = me.picker || Ext.widget(pickerCfg);
-
-        if (picker.getStore() !== me.store) {
-            picker.bindStore(me.store);
-        }
-
-        if (me.pageSize) {
-            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
-        }
-
-        // proxmox overrides: pass missing method in gridPanel to its view
-        picker.refresh = function() {
-            picker.getSelectionModel().select(me.valueCollection.getRange());
-            picker.getView().refresh();
-        };
-        picker.getNodeByRecord = function() {
-            picker.getView().getNodeByRecord(arguments);
-        };
-
-        // We limit the height of the picker to fit in the space above
-        // or below this field unless the picker has its own ideas about that.
-        if (!picker.initialConfig.maxHeight) {
-            picker.on({
-                beforeshow: me.onBeforePickerShow,
-                scope: me
-            });
-        }
-        picker.getSelectionModel().on({
-            beforeselect: me.onBeforeSelect,
-            beforedeselect: me.onBeforeDeselect,
-            focuschange: me.onFocusChange,
-            selectionChange: function (sm, selectedRecords) {
-                var me = this;
-                if (selectedRecords.length) {
-                    me.setValue(selectedRecords);
-                    me.fireEvent('select', me, selectedRecords);
-                }
-            },
-            scope: me
-        });
-
-	// hack for extjs6
-	// when the clicked item is the same as the previously selected,
-	// it does not select the item
-	// instead we hide the picker
-	if (!me.multiSelect) {
-	    picker.on('itemclick', function (sm,record) {
-		if (picker.getSelection()[0] === record) {
-		    picker.hide();
-		}
-	    });
-	}
-
-	// when our store is not yet loaded, we increase
-	// the height of the gridpanel, so that we can see
-	// the loading mask
-	//
-	// we save the minheight to reset it after the load
-	picker.on('show', function() {
-	    if (me.enableLoadMask) {
-		me.savedMinHeight = picker.getMinHeight();
-		picker.setMinHeight(100);
-	    }
-	});
-
-        picker.getNavigationModel().navigateOnSpace = false;
-
-        return picker;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    queryMode: 'local',
-	    matchFieldWidth: false
-	});
-
-	Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-	Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-        // Create the picker at an early stage, so it is available to store the previous selection
-        if (!me.picker) {
-            me.createPicker();
-        }
-
-	if (me.editable) {
-	    // The trigger.picker causes first a focus event on the field then
-	    // toggles the selection picker. Thus skip expanding in this case,
-	    // else our focus listner expands and the picker.trigger then
-	    // collapses it directly afterwards.
-	    Ext.override(me.triggers.picker, {
-		onMouseDown : function (e) {
-		    // copied "should we focus" check from Ext.form.trigger.Trigger
-		    if (e.pointerType !== 'touch' && !this.field.owns(Ext.Element.getActiveElement())) {
-			me.skip_expand_on_focus = true;
-		    }
-		    this.callParent(arguments);
-		}
-	    });
-
-	    me.on("focus", function(me) {
-		if (!me.isExpanded && !me.skip_expand_on_focus) {
-		    me.expand();
-		}
-		me.skip_expand_on_focus = false;
-	    });
-	}
-
-	me.mon(me.store, 'beforeload', function() {
-	    if (!me.isDisabled()) {
-		me.enableLoadMask = true;
-	    }
-	});
-
-	// hack: autoSelect does not work
-	me.mon(me.store, 'load', function(store, r, success, o) {
-	    if (success) {
-		me.clearInvalid();
-
-		if (me.enableLoadMask) {
-		    delete me.enableLoadMask;
-
-		    // if the picker exists,
-		    // we reset its minheight to the saved var/0
-		    // we have to update the layout, otherwise the height
-		    // gets not recalculated
-		    if (me.picker) {
-			me.picker.setMinHeight(me.savedMinHeight || 0);
-			delete me.savedMinHeight;
-			me.picker.updateLayout();
-		    }
-		}
-
-		var def = me.getValue() || me.preferredValue;
-		if (def) {
-		    me.setValue(def, true); // sync with grid
-		}
-		var found = false;
-		if (def) {
-		    if (Ext.isArray(def)) {
-			Ext.Array.each(def, function(v) {
-			    if (store.findRecord(me.valueField, v)) {
-				found = true;
-				return false; // break
-			    }
-			});
-		    } else {
-			found = store.findRecord(me.valueField, def);
-		    }
-		}
-
-		if (!found) {
-		    var rec = me.store.first();
-		    if (me.autoSelect && rec && rec.data) {
-			def = rec.data[me.valueField];
-			me.setValue(def, true);
-		    } else {
-			me.setValue(me.editable ? def : '', true);
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Proxmox.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxRRDTypeSelector'],
-
-    displayField: 'text',
-    valueField: 'id',
-    editable: false,
-    queryMode: 'local',
-    value: 'hour',
-    stateEvents: [ 'select' ],
-    stateful: true,
-    stateId: 'proxmoxRRDTypeSelection',
-    store: {
-	type: 'array',
-	fields: [ 'id', 'timeframe', 'cf', 'text' ],
-	data : [
-	    [ 'hour', 'hour', 'AVERAGE',
-	      gettext('Hour') + ' (' + gettext('average') +')' ],
-	    [ 'hourmax', 'hour', 'MAX',
-	      gettext('Hour') + ' (' + gettext('maximum') + ')' ],
-	    [ 'day', 'day', 'AVERAGE',
-	      gettext('Day') + ' (' + gettext('average') + ')' ],
-	    [ 'daymax', 'day', 'MAX',
-	      gettext('Day') + ' (' + gettext('maximum') + ')' ],
-	    [ 'week', 'week', 'AVERAGE',
-	      gettext('Week') + ' (' + gettext('average') + ')' ],
-	    [ 'weekmax', 'week', 'MAX',
-	      gettext('Week') + ' (' + gettext('maximum') + ')' ],
-	    [ 'month', 'month', 'AVERAGE',
-	      gettext('Month') + ' (' + gettext('average') + ')' ],
-	    [ 'monthmax', 'month', 'MAX',
-	      gettext('Month') + ' (' + gettext('maximum') + ')' ],
-	    [ 'year', 'year', 'AVERAGE',
-	      gettext('Year') + ' (' + gettext('average') + ')' ],
-	    [ 'yearmax', 'year', 'MAX',
-	      gettext('Year') + ' (' + gettext('maximum') + ')' ]
-	]
-    },
-    // save current selection in the state Provider so RRDView can read it
-    getState: function() {
-	var ind = this.getStore().findExact('id', this.getValue());
-	var rec = this.getStore().getAt(ind);
-	if (!rec) {
-	    return;
-	}
-	return {
-	    id: rec.data.id,
-	    timeframe: rec.data.timeframe,
-	    cf: rec.data.cf
-	};
-    },
-    // set selection based on last saved state
-    applyState : function(state) {
-	if (state && state.id) {
-	    this.setValue(state.id);
-	}
-    }
-});
-Ext.define('Proxmox.form.BondModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-
-    openvswitch: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.openvswitch) {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-	       'active-backup',
-	       'balance-slb',
-	       'lacp-balance-slb',
-	       'lacp-balance-tcp',
-	    ]);
-	} else {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-		'balance-rr',
-		'active-backup',
-		'balance-xor',
-		'broadcast',
-		'802.3ad',
-		'balance-tlb',
-		'balance-alb',
-	    ]);
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('Proxmox.form.BondPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-    comboItems: [
-	    ['layer2', 'layer2'],
-	    ['layer2+3', 'layer2+3'],
-	    ['layer3+4', 'layer3+4']
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelectorController', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.proxmoxNetworkSelectorController',
-
-    init: function(view) {
-	var me = this;
-
-	if (!view.nodename) {
-	    throw "missing custom view config: nodename";
-	}
-	view.getStore().getProxy().setUrl('/api2/json/nodes/'+ view.nodename + '/network');
-    }
-});
-
-Ext.define('Proxmox.data.NetworkSelector', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{name: 'active'},
-	{name: 'cidr'},
-	{name: 'cidr6'},
-	{name: 'address'},
-	{name: 'address6'},
-	{name: 'comments'},
-	{name: 'iface'},
-	{name: 'slaves'},
-	{name: 'type'}
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.proxmoxNetworkSelector',
-
-    controller: 'proxmoxNetworkSelectorController',
-
-    nodename: 'localhost',
-    setNodename: function(nodename) {
-	this.nodename = nodename;
-	var networkSelectorStore = this.getStore();
-	networkSelectorStore.removeAll();
-	// because of manual local copy of data for ip4/6
-	this.getPicker().refresh();
-	if (networkSelectorStore && typeof networkSelectorStore.getProxy === 'function') {
-	    networkSelectorStore.getProxy().setUrl('/api2/json/nodes/'+ nodename + '/network');
-	    networkSelectorStore.load();
-	}
-    },
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'cidr',
-    displayField: 'cidr',
-    store: {
-	autoLoad: true,
-	model: 'Proxmox.data.NetworkSelector',
-	proxy: {
-	    type: 'proxmox'
-	},
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	],
-	filters: [
-	    function(item) {
-		return item.data.cidr;
-	    }
-	],
-	listeners: {
-	    load: function(store, records, successfull) {
-
-		if (successfull) {
-		    records.forEach(function(record) {
-			if (record.data.cidr6) {
-			    let dest = (record.data.cidr) ? record.copy(null) : record;
-			    dest.data.cidr = record.data.cidr6;
-			    dest.data.address = record.data.address6;
-			    delete record.data.cidr6;
-			    dest.data.comments = record.data.comments6;
-			    delete record.data.comments6;
-			    store.add(dest);
-			}
-		    });
-		}
-	    }
-	}
-    },
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-
-		header: gettext('CIDR'),
-		dataIndex: 'cidr',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-
-		header: gettext('IP'),
-		dataIndex: 'address',
-		hidden: true,
-	    },
-	    {
-		header: gettext('Interface'),
-		width: 90,
-		dataIndex: 'iface'
-	    },
-	    {
-		header: gettext('Active'),
-		renderer: Proxmox.Utils.format_boolean,
-		width: 60,
-		dataIndex: 'active'
-	    },
-	    {
-		header: gettext('Type'),
-		width: 80,
-		hidden: true,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 2,
-		dataIndex: 'comments'
-	    }
-	]
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('Proxmox.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.proxmoxButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-
-	    // Note: me.realHandler may be a string (see named scopes)
-	    var realHandler = me.handler;
-
-	    me.handler = function(button, event) {
-		var rec, msg;
-		if (me.selModel) {
-		    rec = me.selModel.getSelection()[0];
-		    if (!rec || (me.enableFn(rec) === false)) {
-			return;
-		    }
-		}
-
-		if (me.confirmMsg) {
-		    msg = me.confirmMsg;
-		    if (Ext.isFunction(me.confirmMsg)) {
-			msg = me.confirmMsg(rec);
-		    }
-		    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		    Ext.Msg.show({
-			title: gettext('Confirm'),
-			icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-			msg: msg,
-			buttons: Ext.Msg.YESNO,
-			defaultFocus: me.dangerous ? 'no' : 'yes',
-			callback: function(btn) {
-			    if (btn !== 'yes') {
-				return;
-			    }
-			    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-			}
-		    });
-		} else {
-		    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-		}
-	    };
-	}
-
-	me.callParent();
-
-	var grid;
-	if (!me.selModel && me.selModel !== null) {
-	    grid = me.up('grid');
-	    if (grid && grid.selModel) {
-		me.selModel = grid.selModel;
-	    }
-	}
-
-	if (me.waitMsgTarget === true) {
-	    grid = me.up('grid');
-	    if (grid) {
-		me.waitMsgTarget = grid;
-	    } else {
-		throw "unable to find waitMsgTarget";
-	    }
-	}
-	
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else  {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-
-
-Ext.define('Proxmox.button.StdRemoveButton', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.proxmoxStdRemoveButton',
-
-    text: gettext('Remove'),
-
-    disabled: true,
-
-    config: {
-	baseurl: undefined
-    },
-
-    getUrl: function(rec) {
-	var me = this;
-	
-	return me.baseurl + '/' + rec.getId();
-    },
-
-    // also works with names scopes
-    callback: function(options, success, response) {},
-
-    getRecordName: function(rec) { return rec.getId() },
-
-    confirmMsg: function (rec) {
-	var me = this;
-
-	var name = me.getRecordName(rec);
-	return Ext.String.format(
-	    gettext('Are you sure you want to remove entry {0}'),
-	    "'" + name + "'");
-    },
-
-    handler: function(btn, event, rec) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.getUrl(rec),
-	    method: 'DELETE',
-	    waitMsgTarget: me.waitMsgTarget,
-	    callback: function(options, success, response) {
-		Ext.callback(me.callback, me.scope, [options, success, response], 0, me);
-	    },
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-/* help button pointing to an online documentation
-   for components contained in a modal window
-*/
-/*global
-  proxmoxOnlineHelpInfo
-*/
-Ext.define('Proxmox.button.Help', {
-    extend: 'Ext.button.Button',
-    xtype: 'proxmoxHelpButton',
-
-    text: gettext('Help'),
-
-    // make help button less flashy by styling it like toolbar buttons
-    iconCls: ' x-btn-icon-el-default-toolbar-small fa fa-question-circle',
-    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-
-    hidden: true,
-
-    listenToGlobalEvent: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	listen: {
-	    global: {
-		proxmoxShowHelp: 'onProxmoxShowHelp',
-		proxmoxHideHelp: 'onProxmoxHideHelp'
-	    }
-	},
-	onProxmoxShowHelp: function(helpLink) {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.setOnlineHelp(helpLink);
-		me.show();
-	    }
-	},
-	onProxmoxHideHelp: function() {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.hide();
-	    }
-	}
-    },
-
-    // this sets the link and the tooltip text
-    setOnlineHelp:function(blockid) {
-	var me = this;
-
-	var info = Proxmox.Utils.get_help_info(blockid);
-	if (info) {
-	    me.onlineHelp = blockid;
-	    var title = info.title;
-	    if (info.subtitle) {
-		title += ' - ' + info.subtitle;
-	    }
-	    me.setTooltip(title);
-	}
-    },
-
-    // helper to set the onlineHelp via a config object
-    setHelpConfig: function(config) {
-	var me = this;
-	me.setOnlineHelp(config.onlineHelp);
-    },
-
-    handler: function() {
-	var me = this;
-	var docsURI;
-
-	if (me.onlineHelp) {
-	    docsURI = Proxmox.Utils.get_help_link(me.onlineHelp);
-	}
-
-	if (docsURI) {
-	    window.open(docsURI);
-	} else {
-	    Ext.Msg.alert(gettext('Help'), gettext('No Help available'));
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-	var me = this;
-
-	me.callParent();
-
-	if  (me.onlineHelp) {
-	    me.setOnlineHelp(me.onlineHelp); // set tooltip
-	}
-    }
-});
-/* Renders a list of key values objets
-
-mandatory config parameters:
-rows: an object container where each propery is a key-value object we want to render
-       var rows = {
-           keyboard: {
-               header: gettext('Keyboard Layout'),
-               editor: 'Your.KeyboardEdit',
-               required: true
-           },
-
-optional:
-disabled: setting this parameter to true will disable selection and focus on the
-proxmoxObjectGrid as well as greying out input elements.
-Useful for a readonly tabular display
-
-*/
-
-Ext.define('Proxmox.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.proxmoxObjectGrid'],
-    disabled: false,
-    hideHeaders: true,
-
-    monStoreErrors: false,
-
-    add_combobox_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxKVComboBox',
-		    name: name,
-		    comboItems: opts.comboItems,
-		    value: opts.defaultValue,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_text_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxtextfield',
-		    name: name,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    vtype: opts.vtype,
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_boolean_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue || 0,
-	    header: text,
-	    renderer: opts.renderer || Proxmox.Utils.format_boolean,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxcheckbox',
-		    name: name,
-		    uncheckedValue: 0,
-		    defaultValue: opts.defaultValue  || 0,
-		    checked: opts.defaultValue ? true : false,
-		    deleteDefaultValue: opts.deleteDefaultValue ? true : false,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_integer_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {}
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxintegerfield',
-		    name: name,
-		    minValue: opts.minValue,
-		    maxValue: opts.maxValue,
-		    emptyText: gettext('Default'),
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    value: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    editorConfig: {}, // default config passed to editor
-
-    run_editor: function() {
-	var me = this;
-
-	var sm = me.getSelectionModel();
-	var rec = sm.getSelection()[0];
-	if (!rec) {
-	    return;
-	}
-
-	var rows = me.rows;
-	var rowdef = rows[rec.data.key];
-	if (!rowdef.editor) {
-	    return;
-	}
-
-	var win;
-	var config;
-	if (Ext.isString(rowdef.editor)) {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    win = Ext.create(rowdef.editor, config);
-	} else {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    Ext.apply(config, rowdef.editor);
-	    win = Ext.createWidget(rowdef.editor.xtype, config);
-	    win.load();
-	}
-
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    getObjectValue: function(key, defaultValue) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-	return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-	var renderer = rowdef.renderer;
-	if (renderer) {
-	    return renderer(value, metaData, record, rowIndex, colIndex, store);
-	}
-
-	return value;
-    },
-
-    listeners: {
-	itemkeydown: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER) {
-		this.pressedIndex = index;
-	    }
-	},
-	itemkeyup: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER && index == this.pressedIndex) {
-		this.run_editor();
-	    }
-
-	    this.pressedIndex = undefined;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	var rstore = me.rstore;
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore,
-	    sorters: [],
-	    filters: []
-	});
-
-	if (rows) {
-	    Ext.Object.each(rows, function(key, rowdef) {
-		if (Ext.isDefined(rowdef.defaultValue)) {
-		    store.add({ key: key, value: rowdef.defaultValue });
-		} else if (rowdef.required) {
-		    store.add({ key: key, value: undefined });
-		}
-	    });
-	}
-
-	if (me.sorterFn) {
-	    store.sorters.add(Ext.create('Ext.util.Sorter', {
-		sorterFn: me.sorterFn
-	    }));
-	}
-
-	store.filters.add(Ext.create('Ext.util.Filter', {
-	    filterFn: function(item) {
-		if (rows) {
-		    var rowdef = rows[item.data.key];
-		    if (!rowdef || (rowdef.visible === false)) {
-			return false;
-		    }
-		}
-		return true;
-	    }
-	}));
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.applyIf(me, {
-	    store: store,
-	    stateful: false,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: me.cwidth1 || 200,
-		    dataIndex: 'key',
-		    renderer: me.renderKey
-		},
-		{
-		    flex: 1,
-		    header: gettext('Value'),
-		    dataIndex: 'value',
-		    renderer: me.renderValue
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.monStoreErrors) {
-	    Proxmox.Utils.monStoreErrors(me, me.store);
-	}
-   }
-});
-Ext.define('Proxmox.grid.PendingObjectGrid', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxPendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    var value = rec.data.value;
-	    if (pending) {
-		if (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') {
-		    value = rec.data.pending;
-		} else if (rec.data['delete'] === 1) {
-		    value = defaultValue;
-		}
-	    }
-
-            if (Ext.isDefined(value) && (value !== '')) {
-		return value;
-            } else {
-		return defaultValue;
-            }
-	}
-	return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var keys = rowdef.multiKey ||  [ key ];
-	var pending = false;
-
-	Ext.Array.each(keys, function(k) {
-	    var rec = me.store.getById(k);
-	    if (rec && rec.data && (
-		    (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') ||
-		    rec.data['delete'] === 1
-	    )) {
-		pending = true;
-		return false; // break
-	    }
-	});
-
-	return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var renderer = rowdef.renderer;
-	var current = '';
-	var pendingdelete = '';
-	var pending = '';
-
-	if (renderer) {
-	    current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-	    if (me.hasPendingChanges(key)) {
-		pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-	    }
-	    if (pending == current) {
-		pending = undefined;
-	    }
-	} else {
-	    current = value || '';
-	    pending = record.data.pending;
-	}
-
-	if (record.data['delete']) {
-	    var delete_all = true;
-	    if (rowdef.multiKey) {
-		Ext.Array.each(rowdef.multiKey, function(k) {
-		    var rec = me.store.getById(k);
-		    if (rec && rec.data && rec.data['delete'] !== 1) {
-			delete_all = false;
-			return false; // break
-		    }
-		});
-	    }
-	    if (delete_all) {
-		pending = '<div style="text-decoration: line-through;">'+ current +'</div>';
-	    }
-	}
-
-	if (pending) {
-	    return current + '<div style="color:red">' + pending + '</div>';
-	} else {
-	    return current;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		model: 'KeyValuePendingDelete',
-		readArray: true,
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('Proxmox.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-    listeners: {
-	activate: function() {
-	    // notify owning container that it should display a help button
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-	    }
-	},
-	deactivate: function() {
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-	    }
-	}
-    },
-    border: false,
-
-    // override this with an URL to a relevant chapter of the pve manual
-    // setting this will display a help button in our parent panel
-    onlineHelp: undefined,
-
-    // will be set if the inputpanel has advanced items
-    hasAdvanced: false,
-
-    // if the panel has advanced items,
-    // this will determine if they are shown by default
-    showAdvanced: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-	return values;
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-	if (Ext.isFunction(me.onGetValues)) {
-	    dirtyOnly = false;
-	}
-
-	var values = {};
-
-	Ext.Array.each(me.query('[isFormField]'), function(field) {
-            if (!dirtyOnly || field.isDirty()) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-	    }
-	});
-
-	return me.onGetValues(values);
-    },
-
-    setAdvancedVisible: function(visible) {
-	var me = this;
-	var advItems = me.getComponent('advancedContainer');
-	if (advItems) {
-	    advItems.setVisible(visible);
-	}
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-	    var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-		field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var items;
-
-	if (me.items) {
-	    me.columns = 1;
-	    items = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.items
-		}
-	    ];
-	    me.items = undefined;
-	} else if (me.column4) {
-	    me.columns = 4;
-	    items = [
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column2
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column3
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column4
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else if (me.column1) {
-	    me.columns = 2;
-	    items = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column2 || [] // allow empty column
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else {
-	    throw "unsupported config";
-	}
-
-	var advItems;
-	if (me.advancedItems) {
-	    advItems = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.advancedItems
-		}
-	    ];
-	    me.advancedItems = undefined;
-	} else if (me.advancedColumn1) {
-	    advItems = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumn1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.advancedColumn2 || [] // allow empty column
-		}
-	    ];
-
-	    me.advancedColumn1 = undefined;
-	    me.advancedColumn2 = undefined;
-
-	    if (me.advancedColumnB) {
-		advItems.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumnB
-		});
-		me.advancedColumnB = undefined;
-	    }
-	}
-
-	if (advItems) {
-	    me.hasAdvanced = true;
-	    advItems.unshift({
-		columnWidth: 1,
-		xtype: 'box',
-		hidden: false,
-		border: true,
-		autoEl: {
-		    tag: 'hr'
-		}
-	    });
-	    items.push({
-		columnWidth: 1,
-		xtype: 'container',
-		itemId: 'advancedContainer',
-		hidden: !me.showAdvanced,
-		layout: 'column',
-		defaults: {
-		    border: false
-		},
-		items: advItems
-	    });
-	}
-
-	if (me.useFieldContainer) {
-	    Ext.apply(me, {
-		layout: 'fit',
-		items: Ext.apply(me.useFieldContainer, {
-		    layout: 'column',
-		    defaultType: 'container',
-		    items: items
-		})
-	    });
-	} else {
-	    Ext.apply(me, {
-		layout: 'column',
-		defaultType: 'container',
-		items: items
-	    });
-	}
-
-	me.callParent();
-    }
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxLogView',
-
-    pageSize: 500,
-    viewBuffer: 50,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    // callback for load failure, used for ceph
-    failCallback: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-	    if (viewModel.get('hide_timespan')) {
-		return;
-	    }
-
-	    if (since > until) {
-		Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
-		return;
-	    }
-
-	    viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
-	    viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
-	    me.getView().loadTask.delay(200);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	updateView: function(text, first, total) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    var content = me.lookup('content');
-	    var data = viewModel.get('data');
-
-	    if (first === data.first && total === data.total && text.length === data.textlen) {
-		return; // same content, skip setting and scrolling
-	    }
-	    viewModel.set('data', {
-		first: first,
-		total: total,
-		textlen: text.length
-	    });
-
-	    var scrollPos = me.scrollPosBottom();
-
-	    content.update(text);
-
-	    if (view.scrollToEnd && scrollPos <= 0) {
-		// we use setTimeout to work around scroll handling on touchscreens
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    }
-	},
-
-	doLoad: function() {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    Proxmox.Utils.API2Request({
-		url: me.getView().url,
-		params: viewModel.get('params'),
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var total = response.result.total;
-		    var lines = new Array();
-		    var first = Infinity;
-
-		    Ext.Array.each(response.result.data, function(line) {
-			if (first > line.n) {
-			    first = line.n;
-			}
-			lines[line.n - 1] = Ext.htmlEncode(line.t);
-		    });
-
-		    lines.length = total;
-		    me.updateView(lines.join('<br>'), first - 1, total);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    if (view.failCallback) {
-			view.failCallback(response);
-		    } else {
-			var msg = response.htmlStatus;
-			Proxmox.Utils.setErrorMask(me, msg);
-		    }
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-
-	    var lineHeight = view.lineHeight;
-	    var line = view.getScrollY()/lineHeight;
-	    var start = viewModel.get('params.start');
-	    var limit = viewModel.get('params.limit');
-	    var viewLines = view.getHeight()/lineHeight;
-
-	    var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
-	    var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
-
-	    if (viewStart < start || viewEnd > (start+limit)) {
-		viewModel.set('params.start',
-		    Math.max(parseInt(line - limit/2 + 10, 10), 0));
-		view.loadTask.delay(200);
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    viewModel.set('params.limit', view.pageSize);
-	    viewModel.set('hide_timespan', !view.log_select_timespan);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200);
-		    }
-		},
-		interval: 1000
-	    });
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    until: null,
-	    since: null,
-	    hide_timespan: false,
-	    data: {
-		start: 0,
-		total: 0,
-		textlen: 0
-	    },
-	    params: {
-		start: 0,
-		limit: 500,
-	    }
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-	bind: {
-	    hidden: '{hide_timespan}'
-	},
-	items: [
-	    '->',
-	    'Since: ',
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    'Until: ',
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		handler: 'updateParams'
-	    }
-	],
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.JournalView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxJournalView',
-
-    numEntries: 500,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-
-	    since.setHours(0, 0, 0, 0);
-	    until.setHours(0, 0, 0, 0);
-	    until.setDate(until.getDate()+1);
-
-	    me.getView().loadTask.delay(200, undefined, undefined, [
-		false,
-		false,
-		Ext.Date.format(since, "U"),
-		Ext.Date.format(until, "U")
-	    ]);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	scrollPosTop: function() {
-	    var view = this.getView();
-	    return view.getScrollY();
-	},
-
-	updateScroll: function(livemode, num, scrollPos, scrollPosTop) {
-	    var me = this;
-	    var view = me.getView();
-
-	    if (!livemode) {
-		setTimeout(function() { view.scrollTo(0, 0); }, 10);
-	    } else if (view.scrollToEnd && scrollPos <= 0) {
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    } else if (!view.scrollToEnd && scrollPosTop < 20*view.lineHeight) {
-		setTimeout(function() { view.scrollTo(0, num*view.lineHeight + scrollPosTop); }, 10);
-	    }
-	},
-
-	updateView: function(lines, livemode, top) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    if (viewmodel.get('livemode') !== livemode) {
-		return; // we switched mode, do not update the content
-	    }
-	    var contentEl = me.lookup('content');
-
-	    // save old scrollpositions
-	    var scrollPos = me.scrollPosBottom();
-	    var scrollPosTop = me.scrollPosTop();
-
-	    var newend = lines.shift();
-	    var newstart = lines.pop();
-
-	    var num = lines.length;
-	    var text = lines.map(Ext.htmlEncode).join('<br>');
-
-	    if (!livemode) {
-		if (num) {
-		    view.content = text;
-		} else {
-		    view.content = 'nothing logged or no timespan selected';
-		}
-	    } else {
-		// update content
-		if (top && num) {
-		    view.content = view.content ? text + '<br>' + view.content : text;
-		} else if (!top && num) {
-		    view.content = view.content ? view.content + '<br>' + text : text;
-		}
-
-		// update cursors
-		if (!top || !view.startcursor) {
-		    view.startcursor = newstart;
-		}
-
-		if (top || !view.endcursor) {
-		    view.endcursor = newend;
-		}
-	    }
-
-	    contentEl.update(view.content);
-
-	    me.updateScroll(livemode, num, scrollPos, scrollPosTop);
-	},
-
-	doLoad: function(livemode, top, since, until) {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var params = {
-		lastentries: view.numEntries || 500,
-	    };
-	    if (livemode) {
-		if (!top && view.startcursor) {
-		    params = {
-			startcursor: view.startcursor
-		    };
-		} else if (view.endcursor) {
-		    params.endcursor = view.endcursor;
-		}
-	    } else {
-		params = {
-		    since: since,
-		    until: until
-		};
-	    }
-	    Proxmox.Utils.API2Request({
-		url: view.url,
-		params: params,
-		waitMsgTarget: (!livemode) ? view : undefined,
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var lines = response.result.data;
-		    me.updateView(lines, livemode, top);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    var msg = response.htmlStatus;
-		    Proxmox.Utils.setErrorMask(me, msg);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    var livemode = viewmodel.get('livemode');
-	    if (!livemode) {
-		return;
-	    }
-
-	    if (me.scrollPosTop() < 20*view.lineHeight) {
-		view.scrollToEnd = false;
-		view.loadTask.delay(200, undefined, undefined, [true, true]);
-	    } else if (me.scrollPosBottom() <= 1) {
-		view.scrollToEnd = true;
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewmodel = me.getViewModel();
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me, [true, false]);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd || !viewmodel.get('livemode')) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200, undefined, undefined, [true, false]);
-		    }
-		},
-		interval: 1000
-	    });
-	},
-
-	onLiveMode: function() {
-	    var me = this;
-	    var view = me.getView();
-	    delete view.startcursor;
-	    delete view.endcursor;
-	    delete view.content;
-	    me.getViewModel().set('livemode', true);
-	    view.scrollToEnd = true;
-	    me.updateView([], true, false);
-	},
-
-	onTimespan: function() {
-	    var me = this;
-	    me.getViewModel().set('livemode', false);
-	    me.updateView([], false);
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-	delete me.content;
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    livemode: true,
-	    until: null,
-	    since: null
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-
-	items: [
-	    '->',
-	    {
-		xtype: 'segmentedbutton',
-		items: [
-		    {
-			text: gettext('Live Mode'),
-			bind: {
-			    pressed: '{livemode}'
-			},
-			handler: 'onLiveMode',
-		    },
-		    {
-			text: gettext('Select Timespan'),
-			bind: {
-			    pressed: '{!livemode}'
-			},
-			handler: 'onTimespan',
-		    }
-		]
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Since') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Until') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		reference: 'updateBtn',
-		handler: 'updateParams',
-		bind: {
-		    disabled: '{livemode}'
-		}
-	    }
-	]
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-Ext.define('Proxmox.widget.RRDChart', {
-    extend: 'Ext.chart.CartesianChart',
-    alias: 'widget.proxmoxRRDChart',
-
-    unit: undefined, // bytes, bytespersecond, percent
-    
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	convertToUnits: function(value) {
-	    var units = ['', 'k','M','G','T', 'P'];
-	    var si = 0;
-	    while(value >= 1000  && si < (units.length -1)){
-		value = value / 1000;
-		si++;
-	    }
-
-	    // javascript floating point weirdness
-	    value = Ext.Number.correctFloat(value);
-	    
-	    // limit to 2 decimal points
-	    value = Ext.util.Format.number(value, "0.##");
-	    
-	    return value.toString() + " " + units[si];
-	},
-
-	leftAxisRenderer: function(axis, label, layoutContext) {
-	    var me = this;
-
-	    return me.convertToUnits(label);
-	},
-
-	onSeriesTooltipRender: function(tooltip, record, item) {
-	    var me = this.getView();
-	    
-	    var suffix = '';
-	    
-	    if (me.unit === 'percent') {
-		suffix = '%';
-	    } else if (me.unit === 'bytes') {
-		suffix = 'B';
-	    } else if (me.unit === 'bytespersecond') {
-		suffix = 'B/s';
-	    }
-	    
-	    var prefix = item.field;
-	    if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
-		prefix = me.fieldTitles[me.fields.indexOf(item.field)];
-	    }
-            tooltip.setHtml(prefix + ': ' + this.convertToUnits(record.get(item.field)) + suffix +
-			    '<br>' + new Date(record.get('time')));
-	},
-
-	onAfterAnimation: function(chart, eopts) {
-	    // if the undobuton is disabled,
-	    // disable our tool
-
-	    var ourUndoZoomButton = chart.tools[0];
-	    var undoButton = chart.interactions[0].getUndoButton();
-	    ourUndoZoomButton.setDisabled(undoButton.isDisabled());
-	}
-    },
-    
-    width: 770,
-    height: 300,
-    animation: false,
-    interactions: [{
-	type: 'crosszoom'
-    }],
-    axes: [{
-	type: 'numeric',
-	position: 'left',
-	grid: true,
-	renderer: 'leftAxisRenderer',
-	//renderer: function(axis, label) { return label; },
-	minimum: 0
-    }, {
-	type: 'time',
-	position: 'bottom',
-	grid: true,
-	fields: ['time']
-    }],
-    legend: {
-	docked: 'bottom'
-    },
-    listeners: {
-	animationend: 'onAfterAnimation'
-    },
-
-
-    initComponent: function() {
-	var me = this;
-	var series = {};
-
-	if (!me.store) {
-	    throw "cannot work without store";
-	}
-
-	if (!me.fields) {
-	    throw "cannot work without fields";
-	}
-
-	me.callParent();
-
-	// add correct label for left axis
-	var axisTitle = "";
-	if (me.unit === 'percent') {
-	    axisTitle = "%";
-	} else if (me.unit === 'bytes') {
-	    axisTitle = "Bytes";
-	} else if (me.unit === 'bytespersecond') {
-	    axisTitle = "Bytes/s";
-	} else if (me.fieldTitles && me.fieldTitles.length === 1) {
-	    axisTitle = me.fieldTitles[0];
-	} else if (me.fields.length === 1) {
-	    axisTitle = me.fields[0];
-	}
-
-	me.axes[0].setTitle(axisTitle);
-
-	if (!me.noTool) {
-	    me.addTool([{
-		type: 'minus',
-		disabled: true,
-		tooltip: gettext('Undo Zoom'),
-		handler: function(){
-		    var undoButton = me.interactions[0].getUndoButton();
-		    if (undoButton.handler) {
-			undoButton.handler();
-		    }
-		}
-	    },{
-		type: 'restore',
-		tooltip: gettext('Toggle Legend'),
-		handler: function(){
-		    if (me.legend) {
-			me.legend.setVisible(!me.legend.isVisible());
-		    }
-		}
-	    }]);
-	}
-
-	// add a series for each field we get
-	me.fields.forEach(function(item, index){
-	    var title = item;
-	    if (me.fieldTitles && me.fieldTitles[index]) {
-		title = me.fieldTitles[index];
-	    }
-	    me.addSeries(Ext.apply(
-		{
-		    type: 'line',
-		    xField: 'time',
-		    yField: item,
-		    title: title,
-		    fill: true,
-		    style: {
-			lineWidth: 1.5,
-			opacity: 0.60
-		    },
-		    marker: {
-			opacity: 0,
-			scaling: 0.01,
-			fx: {
-			    duration: 200,
-			    easing: 'easeOut'
-			}
-		    },
-		    highlightCfg: {
-			opacity: 1,
-			scaling: 1.5
-		    },
-		    tooltip: {
-			trackMouse: true,
-			renderer: 'onSeriesTooltipRender'
-		    }
-		},
-		me.seriesConfig
-	    ));
-	});
-
-	// enable animation after the store is loaded
-	me.store.onAfter('load', function() {
-	    me.setAnimation(true);
-	}, this, {single: true});
-    }
-});
-Ext.define('Proxmox.panel.GaugeWidget', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.proxmoxGauge',
-
-    defaults: {
-	style: {
-	    'text-align':'center'
-	}
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	},
-	{
-	    xtype: 'polar',
-	    height: 120,
-	    border: false,
-	    itemId: 'chart',
-	    series: [{
-		type: 'gauge',
-		value: 0,
-		colors: ['#f5f5f5'],
-		sectors: [0],
-		donut: 90,
-		needleLength: 100,
-		totalAngle: Math.PI
-	    }],
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '',
-		textAlign: 'center',
-		textBaseline: 'bottom',
-		x: 125,
-		y: 110,
-		fontSize: 30
-	    }]
-	},
-	{
-	    xtype: 'box',
-	    itemId: 'text'
-	}
-    ],
-
-    header: false,
-    border: false,
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-    warningColor: '#fc0',
-    criticalColor: '#FF6C59',
-    defaultColor: '#7289DA',
-    backgroundColor: '#2C2F33',
-
-    initialValue: 0,
-
-
-    updateValue: function(value, text) {
-	var me = this;
-	var color = me.defaultColor;
-	var attr = {};
-
-	if (value >= me.criticalThreshold) {
-	    color = me.criticalColor;
-	} else if (value >= me.warningThreshold) {
-	    color = me.warningColor;
-	}
-
-	me.chart.series[0].setColors([color, me.backgroundColor]);
-	me.chart.series[0].setValue(value*100);
-
-	me.valueSprite.setText(' '+(value*100).toFixed(0) + '%');
-	attr.x = me.chart.getWidth()/2;
-	attr.y = me.chart.getHeight()-20;
-	if (me.spriteFontSize) {
-	    attr.fontSize = me.spriteFontSize;
-	}
-	me.valueSprite.setAttributes(attr, true);
-
-	if (text !== undefined) {
-	    me.text.setHtml(text);
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.text = me.getComponent('text');
-	me.chart = me.getComponent('chart');
-	me.valueSprite = me.chart.getSurface('chart').get('valueSprite');
-    }
-});
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('Proxmox.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxWindowEdit',
-
-    // autoLoad trigger a load() after component creation
-    autoLoad: false,
-
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set isCreate to true if you want a Create button (instead
-    // OK and RESET)
-    isCreate: false,
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    // custom submitText
-    submitText: undefined,
-
-    backgroundDelay: 0,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-
-    // finds the first form field
-    defaultFocus: 'field[disabled=false][hidden=false]',
-
-    showProgress: false,
-
-    showTaskViewer: false,
-
-    // gets called if we have a progress bar or taskview and it detected that
-    // the task finished. function(success)
-    taskDone: Ext.emptyFn,
-
-    // gets called when the api call is finished, right at the beginning
-    // function(success, response, options)
-    apiCallDone: Ext.emptyFn,
-
-    // assign a reference from docs, to add a help button docked to the
-    // bottom of the window. If undefined we magically fall back to the
-    // onlineHelp of our first item, if set.
-    onlineHelp: undefined,
-
-    isValid: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-	return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	Ext.iterate(values, function(fieldId, val) {
-	    var field = form.findField(fieldId);
-	    if (field && !field.up('inputpanel')) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setValues(values);
-	});
-    },
-
-    submit: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	var values = me.getValues();
-	Ext.Object.each(values, function(name, val) {
-	    if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-		    values[name] = '';
-		}
-	    }
-	});
-
-	if (me.digest) {
-	    values.digest = me.digest;
-	}
-
-	if (me.backgroundDelay) {
-	    values.background_delay = me.backgroundDelay;
-	}
-
-	var url =  me.url;
-	if (me.method === 'DELETE') {
-	    url = url + "?" + Ext.Object.toQueryString(values);
-	    values = undefined;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    waitMsgTarget: me,
-	    method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-	    params: values,
-	    failure: function(response, options) {
-		me.apiCallDone(false, response, options);
-
-		if (response.result && response.result.errors) {
-		    form.markInvalid(response.result.errors);
-		}
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var hasProgressBar = (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
-		    response.result.data ? true : false;
-
-		me.apiCallDone(true, response, options);
-
-		if (hasProgressBar) {
-		    // stay around so we can trigger our close events
-		    // when background action is completed
-		    me.hide();
-
-		    var upid = response.result.data;
-		    var viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
-		    var win = Ext.create('Proxmox.window.Task' + viewerClass, {
-			upid: upid,
-			taskDone: me.taskDone,
-			listeners: {
-			    destroy: function () {
-				me.close();
-			    }
-			}
-		    });
-		    win.show();
-		} else {
-		    me.close();
-		}
-	    }
-	});
-    },
-
-    load: function(options) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	options = options || {};
-
-	var newopts = Ext.apply({
-	    waitMsgTarget: me
-	}, options);
-
-	var createWrapper = function(successFn) {
-	    Ext.apply(newopts, {
-		url: me.url,
-		method: 'GET',
-		success: function(response, opts) {
-		    form.clearInvalid();
-		    me.digest = response.result.data.digest;
-		    if (successFn) {
-			successFn(response, opts);
-		    } else {
-			me.setValues(response.result.data);
-		    }
-		    // hack: fix ExtJS bug
-		    Ext.Array.each(me.query('radiofield'), function(f) {
-			f.resetOriginalValue();
-		    });
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-			me.close();
-		    });
-		}
-	    });
-	};
-
-	createWrapper(options.success);
-
-	Proxmox.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.url) {
-	    throw "no url specified";
-	}
-
-	if (me.create) {throw "deprecated parameter, use isCreate";}
-
-	var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-	me.items = undefined;
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    url: me.url,
-	    method: me.method || 'PUT',
-	    trackResetOnLoad: true,
-	    bodyPadding: 10,
-	    border: false,
-	    defaults: Ext.apply({}, me.defaults, {
-		border: false
-	    }),
-	    fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-		labelWidth: 100,
-		anchor: '100%'
-            }),
-	    items: items
-	});
-
-	var inputPanel = me.formPanel.down('inputpanel');
-
-	var form = me.formPanel.getForm();
-
-	var submitText;
-	if (me.isCreate) {
-	    if (me.submitText) {
-		submitText = me.submitText;
-	    } else if (me.isAdd) {
-		submitText = gettext('Add');
-	    } else if (me.isRemove) {
-		submitText = gettext('Remove');
-	    } else {
-		submitText = gettext('Create');
-	    }
-	} else {
-	    submitText = me.submitText || gettext('OK');
-	}
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    reference: 'submitbutton',
-	    text: submitText,
-	    disabled: !me.isCreate,
-	    handler: function() {
-		me.submit();
-	    }
-	});
-
-	var resetBtn = Ext.create('Ext.Button', {
-	    text: 'Reset',
-	    disabled: true,
-	    handler: function(){
-		form.reset();
-	    }
-	});
-
-	var set_button_status = function() {
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-	    submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
-	    resetBtn.setDisabled(!dirty);
-
-	    if (inputPanel && inputPanel.hasAdvanced) {
-		// we want to show the advanced options
-		// as soon as some of it is not valid
-		var advancedItems = me.down('#advancedContainer').query('field');
-		var valid = true;
-		advancedItems.forEach(function(field) {
-		    if (!field.isValid()) {
-			valid = false;
-		    }
-		});
-
-		if (!valid) {
-		    inputPanel.setAdvancedVisible(true);
-		    me.down('#advancedcb').setValue(true);
-		}
-	    }
-	};
-
-	form.on('dirtychange', set_button_status);
-	form.on('validitychange', set_button_status);
-
-	var colwidth = 300;
-	if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-	    colwidth += me.fieldDefaults.labelWidth - 100;
-	}
-
-	var twoColumn = inputPanel &&
-	    (inputPanel.column1 || inputPanel.column2);
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
-	}
-
-	if (me.isCreate) {
-		me.buttons = [ submitBtn ] ;
-	} else {
-		me.buttons = [ submitBtn, resetBtn ];
-	}
-
-	if (inputPanel && inputPanel.hasAdvanced) {
-	    var sp = Ext.state.Manager.getProvider();
-	    var advchecked = sp.get('proxmox-advanced-cb');
-	    inputPanel.setAdvancedVisible(advchecked);
-	    me.buttons.unshift(
-	       {
-		   xtype: 'proxmoxcheckbox',
-		   itemId: 'advancedcb',
-		   boxLabelAlign: 'before',
-		   boxLabel: gettext('Advanced'),
-		   stateId: 'proxmox-advanced-cb',
-		   value: advchecked,
-		   listeners: {
-		       change: function(cb, val) {
-			   inputPanel.setAdvancedVisible(val);
-			   sp.set('proxmox-advanced-cb', val);
-		       }
-		   }
-	       }
-	    );
-	}
-
-	var onlineHelp = me.onlineHelp;
-	if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
-	    onlineHelp = inputPanel.onlineHelp;
-	}
-
-	if (onlineHelp) {
-	    var helpButton = Ext.create('Proxmox.button.Help');
-	    me.buttons.unshift(helpButton, '->');
-	    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
-	}
-
-	Ext.applyIf(me, {
-	    modal: true,
-	    width: twoColumn ? colwidth*2 : colwidth,
-	    border: false,
-	    items: [ me.formPanel ]
-	});
-
-	me.callParent();
-
-	// always mark invalid fields
-	me.on('afterlayout', function() {
-	    // on touch devices, the isValid function
-	    // triggers a layout, which triggers an isValid
-	    // and so on
-	    // to prevent this we disable the layouting here
-	    // and enable it afterwards
-	    me.suspendLayout = true;
-	    me.isValid();
-	    me.suspendLayout = false;
-	});
-
-	if (me.autoLoad) {
-	    me.load();
-	}
-    }
-});
-Ext.define('Proxmox.window.PasswordEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'proxmoxWindowPasswordEdit',
-
-    subject: gettext('Password'),
-
-    url: '/api2/extjs/access/password',
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    allowBlank: false,
-	    name: 'password',
-	    listeners: {
-                change: function(field){
-		    field.next().validate();
-                },
-                blur: function(field){
-		    field.next().validate();
-                }
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'),
-	    name: 'verifypassword',
-	    allowBlank: false,
-	    vtype: 'password',
-	    initialPassField: 'password',
-	    submitValue: false
-	},
-	{
-	    xtype: 'hiddenfield',
-	    name: 'userid'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	me.callParent();
-	me.down('[name=userid]').setValue(me.userid);
-    }
-});
-Ext.define('Proxmox.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskProgress',
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: {
-		status: { defaultValue: 'unknown' },
-		exitstatus: { defaultValue: 'unknown' }
-	    }
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var getObjectValue = function(key, defaultValue) {
-	    var rec = statstore.getById(key);
-	    if (rec) {
-		return rec.data.value;
-	    }
-	    return defaultValue;
-	};
-
-	var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-	me.mon(statstore, 'load', function() {
-	    var status = getObjectValue('status');
-	    if (status === 'stopped') {
-		var exitstatus = getObjectValue('exitstatus');
-		if (exitstatus == 'OK') {
-		    pbar.reset();
-		    pbar.updateText("Done!");
-		    Ext.Function.defer(me.close, 1000, me);
-		} else {
-		    me.close();
-		    Ext.Msg.alert('Task failed', exitstatus);
-		}
-		me.taskDone(exitstatus == 'OK');
-	    }
-	});
-
-	var descr = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	Ext.apply(me, {
-	    title: gettext('Task') + ': ' + descr,
-	    width: 300,
-	    layout: 'auto',
-	    modal: true,
-	    bodyPadding: 5,
-	    items: pbar,
-	    buttons: [
-		{ 
-		    text: gettext('Details'),
-		    handler: function() {			
-			var win = Ext.create('Proxmox.window.TaskViewer', { 
-			    taskDone: me.taskDone,
-			    upid: me.upid
-			});
-			win.show();
-			me.close();
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	statstore.startUpdate();
-
-	pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('Proxmox.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskViewer',
-
-    extraTitle: '', // string to prepend after the generic task title
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statgrid;
-
-	var rows = {
-	    status: {
-		header: gettext('Status'),
-		defaultValue: 'unknown',
-		renderer: function(value) {
-		    if (value != 'stopped') {
-			return value;
-		    }
-		    var es = statgrid.getObjectValue('exitstatus');
-		    if (es) {
-			return value + ': ' + es;
-		    }
-		}
-	    },
-	    exitstatus: { 
-		visible: false
-	    },
-	    type: {
-		header: gettext('Task type'),
-		required: true
-	    },
-	    user: {
-		header: gettext('User name'),
-		required: true 
-	    },
-	    node: {
-		header: gettext('Node'),
-		required: true 
-	    },
-	    pid: {
-		header: gettext('Process ID'),
-		required: true
-	    },
-	    starttime: {
-		header: gettext('Start Time'),
-		required: true, 
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    upid: {
-		header: gettext('Unique task ID')
-	    }
-	};
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: rows
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var stop_task = function() {
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + task.node + "/tasks/" + me.upid,
-		waitMsgTarget: me,
-		method: 'DELETE',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var stop_btn1 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	var stop_btn2 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	statgrid = Ext.create('Proxmox.grid.ObjectGrid', {
-	    title: gettext('Status'),
-	    layout: 'fit',
-	    tbar: [ stop_btn1 ],
-	    rstore: statstore,
-	    rows: rows,
-	    border: false
-	});
-
-	var logView = Ext.create('Proxmox.panel.LogView', {
-	    title: gettext('Output'),
-	    tbar: [ stop_btn2 ],
-	    border: false,
-	    url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-	});
-
-	me.mon(statstore, 'load', function() {
-	    var status = statgrid.getObjectValue('status');
-	    
-	    if (status === 'stopped') {
-		logView.scrollToEnd = false;
-		logView.requestUpdate();
-		statstore.stopUpdate();
-		me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
-	    }
-
-	    stop_btn1.setDisabled(status !== 'running');
-	    stop_btn2.setDisabled(status !== 'running');
-	});
-
-	statstore.startUpdate();
-
-	Ext.apply(me, {
-	    title: "Task viewer: " + task.desc + me.extraTitle,
-	    width: 800,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [{
-		xtype: 'tabpanel',
-		region: 'center',
-		items: [ logView, statgrid ]
-	    }]
-        });
-
-	me.callParent();
-
-	logView.fireEvent('show', logView);
-    }
-});
-
-Ext.define('apt-pkglist', {
-    extend: 'Ext.data.Model',
-    fields: [ 'Package', 'Title', 'Description', 'Section', 'Arch',
-	      'Priority', 'Version', 'OldVersion', 'ChangeLogUrl', 'Origin' ],
-    idProperty: 'Package'
-});
-
-Ext.define('Proxmox.node.APT', {
-    extend: 'Ext.grid.GridPanel',
-
-    xtype: 'proxmoxNodeAPT',
-
-    upgradeBtn: undefined,
-
-    columns: [
-	{
-	    header: gettext('Package'),
-	    width: 200,
-	    sortable: true,
-	    dataIndex: 'Package'
-	},
-	{
-	    text: gettext('Version'),
-	    columns: [
-		{
-		    header: gettext('current'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'OldVersion'
-		},
-		{
-		    header: gettext('new'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'Version'
-		}
-	    ]
-	},
-	{
-	    header: gettext('Description'),
-	    sortable: false,
-	    dataIndex: 'Title',
-	    flex: 1
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'apt-pkglist',
-	    groupField: 'Origin',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/apt/update"
-	    },
-	    sorters: [
-		{
-		    property : 'Package',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
-            groupHeaderTpl: '{[ "Origin: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
-	    enableGroupingMenu: false
-	});
-
-	var rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {
-            getAdditionalData: function (data, rowIndex, record, orig) {
-		var headerCt = this.view.headerCt;
-		var colspan = headerCt.getColumnCount();
-		return {
-		    rowBody: '<div style="padding: 1em">' +
-			Ext.String.htmlEncode(data.Description) +
-			'</div>',
-		    rowBodyCls: me.full_description ? '' : Ext.baseCSSPrefix + 'grid-row-body-hidden',
-		    rowBodyColspan: colspan
-		};
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	var apt_command = function(cmd){
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/apt/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.mon(win, 'close', reload);
-		}
-	    });
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var update_btn = new Ext.Button({
-	    text: gettext('Refresh'),
-	    handler: function() {
-		Proxmox.Utils.checked_command(function() { apt_command('update'); });
-	    }
-	});
-
-	var show_changelog = function(rec) {
-	    if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		return;
-	    }
-
-	    var view = Ext.createWidget('component', {
-		autoScroll: true,
-		style: {
-		    'background-color': 'white',
-		    'white-space': 'pre',
-		    'font-family': 'monospace',
-		    padding: '5px'
-		}
-	    });
-
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Changelog') + ": " + rec.data.Package,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		modal: true,
-		items: [ view ]
-	    });
-
-	    Proxmox.Utils.API2Request({
-		waitMsgTarget: me,
-		url: "/nodes/" + me.nodename + "/apt/changelog",
-		params: {
-		    name: rec.data.Package,
-		    version: rec.data.Version
-		},
-		method: 'GET',
-		failure: function(response, opts) {
-		    win.close();
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    win.show();
-		    view.update(Ext.htmlEncode(response.result.data));
-		}
-	    });
-
-	};
-
-	var changelog_btn = new Proxmox.button.Button({
-	    text: gettext('Changelog'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function(b, e, rec) {
-		show_changelog(rec);
-	    }
-	});
-
-	var verbose_desc_checkbox = new Ext.form.field.Checkbox({
-	    boxLabel: gettext('Show details'),
-	    value: false,
-	    listeners: {
-		change: (f, val) => {
-		    me.full_description = val;
-		    me.getView().refresh();
-		}
-	    }
-	});
-
-	if (me.upgradeBtn) {
-	    me.tbar =  [ update_btn, me.upgradeBtn, changelog_btn, '->', verbose_desc_checkbox ];
-	} else {
-	    me.tbar =  [ update_btn, changelog_btn, '->', verbose_desc_checkbox ];
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-update',
-	    selModel: sm,
-            viewConfig: {
-		stripeRows: false,
-		emptyText: '<div style="display:table; width:100%; height:100%;"><div style="display:table-cell; vertical-align: middle; text-align:center;"><b>' + gettext('No updates available.') + '</div></div>'
-	    },
-	    features: [ groupingFeature, rowBodyFeature ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: function(v, rec) {
-		    show_changelog(rec);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeNetworkEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.iftype) {
-	    throw "no network device type specified";
-	}
-
-	me.isCreate = !me.iface;
-
-	var iface_vtype;
-
-	if (me.iftype === 'bridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'bond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'eth' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'vlan' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSBridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'OVSBond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'OVSIntPort') {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSPort') {
-	    iface_vtype = 'InterfaceName';
-	} else {
-	    console.log(me.iftype);
-	    throw "unknown network device type specified";
-	}
-
-	me.subject = Proxmox.Utils.render_network_iface_type(me.iftype);
-
-	var column2 = [];
-
-	if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' ||
-	      me.iftype === 'OVSBond')) {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Autostart'),
-		name: 'autostart',
-		uncheckedValue: 0,
-		checked: me.isCreate ? true : undefined
-	    });
-	}
-
-	if (me.iftype === 'bridge') {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('VLAN aware'),
-		name: 'bridge_vlan_aware',
-		deleteEmpty: !me.isCreate
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'bridge_ports'
-	    });
-	} else if (me.iftype === 'OVSBridge') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'ovs_ports'
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'OVSPort' || me.iftype === 'OVSIntPort') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'bond') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Slaves'),
-		name: 'slaves'
-	    });
-
-	    var policySelector = Ext.createWidget('bondPolicySelector', {
-		fieldLabel: gettext('Hash policy'),
-		name: 'bond_xmit_hash_policy',
-		deleteEmpty: !me.isCreate,
-		disabled: true
-	    });
-
-	    column2.push({
-		xtype: 'bondModeSelector',
-		fieldLabel: gettext('Mode'),
-		name: 'bond_mode',
-		value: me.isCreate ? 'balance-rr' : undefined,
-		listeners: {
-		    change: function(f, value) {
-			if (value === 'balance-xor' ||
-			    value === '802.3ad') {
-			    policySelector.setDisabled(false);
-			} else {
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			}
-		    }
-		},
-		allowBlank: false
-	    });
-
-	    column2.push(policySelector);
-
-	} else if (me.iftype === 'OVSBond') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	}
-
-	column2.push({
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Comment'),
-	    allowBlank: true,
-	    nodename: me.nodename,
-	    name: 'comments'
-	});
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network";
-	    method = 'POST';
-	} else {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network/" + me.iface;
-	    method = 'PUT';
-	}
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: me.iftype
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		fieldLabel: gettext('Name'),
-		name: 'iface',
-		value: me.iface,
-		vtype: iface_vtype,
-		allowBlank: false
-	    }
-	];
-
-	if (me.iftype === 'OVSBond') {
-	    column1.push(
-		{
-		    xtype: 'bondModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    name: 'bond_mode',
-		    openvswitch: true,
-		    value: me.isCreate ? 'active-backup' : undefined,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Slaves'),
-		    name: 'ovs_bonds'
-		}
-	    );
-	} else {
-
-	    column1.push(
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv4/CIDR',
-		    vtype: 'IPCIDRAddress',
-		    name: 'cidr'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv4)',
-		    vtype: 'IPAddress',
-		    name: 'gateway'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv6/CIDR',
-		    vtype: 'IP6CIDRAddress',
-		    name: 'cidr6'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv6)',
-		    vtype: 'IP6Address',
-		    name: 'gateway6'
-		}
-	    );
-	}
-
-	Ext.applyIf(me, {
-	    url: url,
-	    method: method,
-	    items: {
-                xtype: 'inputpanel',
-		column1: column1,
-		column2: column2
-	    }
-	});
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.down('field[name=iface]').setValue(me.iface_default);
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.type !== me.iftype) {
-			var msg = "Got unexpected device type";
-			Ext.Msg.alert(gettext('Error'), msg, function() {
-			    me.close();
-			});
-			return;
-		    }
-		    me.setValues(data);
-		    me.isValid(); // trigger validation
-		}
-	    });
-	}
-    }
-});
-Ext.define('proxmox-networks', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'iface', 'type', 'active', 'autostart',
-	'bridge_ports', 'slaves',
-	'address', 'netmask', 'gateway',
-	'address6', 'netmask6', 'gateway6',
-	'cidr', 'cidr6',
-	'comments'
-    ],
-    idProperty: 'iface'
-});
-
-Ext.define('Proxmox.node.NetworkView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.proxmoxNodeNetworkView'],
-
-    // defines what types of network devices we want to create
-    // order is always the same
-    types: ['bridge', 'bond', 'ovs'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseUrl = '/nodes/' + me.nodename + '/network';
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'proxmox-networks',
-	    proxy: {
-                type: 'proxmox',
-                url: '/api2/json' + baseUrl
-	    },
-	    sorters: [
-		{
-		    property : 'iface',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reload = function() {
-	    var changeitem = me.down('#changes');
-	    Proxmox.Utils.API2Request({
-		url: baseUrl,
-		failure: function(response, opts) {
-		    store.loadData({});
-		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		    changeitem.update('');
-		    changeitem.setHidden(true);
-		},
-		success: function(response, opts) {
-		    var result = Ext.decode(response.responseText);
-		    store.loadData(result.data);
-		    var changes = result.changes;
-		    if (changes === undefined || changes === '') {
-			changes = gettext("No changes");
-			changeitem.setHidden(true);
-		    } else {
-			changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
-			changeitem.setHidden(false);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.node.NetworkEdit', {
-		nodename: me.nodename,
-		iface: rec.data.iface,
-		iftype: rec.data.type
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: run_editor
-	});
-
-	var del_btn = new Ext.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    handler: function(){
-		var grid = me.down('gridpanel');
-		var sm = grid.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var iface = rec.data.iface;
-
-		Proxmox.Utils.API2Request({
-		    url: baseUrl + '/' + iface,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var set_button_status = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    edit_btn.setDisabled(!rec);
-	    del_btn.setDisabled(!rec);
-	};
-
-	var render_ports = function(value, metaData, record) {
-	    if (value === 'bridge') {
-		return record.data.bridge_ports;
-	    } else if (value === 'bond') {
-		return record.data.slaves;
-	    } else if (value === 'OVSBridge') {
-		return record.data.ovs_ports;
-	    } else if (value === 'OVSBond') {
-		return record.data.ovs_bonds;
-	    }
-	};
-
-	var find_next_iface_id = function(prefix) {
-	    var next;
-	    for (next = 0; next <= 9999; next++) {
-		if (!store.getById(prefix + next.toString())) {
-		    break;
-		}
-	    }
-	    return prefix + next.toString();
-	};
-
-	var menu_items = [];
-
-	if (me.types.indexOf('bridge') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bridge'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bridge',
-			iface_default: find_next_iface_id('vmbr')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('bond') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bond'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bond',
-			iface_default: find_next_iface_id('bond')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('ovs') !== -1) {
-	    if (menu_items.length > 0) {
-		menu_items.push({ xtype: 'menuseparator' });
-	    }
-
-	    menu_items.push(
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBridge',
-			    iface_default: find_next_iface_id('vmbr')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBond'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBond',
-			    iface_default: find_next_iface_id('bond')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSIntPort'
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		}
-	    );
-	}
-
-	var renderer_generator = function(fieldname) {
-	    return function(val, metaData, rec) {
-		var tmp = [];
-		if (rec.data[fieldname]) {
-		    tmp.push(rec.data[fieldname]);
-		}
-		if (rec.data[fieldname + '6']) {
-		    tmp.push(rec.data[fieldname + '6']);
-		}
-		return tmp.join('<br>') || '';
-	    };
-	};
-
-	Ext.apply(me, {
-	    layout: 'border',
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    menu: {
-			plain: true,
-			items: menu_items
-		    }
-		}, ' ',
-		{
-		    text: gettext('Revert'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: baseUrl,
-			    method: 'DELETE',
-			    waitMsgTarget: me,
-			    callback: function() {
-				reload();
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		edit_btn,
-		del_btn
-	    ],
-	    items: [
-		{
-		    xtype: 'gridpanel',
-		    stateful: true,
-		    stateId: 'grid-node-network',
-		    store: store,
-		    region: 'center',
-		    border: false,
-		    columns: [
-			{
-			    header: gettext('Name'),
-			    sortable: true,
-			    dataIndex: 'iface'
-			},
-			{
-			    header: gettext('Type'),
-			    sortable: true,
-			    width: 120,
-			    renderer: Proxmox.Utils.render_network_iface_type,
-			    dataIndex: 'type'
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Active'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'active',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText,
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Autostart'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'autostart',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('VLAN aware'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'bridge_vlan_aware',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    header: gettext('Ports/Slaves'),
-			    dataIndex: 'type',
-			    renderer: render_ports
-			},
-			{
-			    header: gettext('Bond Mode'),
-			    dataIndex: 'bond_mode',
-			    renderer: Proxmox.Utils.render_bond_mode,
-			},
-			{
-			    header: gettext('Hash Policy'),
-			    hidden: true,
-			    dataIndex: 'bond_xmit_hash_policy',
-			},
-			{
-			    header: gettext('IP address'),
-			    sortable: true,
-			    width: 120,
-			    hidden: true,
-			    dataIndex: 'address',
-			    renderer: renderer_generator('address'),
-			},
-			{
-			    header: gettext('Subnet mask'),
-			    width: 120,
-			    sortable: true,
-			    hidden: true,
-			    dataIndex: 'netmask',
-			    renderer: renderer_generator('netmask'),
-			},
-			{
-			    header: gettext('CIDR'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'cidr',
-			    renderer: renderer_generator('cidr'),
-			},
-			{
-			    header: gettext('Gateway'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'gateway',
-			    renderer: renderer_generator('gateway'),
-			},
-			{
-			    header: gettext('Comment'),
-			    dataIndex: 'comments',
-			    flex: 1,
-			    renderer: Ext.String.htmlEncode
-			}
-		    ],
-		    listeners: {
-			selectionchange: set_button_status,
-			itemdblclick: run_editor
-		    }
-		},
-		{
-		    border: false,
-		    region: 'south',
-		    autoScroll: true,
-		    hidden: true,
-		    itemId: 'changes',
-		    tbar: [
-			gettext('Pending changes') + ' (' +
-			    gettext('Please reboot to activate changes') + ')'
-		    ],
-		    split: true,
-		    bodyPadding: 5,
-		    flex: 0.6,
-		    html: gettext("No changes")
-		}
-	    ],
-	});
-
-	me.callParent();
-	reload();
-    }
-});
-Ext.define('Proxmox.node.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeDNSEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-                fieldLabel: gettext('Search domain'),
-                name: 'search',
-                allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 1",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns1'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS server') + " 2",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns2'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 3",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns3'
-	    }
-	];
-
-	Ext.applyIf(me, {
-	    subject: gettext('DNS'),
-	    url: "/api2/extjs/nodes/" + me.nodename + "/dns",
-	    fieldDefaults: {
-		labelWidth: 120
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('Proxmox.node.HostsView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxNodeHostsView',
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-    },
-
-    tbar: [
-	{
-	    text: gettext('Save'),
-	    disabled: true,
-	    itemId: 'savebtn',
-	    handler: function() {
-		var me = this.up('panel');
-		Proxmox.Utils.API2Request({
-		    params: {
-			digest: me.digest,
-			data: me.down('#hostsfield').getValue()
-		    },
-		    method: 'POST',
-		    url: '/nodes/' + me.nodename + '/hosts',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			me.reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	{
-	    text: gettext('Revert'),
-	    disabled: true,
-	    itemId: 'resetbtn',
-	    handler: function() {
-		var me = this.up('panel');
-		me.down('#hostsfield').reset();
-	    }
-	}
-    ],
-
-	    layout: 'fit',
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'hostsfield',
-	    fieldStyle: {
-		'font-family': 'monospace',
-		'white-space': 'pre'
-	    },
-	    listeners: {
-		dirtychange: function(ta, dirty) {
-		    var me = this.up('panel');
-		    me.down('#savebtn').setDisabled(!dirty);
-		    me.down('#resetbtn').setDisabled(!dirty);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/hosts",
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.store);
-
-	me.mon(me.store, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    me.digest = records[0].data.digest;
-	    var data = records[0].data.data;
-	    me.down('#hostsfield').setValue(data);
-	    me.down('#hostsfield').resetOriginalValue();
-	});
-
-	me.reload();
-    }
-});
-Ext.define('Proxmox.node.DNSView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeDNSView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.DNSEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/dns",
-	    cwidth1: 130,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		search: {
-		    header: 'Search domain',
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns1: {
-		    header: gettext('DNS server') + " 1",
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns2: {
-		    header: gettext('DNS server') + " 2",
-		    renderer: Ext.htmlEncode
-		},
-		dns3: {
-		    header: gettext('DNS server') + " 3",
-		    renderer: Ext.htmlEncode
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
-Ext.define('Proxmox.node.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeTasks'],
-    stateful: true,
-    stateId: 'grid-node-tasks',
-    loadMask: true,
-    sortableColumns: false,
-    vmidFilter: 0,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.BufferedStore', {
-	    pageSize: 500,
-	    autoLoad: true,
-	    remoteFilter: true,
-	    model: 'proxmox-tasks',
-	    proxy: {
-                type: 'proxmox',
-		startParam: 'start',
-		limitParam: 'limit',
-                url: "/api2/json/nodes/" + me.nodename + "/tasks"
-	    }
-	});
-
-	var userfilter = '';
-	var filter_errors = 0;
-
-	var updateProxyParams = function() {
-	    var params = {
-		errors: filter_errors
-	    };
-	    if (userfilter) {
-		params.userfilter = userfilter;
-	    }
-	    if (me.vmidFilter) {
-		params.vmid = me.vmidFilter;
-	    }
-	    store.proxy.extraParams = params;
-	};
-
-	updateProxyParams();
-
-	var reload_task = Ext.create('Ext.util.DelayedTask',function() {
-	    updateProxyParams();
-	    store.reload();
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	var view_btn = new Ext.Button({
-	    text: gettext('View'),
-	    disabled: true,
-	    handler: run_task_viewer
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	Ext.apply(me, {
-	    store: store,
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: false, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    tbar: [
-		view_btn, '->', gettext('User name') +':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: userfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    userfilter = field.getValue();
-			    reload_task.delay(500);
-			}
-		    }
-		}, ' ', gettext('Only Errors') + ':', ' ',
-		{
-		    xtype: 'checkbox',
-		    hideLabel: true,
-		    checked: filter_errors,
-		    listeners: {
-			change: function(field, checked) {
-			    filter_errors = checked ? 1 : 0;
-			    reload_task.delay(10);
-			}
-		    }
-		}, ' '
-	    ],
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 100,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 100,
-		    renderer: function(value, metaData, record) {
-			return Ext.Date.format(value,"M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return "ERROR: " + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		selectionchange: function(v, selections) {
-		    view_btn.setDisabled(!(selections && selections[0]));
-		},
-		show: function() { reload_task.delay(10); },
-		destroy: function() { reload_task.cancel(); }
-	    }
-	});
-
-	me.callParent();
-
-    }
-});
-Ext.define('proxmox-services', {
-    extend: 'Ext.data.Model',
-    fields: [ 'service', 'name', 'desc', 'state' ],
-    idProperty: 'service'
-});
-
-Ext.define('Proxmox.node.ServiceView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeServiceView'],
-
-    startOnlyServices: {},
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 1000,
-	    storeid: 'proxmox-services' + me.nodename,
-	    model: 'proxmox-services',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/services"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sortAfterUpdate: true,
-	    sorters: [
-		{
-		    property : 'name',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var view_service_log = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + rec.data.service,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: {
-		    xtype: 'proxmoxLogView',
-		    url: "/api2/extjs/nodes/" + me.nodename + "/syslog?service=" +
-			rec.data.service,
-		    log_select_timespan: 1
-		}
-	    });
-	    win.show();
-	};
-
-	var service_cmd = function(cmd) {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/services/" + rec.data.service + "/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.loading = true;
-		},
-		success: function(response, opts) {
-		    rstore.startUpdate();
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid
-		    });
-		    win.show();
-		}
-	    });
-	};
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var syslog_btn = new Ext.Button({
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: view_service_log
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		start_btn.disable();
-		stop_btn.disable();
-		restart_btn.disable();
-		syslog_btn.disable();
-		return;
-	    }
-	    var service = rec.data.service;
-	    var state = rec.data.state;
-
-	    syslog_btn.enable();
-
-	    if (me.startOnlyServices[service]) {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		}
-		stop_btn.disable();
-	    } else {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		    stop_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		    stop_btn.disable();
-		}
-	    }
-	};
-
-	me.mon(store, 'refresh', set_button_status);
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    tbar: [ start_btn, stop_btn, restart_btn, syslog_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Description'),
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'desc',
-		    flex: 2
-		}
-	    ],
-	    listeners: {
-		selectionchange: set_button_status,
-		itemdblclick: view_service_log,
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeTimeEdit'],
-
-    subject: gettext('Time zone'),
-
-    width: 400,
-
-    autoLoad: true,
-
-    fieldDefaults: {
-	labelWidth: 70
-    },
-
-    items: {
-	xtype: 'combo',
-	fieldLabel: gettext('Time zone'),
-	name: 'timezone',
-	queryMode: 'local',
-	store: Ext.create('Proxmox.data.TimezoneStore'),
-	displayField: 'zone',
-	editable: true,
-	anyMatch: true,
-	forceSelection: true,
-	allowBlank: false
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/time";
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeTimeView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var tzoffset = (new Date()).getTimezoneOffset()*60000;
-	var renderlocaltime = function(value) {
-	    var servertime = new Date((value * 1000) + tzoffset);
-	    return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-	};
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.TimeEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/time",
-	    cwidth1: 150,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		timezone: { 
-		    header: gettext('Time zone'), 
-		    required: true
-		},
-		localtime: { 
-		    header: gettext('Server time'), 
-		    required: true, 
-		    renderer: renderlocaltime 
-		}
-	    },
-	    tbar: [ 
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
diff --git a/serverside/jsmod/6.0-4/proxmoxlib.js.original b/serverside/jsmod/6.0-4/proxmoxlib.js.original
deleted file mode 100644
index e4e71b74d9bdd7ddf142a785d45c42f74f360d53..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/proxmoxlib.js.original
+++ /dev/null
@@ -1,7357 +0,0 @@
-// 2.0-5
-Ext.ns('Proxmox');
-Ext.ns('Proxmox.Setup');
-
-if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
-    throw "Proxmox library not initialized";
-}
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	dir: function() {},
-	log: function() {}
-    };
-}
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (Proxmox.CSRFPreventionToken) {
-	if (!options.headers) {
-	    options.headers = {};
-	}
-	options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-    }
-});
-
-Ext.define('Proxmox.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    enabledText: gettext('Enabled'),
-    disabledText: gettext('Disabled'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    stateText: gettext('State'),
-    groupText: gettext('Group'),
-
-    language_map: {
-	zh_CN: 'Chinese (Simplified)',
-	zh_TW: 'Chinese (Traditional)',
-	ca: 'Catalan',
-	da: 'Danish',
-	en: 'English',
-	eu: 'Euskera (Basque)',
-	fr: 'French',
-	de: 'German',
-	it: 'Italian',
-	es: 'Spanish',
-	ja: 'Japanese',
-	nb: 'Norwegian (Bokmal)',
-	nn: 'Norwegian (Nynorsk)',
-	fa: 'Persian (Farsi)',
-	pl: 'Polish',
-	pt_BR: 'Portuguese (Brazil)',
-	ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	tr: 'Turkish'
-    },
-
-    render_language: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (English)';
-	}
-	var text = Proxmox.Utils.language_map[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    language_array: function() {
-	var data = [['__default__', Proxmox.Utils.render_language('')]];
-	Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
-	    data.push([key, Proxmox.Utils.render_language(value)]);
-	});
-
-	return data;
-    },
-
-    bond_mode_gettext_map: {
-	'802.3ad': 'LACP (802.3ad)',
-	'lacp-balance-slb': 'LACP (balance-slb)',
-	'lacp-balance-tcp': 'LACP (balance-tcp)',
-    },
-
-    render_bond_mode: value => Proxmox.Utils.bond_mode_gettext_map[value] || value || '',
-
-    bond_mode_array: function(modes) {
-	return modes.map(mode => [mode, Proxmox.Utils.render_bond_mode(mode)]);
-    },
-
-    getNoSubKeyHtml: function(url) {
-	// url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
-	return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'https://www.proxmox.com');
-    },
-
-    format_boolean_with_default: function(value) {
-	if (Ext.isDefined(value) && value !== '__default__') {
-	    return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-	}
-	return Proxmox.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-	return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-	return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_enabled_toggle: function(value) {
-	return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
-    },
-
-    format_expire: function(date) {
-	if (!date) {
-	    return Proxmox.Utils.neverText;
-	}
-	return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_duration_long: function(ut) {
-
-	var days = Math.floor(ut / 86400);
-	ut -= days*86400;
-	var hours = Math.floor(ut / 3600);
-	ut -= hours*3600;
-	var mins = Math.floor(ut / 60);
-	ut -= mins*60;
-
-	var hours_str = '00' + hours.toString();
-	hours_str = hours_str.substr(hours_str.length - 2);
-	var mins_str = "00" + mins.toString();
-	mins_str = mins_str.substr(mins_str.length - 2);
-	var ut_str = "00" + ut.toString();
-	ut_str = ut_str.substr(ut_str.length - 2);
-
-	if (days) {
-	    var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
-	    return days.toString() + ' ' + ds + ' ' +
-		hours_str + ':' + mins_str + ':' + ut_str;
-	} else {
-	    return hours_str + ':' + mins_str + ':' + ut_str;
-	}
-    },
-
-    format_subscription_level: function(level) {
-	if (level === 'c') {
-	    return 'Community';
-	} else if (level === 'b') {
-	    return 'Basic';
-	} else if (level === 's') {
-	    return 'Standard';
-	} else if (level === 'p') {
-	    return 'Premium';
-	} else {
-	    return Proxmox.Utils.noneText;
-	}
-    },
-
-    compute_min_label_width: function(text, width) {
-
-	if (width === undefined) { width = 100; }
-
-	var tm = new Ext.util.TextMetrics();
-	var min = tm.getWidth(text + ':');
-
-	return min < width ? width : min;
-    },
-
-    setAuthData: function(data) {
-	Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
-	Proxmox.UserName = data.username;
-	Proxmox.LoggedOut = data.LoggedOut;
-	// creates a session cookie (expire = null)
-	// that way the cookie gets deleted after the browser window is closed
-	Ext.util.Cookies.set(Proxmox.Setup.auth_cookie_name, data.ticket, null, '/', null, true);
-    },
-
-    authOK: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
-    },
-
-    authClear: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-	var el = comp.el;
-	if (!el) {
-	    return;
-	}
-	if (!msg) {
-	    el.unmask();
-	} else {
-	    if (msg === true) {
-		el.mask(gettext("Loading..."));
-	    } else {
-		el.mask(msg);
-	    }
-	}
-    },
-
-    monStoreErrors: function(me, store, clearMaskBeforeLoad) {
-	if (clearMaskBeforeLoad) {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		Proxmox.Utils.setErrorMask(me, false);
-	    });
-	} else {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		if (!me.loadCount) {
-		    me.loadCount = 0; // make sure it is numeric
-		    Proxmox.Utils.setErrorMask(me, true);
-		}
-	    });
-	}
-
-	// only works with 'proxmox' proxy
-	me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-	    me.loadCount++;
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-
-	    var msg;
-	    /*jslint nomen: true */
-	    var operation = request._operation;
-	    var error = operation.getError();
-	    if (error.statusText) {
-		msg = error.statusText + ' (' + error.status + ')';
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    extractRequestError: function(result, verbose) {
-	var msg = gettext('Successful');
-
-	if (!result.success) {
-	    msg = gettext("Unknown error");
-	    if (result.message) {
-		msg = result.message;
-		if (result.status) {
-		    msg += ' (' + result.status + ')';
-		}
-	    }
-	    if (verbose && Ext.isObject(result.errors)) {
-		msg += "<br>";
-		Ext.Object.each(result.errors, function(prop, desc) {
-		    msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
-			Ext.htmlEncode(desc);
-		});
-	    }
-	}
-
-	return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-	var newopts = Ext.apply({
-	    waitMsg: gettext('Please wait...')
-	}, reqOpts);
-
-	if (!newopts.url.match(/^\/api2/)) {
-	    newopts.url = '/api2/extjs' + newopts.url;
-	}
-	delete newopts.callback;
-
-	var createWrapper = function(successFn, callbackFn, failureFn) {
-	    Ext.apply(newopts, {
-		success: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    var result = Ext.decode(response.responseText);
-		    response.result = result;
-		    if (!result.success) {
-			response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.callback(callbackFn, options.scope, [options, false, response]);
-			Ext.callback(failureFn, options.scope, [response, options]);
-			return;
-		    }
-		    Ext.callback(callbackFn, options.scope, [options, true, response]);
-		    Ext.callback(successFn, options.scope, [response, options]);
-		},
-		failure: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    response.result = {};
-		    try {
-			response.result = Ext.decode(response.responseText);
-		    } catch(e) {}
-		    var msg = gettext('Connection error') + ' - server offline?';
-		    if (response.aborted) {
-			msg = gettext('Connection error') + ' - aborted.';
-		    } else if (response.timedout) {
-			msg = gettext('Connection error') + ' - Timeout.';
-		    } else if (response.status && response.statusText) {
-			msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-		    }
-		    response.htmlStatus = msg;
-		    Ext.callback(callbackFn, options.scope, [options, false, response]);
-		    Ext.callback(failureFn, options.scope, [response, options]);
-		}
-	    });
-	};
-
-	createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-	var target = newopts.waitMsgTarget;
-	if (target) {
-	    if (Proxmox.Utils.toolkit === 'touch') {
-		target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-	    } else {
-		// Note: ExtJS bug - this does not work when component is not rendered
-		target.setLoading(newopts.waitMsg);
-	    }
-	}
-	Ext.Ajax.request(newopts);
-    },
-
-    checked_command: function(orig_cmd) {
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/localhost/subscription',
-	    method: 'GET',
-	    //waitMsgTarget: me,
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-
-		if (data.status !== 'Active') {
-		    Ext.Msg.show({
-			title: gettext('No valid subscription'),
-			icon: Ext.Msg.WARNING,
-			msg: Proxmox.Utils.getNoSubKeyHtml(data.url),
-			buttons: Ext.Msg.OK,
-			callback: function(btn) {
-			    if (btn !== 'ok') {
-				return;
-			    }
-			    orig_cmd();
-			}
-		    });
-		} else {
-		    orig_cmd();
-		}
-	    }
-	});
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-	    Ext.Object.each(data, function(name, val) {
-		if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-		    values[name] = val;
-                }
-            });
-	}
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-	if (create) {
-	    if (isAdd) {
-		return gettext('Add') + ': ' + subject;
-	    } else {
-		return gettext('Create') + ': ' + subject;
-	    }
-	} else {
-	    return gettext('Edit') + ': ' + subject;
-	}
-    },
-
-    network_iface_types: {
-	eth: gettext("Network Device"),
-	bridge: 'Linux Bridge',
-	bond: 'Linux Bond',
-	vlan: 'Linux VLAN',
-	OVSBridge: 'OVS Bridge',
-	OVSBond: 'OVS Bond',
-	OVSPort: 'OVS Port',
-	OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-	return Proxmox.Utils.network_iface_types[value] ||
-	    Proxmox.Utils.unknownText;
-    },
-
-    task_desc_table: {
-	acmenewcert: [ 'SRV', gettext('Order Certificate') ],
-	acmeregister: [ 'ACME Account', gettext('Register') ],
-	acmedeactivate: [ 'ACME Account', gettext('Deactivate') ],
-	acmeupdate: [ 'ACME Account', gettext('Update') ],
-	acmerefresh: [ 'ACME Account', gettext('Refresh') ],
-	acmerenew: [ 'SRV', gettext('Renew Certificate') ],
-	acmerevoke: [ 'SRV', gettext('Revoke Certificate') ],
-	'move_volume': [ 'CT', gettext('Move Volume') ],
-	clustercreate: [ '', gettext('Create Cluster') ],
-	clusterjoin: [ '', gettext('Join Cluster') ],
-	diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ],
-	vncproxy: [ 'VM/CT', gettext('Console') ],
-	spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-	vncshell: [ '', gettext('Shell') ],
-	spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-	qmsnapshot: [ 'VM', gettext('Snapshot') ],
-	qmrollback: [ 'VM', gettext('Rollback') ],
-	qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-	qmcreate: [ 'VM', gettext('Create') ],
-	qmrestore: [ 'VM', gettext('Restore') ],
-	qmdestroy: [ 'VM', gettext('Destroy') ],
-	qmigrate: [ 'VM', gettext('Migrate') ],
-	qmclone: [ 'VM', gettext('Clone') ],
-	qmmove: [ 'VM', gettext('Move disk') ],
-	qmtemplate: [ 'VM', gettext('Convert to template') ],
-	qmstart: [ 'VM', gettext('Start') ],
-	qmstop: [ 'VM', gettext('Stop') ],
-	qmreset: [ 'VM', gettext('Reset') ],
-	qmshutdown: [ 'VM', gettext('Shutdown') ],
-	qmsuspend: [ 'VM', gettext('Hibernate') ],
-	qmpause: [ 'VM', gettext('Pause') ],
-	qmresume: [ 'VM', gettext('Resume') ],
-	qmconfig: [ 'VM', gettext('Configure') ],
-	vzsnapshot: [ 'CT', gettext('Snapshot') ],
-	vzrollback: [ 'CT', gettext('Rollback') ],
-	vzdelsnapshot: [ 'CT', gettext('Delete Snapshot') ],
-	vzcreate: ['CT', gettext('Create') ],
-	vzrestore: ['CT', gettext('Restore') ],
-	vzdestroy: ['CT', gettext('Destroy') ],
-	vzmigrate: [ 'CT', gettext('Migrate') ],
-	vzclone: [ 'CT', gettext('Clone') ],
-	vztemplate: [ 'CT', gettext('Convert to template') ],
-	vzstart: ['CT', gettext('Start') ],
-	vzstop: ['CT', gettext('Stop') ],
-	vzmount: ['CT', gettext('Mount') ],
-	vzumount: ['CT', gettext('Unmount') ],
-	vzshutdown: ['CT', gettext('Shutdown') ],
-	vzsuspend: [ 'CT', gettext('Suspend') ],
-	vzresume: [ 'CT', gettext('Resume') ],
-	hamigrate: [ 'HA', gettext('Migrate') ],
-	hastart: [ 'HA', gettext('Start') ],
-	hastop: [ 'HA', gettext('Stop') ],
-	srvstart: ['SRV', gettext('Start') ],
-	srvstop: ['SRV', gettext('Stop') ],
-	srvrestart: ['SRV', gettext('Restart') ],
-	srvreload: ['SRV', gettext('Reload') ],
-	cephcreatemgr: ['Ceph Manager', gettext('Create') ],
-	cephdestroymgr: ['Ceph Manager', gettext('Destroy') ],
-	cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-	cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-	cephcreateosd: ['Ceph OSD', gettext('Create') ],
-	cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-	cephcreatepool: ['Ceph Pool', gettext('Create') ],
-	cephdestroypool: ['Ceph Pool', gettext('Destroy') ],
-	cephfscreate: ['CephFS', gettext('Create') ],
-	cephcreatemds: ['Ceph Metadata Server', gettext('Create') ],
-	cephdestroymds: ['Ceph Metadata Server', gettext('Destroy') ],
-	imgcopy: ['', gettext('Copy data') ],
-	imgdel: ['', gettext('Erase data') ],
-	unknownimgdel: ['', gettext('Destroy image from unknown guest') ],
-	download: ['', gettext('Download') ],
-	vzdump: ['VM/CT', gettext('Backup') ],
-	aptupdate: ['', gettext('Update package database') ],
-	startall: [ '', gettext('Start all VMs and Containers') ],
-	stopall: [ '', gettext('Stop all VMs and Containers') ],
-	migrateall: [ '', gettext('Migrate all VMs and Containers') ],
-	dircreate: [ gettext('Directory Storage'), gettext('Create') ],
-	lvmcreate: [ gettext('LVM Storage'), gettext('Create') ],
-	lvmthincreate: [ gettext('LVM-Thin Storage'), gettext('Create') ],
-	zfscreate: [ gettext('ZFS Storage'), gettext('Create') ]
-    },
-
-    format_task_description: function(type, id) {
-	var farray = Proxmox.Utils.task_desc_table[type];
-	var text;
-	if (!farray) {
-	    text = type;
-	    if (id) {
-		type += ' ' + id;
-	    }
-	    return text;
-	}
-	var prefix = farray[0];
-	text = farray[1];
-	if (prefix) {
-	    return prefix + ' ' + id + ' - ' + text;
-	}
-	return text;
-    },
-
-    format_size: function(size) {
-	/*jslint confusion: true */
-
-	var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
-	var num = 0;
-
-	while (size >= 1024 && ((num++)+1) < units.length) {
-	    size = size / 1024;
-	}
-
-	return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    render_uptime: function(value) {
-
-	var uptime = value;
-
-	if (uptime === undefined) {
-	    return '';
-	}
-
-	if (uptime <= 0) {
-	    return '-';
-	}
-
-	return Proxmox.Utils.format_duration_long(uptime);
-    },
-
-    parse_task_upid: function(upid) {
-	var task = {};
-
-	var res = upid.match(/^UPID:(\S+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-	if (!res) {
-	    throw "unable to parse upid '" + upid + "'";
-	}
-	task.node = res[1];
-	task.pid = parseInt(res[2], 16);
-	task.pstart = parseInt(res[3], 16);
-	task.starttime = parseInt(res[4], 16);
-	task.type = res[5];
-	task.id = res[6];
-	task.user = res[7];
-
-	task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	return task;
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-	var servertime = new Date(value * 1000);
-	return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    get_help_info: function(section) {
-	var helpMap;
-	if (typeof proxmoxOnlineHelpInfo !== 'undefined') {
-	    helpMap = proxmoxOnlineHelpInfo;
-	} else if (typeof pveOnlineHelpInfo !== 'undefined') {
-	    // be backward compatible with older pve-doc-generators
-	    helpMap = pveOnlineHelpInfo;
-	} else {
-	    throw "no global OnlineHelpInfo map declared";
-	}
-
-	return helpMap[section];
-    },
-
-    get_help_link: function(section) {
-	var info = Proxmox.Utils.get_help_info(section);
-	if (!info) {
-	    return;
-	}
-
-	return window.location.origin + info.link;
-    },
-
-    openXtermJsViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    xtermjs: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    cmd: cmd,
-
-	});
-	var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
-	if (nw) {
-	    nw.focus();
-	}
-    }
-
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-
-	var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-	var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-	var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-	var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-	var IPV4_CIDR_MASK = "([0-9]{1,2})";
-	var IPV6_CIDR_MASK = "([0-9]{1,3})";
-
-
-	me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-	me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/" + IPV4_CIDR_MASK + "$");
-
-	var IPV6_REGEXP = "(?:" +
-	    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-	    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-	    ")";
-
-	me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-	me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/" + IPV6_CIDR_MASK + "$");
-	me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-	me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-	me.IP64_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + "\/" + IPV6_CIDR_MASK + ")|(?:" + IPV4_REGEXP + "\/" + IPV4_CIDR_MASK + ")$");
-
-	var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
-	me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
-
-	me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
-	me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
-	me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
-    }
-});
-// ExtJS related things
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-	return Proxmox.Utils.IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP4_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 32);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24' + "<br>" + gettext('Valid CIDR Range') + ': 8-32',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return Proxmox.Utils.IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP6_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 128);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64' + "<br>" + gettext('Valid CIDR Range') + ': 8-128',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-	return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-
-    IP64Address:  function(v) {
-        return Proxmox.Utils.IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    IP64CIDRAddress: function(v) {
-	var result = Proxmox.Utils.IP64_cidr_match.exec(v);
-	if (result === null) {
-	    return false;
-	}
-	if (result[1] !== undefined) {
-	    return result[1] >= 8 && result[1] <= 128;
-	} else if (result[2] !== undefined) {
-	    return result[2] >= 8 && result[2] <= 32;
-	} else {
-	    return false;
-	}
-    },
-    IP64CIDRAddressText: gettext('Example') + ': 192.168.1.1/24 2001:DB8::42/64',
-    IP64CIDRAddressMask: /[A-Fa-f0-9\.:\/]/,
-
-    MacAddress: function(v) {
-	return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    MacPrefix:  function(v) {
-	return (/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i).test(v);
-    },
-    MacPrefixMask: /[a-fA-F0-9:]/,
-    MacPrefixText: gettext('Example') + ': 02:8f - ' + gettext('only unicast addresses are allowed'),
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext("Allowed characters") + ": 'a-z', '0-9', '_'" + "<br />" +
-		       gettext("Minimum characters") + ": 2" + "<br />" +
-		       gettext("Maximum characters") + ": 21" + "<br />" +
-		       gettext("Must start with") + ": 'a-z'",
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'" + "<br />" +
-		   gettext("Minimum characters") + ": 2" + "<br />" +
-		   gettext("Must start with") + ": 'A-Z', 'a-z'<br />" +
-		   gettext("Must end with") + ": 'A-Z', 'a-z', '0-9'<br />",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'" + "<br />" +
-		  gettext("Minimum characters") + ": 2" + "<br />" +
-		  gettext("Must start with") + ": " + gettext("letter"),
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-	return Proxmox.Utils.DnsName_match.test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name'),
-
-    // workaround for https://www.sencha.com/forum/showthread.php?302150
-    proxmoxMail: function(v) {
-        return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
-    },
-    proxmoxMailText: gettext('Example') + ": user@example.com",
-
-    DnsOrIp: function(v) {
-	if (!Proxmox.Utils.DnsName_match.test(v) &&
-	    !Proxmox.Utils.IP64_match.test(v)) {
-	    return false;
-	}
-
-	return true;
-    },
-    DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
-
-    HostList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == "") {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
-		!Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
-		!Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    HostListText: gettext('Not a valid list of hosts'),
-
-    password: function(val, field) {
-        if (field.initialPassField) {
-            var pwd = field.up('form').down(
-		'[name=' + field.initialPassField + ']');
-            return (val == pwd.getValue());
-        }
-        return true;
-    },
-
-    passwordText: gettext('Passwords do not match')
-});
-
-// Firefox 52+ Touchscreen bug
-// see https://www.sencha.com/forum/showthread.php?336762-Examples-don-t-work-in-Firefox-52-touchscreen/page2
-// and https://bugzilla.proxmox.com/show_bug.cgi?id=1223
-Ext.define('EXTJS_23846.Element', {
-    override: 'Ext.dom.Element'
-}, function(Element) {
-    var supports = Ext.supports,
-        proto = Element.prototype,
-        eventMap = proto.eventMap,
-        additiveEvents = proto.additiveEvents;
-
-    if (Ext.os.is.Desktop && supports.TouchEvents && !supports.PointerEvents) {
-        eventMap.touchstart = 'mousedown';
-        eventMap.touchmove = 'mousemove';
-        eventMap.touchend = 'mouseup';
-        eventMap.touchcancel = 'mouseup';
-
-        additiveEvents.mousedown = 'mousedown';
-        additiveEvents.mousemove = 'mousemove';
-        additiveEvents.mouseup = 'mouseup';
-        additiveEvents.touchstart = 'touchstart';
-        additiveEvents.touchmove = 'touchmove';
-        additiveEvents.touchend = 'touchend';
-        additiveEvents.touchcancel = 'touchcancel';
-
-        additiveEvents.pointerdown = 'mousedown';
-        additiveEvents.pointermove = 'mousemove';
-        additiveEvents.pointerup = 'mouseup';
-        additiveEvents.pointercancel = 'mouseup';
-    }
-});
-
-Ext.define('EXTJS_23846.Gesture', {
-    override: 'Ext.event.publisher.Gesture'
-}, function(Gesture) {
-    var me = Gesture.instance;
-
-    if (Ext.supports.TouchEvents && !Ext.isWebKit && Ext.os.is.Desktop) {
-        me.handledDomEvents.push('mousedown', 'mousemove', 'mouseup');
-        me.registerEvents();
-    }
-});
-
-Ext.define('EXTJS_18900.Pie', {
-    override: 'Ext.chart.series.Pie',
-
-    // from 6.0.2
-    betweenAngle: function (x, a, b) {
-        var pp = Math.PI * 2,
-            offset = this.rotationOffset;
-
-        if (a === b) {
-            return false;
-        }
-
-        if (!this.getClockwise()) {
-            x *= -1;
-            a *= -1;
-            b *= -1;
-            a -= offset;
-            b -= offset;
-        } else {
-            a += offset;
-            b += offset;
-        }
-
-        x -= a;
-        b -= a;
-
-        // Normalize, so that both x and b are in the [0,360) interval.
-        x %= pp;
-        b %= pp;
-        x += pp;
-        b += pp;
-        x %= pp;
-        b %= pp;
-
-        // Because 360 * n angles will be normalized to 0,
-        // we need to treat b === 0 as a special case.
-        return x < b || b === 0;
-    },
-});
-
-// we always want the number in x.y format and never in, e.g., x,y
-Ext.define('PVE.form.field.Number', {
-    override: 'Ext.form.field.Number',
-    submitLocaleSeparator: false
-});
-
-// ExtJs 5-6 has an issue with caching
-// see https://www.sencha.com/forum/showthread.php?308989
-Ext.define('Proxmox.UnderlayPool', {
-    override: 'Ext.dom.UnderlayPool',
-
-    checkOut: function () {
-        var cache = this.cache,
-            len = cache.length,
-            el;
-
-        // do cleanup because some of the objects might have been destroyed
-	while (len--) {
-            if (cache[len].destroyed) {
-                cache.splice(len, 1);
-            }
-        }
-        // end do cleanup
-
-	el = cache.shift();
-
-        if (!el) {
-            el = Ext.Element.create(this.elementConfig);
-            el.setVisibilityMode(2);
-            //<debug>
-            // tell the spec runner to ignore this element when checking if the dom is clean
-	    el.dom.setAttribute('data-sticky', true);
-            //</debug>
-	}
-
-        return el;
-    }
-});
-
-// 'Enter' in Textareas and aria multiline fields should not activate the
-// defaultbutton, fixed in extjs 6.0.2
-Ext.define('PVE.panel.Panel', {
-    override: 'Ext.panel.Panel',
-
-    fireDefaultButton: function(e) {
-	if (e.target.getAttribute('aria-multiline') === 'true' ||
-	    e.target.tagName === "TEXTAREA") {
-	    return true;
-	}
-	return this.callParent(arguments);
-    }
-});
-
-// if the order of the values are not the same in originalValue and value
-// extjs will not overwrite value, but marks the field dirty and thus
-// the reset button will be enabled (but clicking it changes nothing)
-// so if the arrays are not the same after resetting, we
-// clear and set it
-Ext.define('Proxmox.form.ComboBox', {
-    override: 'Ext.form.field.ComboBox',
-
-    reset: function() {
-	// copied from combobox
-	var me = this;
-	me.callParent();
-
-	// clear and set when not the same
-	var value = me.getValue();
-	if (Ext.isArray(me.originalValue) && Ext.isArray(value) && !Ext.Array.equals(value, me.originalValue)) {
-	    me.clearValue();
-	    me.setValue(me.originalValue);
-	}
-    }
-});
-
-// when refreshing a grid/tree view, restoring the focus moves the view back to
-// the previously focused item. Save scroll position before refocusing.
-Ext.define(null, {
-    override: 'Ext.view.Table',
-
-    jumpToFocus: false,
-
-    saveFocusState: function() {
-        var me = this,
-            store = me.dataSource,
-            actionableMode = me.actionableMode,
-            navModel = me.getNavigationModel(),
-            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
-            refocusRow, refocusCol;
-
-        if (focusPosition) {
-            // Separate this from the instance that the nav model is using.
-            focusPosition = focusPosition.clone();
-
-            // Exit actionable mode.
-            // We must inform any Actionables that they must relinquish control.
-            // Tabbability must be reset.
-            if (actionableMode) {
-                me.ownerGrid.setActionableMode(false);
-            }
-
-            // Blur the focused descendant, but do not trigger focusLeave.
-            me.el.dom.focus();
-
-            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
-            // clear the navigation position
-            navModel.setPosition();
-
-            // The following function will attempt to refocus back in the same mode to the same cell
-            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
-            return function() {
-                // If we still have data, attempt to refocus in the same mode.
-                if (store.getCount()) {
-
-                    // Adjust expectations of where we are able to refocus according to what kind of destruction
-                    // might have been wrought on this view's DOM during focus save.
-                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
-                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
-                    focusPosition = new Ext.grid.CellContext(me).setPosition(
-                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
-
-                    if (actionableMode) {
-                        me.ownerGrid.setActionableMode(true, focusPosition);
-                    } else {
-                        me.cellFocused = true;
-
-			// we sometimes want to scroll back to where we were
-			var x = me.getScrollX();
-			var y = me.getScrollY();
-
-                        // Pass "preventNavigation" as true so that that does not cause selection.
-                        navModel.setPosition(focusPosition, null, null, null, true);
-
-			if (!me.jumpToFocus) {
-			    me.scrollTo(x,y);
-			}
-                    }
-                }
-                // No rows - focus associated column header
-                else {
-                    focusPosition.column.focus();
-                }
-            };
-        }
-        return Ext.emptyFn;
-    }
-});
-
-// should be fixed with ExtJS 6.0.2, see:
-// https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
-Ext.define('Proxmox.Datepicker', {
-    override: 'Ext.picker.Date',
-    hideMode: 'visibility'
-});
-
-// ExtJS 6.0.1 has no setSubmitValue() (although you find it in the docs).
-// Note: this.submitValue is a boolean flag, whereas getSubmitValue() returns
-// data to be submitted.
-Ext.define('Proxmox.form.field.Text', {
-    override: 'Ext.form.field.Text',
-
-    setSubmitValue: function(v) {
-	this.submitValue = v;
-    },
-});
-
-// this should be fixed with ExtJS 6.0.2
-// make mousescrolling work in firefox in the containers overflowhandler
-Ext.define(null, {
-    override: 'Ext.layout.container.boxOverflow.Scroller',
-
-    createWheelListener: function() {
-	var me = this;
-	if (Ext.isFirefox) {
-	    me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
-	} else {
-	    me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
-	}
-    },
-
-    // special wheel handler for firefox. differs from the default onMouseWheel
-    // handler by using deltaY instead of wheelDeltaY and no normalizing,
-    // because it is already
-    onMouseWheelFirefox: function(e) {
-	e.stopEvent();
-	var delta = e.browserEvent.deltaY || 0;
-	this.scrollBy(delta * this.wheelIncrement, false);
-    }
-
-});
-
-// add '@' to the valid id
-Ext.define('Proxmox.validIdReOverride', {
-    override: 'Ext.Component',
-    validIdRe: /^[a-z_][a-z0-9\-_\@]*$/i,
-});
-
-// force alert boxes to be rendered with an Error Icon
-// since Ext.Msg is an object and not a prototype, we need to override it
-// after the framework has been initiated
-Ext.onReady(function() {
-/*jslint confusion: true */
-    Ext.override(Ext.Msg, {
-	alert: function(title, message, fn, scope) {
-	    if (Ext.isString(title)) {
-		var config = {
-		    title: title,
-		    message: message,
-		    icon: this.ERROR,
-		    buttons: this.OK,
-		    fn: fn,
-		    scope : scope,
-		    minWidth: this.minWidth
-		};
-	    return this.show(config);
-	    }
-	}
-    });
-/*jslint confusion: false */
-});
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" id="{id}-iframeEl" data-ref="iframeEl" name="{frameName}" width="100%" height="100%" frameborder="0" allowfullscreen="true"></iframe>'
-    ],
-    childEls: ['iframeEl'],
-
-    initComponent: function () {
-        this.callParent();
-
-        this.frameName = this.frameName || this.id + '-frame';
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-                doc = this.getDoc();
-                if (doc) {
-		    /*jslint nomen: true*/
-                    Ext.get(doc).un(this._docListeners);
-		    /*jslint nomen: false*/
-                    if (destroying && doc.hasOwnProperty) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-		/*jslint nomen: true*/
-                Ext.get(doc).on(
-                    me._docListeners = {
-                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                        mousemove: fn, // window resize drag detection
-                        mouseup: fn,   // window resize termination
-                        click: fn,     // not sure, but just to be safe
-                        dblclick: fn,  // not sure again
-                        scope: me
-                    }
-                );
-		/*jslint nomen: false*/
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.get(this.getWin()).on('beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if (me.src) {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    onRelayedEvent: function (event) {
-        // relay event from the iframe's document to the document that owns the iframe...
-
-        var iframeEl = this.iframeEl,
-
-            // Get the left-based iframe position
-            iframeXY = iframeEl.getTrueXY(),
-            originalEventXY = event.getXY(),
-
-            // Get the left-based XY position.
-            // This is because the consumer of the injected event will
-            // perform its own RTL normalization.
-            eventXY = event.getTrueXY();
-
-        // the event from the inner document has XY relative to that document's origin,
-        // so adjust it to use the origin of the iframe in the outer document:
-        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
-
-        event.injectEvent(iframeEl); // blame the iframe for the event...
-
-        event.xy = originalEventXY; // restore the original XY (just for safety)
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
-Ext.define('Proxmox.Mixin.CBind', {
-    extend: 'Ext.Mixin',
-
-    mixinConfig: {
-        before: {
-            initComponent: 'cloneTemplates'
-        }
-    },
-
-    cloneTemplates: function() {
-	var me = this;
-	
- 	if (typeof(me.cbindData) == "function") {
-	    me.cbindData = me.cbindData(me.initialConfig) || {};
-	}
-	
-	var getConfigValue = function(cname) {
-
-	    if (cname in me.initialConfig) {
-		return me.initialConfig[cname];
-	    }
-	    if (cname in me.cbindData) {
-		return me.cbindData[cname];
-	    }	    
-	    if (cname in me) {
-		return me[cname];
-	    }
-	    throw "unable to get cbind data for '" + cname + "'";
-	};
-	
-	var applyCBind = function(obj) {
-	    var cbind = obj.cbind, prop, cdata, cvalue, match, found;
-	    if (!cbind) return;
-
-	    for (prop in cbind) {
-		cdata = cbind[prop];
-
-		found = false;
-		if (match = /^\{(!)?([a-z_][a-z0-9_]*)\}$/i.exec(cdata)) {
-		    var cvalue = getConfigValue(match[2]);
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)+)\}$/i.exec(cdata)) {
-		    var keys = match[2].split('.');
-		    var cvalue = getConfigValue(keys.shift());
-		    keys.forEach(function(k) {
-			if (k in cvalue) {
-			    cvalue = cvalue[k];
-			} else {
-			    throw "unable to get cbind data for '" + match[2] + "'";
-			}
-		    });
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else {
-		    obj[prop] = cdata.replace(/{([a-z_][a-z0-9_]*)\}/ig, function(match, cname) {
-			var cvalue = getConfigValue(cname);
-			found = true;
-			return cvalue;
-		    });
-		}
-		if (!found) {
-		    throw "unable to parse cbind template '" + cdata + "'";
-		}
-
-	    }
-	};
-
-	if (me.cbind) {
-	    applyCBind(me);
-	}
-	
-	var cloneTemplateArray = function(org) {
-	    var copy, i, found, el, elcopy, arrayLength;
-
-	    arrayLength = org.length;
-	    found = false;
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    found = true;
-		    break;
-		}
-	    }
-
-	    if (!found) return org; // no need to copy
-
-	    copy = [];
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    elcopy = cloneTemplateObject(el);
-		    if (elcopy.cbind) {
-			applyCBind(elcopy);
-		    }
-		    copy.push(elcopy);
-		} else if (el.constructor == Array) {
-		    elcopy = cloneTemplateArray(el);
-		    copy.push(elcopy);
-		} else {
-		    copy.push(el);
-		}
-	    }
-	    return copy;
-	};
-	
-	var cloneTemplateObject = function(org) {
-	    var res = {}, prop, el, copy;
-	    for (prop in org) {
-		el = org[prop];
-		if (el.constructor == Object && el.xtype) {
-		    copy = cloneTemplateObject(el);
-		    if (copy.cbind) {
-			applyCBind(copy);
-		    }
-		    res[prop] = copy;
-		} else if (el.constructor == Array) {
-		    copy = cloneTemplateArray(el);
-		    res[prop] = copy;
-		} else {
-		    res[prop] = el;
-		}
-	    }
-	    return res;
-	};
-
-	var condCloneProperties = function() {
-	    var prop, el, i, tmp;
-	
-	    for (prop in me) {
-		el = me[prop];
-		if (el === undefined || el === null) continue;
-		if (typeof(el) === 'object' && el.constructor == Object) {
-		    if (el.xtype && prop != 'config') {
-			me[prop] = cloneTemplateObject(el);
-		    }
-		} else if (el.constructor == Array) {
-		    tmp = cloneTemplateArray(el);
-		    me[prop] = tmp;
-		}
-	    }
-	};
-
-	condCloneProperties();
-    }
-});
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash. 
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"} 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ] 
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('Proxmox.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-    
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-	me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-	var me = this;
-
-	var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-	    if (me.readArray) {
-
-		var rec_hash = {};
-		Ext.Array.each(root, function(rec) {
-		    if (Ext.isDefined(rec.key)) {
-			rec_hash[rec.key] = rec;
-		    }
-		});
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			var rec = rec_hash[key];
-			if (Ext.isDefined(rec)) {
-			    if (!Ext.isDefined(rec.value)) {
-				rec.value = rowdef.defaultValue;
-			    }
-			    data.push(rec);
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue} );
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined });
-			}
-		    });
-		} else {
-		    Ext.Array.each(root, function(rec) {
-			if (Ext.isDefined(rec.key)) {
-			    data.push(rec);
-			}
-		    });
-		}
-		
-	    } else { 
-		
-		var org_root = root;
-
-		if (Ext.isArray(org_root)) {
-		    if (root.length == 1) {
-			root = org_root[0];
-		    } else {
-			root = {};
-		    }
-		}
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			if (Ext.isDefined(root[key])) {
-			    data.push({key: key, value: root[key]});
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue});
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined});
-			}
-		    });
-		} else {
-		    Ext.Object.each(root, function(key, value) {
-			data.push({key: key, value: value });
-		    });
-		}
-	    }
-	}
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-	return data;
-    }
-});
-
-Ext.define('Proxmox.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.proxmox',
-
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-
-    afterRequest: function(request, success) {
-	this.fireEvent('afterload', this, request, success);
-	return;
-    },
-
-    constructor: function(config) {
-
-	Ext.applyIf(config, {
-	    reader: {
-		type: 'json',
-		rootProperty: config.root || 'data'
-	    }
-	});
-
-	this.callParent([config]);
-    }
-}, function() {
-
-    Ext.define('KeyValue', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value', 'pending', 'delete' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('proxmox-tasks', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'starttime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'endtime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'upid', 'user', 'status', 'type', 'id'
-	],
-	idProperty: 'upid'
-    });
-
-    Ext.define('proxmox-cluster-log', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'uid' , type: 'int' },
-	    { name: 'time', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pri', type: 'int' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'user', 'tag', 'msg',
-	    {
-		name: 'id',
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-		    // compute unique ID
-		    return info.uid + ':' + info.node;
-		}
-	    }
-	],
-	idProperty: 'id'
-    });
-
-});
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- *
- * Note that you have to call yourself startUpdate() for the background load
- * to begin
- */
-Ext.define('Proxmox.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.update',
-
-    isStopped: true,
-
-    autoStart: false,
-
-    destroy: function() {
-	var me = this;
-	me.stopUpdate();
-	me.callParent();
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.interval) {
-	    config.interval = 3000;
-	}
-
-	if (!config.storeid) {
-	    throw "no storeid specified";
-	}
-
-	var load_task = new Ext.util.DelayedTask();
-
-	var run_load_task = function() {
-	    if (me.isStopped) {
-		return;
-	    }
-
-	    if (Proxmox.Utils.authOK()) {
-		var start = new Date();
-		me.load(function() {
-		    var runtime = (new Date()) - start;
-		    var interval = config.interval + runtime*2;
-		    load_task.delay(interval, run_load_task);
-		});
-	    } else {
-		load_task.delay(200, run_load_task);
-	    }
-	};
-
-	Ext.apply(config, {
-	    startUpdate: function() {
-		me.isStopped = false;
-		// run_load_task(); this makes problems with chrome
-		load_task.delay(1, run_load_task);
-	    },
-	    stopUpdate: function() {
-		me.isStopped = true;
-		load_task.cancel();
-	    }
-	});
-
-	me.callParent([config]);
-
-	me.load_task = load_task;
-
-	if (me.autoStart) {
-	    me.startUpdate();
-	}
-    }
-});
-/*
- * The DiffStore is a in-memory store acting as proxy between a real store
- * instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the real store, to avoid the annoying visual flickering of using
- * the real store directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the real store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: the realstore which will autorefresh its content from the API
- * Only works if rstore has a model and use 'idProperty'
- * sortAfterUpdate: sort the diffstore before rendering the view
- */
-Ext.define('Proxmox.data.DiffStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.diff',
-
-    sortAfterUpdate: false,
-    
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.rstore) {
-	    throw "no rstore specified";
-	}
-
-	if (!config.rstore.model) {
-	    throw "no rstore model specified";
-	}
-
-	var rstore = config.rstore;
-
-	Ext.apply(config, {
-	    model: rstore.model,
-	    proxy: { type: 'memory' }
-	});
-
-	me.callParent([config]);
-
-	var first_load = true;
-
-	var cond_add_item = function(data, id) {
-	    var olditem = me.getById(id);
-	    if (olditem) {
-		olditem.beginEdit();
-		Ext.Array.each(me.model.prototype.fields, function(field) {
-		    if (olditem.data[field.name] !== data[field.name]) {
-			olditem.set(field.name, data[field.name]);
-		    }
-		});
-		olditem.endEdit(true);
-		olditem.commit(); 
-	    } else {
-		var newrec = Ext.create(me.model, data);
-		var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-		me.insert(pos, newrec);
-	    }
-	};
-
-	var loadFn = function(s, records, success) {
-
-	    if (!success) {
-		return;
-	    }
-
-	    me.suspendEvents();
-
-	    // getSource returns null if data is not filtered
-	    // if it is filtered it returns all records
-	    var allItems = me.getData().getSource() || me.getData();
-
-	    // remove vanished items
-	    allItems.each(function(olditem) {
-		var item = rstore.getById(olditem.getId());
-		if (!item) {
-		    me.remove(olditem);
-		}
-	    });
-
-	    rstore.each(function(item) {
-		cond_add_item(item.data, item.getId());
-	    });
-
-	    me.filter();
-
-	    if (me.sortAfterUpdate) {
-		me.sort();
-	    }
-
-	    first_load = false;
-
-	    me.resumeEvents();
-	    me.fireEvent('refresh', me);
-	    me.fireEvent('datachanged', me);
-	};
-
-	if (rstore.isLoaded()) {
-	    // if store is already loaded,
-	    // insert items instantly
-	    loadFn(rstore, [], true);
-	}
-
-	me.mon(rstore, 'load', loadFn);
-    }
-});
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('Proxmox.data.ObjectStore',  {
-    extend: 'Proxmox.data.UpdateStore',
-
-    getRecord: function() {
-	var me = this;
-	var record = Ext.create('Ext.data.Model');
-	me.getData().each(function(item) {
-	    record.set(item.data.key, item.data.value);
-	});
-	record.commit(true);
-	return record;
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-        config = config || {};
-
-	if (!config.storeid) {
-	    config.storeid =  'proxmox-store-' + (++Ext.idSeed);
-	}
-
-        Ext.applyIf(config, {
-	    model: 'KeyValue',
-            proxy: {
-                type: 'proxmox',
-		url: config.url,
-		extraParams: config.extraParams,
-                reader: {
-		    type: 'jsonobject',
-		    rows: config.rows,
-		    readArray: config.readArray,
-		    rootProperty: config.root || 'data'
-		}
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
-/* Extends the Proxmox.data.UpdateStore type
- *
- *
- */
-Ext.define('Proxmox.data.RRDStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    alias: 'store.proxmoxRRDStore',
-
-    setRRDUrl: function(timeframe, cf) {
-	var me = this;
-	if (!timeframe) {
-	    timeframe = me.timeframe;
-	}
-
-	if (!cf) {
-	    cf = me.cf;
-	}
-
-	me.proxy.url = me.rrdurl + "?timeframe=" + timeframe + "&cf=" + cf;
-    },
-
-    proxy: {
-	type: 'proxmox'
-    },
-
-    timeframe: 'hour',
-
-    cf: 'AVERAGE',
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	// set default interval to 30seconds
-	if (!config.interval) {
-	    config.interval = 30000;
-	}
-
-	// set a new storeid
-	if (!config.storeid) {
-	    config.storeid = 'rrdstore-' + (++Ext.idSeed);
-	}
-
-	// rrdurl is required
-	if (!config.rrdurl) {
-	    throw "no rrdurl specified";
-	}
-
-	var stateid = 'proxmoxRRDTypeSelection';
-	var sp = Ext.state.Manager.getProvider();
-	var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-	    if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-		me.timeframe = stateinit.timeframe;
-		me.rrdcffn = stateinit.cf;
-	    }
-	}
-
-	me.callParent([config]);
-
-	me.setRRDUrl();
-	me.mon(sp, 'statechange', function(prov, key, state){
-	    if (key === stateid) {
-		if (state && state.id) {
-		    if (state.timeframe !== me.timeframe || state.cf !== me.cf) {
-		        me.timeframe = state.timeframe;
-		        me.cf = state.cf;
-			me.setRRDUrl();
-			me.reload();
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Timezone', {
-    extend: 'Ext.data.Model',
-    fields: ['zone']
-});
-
-Ext.define('Proxmox.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-    model: 'Timezone',
-    data: [
-	    ['Africa/Abidjan'],
-	    ['Africa/Accra'],
-	    ['Africa/Addis_Ababa'],
-	    ['Africa/Algiers'],
-	    ['Africa/Asmara'],
-	    ['Africa/Bamako'],
-	    ['Africa/Bangui'],
-	    ['Africa/Banjul'],
-	    ['Africa/Bissau'],
-	    ['Africa/Blantyre'],
-	    ['Africa/Brazzaville'],
-	    ['Africa/Bujumbura'],
-	    ['Africa/Cairo'],
-	    ['Africa/Casablanca'],
-	    ['Africa/Ceuta'],
-	    ['Africa/Conakry'],
-	    ['Africa/Dakar'],
-	    ['Africa/Dar_es_Salaam'],
-	    ['Africa/Djibouti'],
-	    ['Africa/Douala'],
-	    ['Africa/El_Aaiun'],
-	    ['Africa/Freetown'],
-	    ['Africa/Gaborone'],
-	    ['Africa/Harare'],
-	    ['Africa/Johannesburg'],
-	    ['Africa/Kampala'],
-	    ['Africa/Khartoum'],
-	    ['Africa/Kigali'],
-	    ['Africa/Kinshasa'],
-	    ['Africa/Lagos'],
-	    ['Africa/Libreville'],
-	    ['Africa/Lome'],
-	    ['Africa/Luanda'],
-	    ['Africa/Lubumbashi'],
-	    ['Africa/Lusaka'],
-	    ['Africa/Malabo'],
-	    ['Africa/Maputo'],
-	    ['Africa/Maseru'],
-	    ['Africa/Mbabane'],
-	    ['Africa/Mogadishu'],
-	    ['Africa/Monrovia'],
-	    ['Africa/Nairobi'],
-	    ['Africa/Ndjamena'],
-	    ['Africa/Niamey'],
-	    ['Africa/Nouakchott'],
-	    ['Africa/Ouagadougou'],
-	    ['Africa/Porto-Novo'],
-	    ['Africa/Sao_Tome'],
-	    ['Africa/Tripoli'],
-	    ['Africa/Tunis'],
-	    ['Africa/Windhoek'],
-	    ['America/Adak'],
-	    ['America/Anchorage'],
-	    ['America/Anguilla'],
-	    ['America/Antigua'],
-	    ['America/Araguaina'],
-	    ['America/Argentina/Buenos_Aires'],
-	    ['America/Argentina/Catamarca'],
-	    ['America/Argentina/Cordoba'],
-	    ['America/Argentina/Jujuy'],
-	    ['America/Argentina/La_Rioja'],
-	    ['America/Argentina/Mendoza'],
-	    ['America/Argentina/Rio_Gallegos'],
-	    ['America/Argentina/Salta'],
-	    ['America/Argentina/San_Juan'],
-	    ['America/Argentina/San_Luis'],
-	    ['America/Argentina/Tucuman'],
-	    ['America/Argentina/Ushuaia'],
-	    ['America/Aruba'],
-	    ['America/Asuncion'],
-	    ['America/Atikokan'],
-	    ['America/Bahia'],
-	    ['America/Bahia_Banderas'],
-	    ['America/Barbados'],
-	    ['America/Belem'],
-	    ['America/Belize'],
-	    ['America/Blanc-Sablon'],
-	    ['America/Boa_Vista'],
-	    ['America/Bogota'],
-	    ['America/Boise'],
-	    ['America/Cambridge_Bay'],
-	    ['America/Campo_Grande'],
-	    ['America/Cancun'],
-	    ['America/Caracas'],
-	    ['America/Cayenne'],
-	    ['America/Cayman'],
-	    ['America/Chicago'],
-	    ['America/Chihuahua'],
-	    ['America/Costa_Rica'],
-	    ['America/Cuiaba'],
-	    ['America/Curacao'],
-	    ['America/Danmarkshavn'],
-	    ['America/Dawson'],
-	    ['America/Dawson_Creek'],
-	    ['America/Denver'],
-	    ['America/Detroit'],
-	    ['America/Dominica'],
-	    ['America/Edmonton'],
-	    ['America/Eirunepe'],
-	    ['America/El_Salvador'],
-	    ['America/Fortaleza'],
-	    ['America/Glace_Bay'],
-	    ['America/Godthab'],
-	    ['America/Goose_Bay'],
-	    ['America/Grand_Turk'],
-	    ['America/Grenada'],
-	    ['America/Guadeloupe'],
-	    ['America/Guatemala'],
-	    ['America/Guayaquil'],
-	    ['America/Guyana'],
-	    ['America/Halifax'],
-	    ['America/Havana'],
-	    ['America/Hermosillo'],
-	    ['America/Indiana/Indianapolis'],
-	    ['America/Indiana/Knox'],
-	    ['America/Indiana/Marengo'],
-	    ['America/Indiana/Petersburg'],
-	    ['America/Indiana/Tell_City'],
-	    ['America/Indiana/Vevay'],
-	    ['America/Indiana/Vincennes'],
-	    ['America/Indiana/Winamac'],
-	    ['America/Inuvik'],
-	    ['America/Iqaluit'],
-	    ['America/Jamaica'],
-	    ['America/Juneau'],
-	    ['America/Kentucky/Louisville'],
-	    ['America/Kentucky/Monticello'],
-	    ['America/La_Paz'],
-	    ['America/Lima'],
-	    ['America/Los_Angeles'],
-	    ['America/Maceio'],
-	    ['America/Managua'],
-	    ['America/Manaus'],
-	    ['America/Marigot'],
-	    ['America/Martinique'],
-	    ['America/Matamoros'],
-	    ['America/Mazatlan'],
-	    ['America/Menominee'],
-	    ['America/Merida'],
-	    ['America/Mexico_City'],
-	    ['America/Miquelon'],
-	    ['America/Moncton'],
-	    ['America/Monterrey'],
-	    ['America/Montevideo'],
-	    ['America/Montreal'],
-	    ['America/Montserrat'],
-	    ['America/Nassau'],
-	    ['America/New_York'],
-	    ['America/Nipigon'],
-	    ['America/Nome'],
-	    ['America/Noronha'],
-	    ['America/North_Dakota/Center'],
-	    ['America/North_Dakota/New_Salem'],
-	    ['America/Ojinaga'],
-	    ['America/Panama'],
-	    ['America/Pangnirtung'],
-	    ['America/Paramaribo'],
-	    ['America/Phoenix'],
-	    ['America/Port-au-Prince'],
-	    ['America/Port_of_Spain'],
-	    ['America/Porto_Velho'],
-	    ['America/Puerto_Rico'],
-	    ['America/Rainy_River'],
-	    ['America/Rankin_Inlet'],
-	    ['America/Recife'],
-	    ['America/Regina'],
-	    ['America/Resolute'],
-	    ['America/Rio_Branco'],
-	    ['America/Santa_Isabel'],
-	    ['America/Santarem'],
-	    ['America/Santiago'],
-	    ['America/Santo_Domingo'],
-	    ['America/Sao_Paulo'],
-	    ['America/Scoresbysund'],
-	    ['America/Shiprock'],
-	    ['America/St_Barthelemy'],
-	    ['America/St_Johns'],
-	    ['America/St_Kitts'],
-	    ['America/St_Lucia'],
-	    ['America/St_Thomas'],
-	    ['America/St_Vincent'],
-	    ['America/Swift_Current'],
-	    ['America/Tegucigalpa'],
-	    ['America/Thule'],
-	    ['America/Thunder_Bay'],
-	    ['America/Tijuana'],
-	    ['America/Toronto'],
-	    ['America/Tortola'],
-	    ['America/Vancouver'],
-	    ['America/Whitehorse'],
-	    ['America/Winnipeg'],
-	    ['America/Yakutat'],
-	    ['America/Yellowknife'],
-	    ['Antarctica/Casey'],
-	    ['Antarctica/Davis'],
-	    ['Antarctica/DumontDUrville'],
-	    ['Antarctica/Macquarie'],
-	    ['Antarctica/Mawson'],
-	    ['Antarctica/McMurdo'],
-	    ['Antarctica/Palmer'],
-	    ['Antarctica/Rothera'],
-	    ['Antarctica/South_Pole'],
-	    ['Antarctica/Syowa'],
-	    ['Antarctica/Vostok'],
-	    ['Arctic/Longyearbyen'],
-	    ['Asia/Aden'],
-	    ['Asia/Almaty'],
-	    ['Asia/Amman'],
-	    ['Asia/Anadyr'],
-	    ['Asia/Aqtau'],
-	    ['Asia/Aqtobe'],
-	    ['Asia/Ashgabat'],
-	    ['Asia/Baghdad'],
-	    ['Asia/Bahrain'],
-	    ['Asia/Baku'],
-	    ['Asia/Bangkok'],
-	    ['Asia/Beirut'],
-	    ['Asia/Bishkek'],
-	    ['Asia/Brunei'],
-	    ['Asia/Choibalsan'],
-	    ['Asia/Chongqing'],
-	    ['Asia/Colombo'],
-	    ['Asia/Damascus'],
-	    ['Asia/Dhaka'],
-	    ['Asia/Dili'],
-	    ['Asia/Dubai'],
-	    ['Asia/Dushanbe'],
-	    ['Asia/Gaza'],
-	    ['Asia/Harbin'],
-	    ['Asia/Ho_Chi_Minh'],
-	    ['Asia/Hong_Kong'],
-	    ['Asia/Hovd'],
-	    ['Asia/Irkutsk'],
-	    ['Asia/Jakarta'],
-	    ['Asia/Jayapura'],
-	    ['Asia/Jerusalem'],
-	    ['Asia/Kabul'],
-	    ['Asia/Kamchatka'],
-	    ['Asia/Karachi'],
-	    ['Asia/Kashgar'],
-	    ['Asia/Kathmandu'],
-	    ['Asia/Kolkata'],
-	    ['Asia/Krasnoyarsk'],
-	    ['Asia/Kuala_Lumpur'],
-	    ['Asia/Kuching'],
-	    ['Asia/Kuwait'],
-	    ['Asia/Macau'],
-	    ['Asia/Magadan'],
-	    ['Asia/Makassar'],
-	    ['Asia/Manila'],
-	    ['Asia/Muscat'],
-	    ['Asia/Nicosia'],
-	    ['Asia/Novokuznetsk'],
-	    ['Asia/Novosibirsk'],
-	    ['Asia/Omsk'],
-	    ['Asia/Oral'],
-	    ['Asia/Phnom_Penh'],
-	    ['Asia/Pontianak'],
-	    ['Asia/Pyongyang'],
-	    ['Asia/Qatar'],
-	    ['Asia/Qyzylorda'],
-	    ['Asia/Rangoon'],
-	    ['Asia/Riyadh'],
-	    ['Asia/Sakhalin'],
-	    ['Asia/Samarkand'],
-	    ['Asia/Seoul'],
-	    ['Asia/Shanghai'],
-	    ['Asia/Singapore'],
-	    ['Asia/Taipei'],
-	    ['Asia/Tashkent'],
-	    ['Asia/Tbilisi'],
-	    ['Asia/Tehran'],
-	    ['Asia/Thimphu'],
-	    ['Asia/Tokyo'],
-	    ['Asia/Ulaanbaatar'],
-	    ['Asia/Urumqi'],
-	    ['Asia/Vientiane'],
-	    ['Asia/Vladivostok'],
-	    ['Asia/Yakutsk'],
-	    ['Asia/Yekaterinburg'],
-	    ['Asia/Yerevan'],
-	    ['Atlantic/Azores'],
-	    ['Atlantic/Bermuda'],
-	    ['Atlantic/Canary'],
-	    ['Atlantic/Cape_Verde'],
-	    ['Atlantic/Faroe'],
-	    ['Atlantic/Madeira'],
-	    ['Atlantic/Reykjavik'],
-	    ['Atlantic/South_Georgia'],
-	    ['Atlantic/St_Helena'],
-	    ['Atlantic/Stanley'],
-	    ['Australia/Adelaide'],
-	    ['Australia/Brisbane'],
-	    ['Australia/Broken_Hill'],
-	    ['Australia/Currie'],
-	    ['Australia/Darwin'],
-	    ['Australia/Eucla'],
-	    ['Australia/Hobart'],
-	    ['Australia/Lindeman'],
-	    ['Australia/Lord_Howe'],
-	    ['Australia/Melbourne'],
-	    ['Australia/Perth'],
-	    ['Australia/Sydney'],
-	    ['Europe/Amsterdam'],
-	    ['Europe/Andorra'],
-	    ['Europe/Athens'],
-	    ['Europe/Belgrade'],
-	    ['Europe/Berlin'],
-	    ['Europe/Bratislava'],
-	    ['Europe/Brussels'],
-	    ['Europe/Bucharest'],
-	    ['Europe/Budapest'],
-	    ['Europe/Chisinau'],
-	    ['Europe/Copenhagen'],
-	    ['Europe/Dublin'],
-	    ['Europe/Gibraltar'],
-	    ['Europe/Guernsey'],
-	    ['Europe/Helsinki'],
-	    ['Europe/Isle_of_Man'],
-	    ['Europe/Istanbul'],
-	    ['Europe/Jersey'],
-	    ['Europe/Kaliningrad'],
-	    ['Europe/Kiev'],
-	    ['Europe/Lisbon'],
-	    ['Europe/Ljubljana'],
-	    ['Europe/London'],
-	    ['Europe/Luxembourg'],
-	    ['Europe/Madrid'],
-	    ['Europe/Malta'],
-	    ['Europe/Mariehamn'],
-	    ['Europe/Minsk'],
-	    ['Europe/Monaco'],
-	    ['Europe/Moscow'],
-	    ['Europe/Oslo'],
-	    ['Europe/Paris'],
-	    ['Europe/Podgorica'],
-	    ['Europe/Prague'],
-	    ['Europe/Riga'],
-	    ['Europe/Rome'],
-	    ['Europe/Samara'],
-	    ['Europe/San_Marino'],
-	    ['Europe/Sarajevo'],
-	    ['Europe/Simferopol'],
-	    ['Europe/Skopje'],
-	    ['Europe/Sofia'],
-	    ['Europe/Stockholm'],
-	    ['Europe/Tallinn'],
-	    ['Europe/Tirane'],
-	    ['Europe/Uzhgorod'],
-	    ['Europe/Vaduz'],
-	    ['Europe/Vatican'],
-	    ['Europe/Vienna'],
-	    ['Europe/Vilnius'],
-	    ['Europe/Volgograd'],
-	    ['Europe/Warsaw'],
-	    ['Europe/Zagreb'],
-	    ['Europe/Zaporozhye'],
-	    ['Europe/Zurich'],
-	    ['Indian/Antananarivo'],
-	    ['Indian/Chagos'],
-	    ['Indian/Christmas'],
-	    ['Indian/Cocos'],
-	    ['Indian/Comoro'],
-	    ['Indian/Kerguelen'],
-	    ['Indian/Mahe'],
-	    ['Indian/Maldives'],
-	    ['Indian/Mauritius'],
-	    ['Indian/Mayotte'],
-	    ['Indian/Reunion'],
-	    ['Pacific/Apia'],
-	    ['Pacific/Auckland'],
-	    ['Pacific/Chatham'],
-	    ['Pacific/Chuuk'],
-	    ['Pacific/Easter'],
-	    ['Pacific/Efate'],
-	    ['Pacific/Enderbury'],
-	    ['Pacific/Fakaofo'],
-	    ['Pacific/Fiji'],
-	    ['Pacific/Funafuti'],
-	    ['Pacific/Galapagos'],
-	    ['Pacific/Gambier'],
-	    ['Pacific/Guadalcanal'],
-	    ['Pacific/Guam'],
-	    ['Pacific/Honolulu'],
-	    ['Pacific/Johnston'],
-	    ['Pacific/Kiritimati'],
-	    ['Pacific/Kosrae'],
-	    ['Pacific/Kwajalein'],
-	    ['Pacific/Majuro'],
-	    ['Pacific/Marquesas'],
-	    ['Pacific/Midway'],
-	    ['Pacific/Nauru'],
-	    ['Pacific/Niue'],
-	    ['Pacific/Norfolk'],
-	    ['Pacific/Noumea'],
-	    ['Pacific/Pago_Pago'],
-	    ['Pacific/Palau'],
-	    ['Pacific/Pitcairn'],
-	    ['Pacific/Pohnpei'],
-	    ['Pacific/Port_Moresby'],
-	    ['Pacific/Rarotonga'],
-	    ['Pacific/Saipan'],
-	    ['Pacific/Tahiti'],
-	    ['Pacific/Tarawa'],
-	    ['Pacific/Tongatapu'],
-	    ['Pacific/Wake'],
-	    ['Pacific/Wallis'],
-	    ['UTC']
-	]
-});
-Ext.define('Proxmox.form.field.Integer',{
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.proxmoxintegerfield',
-
-    config: {
-	deleteEmpty: false
-    },
-
-    allowDecimals: false,
-    allowExponential: false,
-    step: 1,
-
-   getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== undefined && val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    }
-
-});
-Ext.define('Proxmox.form.field.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.proxmoxtextfield'],
-
-    config: {
-	skipEmptyText: true,
-
-	deleteEmpty: false,
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-	var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    }
-});
-Ext.define('Proxmox.DateTimeField', {
-    extend: 'Ext.form.FieldContainer',
-    xtype: 'promxoxDateTimeField',
-
-    layout: 'hbox',
-
-    referenceHolder: true,
-
-    submitFormat: 'U',
-
-    getValue: function() {
-	var me = this;
-	var d = me.lookupReference('dateentry').getValue();
-
-	if (d === undefined || d === null) { return null; }
-
-	var t = me.lookupReference('timeentry').getValue();
-
-	if (t === undefined || t === null) { return null; }
-
-	var offset = (t.getHours()*3600+t.getMinutes()*60)*1000;
-
-	return new Date(d.getTime() + offset);
-    },
-
-    getSubmitValue: function() {
-        var me = this;
-        var format = me.submitFormat;
-        var value = me.getValue();
-
-        return value ? Ext.Date.format(value, format) : null;
-    },
-
-    items: [
-	{
-	    xtype: 'datefield',
-	    editable: false,
-	    reference: 'dateentry',
-	    flex: 1,
-	    format: 'Y-m-d'
-	},
-	{
-	    xtype: 'timefield',
-	    reference: 'timeentry',
-	    format: 'H:i',
-	    width: 80,
-	    value: '00:00',
-	    increment: 60
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	var value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    }
-});
-Ext.define('Proxmox.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.proxmoxcheckbox'],
-
-    config: {
-	defaultValue: undefined,
-	deleteDefaultValue: false,
-	deleteEmpty: false
-    },
-
-    inputValue: '1',
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-		if ((val == me.getDefaultValue()) && me.getDeleteDefaultValue()) {
-		    data['delete'] = me.getName();
-		} else {
-                    data[me.getName()] = val;
-		}
-            } else if (me.getDeleteEmpty()) {
-               data = {};
-               data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-	var me = this;
-
-	if (value === 1) {
-            me.callParent([true]);
-	} else {
-            me.callParent([value]);
-	}
-    }
-
-});
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('Proxmox.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.proxmoxKVComboBox',
-
-    config: {
-	deleteEmpty: true
-    },
-
-    comboItems: undefined,
-    displayField: 'value',
-    valueField: 'key',
-    queryMode: 'local',
-
-    // overide framework function to implement deleteEmpty behaviour
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '' && val !== '__default__') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    validator: function(val) {
-	var me = this;
-
-	if (me.editable || val === null || val === '') {
-	    return true;
-	}
-
-	if (me.store.getCount() > 0) {
-	    var values = me.multiSelect ? val.split(me.delimiter) : [val];
-	    var items = me.store.getData().collect('value', 'data');
-	    if (Ext.Array.every(values, function(value) {
-		return Ext.Array.contains(items, value);
-	    })) {
-		return true;
-	    }
-	}
-
-	// returns a boolean or string
-	/*jslint confusion: true */
-	return "value '" + val + "' not allowed!";
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.store = Ext.create('Ext.data.ArrayStore', {
-	    model: 'KeyValue',
-	    data : me.comboItems
-	});
-
-	if (me.initialConfig.editable === undefined) {
-	    me.editable = false;
-	}
-
-	me.callParent();
-    },
-
-    setComboItems: function(items) {
-	var me = this;
-
-	me.getStore().setData(items);
-    }
-
-});
-Ext.define('Proxmox.form.LanguageSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'proxmoxLanguageSelector',
-
-    comboItems: Proxmox.Utils.language_array()
-});
-/*
- * ComboGrid component: a ComboBox where the dropdown menu (the
- * "Picker") is a Grid with Rows and Columns expects a listConfig
- * object with a columns property roughly based on the GridPicker from
- * https://www.sencha.com/forum/showthread.php?299909
- *
-*/
-
-Ext.define('Proxmox.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-	    (key == e.BACKSPACE || key == e.DELETE)) {
-	    me.setValue('');
-	}
-
-        me.callParent(arguments);
-    },
-
-    config: {
-	skipEmptyText: false,
-	deleteEmpty: false,
-    },
-
-    // needed to trigger onKeyUp etc.
-    enableKeyEvents: true,
-
-    editable: false,
-
-    // override ExtJS method
-    // if the field has multiSelect enabled, the store is not loaded, and
-    // the displayfield == valuefield, it saves the rawvalue as an array
-    // but the getRawValue method is only defined in the textfield class
-    // (which has not to deal with arrays) an returns the string in the
-    // field (not an array)
-    //
-    // so if we have multiselect enabled, return the rawValue (which
-    // should be an array) and else we do callParent so
-    // it should not impact any other use of the class
-    getRawValue: function() {
-	var me = this;
-	if (me.multiSelect) {
-	    return me.rawValue;
-	} else {
-	    return me.callParent();
-	}
-    },
-
-    getSubmitData: function() {
-	var me = this;
-
-	let data = null;
-	if (!me.disabled && me.submitValue) {
-	    let val = me.getSubmitValue();
-	    if (val !== null) {
-		data = {};
-		data[me.getName()] = val;
-	    } else if (me.getDeleteEmpty()) {
-		data = {};
-		data['delete'] = me.getName();
-	    }
-	}
-	return data;
-   },
-
-    getSubmitValue: function() {
-	var me = this;
-
-	var value = me.callParent();
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    },
-
-// override ExtJS protected method
-    onBindStore: function(store, initial) {
-        var me = this,
-            picker = me.picker,
-            extraKeySpec,
-            valueCollectionConfig;
-
-        // We're being bound, not unbound...
-        if (store) {
-            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2'
-            if (store.autoCreated) {
-                me.queryMode = 'local';
-                me.valueField = me.displayField = 'field1';
-                if (!store.expanded) {
-                    me.displayField = 'field2';
-                }
-
-                // displayTpl config will need regenerating with the autogenerated displayField name 'field1'
-                me.setDisplayTpl(null);
-            }
-            if (!Ext.isDefined(me.valueField)) {
-                me.valueField = me.displayField;
-            }
-
-            // Add a byValue index to the store so that we can efficiently look up records by the value field
-            // when setValue passes string value(s).
-            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys
-            // are found, they are all returned by the get call.
-            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default,
-            // if unique is true, CollectionKey keeps the *last* matching value.
-            extraKeySpec = {
-                byValue: {
-                    rootProperty: 'data',
-                    unique: false
-                }
-            };
-            extraKeySpec.byValue.property = me.valueField;
-            store.setExtraKeys(extraKeySpec);
-
-            if (me.displayField === me.valueField) {
-                store.byText = store.byValue;
-            } else {
-                extraKeySpec.byText = {
-                    rootProperty: 'data',
-                    unique: false
-                };
-                extraKeySpec.byText.property = me.displayField;
-                store.setExtraKeys(extraKeySpec);
-            }
-
-            // We hold a collection of the values which have been selected, keyed by this field's valueField.
-            // This collection also functions as the selected items collection for the BoundList's selection model
-            valueCollectionConfig = {
-                rootProperty: 'data',
-                extraKeys: {
-                    byInternalId: {
-                        property: 'internalId'
-                    },
-                    byValue: {
-                        property: me.valueField,
-                        rootProperty: 'data'
-                    }
-                },
-                // Whenever this collection is changed by anyone, whether by this field adding to it,
-                // or the BoundList operating, we must refresh our value.
-                listeners: {
-                    beginupdate: me.onValueCollectionBeginUpdate,
-                    endupdate: me.onValueCollectionEndUpdate,
-                    scope: me
-                }
-            };
-
-            // This becomes our collection of selected records for the Field.
-            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);
-
-            // We use the selected Collection as our value collection and the basis
-            // for rendering the tag list.
-
-            //proxmox override: since the picker is represented by a grid panel,
-            // we changed here the selection to RowModel
-            me.pickerSelectionModel = new Ext.selection.RowModel({
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
-                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row
-                // and released.  In these situations, the event target for the click event won't be the row where the mouse
-                // was released but the boundview.  The view will then determine that it should fire a container click, and
-                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will
-                // prevent the model from deselecting.
-                deselectOnContainerClick: false,
-                enableInitialSelection: false,
-                pruneRemoved: false,
-                selected: me.valueCollection,
-                store: store,
-                listeners: {
-                    scope: me,
-                    lastselectedchanged: me.updateBindSelection
-                }
-            });
-
-            if (!initial) {
-                me.resetToDefault();
-            }
-
-            if (picker) {
-                picker.setSelectionModel(me.pickerSelectionModel);
-                if (picker.getStore() !== store) {
-                    picker.bindStore(store);
-                }
-            }
-        }
-    },
-
-    // copied from ComboBox
-    createPicker: function() {
-        var me = this;
-        var picker;
-
-        var pickerCfg = Ext.apply({
-                // proxmox overrides: display a grid for selection
-                xtype: 'gridpanel',
-                id: me.pickerId,
-                pickerField: me,
-                floating: true,
-                hidden: true,
-                store: me.store,
-                displayField: me.displayField,
-                preserveScrollOnRefresh: true,
-                pageSize: me.pageSize,
-                tpl: me.tpl,
-                selModel: me.pickerSelectionModel,
-                focusOnToFront: false
-            }, me.listConfig, me.defaultListConfig);
-
-        picker = me.picker || Ext.widget(pickerCfg);
-
-        if (picker.getStore() !== me.store) {
-            picker.bindStore(me.store);
-        }
-
-        if (me.pageSize) {
-            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
-        }
-
-        // proxmox overrides: pass missing method in gridPanel to its view
-        picker.refresh = function() {
-            picker.getSelectionModel().select(me.valueCollection.getRange());
-            picker.getView().refresh();
-        };
-        picker.getNodeByRecord = function() {
-            picker.getView().getNodeByRecord(arguments);
-        };
-
-        // We limit the height of the picker to fit in the space above
-        // or below this field unless the picker has its own ideas about that.
-        if (!picker.initialConfig.maxHeight) {
-            picker.on({
-                beforeshow: me.onBeforePickerShow,
-                scope: me
-            });
-        }
-        picker.getSelectionModel().on({
-            beforeselect: me.onBeforeSelect,
-            beforedeselect: me.onBeforeDeselect,
-            focuschange: me.onFocusChange,
-            selectionChange: function (sm, selectedRecords) {
-                var me = this;
-                if (selectedRecords.length) {
-                    me.setValue(selectedRecords);
-                    me.fireEvent('select', me, selectedRecords);
-                }
-            },
-            scope: me
-        });
-
-	// hack for extjs6
-	// when the clicked item is the same as the previously selected,
-	// it does not select the item
-	// instead we hide the picker
-	if (!me.multiSelect) {
-	    picker.on('itemclick', function (sm,record) {
-		if (picker.getSelection()[0] === record) {
-		    picker.hide();
-		}
-	    });
-	}
-
-	// when our store is not yet loaded, we increase
-	// the height of the gridpanel, so that we can see
-	// the loading mask
-	//
-	// we save the minheight to reset it after the load
-	picker.on('show', function() {
-	    if (me.enableLoadMask) {
-		me.savedMinHeight = picker.getMinHeight();
-		picker.setMinHeight(100);
-	    }
-	});
-
-        picker.getNavigationModel().navigateOnSpace = false;
-
-        return picker;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    queryMode: 'local',
-	    matchFieldWidth: false
-	});
-
-	Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-	Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-        // Create the picker at an early stage, so it is available to store the previous selection
-        if (!me.picker) {
-            me.createPicker();
-        }
-
-	if (me.editable) {
-	    // The trigger.picker causes first a focus event on the field then
-	    // toggles the selection picker. Thus skip expanding in this case,
-	    // else our focus listner expands and the picker.trigger then
-	    // collapses it directly afterwards.
-	    Ext.override(me.triggers.picker, {
-		onMouseDown : function (e) {
-		    // copied "should we focus" check from Ext.form.trigger.Trigger
-		    if (e.pointerType !== 'touch' && !this.field.owns(Ext.Element.getActiveElement())) {
-			me.skip_expand_on_focus = true;
-		    }
-		    this.callParent(arguments);
-		}
-	    });
-
-	    me.on("focus", function(me) {
-		if (!me.isExpanded && !me.skip_expand_on_focus) {
-		    me.expand();
-		}
-		me.skip_expand_on_focus = false;
-	    });
-	}
-
-	me.mon(me.store, 'beforeload', function() {
-	    if (!me.isDisabled()) {
-		me.enableLoadMask = true;
-	    }
-	});
-
-	// hack: autoSelect does not work
-	me.mon(me.store, 'load', function(store, r, success, o) {
-	    if (success) {
-		me.clearInvalid();
-
-		if (me.enableLoadMask) {
-		    delete me.enableLoadMask;
-
-		    // if the picker exists,
-		    // we reset its minheight to the saved var/0
-		    // we have to update the layout, otherwise the height
-		    // gets not recalculated
-		    if (me.picker) {
-			me.picker.setMinHeight(me.savedMinHeight || 0);
-			delete me.savedMinHeight;
-			me.picker.updateLayout();
-		    }
-		}
-
-		var def = me.getValue() || me.preferredValue;
-		if (def) {
-		    me.setValue(def, true); // sync with grid
-		}
-		var found = false;
-		if (def) {
-		    if (Ext.isArray(def)) {
-			Ext.Array.each(def, function(v) {
-			    if (store.findRecord(me.valueField, v)) {
-				found = true;
-				return false; // break
-			    }
-			});
-		    } else {
-			found = store.findRecord(me.valueField, def);
-		    }
-		}
-
-		if (!found) {
-		    var rec = me.store.first();
-		    if (me.autoSelect && rec && rec.data) {
-			def = rec.data[me.valueField];
-			me.setValue(def, true);
-		    } else {
-			me.setValue(me.editable ? def : '', true);
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Proxmox.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxRRDTypeSelector'],
-
-    displayField: 'text',
-    valueField: 'id',
-    editable: false,
-    queryMode: 'local',
-    value: 'hour',
-    stateEvents: [ 'select' ],
-    stateful: true,
-    stateId: 'proxmoxRRDTypeSelection',
-    store: {
-	type: 'array',
-	fields: [ 'id', 'timeframe', 'cf', 'text' ],
-	data : [
-	    [ 'hour', 'hour', 'AVERAGE',
-	      gettext('Hour') + ' (' + gettext('average') +')' ],
-	    [ 'hourmax', 'hour', 'MAX',
-	      gettext('Hour') + ' (' + gettext('maximum') + ')' ],
-	    [ 'day', 'day', 'AVERAGE',
-	      gettext('Day') + ' (' + gettext('average') + ')' ],
-	    [ 'daymax', 'day', 'MAX',
-	      gettext('Day') + ' (' + gettext('maximum') + ')' ],
-	    [ 'week', 'week', 'AVERAGE',
-	      gettext('Week') + ' (' + gettext('average') + ')' ],
-	    [ 'weekmax', 'week', 'MAX',
-	      gettext('Week') + ' (' + gettext('maximum') + ')' ],
-	    [ 'month', 'month', 'AVERAGE',
-	      gettext('Month') + ' (' + gettext('average') + ')' ],
-	    [ 'monthmax', 'month', 'MAX',
-	      gettext('Month') + ' (' + gettext('maximum') + ')' ],
-	    [ 'year', 'year', 'AVERAGE',
-	      gettext('Year') + ' (' + gettext('average') + ')' ],
-	    [ 'yearmax', 'year', 'MAX',
-	      gettext('Year') + ' (' + gettext('maximum') + ')' ]
-	]
-    },
-    // save current selection in the state Provider so RRDView can read it
-    getState: function() {
-	var ind = this.getStore().findExact('id', this.getValue());
-	var rec = this.getStore().getAt(ind);
-	if (!rec) {
-	    return;
-	}
-	return {
-	    id: rec.data.id,
-	    timeframe: rec.data.timeframe,
-	    cf: rec.data.cf
-	};
-    },
-    // set selection based on last saved state
-    applyState : function(state) {
-	if (state && state.id) {
-	    this.setValue(state.id);
-	}
-    }
-});
-Ext.define('Proxmox.form.BondModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-
-    openvswitch: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.openvswitch) {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-	       'active-backup',
-	       'balance-slb',
-	       'lacp-balance-slb',
-	       'lacp-balance-tcp',
-	    ]);
-	} else {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-		'balance-rr',
-		'active-backup',
-		'balance-xor',
-		'broadcast',
-		'802.3ad',
-		'balance-tlb',
-		'balance-alb',
-	    ]);
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('Proxmox.form.BondPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-    comboItems: [
-	    ['layer2', 'layer2'],
-	    ['layer2+3', 'layer2+3'],
-	    ['layer3+4', 'layer3+4']
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelectorController', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.proxmoxNetworkSelectorController',
-
-    init: function(view) {
-	var me = this;
-
-	if (!view.nodename) {
-	    throw "missing custom view config: nodename";
-	}
-	view.getStore().getProxy().setUrl('/api2/json/nodes/'+ view.nodename + '/network');
-    }
-});
-
-Ext.define('Proxmox.data.NetworkSelector', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{name: 'active'},
-	{name: 'cidr'},
-	{name: 'cidr6'},
-	{name: 'address'},
-	{name: 'address6'},
-	{name: 'comments'},
-	{name: 'iface'},
-	{name: 'slaves'},
-	{name: 'type'}
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.proxmoxNetworkSelector',
-
-    controller: 'proxmoxNetworkSelectorController',
-
-    nodename: 'localhost',
-    setNodename: function(nodename) {
-	this.nodename = nodename;
-	var networkSelectorStore = this.getStore();
-	networkSelectorStore.removeAll();
-	// because of manual local copy of data for ip4/6
-	this.getPicker().refresh();
-	if (networkSelectorStore && typeof networkSelectorStore.getProxy === 'function') {
-	    networkSelectorStore.getProxy().setUrl('/api2/json/nodes/'+ nodename + '/network');
-	    networkSelectorStore.load();
-	}
-    },
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'cidr',
-    displayField: 'cidr',
-    store: {
-	autoLoad: true,
-	model: 'Proxmox.data.NetworkSelector',
-	proxy: {
-	    type: 'proxmox'
-	},
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	],
-	filters: [
-	    function(item) {
-		return item.data.cidr;
-	    }
-	],
-	listeners: {
-	    load: function(store, records, successfull) {
-
-		if (successfull) {
-		    records.forEach(function(record) {
-			if (record.data.cidr6) {
-			    let dest = (record.data.cidr) ? record.copy(null) : record;
-			    dest.data.cidr = record.data.cidr6;
-			    dest.data.address = record.data.address6;
-			    delete record.data.cidr6;
-			    dest.data.comments = record.data.comments6;
-			    delete record.data.comments6;
-			    store.add(dest);
-			}
-		    });
-		}
-	    }
-	}
-    },
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-
-		header: gettext('CIDR'),
-		dataIndex: 'cidr',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-
-		header: gettext('IP'),
-		dataIndex: 'address',
-		hidden: true,
-	    },
-	    {
-		header: gettext('Interface'),
-		width: 90,
-		dataIndex: 'iface'
-	    },
-	    {
-		header: gettext('Active'),
-		renderer: Proxmox.Utils.format_boolean,
-		width: 60,
-		dataIndex: 'active'
-	    },
-	    {
-		header: gettext('Type'),
-		width: 80,
-		hidden: true,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 2,
-		dataIndex: 'comments'
-	    }
-	]
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('Proxmox.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.proxmoxButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-
-	    // Note: me.realHandler may be a string (see named scopes)
-	    var realHandler = me.handler;
-
-	    me.handler = function(button, event) {
-		var rec, msg;
-		if (me.selModel) {
-		    rec = me.selModel.getSelection()[0];
-		    if (!rec || (me.enableFn(rec) === false)) {
-			return;
-		    }
-		}
-
-		if (me.confirmMsg) {
-		    msg = me.confirmMsg;
-		    if (Ext.isFunction(me.confirmMsg)) {
-			msg = me.confirmMsg(rec);
-		    }
-		    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		    Ext.Msg.show({
-			title: gettext('Confirm'),
-			icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-			msg: msg,
-			buttons: Ext.Msg.YESNO,
-			defaultFocus: me.dangerous ? 'no' : 'yes',
-			callback: function(btn) {
-			    if (btn !== 'yes') {
-				return;
-			    }
-			    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-			}
-		    });
-		} else {
-		    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-		}
-	    };
-	}
-
-	me.callParent();
-
-	var grid;
-	if (!me.selModel && me.selModel !== null) {
-	    grid = me.up('grid');
-	    if (grid && grid.selModel) {
-		me.selModel = grid.selModel;
-	    }
-	}
-
-	if (me.waitMsgTarget === true) {
-	    grid = me.up('grid');
-	    if (grid) {
-		me.waitMsgTarget = grid;
-	    } else {
-		throw "unable to find waitMsgTarget";
-	    }
-	}
-	
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else  {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-
-
-Ext.define('Proxmox.button.StdRemoveButton', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.proxmoxStdRemoveButton',
-
-    text: gettext('Remove'),
-
-    disabled: true,
-
-    config: {
-	baseurl: undefined
-    },
-
-    getUrl: function(rec) {
-	var me = this;
-	
-	return me.baseurl + '/' + rec.getId();
-    },
-
-    // also works with names scopes
-    callback: function(options, success, response) {},
-
-    getRecordName: function(rec) { return rec.getId() },
-
-    confirmMsg: function (rec) {
-	var me = this;
-
-	var name = me.getRecordName(rec);
-	return Ext.String.format(
-	    gettext('Are you sure you want to remove entry {0}'),
-	    "'" + name + "'");
-    },
-
-    handler: function(btn, event, rec) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.getUrl(rec),
-	    method: 'DELETE',
-	    waitMsgTarget: me.waitMsgTarget,
-	    callback: function(options, success, response) {
-		Ext.callback(me.callback, me.scope, [options, success, response], 0, me);
-	    },
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-/* help button pointing to an online documentation
-   for components contained in a modal window
-*/
-/*global
-  proxmoxOnlineHelpInfo
-*/
-Ext.define('Proxmox.button.Help', {
-    extend: 'Ext.button.Button',
-    xtype: 'proxmoxHelpButton',
-
-    text: gettext('Help'),
-
-    // make help button less flashy by styling it like toolbar buttons
-    iconCls: ' x-btn-icon-el-default-toolbar-small fa fa-question-circle',
-    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-
-    hidden: true,
-
-    listenToGlobalEvent: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	listen: {
-	    global: {
-		proxmoxShowHelp: 'onProxmoxShowHelp',
-		proxmoxHideHelp: 'onProxmoxHideHelp'
-	    }
-	},
-	onProxmoxShowHelp: function(helpLink) {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.setOnlineHelp(helpLink);
-		me.show();
-	    }
-	},
-	onProxmoxHideHelp: function() {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.hide();
-	    }
-	}
-    },
-
-    // this sets the link and the tooltip text
-    setOnlineHelp:function(blockid) {
-	var me = this;
-
-	var info = Proxmox.Utils.get_help_info(blockid);
-	if (info) {
-	    me.onlineHelp = blockid;
-	    var title = info.title;
-	    if (info.subtitle) {
-		title += ' - ' + info.subtitle;
-	    }
-	    me.setTooltip(title);
-	}
-    },
-
-    // helper to set the onlineHelp via a config object
-    setHelpConfig: function(config) {
-	var me = this;
-	me.setOnlineHelp(config.onlineHelp);
-    },
-
-    handler: function() {
-	var me = this;
-	var docsURI;
-
-	if (me.onlineHelp) {
-	    docsURI = Proxmox.Utils.get_help_link(me.onlineHelp);
-	}
-
-	if (docsURI) {
-	    window.open(docsURI);
-	} else {
-	    Ext.Msg.alert(gettext('Help'), gettext('No Help available'));
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-	var me = this;
-
-	me.callParent();
-
-	if  (me.onlineHelp) {
-	    me.setOnlineHelp(me.onlineHelp); // set tooltip
-	}
-    }
-});
-/* Renders a list of key values objets
-
-mandatory config parameters:
-rows: an object container where each propery is a key-value object we want to render
-       var rows = {
-           keyboard: {
-               header: gettext('Keyboard Layout'),
-               editor: 'Your.KeyboardEdit',
-               required: true
-           },
-
-optional:
-disabled: setting this parameter to true will disable selection and focus on the
-proxmoxObjectGrid as well as greying out input elements.
-Useful for a readonly tabular display
-
-*/
-
-Ext.define('Proxmox.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.proxmoxObjectGrid'],
-    disabled: false,
-    hideHeaders: true,
-
-    monStoreErrors: false,
-
-    add_combobox_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxKVComboBox',
-		    name: name,
-		    comboItems: opts.comboItems,
-		    value: opts.defaultValue,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_text_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxtextfield',
-		    name: name,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    vtype: opts.vtype,
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_boolean_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue || 0,
-	    header: text,
-	    renderer: opts.renderer || Proxmox.Utils.format_boolean,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxcheckbox',
-		    name: name,
-		    uncheckedValue: 0,
-		    defaultValue: opts.defaultValue  || 0,
-		    checked: opts.defaultValue ? true : false,
-		    deleteDefaultValue: opts.deleteDefaultValue ? true : false,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_integer_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {}
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxintegerfield',
-		    name: name,
-		    minValue: opts.minValue,
-		    maxValue: opts.maxValue,
-		    emptyText: gettext('Default'),
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    value: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    editorConfig: {}, // default config passed to editor
-
-    run_editor: function() {
-	var me = this;
-
-	var sm = me.getSelectionModel();
-	var rec = sm.getSelection()[0];
-	if (!rec) {
-	    return;
-	}
-
-	var rows = me.rows;
-	var rowdef = rows[rec.data.key];
-	if (!rowdef.editor) {
-	    return;
-	}
-
-	var win;
-	var config;
-	if (Ext.isString(rowdef.editor)) {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    win = Ext.create(rowdef.editor, config);
-	} else {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    Ext.apply(config, rowdef.editor);
-	    win = Ext.createWidget(rowdef.editor.xtype, config);
-	    win.load();
-	}
-
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    getObjectValue: function(key, defaultValue) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-	return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-	var renderer = rowdef.renderer;
-	if (renderer) {
-	    return renderer(value, metaData, record, rowIndex, colIndex, store);
-	}
-
-	return value;
-    },
-
-    listeners: {
-	itemkeydown: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER) {
-		this.pressedIndex = index;
-	    }
-	},
-	itemkeyup: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER && index == this.pressedIndex) {
-		this.run_editor();
-	    }
-
-	    this.pressedIndex = undefined;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	var rstore = me.rstore;
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore,
-	    sorters: [],
-	    filters: []
-	});
-
-	if (rows) {
-	    Ext.Object.each(rows, function(key, rowdef) {
-		if (Ext.isDefined(rowdef.defaultValue)) {
-		    store.add({ key: key, value: rowdef.defaultValue });
-		} else if (rowdef.required) {
-		    store.add({ key: key, value: undefined });
-		}
-	    });
-	}
-
-	if (me.sorterFn) {
-	    store.sorters.add(Ext.create('Ext.util.Sorter', {
-		sorterFn: me.sorterFn
-	    }));
-	}
-
-	store.filters.add(Ext.create('Ext.util.Filter', {
-	    filterFn: function(item) {
-		if (rows) {
-		    var rowdef = rows[item.data.key];
-		    if (!rowdef || (rowdef.visible === false)) {
-			return false;
-		    }
-		}
-		return true;
-	    }
-	}));
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.applyIf(me, {
-	    store: store,
-	    stateful: false,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: me.cwidth1 || 200,
-		    dataIndex: 'key',
-		    renderer: me.renderKey
-		},
-		{
-		    flex: 1,
-		    header: gettext('Value'),
-		    dataIndex: 'value',
-		    renderer: me.renderValue
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.monStoreErrors) {
-	    Proxmox.Utils.monStoreErrors(me, me.store);
-	}
-   }
-});
-Ext.define('Proxmox.grid.PendingObjectGrid', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxPendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    var value = rec.data.value;
-	    if (pending) {
-		if (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') {
-		    value = rec.data.pending;
-		} else if (rec.data['delete'] === 1) {
-		    value = defaultValue;
-		}
-	    }
-
-            if (Ext.isDefined(value) && (value !== '')) {
-		return value;
-            } else {
-		return defaultValue;
-            }
-	}
-	return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var keys = rowdef.multiKey ||  [ key ];
-	var pending = false;
-
-	Ext.Array.each(keys, function(k) {
-	    var rec = me.store.getById(k);
-	    if (rec && rec.data && (
-		    (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') ||
-		    rec.data['delete'] === 1
-	    )) {
-		pending = true;
-		return false; // break
-	    }
-	});
-
-	return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var renderer = rowdef.renderer;
-	var current = '';
-	var pendingdelete = '';
-	var pending = '';
-
-	if (renderer) {
-	    current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-	    if (me.hasPendingChanges(key)) {
-		pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-	    }
-	    if (pending == current) {
-		pending = undefined;
-	    }
-	} else {
-	    current = value || '';
-	    pending = record.data.pending;
-	}
-
-	if (record.data['delete']) {
-	    var delete_all = true;
-	    if (rowdef.multiKey) {
-		Ext.Array.each(rowdef.multiKey, function(k) {
-		    var rec = me.store.getById(k);
-		    if (rec && rec.data && rec.data['delete'] !== 1) {
-			delete_all = false;
-			return false; // break
-		    }
-		});
-	    }
-	    if (delete_all) {
-		pending = '<div style="text-decoration: line-through;">'+ current +'</div>';
-	    }
-	}
-
-	if (pending) {
-	    return current + '<div style="color:red">' + pending + '</div>';
-	} else {
-	    return current;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		model: 'KeyValuePendingDelete',
-		readArray: true,
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('Proxmox.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-    listeners: {
-	activate: function() {
-	    // notify owning container that it should display a help button
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-	    }
-	},
-	deactivate: function() {
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-	    }
-	}
-    },
-    border: false,
-
-    // override this with an URL to a relevant chapter of the pve manual
-    // setting this will display a help button in our parent panel
-    onlineHelp: undefined,
-
-    // will be set if the inputpanel has advanced items
-    hasAdvanced: false,
-
-    // if the panel has advanced items,
-    // this will determine if they are shown by default
-    showAdvanced: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-	return values;
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-	if (Ext.isFunction(me.onGetValues)) {
-	    dirtyOnly = false;
-	}
-
-	var values = {};
-
-	Ext.Array.each(me.query('[isFormField]'), function(field) {
-            if (!dirtyOnly || field.isDirty()) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-	    }
-	});
-
-	return me.onGetValues(values);
-    },
-
-    setAdvancedVisible: function(visible) {
-	var me = this;
-	var advItems = me.getComponent('advancedContainer');
-	if (advItems) {
-	    advItems.setVisible(visible);
-	}
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-	    var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-		field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var items;
-
-	if (me.items) {
-	    me.columns = 1;
-	    items = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.items
-		}
-	    ];
-	    me.items = undefined;
-	} else if (me.column4) {
-	    me.columns = 4;
-	    items = [
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column2
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column3
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column4
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else if (me.column1) {
-	    me.columns = 2;
-	    items = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column2 || [] // allow empty column
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else {
-	    throw "unsupported config";
-	}
-
-	var advItems;
-	if (me.advancedItems) {
-	    advItems = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.advancedItems
-		}
-	    ];
-	    me.advancedItems = undefined;
-	} else if (me.advancedColumn1) {
-	    advItems = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumn1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.advancedColumn2 || [] // allow empty column
-		}
-	    ];
-
-	    me.advancedColumn1 = undefined;
-	    me.advancedColumn2 = undefined;
-
-	    if (me.advancedColumnB) {
-		advItems.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumnB
-		});
-		me.advancedColumnB = undefined;
-	    }
-	}
-
-	if (advItems) {
-	    me.hasAdvanced = true;
-	    advItems.unshift({
-		columnWidth: 1,
-		xtype: 'box',
-		hidden: false,
-		border: true,
-		autoEl: {
-		    tag: 'hr'
-		}
-	    });
-	    items.push({
-		columnWidth: 1,
-		xtype: 'container',
-		itemId: 'advancedContainer',
-		hidden: !me.showAdvanced,
-		layout: 'column',
-		defaults: {
-		    border: false
-		},
-		items: advItems
-	    });
-	}
-
-	if (me.useFieldContainer) {
-	    Ext.apply(me, {
-		layout: 'fit',
-		items: Ext.apply(me.useFieldContainer, {
-		    layout: 'column',
-		    defaultType: 'container',
-		    items: items
-		})
-	    });
-	} else {
-	    Ext.apply(me, {
-		layout: 'column',
-		defaultType: 'container',
-		items: items
-	    });
-	}
-
-	me.callParent();
-    }
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxLogView',
-
-    pageSize: 500,
-    viewBuffer: 50,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    // callback for load failure, used for ceph
-    failCallback: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-	    if (viewModel.get('hide_timespan')) {
-		return;
-	    }
-
-	    if (since > until) {
-		Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
-		return;
-	    }
-
-	    viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
-	    viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
-	    me.getView().loadTask.delay(200);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	updateView: function(text, first, total) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    var content = me.lookup('content');
-	    var data = viewModel.get('data');
-
-	    if (first === data.first && total === data.total && text.length === data.textlen) {
-		return; // same content, skip setting and scrolling
-	    }
-	    viewModel.set('data', {
-		first: first,
-		total: total,
-		textlen: text.length
-	    });
-
-	    var scrollPos = me.scrollPosBottom();
-
-	    content.update(text);
-
-	    if (view.scrollToEnd && scrollPos <= 0) {
-		// we use setTimeout to work around scroll handling on touchscreens
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    }
-	},
-
-	doLoad: function() {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    Proxmox.Utils.API2Request({
-		url: me.getView().url,
-		params: viewModel.get('params'),
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var total = response.result.total;
-		    var lines = new Array();
-		    var first = Infinity;
-
-		    Ext.Array.each(response.result.data, function(line) {
-			if (first > line.n) {
-			    first = line.n;
-			}
-			lines[line.n - 1] = Ext.htmlEncode(line.t);
-		    });
-
-		    lines.length = total;
-		    me.updateView(lines.join('<br>'), first - 1, total);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    if (view.failCallback) {
-			view.failCallback(response);
-		    } else {
-			var msg = response.htmlStatus;
-			Proxmox.Utils.setErrorMask(me, msg);
-		    }
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-
-	    var lineHeight = view.lineHeight;
-	    var line = view.getScrollY()/lineHeight;
-	    var start = viewModel.get('params.start');
-	    var limit = viewModel.get('params.limit');
-	    var viewLines = view.getHeight()/lineHeight;
-
-	    var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
-	    var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
-
-	    if (viewStart < start || viewEnd > (start+limit)) {
-		viewModel.set('params.start',
-		    Math.max(parseInt(line - limit/2 + 10, 10), 0));
-		view.loadTask.delay(200);
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    viewModel.set('params.limit', view.pageSize);
-	    viewModel.set('hide_timespan', !view.log_select_timespan);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200);
-		    }
-		},
-		interval: 1000
-	    });
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    until: null,
-	    since: null,
-	    hide_timespan: false,
-	    data: {
-		start: 0,
-		total: 0,
-		textlen: 0
-	    },
-	    params: {
-		start: 0,
-		limit: 500,
-	    }
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-	bind: {
-	    hidden: '{hide_timespan}'
-	},
-	items: [
-	    '->',
-	    'Since: ',
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    'Until: ',
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		handler: 'updateParams'
-	    }
-	],
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.JournalView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxJournalView',
-
-    numEntries: 500,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-
-	    since.setHours(0, 0, 0, 0);
-	    until.setHours(0, 0, 0, 0);
-	    until.setDate(until.getDate()+1);
-
-	    me.getView().loadTask.delay(200, undefined, undefined, [
-		false,
-		false,
-		Ext.Date.format(since, "U"),
-		Ext.Date.format(until, "U")
-	    ]);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	scrollPosTop: function() {
-	    var view = this.getView();
-	    return view.getScrollY();
-	},
-
-	updateScroll: function(livemode, num, scrollPos, scrollPosTop) {
-	    var me = this;
-	    var view = me.getView();
-
-	    if (!livemode) {
-		setTimeout(function() { view.scrollTo(0, 0); }, 10);
-	    } else if (view.scrollToEnd && scrollPos <= 0) {
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    } else if (!view.scrollToEnd && scrollPosTop < 20*view.lineHeight) {
-		setTimeout(function() { view.scrollTo(0, num*view.lineHeight + scrollPosTop); }, 10);
-	    }
-	},
-
-	updateView: function(lines, livemode, top) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    if (viewmodel.get('livemode') !== livemode) {
-		return; // we switched mode, do not update the content
-	    }
-	    var contentEl = me.lookup('content');
-
-	    // save old scrollpositions
-	    var scrollPos = me.scrollPosBottom();
-	    var scrollPosTop = me.scrollPosTop();
-
-	    var newend = lines.shift();
-	    var newstart = lines.pop();
-
-	    var num = lines.length;
-	    var text = lines.map(Ext.htmlEncode).join('<br>');
-
-	    if (!livemode) {
-		if (num) {
-		    view.content = text;
-		} else {
-		    view.content = 'nothing logged or no timespan selected';
-		}
-	    } else {
-		// update content
-		if (top && num) {
-		    view.content = view.content ? text + '<br>' + view.content : text;
-		} else if (!top && num) {
-		    view.content = view.content ? view.content + '<br>' + text : text;
-		}
-
-		// update cursors
-		if (!top || !view.startcursor) {
-		    view.startcursor = newstart;
-		}
-
-		if (top || !view.endcursor) {
-		    view.endcursor = newend;
-		}
-	    }
-
-	    contentEl.update(view.content);
-
-	    me.updateScroll(livemode, num, scrollPos, scrollPosTop);
-	},
-
-	doLoad: function(livemode, top, since, until) {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var params = {
-		lastentries: view.numEntries || 500,
-	    };
-	    if (livemode) {
-		if (!top && view.startcursor) {
-		    params = {
-			startcursor: view.startcursor
-		    };
-		} else if (view.endcursor) {
-		    params.endcursor = view.endcursor;
-		}
-	    } else {
-		params = {
-		    since: since,
-		    until: until
-		};
-	    }
-	    Proxmox.Utils.API2Request({
-		url: view.url,
-		params: params,
-		waitMsgTarget: (!livemode) ? view : undefined,
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var lines = response.result.data;
-		    me.updateView(lines, livemode, top);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    var msg = response.htmlStatus;
-		    Proxmox.Utils.setErrorMask(me, msg);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    var livemode = viewmodel.get('livemode');
-	    if (!livemode) {
-		return;
-	    }
-
-	    if (me.scrollPosTop() < 20*view.lineHeight) {
-		view.scrollToEnd = false;
-		view.loadTask.delay(200, undefined, undefined, [true, true]);
-	    } else if (me.scrollPosBottom() <= 1) {
-		view.scrollToEnd = true;
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewmodel = me.getViewModel();
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me, [true, false]);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd || !viewmodel.get('livemode')) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200, undefined, undefined, [true, false]);
-		    }
-		},
-		interval: 1000
-	    });
-	},
-
-	onLiveMode: function() {
-	    var me = this;
-	    var view = me.getView();
-	    delete view.startcursor;
-	    delete view.endcursor;
-	    delete view.content;
-	    me.getViewModel().set('livemode', true);
-	    view.scrollToEnd = true;
-	    me.updateView([], true, false);
-	},
-
-	onTimespan: function() {
-	    var me = this;
-	    me.getViewModel().set('livemode', false);
-	    me.updateView([], false);
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-	delete me.content;
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    livemode: true,
-	    until: null,
-	    since: null
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-
-	items: [
-	    '->',
-	    {
-		xtype: 'segmentedbutton',
-		items: [
-		    {
-			text: gettext('Live Mode'),
-			bind: {
-			    pressed: '{livemode}'
-			},
-			handler: 'onLiveMode',
-		    },
-		    {
-			text: gettext('Select Timespan'),
-			bind: {
-			    pressed: '{!livemode}'
-			},
-			handler: 'onTimespan',
-		    }
-		]
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Since') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Until') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		reference: 'updateBtn',
-		handler: 'updateParams',
-		bind: {
-		    disabled: '{livemode}'
-		}
-	    }
-	]
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-Ext.define('Proxmox.widget.RRDChart', {
-    extend: 'Ext.chart.CartesianChart',
-    alias: 'widget.proxmoxRRDChart',
-
-    unit: undefined, // bytes, bytespersecond, percent
-    
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	convertToUnits: function(value) {
-	    var units = ['', 'k','M','G','T', 'P'];
-	    var si = 0;
-	    while(value >= 1000  && si < (units.length -1)){
-		value = value / 1000;
-		si++;
-	    }
-
-	    // javascript floating point weirdness
-	    value = Ext.Number.correctFloat(value);
-	    
-	    // limit to 2 decimal points
-	    value = Ext.util.Format.number(value, "0.##");
-	    
-	    return value.toString() + " " + units[si];
-	},
-
-	leftAxisRenderer: function(axis, label, layoutContext) {
-	    var me = this;
-
-	    return me.convertToUnits(label);
-	},
-
-	onSeriesTooltipRender: function(tooltip, record, item) {
-	    var me = this.getView();
-	    
-	    var suffix = '';
-	    
-	    if (me.unit === 'percent') {
-		suffix = '%';
-	    } else if (me.unit === 'bytes') {
-		suffix = 'B';
-	    } else if (me.unit === 'bytespersecond') {
-		suffix = 'B/s';
-	    }
-	    
-	    var prefix = item.field;
-	    if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
-		prefix = me.fieldTitles[me.fields.indexOf(item.field)];
-	    }
-            tooltip.setHtml(prefix + ': ' + this.convertToUnits(record.get(item.field)) + suffix +
-			    '<br>' + new Date(record.get('time')));
-	},
-
-	onAfterAnimation: function(chart, eopts) {
-	    // if the undobuton is disabled,
-	    // disable our tool
-
-	    var ourUndoZoomButton = chart.tools[0];
-	    var undoButton = chart.interactions[0].getUndoButton();
-	    ourUndoZoomButton.setDisabled(undoButton.isDisabled());
-	}
-    },
-    
-    width: 770,
-    height: 300,
-    animation: false,
-    interactions: [{
-	type: 'crosszoom'
-    }],
-    axes: [{
-	type: 'numeric',
-	position: 'left',
-	grid: true,
-	renderer: 'leftAxisRenderer',
-	//renderer: function(axis, label) { return label; },
-	minimum: 0
-    }, {
-	type: 'time',
-	position: 'bottom',
-	grid: true,
-	fields: ['time']
-    }],
-    legend: {
-	docked: 'bottom'
-    },
-    listeners: {
-	animationend: 'onAfterAnimation'
-    },
-
-
-    initComponent: function() {
-	var me = this;
-	var series = {};
-
-	if (!me.store) {
-	    throw "cannot work without store";
-	}
-
-	if (!me.fields) {
-	    throw "cannot work without fields";
-	}
-
-	me.callParent();
-
-	// add correct label for left axis
-	var axisTitle = "";
-	if (me.unit === 'percent') {
-	    axisTitle = "%";
-	} else if (me.unit === 'bytes') {
-	    axisTitle = "Bytes";
-	} else if (me.unit === 'bytespersecond') {
-	    axisTitle = "Bytes/s";
-	} else if (me.fieldTitles && me.fieldTitles.length === 1) {
-	    axisTitle = me.fieldTitles[0];
-	} else if (me.fields.length === 1) {
-	    axisTitle = me.fields[0];
-	}
-
-	me.axes[0].setTitle(axisTitle);
-
-	if (!me.noTool) {
-	    me.addTool([{
-		type: 'minus',
-		disabled: true,
-		tooltip: gettext('Undo Zoom'),
-		handler: function(){
-		    var undoButton = me.interactions[0].getUndoButton();
-		    if (undoButton.handler) {
-			undoButton.handler();
-		    }
-		}
-	    },{
-		type: 'restore',
-		tooltip: gettext('Toggle Legend'),
-		handler: function(){
-		    if (me.legend) {
-			me.legend.setVisible(!me.legend.isVisible());
-		    }
-		}
-	    }]);
-	}
-
-	// add a series for each field we get
-	me.fields.forEach(function(item, index){
-	    var title = item;
-	    if (me.fieldTitles && me.fieldTitles[index]) {
-		title = me.fieldTitles[index];
-	    }
-	    me.addSeries(Ext.apply(
-		{
-		    type: 'line',
-		    xField: 'time',
-		    yField: item,
-		    title: title,
-		    fill: true,
-		    style: {
-			lineWidth: 1.5,
-			opacity: 0.60
-		    },
-		    marker: {
-			opacity: 0,
-			scaling: 0.01,
-			fx: {
-			    duration: 200,
-			    easing: 'easeOut'
-			}
-		    },
-		    highlightCfg: {
-			opacity: 1,
-			scaling: 1.5
-		    },
-		    tooltip: {
-			trackMouse: true,
-			renderer: 'onSeriesTooltipRender'
-		    }
-		},
-		me.seriesConfig
-	    ));
-	});
-
-	// enable animation after the store is loaded
-	me.store.onAfter('load', function() {
-	    me.setAnimation(true);
-	}, this, {single: true});
-    }
-});
-Ext.define('Proxmox.panel.GaugeWidget', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.proxmoxGauge',
-
-    defaults: {
-	style: {
-	    'text-align':'center'
-	}
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	},
-	{
-	    xtype: 'polar',
-	    height: 120,
-	    border: false,
-	    itemId: 'chart',
-	    series: [{
-		type: 'gauge',
-		value: 0,
-		colors: ['#f5f5f5'],
-		sectors: [0],
-		donut: 90,
-		needleLength: 100,
-		totalAngle: Math.PI
-	    }],
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '',
-		textAlign: 'center',
-		textBaseline: 'bottom',
-		x: 125,
-		y: 110,
-		fontSize: 30
-	    }]
-	},
-	{
-	    xtype: 'box',
-	    itemId: 'text'
-	}
-    ],
-
-    header: false,
-    border: false,
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-    warningColor: '#fc0',
-    criticalColor: '#FF6C59',
-    defaultColor: '#c2ddf2',
-    backgroundColor: '#f5f5f5',
-
-    initialValue: 0,
-
-
-    updateValue: function(value, text) {
-	var me = this;
-	var color = me.defaultColor;
-	var attr = {};
-
-	if (value >= me.criticalThreshold) {
-	    color = me.criticalColor;
-	} else if (value >= me.warningThreshold) {
-	    color = me.warningColor;
-	}
-
-	me.chart.series[0].setColors([color, me.backgroundColor]);
-	me.chart.series[0].setValue(value*100);
-
-	me.valueSprite.setText(' '+(value*100).toFixed(0) + '%');
-	attr.x = me.chart.getWidth()/2;
-	attr.y = me.chart.getHeight()-20;
-	if (me.spriteFontSize) {
-	    attr.fontSize = me.spriteFontSize;
-	}
-	me.valueSprite.setAttributes(attr, true);
-
-	if (text !== undefined) {
-	    me.text.setHtml(text);
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.text = me.getComponent('text');
-	me.chart = me.getComponent('chart');
-	me.valueSprite = me.chart.getSurface('chart').get('valueSprite');
-    }
-});
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('Proxmox.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxWindowEdit',
-
-    // autoLoad trigger a load() after component creation
-    autoLoad: false,
-
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set isCreate to true if you want a Create button (instead
-    // OK and RESET)
-    isCreate: false,
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    // custom submitText
-    submitText: undefined,
-
-    backgroundDelay: 0,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-
-    // finds the first form field
-    defaultFocus: 'field[disabled=false][hidden=false]',
-
-    showProgress: false,
-
-    showTaskViewer: false,
-
-    // gets called if we have a progress bar or taskview and it detected that
-    // the task finished. function(success)
-    taskDone: Ext.emptyFn,
-
-    // gets called when the api call is finished, right at the beginning
-    // function(success, response, options)
-    apiCallDone: Ext.emptyFn,
-
-    // assign a reference from docs, to add a help button docked to the
-    // bottom of the window. If undefined we magically fall back to the
-    // onlineHelp of our first item, if set.
-    onlineHelp: undefined,
-
-    isValid: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-	return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	Ext.iterate(values, function(fieldId, val) {
-	    var field = form.findField(fieldId);
-	    if (field && !field.up('inputpanel')) {
-               field.setValue(val);
-                if (form.trackResetOnLoad) {
-                    field.resetOriginalValue();
-                }
-            }
-	});
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setValues(values);
-	});
-    },
-
-    submit: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	var values = me.getValues();
-	Ext.Object.each(values, function(name, val) {
-	    if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-		    values[name] = '';
-		}
-	    }
-	});
-
-	if (me.digest) {
-	    values.digest = me.digest;
-	}
-
-	if (me.backgroundDelay) {
-	    values.background_delay = me.backgroundDelay;
-	}
-
-	var url =  me.url;
-	if (me.method === 'DELETE') {
-	    url = url + "?" + Ext.Object.toQueryString(values);
-	    values = undefined;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    waitMsgTarget: me,
-	    method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-	    params: values,
-	    failure: function(response, options) {
-		me.apiCallDone(false, response, options);
-
-		if (response.result && response.result.errors) {
-		    form.markInvalid(response.result.errors);
-		}
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var hasProgressBar = (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
-		    response.result.data ? true : false;
-
-		me.apiCallDone(true, response, options);
-
-		if (hasProgressBar) {
-		    // stay around so we can trigger our close events
-		    // when background action is completed
-		    me.hide();
-
-		    var upid = response.result.data;
-		    var viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
-		    var win = Ext.create('Proxmox.window.Task' + viewerClass, {
-			upid: upid,
-			taskDone: me.taskDone,
-			listeners: {
-			    destroy: function () {
-				me.close();
-			    }
-			}
-		    });
-		    win.show();
-		} else {
-		    me.close();
-		}
-	    }
-	});
-    },
-
-    load: function(options) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	options = options || {};
-
-	var newopts = Ext.apply({
-	    waitMsgTarget: me
-	}, options);
-
-	var createWrapper = function(successFn) {
-	    Ext.apply(newopts, {
-		url: me.url,
-		method: 'GET',
-		success: function(response, opts) {
-		    form.clearInvalid();
-		    me.digest = response.result.data.digest;
-		    if (successFn) {
-			successFn(response, opts);
-		    } else {
-			me.setValues(response.result.data);
-		    }
-		    // hack: fix ExtJS bug
-		    Ext.Array.each(me.query('radiofield'), function(f) {
-			f.resetOriginalValue();
-		    });
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-			me.close();
-		    });
-		}
-	    });
-	};
-
-	createWrapper(options.success);
-
-	Proxmox.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.url) {
-	    throw "no url specified";
-	}
-
-	if (me.create) {throw "deprecated parameter, use isCreate";}
-
-	var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-	me.items = undefined;
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    url: me.url,
-	    method: me.method || 'PUT',
-	    trackResetOnLoad: true,
-	    bodyPadding: 10,
-	    border: false,
-	    defaults: Ext.apply({}, me.defaults, {
-		border: false
-	    }),
-	    fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-		labelWidth: 100,
-		anchor: '100%'
-            }),
-	    items: items
-	});
-
-	var inputPanel = me.formPanel.down('inputpanel');
-
-	var form = me.formPanel.getForm();
-
-	var submitText;
-	if (me.isCreate) {
-	    if (me.submitText) {
-		submitText = me.submitText;
-	    } else if (me.isAdd) {
-		submitText = gettext('Add');
-	    } else if (me.isRemove) {
-		submitText = gettext('Remove');
-	    } else {
-		submitText = gettext('Create');
-	    }
-	} else {
-	    submitText = me.submitText || gettext('OK');
-	}
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    reference: 'submitbutton',
-	    text: submitText,
-	    disabled: !me.isCreate,
-	    handler: function() {
-		me.submit();
-	    }
-	});
-
-	var resetBtn = Ext.create('Ext.Button', {
-	    text: 'Reset',
-	    disabled: true,
-	    handler: function(){
-		form.reset();
-	    }
-	});
-
-	var set_button_status = function() {
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-	    submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
-	    resetBtn.setDisabled(!dirty);
-
-	    if (inputPanel && inputPanel.hasAdvanced) {
-		// we want to show the advanced options
-		// as soon as some of it is not valid
-		var advancedItems = me.down('#advancedContainer').query('field');
-		var valid = true;
-		advancedItems.forEach(function(field) {
-		    if (!field.isValid()) {
-			valid = false;
-		    }
-		});
-
-		if (!valid) {
-		    inputPanel.setAdvancedVisible(true);
-		    me.down('#advancedcb').setValue(true);
-		}
-	    }
-	};
-
-	form.on('dirtychange', set_button_status);
-	form.on('validitychange', set_button_status);
-
-	var colwidth = 300;
-	if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-	    colwidth += me.fieldDefaults.labelWidth - 100;
-	}
-
-	var twoColumn = inputPanel &&
-	    (inputPanel.column1 || inputPanel.column2);
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
-	}
-
-	if (me.isCreate) {
-		me.buttons = [ submitBtn ] ;
-	} else {
-		me.buttons = [ submitBtn, resetBtn ];
-	}
-
-	if (inputPanel && inputPanel.hasAdvanced) {
-	    var sp = Ext.state.Manager.getProvider();
-	    var advchecked = sp.get('proxmox-advanced-cb');
-	    inputPanel.setAdvancedVisible(advchecked);
-	    me.buttons.unshift(
-	       {
-		   xtype: 'proxmoxcheckbox',
-		   itemId: 'advancedcb',
-		   boxLabelAlign: 'before',
-		   boxLabel: gettext('Advanced'),
-		   stateId: 'proxmox-advanced-cb',
-		   value: advchecked,
-		   listeners: {
-		       change: function(cb, val) {
-			   inputPanel.setAdvancedVisible(val);
-			   sp.set('proxmox-advanced-cb', val);
-		       }
-		   }
-	       }
-	    );
-	}
-
-	var onlineHelp = me.onlineHelp;
-	if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
-	    onlineHelp = inputPanel.onlineHelp;
-	}
-
-	if (onlineHelp) {
-	    var helpButton = Ext.create('Proxmox.button.Help');
-	    me.buttons.unshift(helpButton, '->');
-	    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
-	}
-
-	Ext.applyIf(me, {
-	    modal: true,
-	    width: twoColumn ? colwidth*2 : colwidth,
-	    border: false,
-	    items: [ me.formPanel ]
-	});
-
-	me.callParent();
-
-	// always mark invalid fields
-	me.on('afterlayout', function() {
-	    // on touch devices, the isValid function
-	    // triggers a layout, which triggers an isValid
-	    // and so on
-	    // to prevent this we disable the layouting here
-	    // and enable it afterwards
-	    me.suspendLayout = true;
-	    me.isValid();
-	    me.suspendLayout = false;
-	});
-
-	if (me.autoLoad) {
-	    me.load();
-	}
-    }
-});
-Ext.define('Proxmox.window.PasswordEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'proxmoxWindowPasswordEdit',
-
-    subject: gettext('Password'),
-
-    url: '/api2/extjs/access/password',
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    allowBlank: false,
-	    name: 'password',
-	    listeners: {
-                change: function(field){
-		    field.next().validate();
-                },
-                blur: function(field){
-		    field.next().validate();
-                }
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'),
-	    name: 'verifypassword',
-	    allowBlank: false,
-	    vtype: 'password',
-	    initialPassField: 'password',
-	    submitValue: false
-	},
-	{
-	    xtype: 'hiddenfield',
-	    name: 'userid'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	me.callParent();
-	me.down('[name=userid]').setValue(me.userid);
-    }
-});
-Ext.define('Proxmox.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskProgress',
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: {
-		status: { defaultValue: 'unknown' },
-		exitstatus: { defaultValue: 'unknown' }
-	    }
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var getObjectValue = function(key, defaultValue) {
-	    var rec = statstore.getById(key);
-	    if (rec) {
-		return rec.data.value;
-	    }
-	    return defaultValue;
-	};
-
-	var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-	me.mon(statstore, 'load', function() {
-	    var status = getObjectValue('status');
-	    if (status === 'stopped') {
-		var exitstatus = getObjectValue('exitstatus');
-		if (exitstatus == 'OK') {
-		    pbar.reset();
-		    pbar.updateText("Done!");
-		    Ext.Function.defer(me.close, 1000, me);
-		} else {
-		    me.close();
-		    Ext.Msg.alert('Task failed', exitstatus);
-		}
-		me.taskDone(exitstatus == 'OK');
-	    }
-	});
-
-	var descr = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	Ext.apply(me, {
-	    title: gettext('Task') + ': ' + descr,
-	    width: 300,
-	    layout: 'auto',
-	    modal: true,
-	    bodyPadding: 5,
-	    items: pbar,
-	    buttons: [
-		{ 
-		    text: gettext('Details'),
-		    handler: function() {			
-			var win = Ext.create('Proxmox.window.TaskViewer', { 
-			    taskDone: me.taskDone,
-			    upid: me.upid
-			});
-			win.show();
-			me.close();
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	statstore.startUpdate();
-
-	pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('Proxmox.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskViewer',
-
-    extraTitle: '', // string to prepend after the generic task title
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statgrid;
-
-	var rows = {
-	    status: {
-		header: gettext('Status'),
-		defaultValue: 'unknown',
-		renderer: function(value) {
-		    if (value != 'stopped') {
-			return value;
-		    }
-		    var es = statgrid.getObjectValue('exitstatus');
-		    if (es) {
-			return value + ': ' + es;
-		    }
-		}
-	    },
-	    exitstatus: { 
-		visible: false
-	    },
-	    type: {
-		header: gettext('Task type'),
-		required: true
-	    },
-	    user: {
-		header: gettext('User name'),
-		required: true 
-	    },
-	    node: {
-		header: gettext('Node'),
-		required: true 
-	    },
-	    pid: {
-		header: gettext('Process ID'),
-		required: true
-	    },
-	    starttime: {
-		header: gettext('Start Time'),
-		required: true, 
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    upid: {
-		header: gettext('Unique task ID')
-	    }
-	};
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: rows
-	});
-
-	me.on('destroy', statstore.stopUpdate);	
-
-	var stop_task = function() {
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + task.node + "/tasks/" + me.upid,
-		waitMsgTarget: me,
-		method: 'DELETE',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var stop_btn1 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	var stop_btn2 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	statgrid = Ext.create('Proxmox.grid.ObjectGrid', {
-	    title: gettext('Status'),
-	    layout: 'fit',
-	    tbar: [ stop_btn1 ],
-	    rstore: statstore,
-	    rows: rows,
-	    border: false
-	});
-
-	var logView = Ext.create('Proxmox.panel.LogView', {
-	    title: gettext('Output'),
-	    tbar: [ stop_btn2 ],
-	    border: false,
-	    url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-	});
-
-	me.mon(statstore, 'load', function() {
-	    var status = statgrid.getObjectValue('status');
-	    
-	    if (status === 'stopped') {
-		logView.scrollToEnd = false;
-		logView.requestUpdate();
-		statstore.stopUpdate();
-		me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
-	    }
-
-	    stop_btn1.setDisabled(status !== 'running');
-	    stop_btn2.setDisabled(status !== 'running');
-	});
-
-	statstore.startUpdate();
-
-	Ext.apply(me, {
-	    title: "Task viewer: " + task.desc + me.extraTitle,
-	    width: 800,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [{
-		xtype: 'tabpanel',
-		region: 'center',
-		items: [ logView, statgrid ]
-	    }]
-        });
-
-	me.callParent();
-
-	logView.fireEvent('show', logView);
-    }
-});
-
-Ext.define('apt-pkglist', {
-    extend: 'Ext.data.Model',
-    fields: [ 'Package', 'Title', 'Description', 'Section', 'Arch',
-	      'Priority', 'Version', 'OldVersion', 'ChangeLogUrl', 'Origin' ],
-    idProperty: 'Package'
-});
-
-Ext.define('Proxmox.node.APT', {
-    extend: 'Ext.grid.GridPanel',
-
-    xtype: 'proxmoxNodeAPT',
-
-    upgradeBtn: undefined,
-
-    columns: [
-	{
-	    header: gettext('Package'),
-	    width: 200,
-	    sortable: true,
-	    dataIndex: 'Package'
-	},
-	{
-	    text: gettext('Version'),
-	    columns: [
-		{
-		    header: gettext('current'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'OldVersion'
-		},
-		{
-		    header: gettext('new'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'Version'
-		}
-	    ]
-	},
-	{
-	    header: gettext('Description'),
-	    sortable: false,
-	    dataIndex: 'Title',
-	    flex: 1
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'apt-pkglist',
-	    groupField: 'Origin',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/apt/update"
-	    },
-	    sorters: [
-		{
-		    property : 'Package',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
-            groupHeaderTpl: '{[ "Origin: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
-	    enableGroupingMenu: false
-	});
-
-	var rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {
-            getAdditionalData: function (data, rowIndex, record, orig) {
-		var headerCt = this.view.headerCt;
-		var colspan = headerCt.getColumnCount();
-		return {
-		    rowBody: '<div style="padding: 1em">' +
-			Ext.String.htmlEncode(data.Description) +
-			'</div>',
-		    rowBodyCls: me.full_description ? '' : Ext.baseCSSPrefix + 'grid-row-body-hidden',
-		    rowBodyColspan: colspan
-		};
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	var apt_command = function(cmd){
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/apt/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.mon(win, 'close', reload);
-		}
-	    });
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var update_btn = new Ext.Button({
-	    text: gettext('Refresh'),
-	    handler: function() {
-		Proxmox.Utils.checked_command(function() { apt_command('update'); });
-	    }
-	});
-
-	var show_changelog = function(rec) {
-	    if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		return;
-	    }
-
-	    var view = Ext.createWidget('component', {
-		autoScroll: true,
-		style: {
-		    'background-color': 'white',
-		    'white-space': 'pre',
-		    'font-family': 'monospace',
-		    padding: '5px'
-		}
-	    });
-
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Changelog') + ": " + rec.data.Package,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		modal: true,
-		items: [ view ]
-	    });
-
-	    Proxmox.Utils.API2Request({
-		waitMsgTarget: me,
-		url: "/nodes/" + me.nodename + "/apt/changelog",
-		params: {
-		    name: rec.data.Package,
-		    version: rec.data.Version
-		},
-		method: 'GET',
-		failure: function(response, opts) {
-		    win.close();
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    win.show();
-		    view.update(Ext.htmlEncode(response.result.data));
-		}
-	    });
-
-	};
-
-	var changelog_btn = new Proxmox.button.Button({
-	    text: gettext('Changelog'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function(b, e, rec) {
-		show_changelog(rec);
-	    }
-	});
-
-	var verbose_desc_checkbox = new Ext.form.field.Checkbox({
-	    boxLabel: gettext('Show details'),
-	    value: false,
-	    listeners: {
-		change: (f, val) => {
-		    me.full_description = val;
-		    me.getView().refresh();
-		}
-	    }
-	});
-
-	if (me.upgradeBtn) {
-	    me.tbar =  [ update_btn, me.upgradeBtn, changelog_btn, '->', verbose_desc_checkbox ];
-	} else {
-	    me.tbar =  [ update_btn, changelog_btn, '->', verbose_desc_checkbox ];
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-update',
-	    selModel: sm,
-            viewConfig: {
-		stripeRows: false,
-		emptyText: '<div style="display:table; width:100%; height:100%;"><div style="display:table-cell; vertical-align: middle; text-align:center;"><b>' + gettext('No updates available.') + '</div></div>'
-	    },
-	    features: [ groupingFeature, rowBodyFeature ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: function(v, rec) {
-		    show_changelog(rec);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeNetworkEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.iftype) {
-	    throw "no network device type specified";
-	}
-
-	me.isCreate = !me.iface;
-
-	var iface_vtype;
-
-	if (me.iftype === 'bridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'bond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'eth' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'vlan' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSBridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'OVSBond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'OVSIntPort') {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSPort') {
-	    iface_vtype = 'InterfaceName';
-	} else {
-	    console.log(me.iftype);
-	    throw "unknown network device type specified";
-	}
-
-	me.subject = Proxmox.Utils.render_network_iface_type(me.iftype);
-
-	var column2 = [];
-
-	if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' ||
-	      me.iftype === 'OVSBond')) {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Autostart'),
-		name: 'autostart',
-		uncheckedValue: 0,
-		checked: me.isCreate ? true : undefined
-	    });
-	}
-
-	if (me.iftype === 'bridge') {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('VLAN aware'),
-		name: 'bridge_vlan_aware',
-		deleteEmpty: !me.isCreate
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'bridge_ports'
-	    });
-	} else if (me.iftype === 'OVSBridge') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'ovs_ports'
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'OVSPort' || me.iftype === 'OVSIntPort') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'bond') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Slaves'),
-		name: 'slaves'
-	    });
-
-	    var policySelector = Ext.createWidget('bondPolicySelector', {
-		fieldLabel: gettext('Hash policy'),
-		name: 'bond_xmit_hash_policy',
-		deleteEmpty: !me.isCreate,
-		disabled: true
-	    });
-
-	    column2.push({
-		xtype: 'bondModeSelector',
-		fieldLabel: gettext('Mode'),
-		name: 'bond_mode',
-		value: me.isCreate ? 'balance-rr' : undefined,
-		listeners: {
-		    change: function(f, value) {
-			if (value === 'balance-xor' ||
-			    value === '802.3ad') {
-			    policySelector.setDisabled(false);
-			} else {
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			}
-		    }
-		},
-		allowBlank: false
-	    });
-
-	    column2.push(policySelector);
-
-	} else if (me.iftype === 'OVSBond') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	}
-
-	column2.push({
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Comment'),
-	    allowBlank: true,
-	    nodename: me.nodename,
-	    name: 'comments'
-	});
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network";
-	    method = 'POST';
-	} else {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network/" + me.iface;
-	    method = 'PUT';
-	}
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: me.iftype
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		fieldLabel: gettext('Name'),
-		name: 'iface',
-		value: me.iface,
-		vtype: iface_vtype,
-		allowBlank: false
-	    }
-	];
-
-	if (me.iftype === 'OVSBond') {
-	    column1.push(
-		{
-		    xtype: 'bondModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    name: 'bond_mode',
-		    openvswitch: true,
-		    value: me.isCreate ? 'active-backup' : undefined,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Slaves'),
-		    name: 'ovs_bonds'
-		}
-	    );
-	} else {
-
-	    column1.push(
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv4/CIDR',
-		    vtype: 'IPCIDRAddress',
-		    name: 'cidr'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv4)',
-		    vtype: 'IPAddress',
-		    name: 'gateway'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv6/CIDR',
-		    vtype: 'IP6CIDRAddress',
-		    name: 'cidr6'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv6)',
-		    vtype: 'IP6Address',
-		    name: 'gateway6'
-		}
-	    );
-	}
-
-	Ext.applyIf(me, {
-	    url: url,
-	    method: method,
-	    items: {
-                xtype: 'inputpanel',
-		column1: column1,
-		column2: column2
-	    }
-	});
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.down('field[name=iface]').setValue(me.iface_default);
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.type !== me.iftype) {
-			var msg = "Got unexpected device type";
-			Ext.Msg.alert(gettext('Error'), msg, function() {
-			    me.close();
-			});
-			return;
-		    }
-		    me.setValues(data);
-		    me.isValid(); // trigger validation
-		}
-	    });
-	}
-    }
-});
-Ext.define('proxmox-networks', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'iface', 'type', 'active', 'autostart',
-	'bridge_ports', 'slaves',
-	'address', 'netmask', 'gateway',
-	'address6', 'netmask6', 'gateway6',
-	'cidr', 'cidr6',
-	'comments'
-    ],
-    idProperty: 'iface'
-});
-
-Ext.define('Proxmox.node.NetworkView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.proxmoxNodeNetworkView'],
-
-    // defines what types of network devices we want to create
-    // order is always the same
-    types: ['bridge', 'bond', 'ovs'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseUrl = '/nodes/' + me.nodename + '/network';
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'proxmox-networks',
-	    proxy: {
-                type: 'proxmox',
-                url: '/api2/json' + baseUrl
-	    },
-	    sorters: [
-		{
-		    property : 'iface',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reload = function() {
-	    var changeitem = me.down('#changes');
-	    Proxmox.Utils.API2Request({
-		url: baseUrl,
-		failure: function(response, opts) {
-		    store.loadData({});
-		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		    changeitem.update('');
-		    changeitem.setHidden(true);
-		},
-		success: function(response, opts) {
-		    var result = Ext.decode(response.responseText);
-		    store.loadData(result.data);
-		    var changes = result.changes;
-		    if (changes === undefined || changes === '') {
-			changes = gettext("No changes");
-			changeitem.setHidden(true);
-		    } else {
-			changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
-			changeitem.setHidden(false);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.node.NetworkEdit', {
-		nodename: me.nodename,
-		iface: rec.data.iface,
-		iftype: rec.data.type
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: run_editor
-	});
-
-	var del_btn = new Ext.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    handler: function(){
-		var grid = me.down('gridpanel');
-		var sm = grid.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var iface = rec.data.iface;
-
-		Proxmox.Utils.API2Request({
-		    url: baseUrl + '/' + iface,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var set_button_status = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    edit_btn.setDisabled(!rec);
-	    del_btn.setDisabled(!rec);
-	};
-
-	var render_ports = function(value, metaData, record) {
-	    if (value === 'bridge') {
-		return record.data.bridge_ports;
-	    } else if (value === 'bond') {
-		return record.data.slaves;
-	    } else if (value === 'OVSBridge') {
-		return record.data.ovs_ports;
-	    } else if (value === 'OVSBond') {
-		return record.data.ovs_bonds;
-	    }
-	};
-
-	var find_next_iface_id = function(prefix) {
-	    var next;
-	    for (next = 0; next <= 9999; next++) {
-		if (!store.getById(prefix + next.toString())) {
-		    break;
-		}
-	    }
-	    return prefix + next.toString();
-	};
-
-	var menu_items = [];
-
-	if (me.types.indexOf('bridge') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bridge'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bridge',
-			iface_default: find_next_iface_id('vmbr')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('bond') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bond'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bond',
-			iface_default: find_next_iface_id('bond')
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('ovs') !== -1) {
-	    if (menu_items.length > 0) {
-		menu_items.push({ xtype: 'menuseparator' });
-	    }
-
-	    menu_items.push(
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBridge',
-			    iface_default: find_next_iface_id('vmbr')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBond'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBond',
-			    iface_default: find_next_iface_id('bond')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSIntPort'
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		}
-	    );
-	}
-
-	var renderer_generator = function(fieldname) {
-	    return function(val, metaData, rec) {
-		var tmp = [];
-		if (rec.data[fieldname]) {
-		    tmp.push(rec.data[fieldname]);
-		}
-		if (rec.data[fieldname + '6']) {
-		    tmp.push(rec.data[fieldname + '6']);
-		}
-		return tmp.join('<br>') || '';
-	    };
-	};
-
-	Ext.apply(me, {
-	    layout: 'border',
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    menu: {
-			plain: true,
-			items: menu_items
-		    }
-		}, ' ',
-		{
-		    text: gettext('Revert'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: baseUrl,
-			    method: 'DELETE',
-			    waitMsgTarget: me,
-			    callback: function() {
-				reload();
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		edit_btn,
-		del_btn
-	    ],
-	    items: [
-		{
-		    xtype: 'gridpanel',
-		    stateful: true,
-		    stateId: 'grid-node-network',
-		    store: store,
-		    region: 'center',
-		    border: false,
-		    columns: [
-			{
-			    header: gettext('Name'),
-			    sortable: true,
-			    dataIndex: 'iface'
-			},
-			{
-			    header: gettext('Type'),
-			    sortable: true,
-			    width: 120,
-			    renderer: Proxmox.Utils.render_network_iface_type,
-			    dataIndex: 'type'
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Active'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'active',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText,
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Autostart'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'autostart',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('VLAN aware'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'bridge_vlan_aware',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    header: gettext('Ports/Slaves'),
-			    dataIndex: 'type',
-			    renderer: render_ports
-			},
-			{
-			    header: gettext('Bond Mode'),
-			    dataIndex: 'bond_mode',
-			    renderer: Proxmox.Utils.render_bond_mode,
-			},
-			{
-			    header: gettext('Hash Policy'),
-			    hidden: true,
-			    dataIndex: 'bond_xmit_hash_policy',
-			},
-			{
-			    header: gettext('IP address'),
-			    sortable: true,
-			    width: 120,
-			    hidden: true,
-			    dataIndex: 'address',
-			    renderer: renderer_generator('address'),
-			},
-			{
-			    header: gettext('Subnet mask'),
-			    width: 120,
-			    sortable: true,
-			    hidden: true,
-			    dataIndex: 'netmask',
-			    renderer: renderer_generator('netmask'),
-			},
-			{
-			    header: gettext('CIDR'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'cidr',
-			    renderer: renderer_generator('cidr'),
-			},
-			{
-			    header: gettext('Gateway'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'gateway',
-			    renderer: renderer_generator('gateway'),
-			},
-			{
-			    header: gettext('Comment'),
-			    dataIndex: 'comments',
-			    flex: 1,
-			    renderer: Ext.String.htmlEncode
-			}
-		    ],
-		    listeners: {
-			selectionchange: set_button_status,
-			itemdblclick: run_editor
-		    }
-		},
-		{
-		    border: false,
-		    region: 'south',
-		    autoScroll: true,
-		    hidden: true,
-		    itemId: 'changes',
-		    tbar: [
-			gettext('Pending changes') + ' (' +
-			    gettext('Please reboot to activate changes') + ')'
-		    ],
-		    split: true,
-		    bodyPadding: 5,
-		    flex: 0.6,
-		    html: gettext("No changes")
-		}
-	    ],
-	});
-
-	me.callParent();
-	reload();
-    }
-});
-Ext.define('Proxmox.node.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeDNSEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-                fieldLabel: gettext('Search domain'),
-                name: 'search',
-                allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 1",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns1'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS server') + " 2",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns2'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 3",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns3'
-	    }
-	];
-
-	Ext.applyIf(me, {
-	    subject: gettext('DNS'),
-	    url: "/api2/extjs/nodes/" + me.nodename + "/dns",
-	    fieldDefaults: {
-		labelWidth: 120
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('Proxmox.node.HostsView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxNodeHostsView',
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-    },
-
-    tbar: [
-	{
-	    text: gettext('Save'),
-	    disabled: true,
-	    itemId: 'savebtn',
-	    handler: function() {
-		var me = this.up('panel');
-		Proxmox.Utils.API2Request({
-		    params: {
-			digest: me.digest,
-			data: me.down('#hostsfield').getValue()
-		    },
-		    method: 'POST',
-		    url: '/nodes/' + me.nodename + '/hosts',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			me.reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	{
-	    text: gettext('Revert'),
-	    disabled: true,
-	    itemId: 'resetbtn',
-	    handler: function() {
-		var me = this.up('panel');
-		me.down('#hostsfield').reset();
-	    }
-	}
-    ],
-
-	    layout: 'fit',
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'hostsfield',
-	    fieldStyle: {
-		'font-family': 'monospace',
-		'white-space': 'pre'
-	    },
-	    listeners: {
-		dirtychange: function(ta, dirty) {
-		    var me = this.up('panel');
-		    me.down('#savebtn').setDisabled(!dirty);
-		    me.down('#resetbtn').setDisabled(!dirty);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/hosts",
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.store);
-
-	me.mon(me.store, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    me.digest = records[0].data.digest;
-	    var data = records[0].data.data;
-	    me.down('#hostsfield').setValue(data);
-	    me.down('#hostsfield').resetOriginalValue();
-	});
-
-	me.reload();
-    }
-});
-Ext.define('Proxmox.node.DNSView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeDNSView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.DNSEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/dns",
-	    cwidth1: 130,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		search: {
-		    header: 'Search domain',
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns1: {
-		    header: gettext('DNS server') + " 1",
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns2: {
-		    header: gettext('DNS server') + " 2",
-		    renderer: Ext.htmlEncode
-		},
-		dns3: {
-		    header: gettext('DNS server') + " 3",
-		    renderer: Ext.htmlEncode
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
-Ext.define('Proxmox.node.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeTasks'],
-    stateful: true,
-    stateId: 'grid-node-tasks',
-    loadMask: true,
-    sortableColumns: false,
-    vmidFilter: 0,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.BufferedStore', {
-	    pageSize: 500,
-	    autoLoad: true,
-	    remoteFilter: true,
-	    model: 'proxmox-tasks',
-	    proxy: {
-                type: 'proxmox',
-		startParam: 'start',
-		limitParam: 'limit',
-                url: "/api2/json/nodes/" + me.nodename + "/tasks"
-	    }
-	});
-
-	var userfilter = '';
-	var filter_errors = 0;
-
-	var updateProxyParams = function() {
-	    var params = {
-		errors: filter_errors
-	    };
-	    if (userfilter) {
-		params.userfilter = userfilter;
-	    }
-	    if (me.vmidFilter) {
-		params.vmid = me.vmidFilter;
-	    }
-	    store.proxy.extraParams = params;
-	};
-
-	updateProxyParams();
-
-	var reload_task = Ext.create('Ext.util.DelayedTask',function() {
-	    updateProxyParams();
-	    store.reload();
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	var view_btn = new Ext.Button({
-	    text: gettext('View'),
-	    disabled: true,
-	    handler: run_task_viewer
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	Ext.apply(me, {
-	    store: store,
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: false, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    tbar: [
-		view_btn, '->', gettext('User name') +':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: userfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    userfilter = field.getValue();
-			    reload_task.delay(500);
-			}
-		    }
-		}, ' ', gettext('Only Errors') + ':', ' ',
-		{
-		    xtype: 'checkbox',
-		    hideLabel: true,
-		    checked: filter_errors,
-		    listeners: {
-			change: function(field, checked) {
-			    filter_errors = checked ? 1 : 0;
-			    reload_task.delay(10);
-			}
-		    }
-		}, ' '
-	    ],
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 100,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 100,
-		    renderer: function(value, metaData, record) {
-			return Ext.Date.format(value,"M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return "ERROR: " + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		selectionchange: function(v, selections) {
-		    view_btn.setDisabled(!(selections && selections[0]));
-		},
-		show: function() { reload_task.delay(10); },
-		destroy: function() { reload_task.cancel(); }
-	    }
-	});
-
-	me.callParent();
-
-    }
-});
-Ext.define('proxmox-services', {
-    extend: 'Ext.data.Model',
-    fields: [ 'service', 'name', 'desc', 'state' ],
-    idProperty: 'service'
-});
-
-Ext.define('Proxmox.node.ServiceView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeServiceView'],
-
-    startOnlyServices: {},
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 1000,
-	    storeid: 'proxmox-services' + me.nodename,
-	    model: 'proxmox-services',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/services"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sortAfterUpdate: true,
-	    sorters: [
-		{
-		    property : 'name',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var view_service_log = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + rec.data.service,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: {
-		    xtype: 'proxmoxLogView',
-		    url: "/api2/extjs/nodes/" + me.nodename + "/syslog?service=" +
-			rec.data.service,
-		    log_select_timespan: 1
-		}
-	    });
-	    win.show();
-	};
-
-	var service_cmd = function(cmd) {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/services/" + rec.data.service + "/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.loading = true;
-		},
-		success: function(response, opts) {
-		    rstore.startUpdate();
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid
-		    });
-		    win.show();
-		}
-	    });
-	};
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var syslog_btn = new Ext.Button({
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: view_service_log
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		start_btn.disable();
-		stop_btn.disable();
-		restart_btn.disable();
-		syslog_btn.disable();
-		return;
-	    }
-	    var service = rec.data.service;
-	    var state = rec.data.state;
-
-	    syslog_btn.enable();
-
-	    if (me.startOnlyServices[service]) {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		}
-		stop_btn.disable();
-	    } else {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		    stop_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		    stop_btn.disable();
-		}
-	    }
-	};
-
-	me.mon(store, 'refresh', set_button_status);
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    tbar: [ start_btn, stop_btn, restart_btn, syslog_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Description'),
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'desc',
-		    flex: 2
-		}
-	    ],
-	    listeners: {
-		selectionchange: set_button_status,
-		itemdblclick: view_service_log,
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeTimeEdit'],
-
-    subject: gettext('Time zone'),
-
-    width: 400,
-
-    autoLoad: true,
-
-    fieldDefaults: {
-	labelWidth: 70
-    },
-
-    items: {
-	xtype: 'combo',
-	fieldLabel: gettext('Time zone'),
-	name: 'timezone',
-	queryMode: 'local',
-	store: Ext.create('Proxmox.data.TimezoneStore'),
-	displayField: 'zone',
-	editable: true,
-	anyMatch: true,
-	forceSelection: true,
-	allowBlank: false
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/time";
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeTimeView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var tzoffset = (new Date()).getTimezoneOffset()*60000;
-	var renderlocaltime = function(value) {
-	    var servertime = new Date((value * 1000) + tzoffset);
-	    return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-	};
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.TimeEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/time",
-	    cwidth1: 150,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		timezone: { 
-		    header: gettext('Time zone'), 
-		    required: true
-		},
-		localtime: { 
-		    header: gettext('Server time'), 
-		    required: true, 
-		    renderer: renderlocaltime 
-		}
-	    },
-	    tbar: [ 
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
diff --git a/serverside/jsmod/6.0-4/pvemanagerlib.js b/serverside/jsmod/6.0-4/pvemanagerlib.js
deleted file mode 100644
index add3e4946789acc4050750af3e179815c48861cf..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/pvemanagerlib.js
+++ /dev/null
@@ -1,39779 +0,0 @@
-var pveOnlineHelpInfo = {
-   "ceph_rados_block_devices" : {
-      "link" : "/pve-docs/chapter-pvesm.html#ceph_rados_block_devices",
-      "title" : "Ceph RADOS Block Devices (RBD)"
-   },
-   "chapter_ha_manager" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#chapter_ha_manager",
-      "title" : "High Availability"
-   },
-   "chapter_lvm" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_lvm",
-      "title" : "Logical Volume Manager (LVM)"
-   },
-   "chapter_pct" : {
-      "link" : "/pve-docs/chapter-pct.html#chapter_pct",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "chapter_pve_firewall" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#chapter_pve_firewall",
-      "title" : "Proxmox VE Firewall"
-   },
-   "chapter_pveceph" : {
-      "link" : "/pve-docs/chapter-pveceph.html#chapter_pveceph",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "chapter_pvecm" : {
-      "link" : "/pve-docs/chapter-pvecm.html#chapter_pvecm",
-      "title" : "Cluster Manager"
-   },
-   "chapter_pvesr" : {
-      "link" : "/pve-docs/chapter-pvesr.html#chapter_pvesr",
-      "title" : "Storage Replication"
-   },
-   "chapter_storage" : {
-      "link" : "/pve-docs/chapter-pvesm.html#chapter_storage",
-      "title" : "Proxmox VE Storage"
-   },
-   "chapter_system_administration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_system_administration",
-      "title" : "Host System Administration"
-   },
-   "chapter_user_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#chapter_user_management",
-      "title" : "User Management"
-   },
-   "chapter_virtual_machines" : {
-      "link" : "/pve-docs/chapter-qm.html#chapter_virtual_machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "chapter_vzdump" : {
-      "link" : "/pve-docs/chapter-vzdump.html#chapter_vzdump",
-      "title" : "Backup and Restore"
-   },
-   "chapter_zfs" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_zfs",
-      "title" : "ZFS on Linux"
-   },
-   "datacenter_configuration_file" : {
-      "link" : "/pve-docs/pve-admin-guide.html#datacenter_configuration_file",
-      "title" : "Datacenter Configuration"
-   },
-   "getting_help" : {
-      "link" : "/pve-docs/pve-admin-guide.html#getting_help",
-      "title" : "Getting Help"
-   },
-   "gui_my_settings" : {
-      "link" : "/pve-docs/chapter-pve-gui.html#gui_my_settings",
-      "subtitle" : "My Settings",
-      "title" : "Graphical User Interface"
-   },
-   "ha_manager_fencing" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_fencing",
-      "subtitle" : "Fencing",
-      "title" : "High Availability"
-   },
-   "ha_manager_groups" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_groups",
-      "subtitle" : "Groups",
-      "title" : "High Availability"
-   },
-   "ha_manager_resource_config" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resource_config",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_resources" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resources",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "pct_configuration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_configuration",
-      "subtitle" : "Configuration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_images" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_images",
-      "subtitle" : "Container Images",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_network" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_network",
-      "subtitle" : "Network",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_storage" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_storage",
-      "subtitle" : "Container Storage",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_cpu" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_cpu",
-      "subtitle" : "CPU",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_general" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_general",
-      "subtitle" : "General Settings",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_memory" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_memory",
-      "subtitle" : "Memory",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_migration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_migration",
-      "subtitle" : "Migration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_options" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_options",
-      "subtitle" : "Options",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_snapshots" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_snapshots",
-      "subtitle" : "Snapshots",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Containers",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pve_admin_guide" : {
-      "link" : "/pve-docs/pve-admin-guide.html",
-      "title" : "Proxmox VE Administration Guide"
-   },
-   "pve_ceph_install" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_install",
-      "subtitle" : "Installation of Ceph Packages",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_osds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_osds",
-      "subtitle" : "Creating Ceph OSDs",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_pools" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_pools",
-      "subtitle" : "Creating Ceph Pools",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_documentation_index" : {
-      "link" : "/pve-docs/index.html",
-      "title" : "Proxmox VE Documentation Index"
-   },
-   "pve_firewall_cluster_wide_setup" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_cluster_wide_setup",
-      "subtitle" : "Cluster Wide Setup",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_host_specific_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_host_specific_configuration",
-      "subtitle" : "Host Specific Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_aliases" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_aliases",
-      "subtitle" : "IP Aliases",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_sets" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_sets",
-      "subtitle" : "IP Sets",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_vm_container_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_vm_container_configuration",
-      "subtitle" : "VM/Container Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_service_daemons" : {
-      "link" : "/pve-docs/index.html#_service_daemons",
-      "title" : "Service Daemons"
-   },
-   "pveceph_fs" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs",
-      "subtitle" : "CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_create" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_create",
-      "subtitle" : "Create a CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pvecm_create_cluster" : {
-      "link" : "/pve-docs/chapter-pvecm.html#pvecm_create_cluster",
-      "subtitle" : "Create the Cluster",
-      "title" : "Cluster Manager"
-   },
-   "pvesr_schedule_time_format" : {
-      "link" : "/pve-docs/chapter-pvesr.html#pvesr_schedule_time_format",
-      "subtitle" : "Schedule Format",
-      "title" : "Storage Replication"
-   },
-   "pveum_authentication_realms" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_authentication_realms",
-      "subtitle" : "Authentication Realms",
-      "title" : "User Management"
-   },
-   "pveum_groups" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_groups",
-      "subtitle" : "Groups",
-      "title" : "User Management"
-   },
-   "pveum_permission_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_permission_management",
-      "subtitle" : "Permission Management",
-      "title" : "User Management"
-   },
-   "pveum_pools" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_pools",
-      "subtitle" : "Pools",
-      "title" : "User Management"
-   },
-   "pveum_roles" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_roles",
-      "subtitle" : "Roles",
-      "title" : "User Management"
-   },
-   "pveum_tfa_auth" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_tfa_auth",
-      "subtitle" : "Two factor authentication",
-      "title" : "User Management"
-   },
-   "pveum_users" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_users",
-      "subtitle" : "Users",
-      "title" : "User Management"
-   },
-   "qm_bios_and_uefi" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_bios_and_uefi",
-      "subtitle" : "BIOS and UEFI",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cloud_init" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cloud_init",
-      "title" : "Cloud-Init Support"
-   },
-   "qm_copy_and_clone" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_copy_and_clone",
-      "subtitle" : "Copies and Clones",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cpu" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cpu",
-      "subtitle" : "CPU",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_general_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_general_settings",
-      "subtitle" : "General Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_hard_disk" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_hard_disk",
-      "subtitle" : "Hard Disk",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_memory" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_memory",
-      "subtitle" : "Memory",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_migration" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_migration",
-      "subtitle" : "Migration",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_network_device" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_network_device",
-      "subtitle" : "Network Device",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_options" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_options",
-      "subtitle" : "Options",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_os_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_os_settings",
-      "subtitle" : "OS Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_pci_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_pci_passthrough",
-      "title" : "PCI(e) Passthrough"
-   },
-   "qm_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Virtual Machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_system_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_system_settings",
-      "subtitle" : "System Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_usb_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_usb_passthrough",
-      "subtitle" : "USB Passthrough",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_virtual_machines_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_virtual_machines_settings",
-      "subtitle" : "Virtual Machines Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "storage_cephfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cephfs",
-      "title" : "Ceph Filesystem (CephFS)"
-   },
-   "storage_cifs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cifs",
-      "title" : "CIFS Backend"
-   },
-   "storage_directory" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_directory",
-      "title" : "Directory Backend"
-   },
-   "storage_glusterfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_glusterfs",
-      "title" : "GlusterFS Backend"
-   },
-   "storage_lvm" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvm",
-      "title" : "LVM Backend"
-   },
-   "storage_lvmthin" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvmthin",
-      "title" : "LVM thin Backend"
-   },
-   "storage_nfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_nfs",
-      "title" : "NFS Backend"
-   },
-   "storage_open_iscsi" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_open_iscsi",
-      "title" : "Open-iSCSI initiator"
-   },
-   "storage_zfspool" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_zfspool",
-      "title" : "Local ZFS Pool Backend"
-   },
-   "sysadmin_certificate_management" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_certificate_management",
-      "title" : "Certificate Management"
-   },
-   "sysadmin_network_configuration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_network_configuration",
-      "title" : "Network Configuration"
-   }
-};
-Ext.ns('PVE');
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	log: function() {}
-    };
-}
-console.log("Starting PVE Manager");
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-/*jslint confusion: true */
-Ext.define('PVE.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js
-
-    bus_match: /^(ide|sata|virtio|scsi)\d+$/,
-
-    log_severity_hash: {
-	0: "panic",
-	1: "alert",
-	2: "critical",
-	3: "error",
-	4: "warning",
-	5: "notice",
-	6: "info",
-	7: "debug"
-    },
-
-    support_level_hash: {
-	'c': gettext('Community'),
-	'b': gettext('Basic'),
-	's': gettext('Standard'),
-	'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="https://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-	'Linux': [
-	    { desc: '5.x - 2.6 Kernel', val: 'l26' },
-	    { desc: '2.4 Kernel', val: 'l24' }
-	],
-	'Microsoft Windows': [
-	    { desc: '10/2016', val: 'win10' },
-	    { desc: '8.x/2012/2012r2', val: 'win8' },
-	    { desc: '7/2008r2', val: 'win7' },
-	    { desc: 'Vista/2008', val: 'w2k8' },
-	    { desc: 'XP/2003', val: 'wxp' },
-	    { desc: '2000', val: 'w2k' }
-	],
-	'Solaris Kernel': [
-	    { desc: '-', val: 'solaris'}
-	],
-	'Other': [
-	    { desc: '-', val: 'other'}
-	]
-    },
-
-    get_health_icon: function(state, circle) {
-	if (circle === undefined) {
-	    circle = false;
-	}
-
-	if (state === undefined) {
-	    state = 'uknown';
-	}
-
-	var icon = 'faded fa-question';
-	switch(state) {
-	    case 'good':
-		icon = 'good fa-check';
-		break;
-	    case 'old':
-		icon = 'warning fa-refresh';
-		break;
-	    case 'warning':
-		icon = 'warning fa-exclamation';
-		break;
-	    case 'critical':
-		icon = 'critical fa-times';
-		break;
-	    default: break;
-	}
-
-	if (circle) {
-	    icon += '-circle';
-	}
-
-	return icon;
-    },
-
-    parse_ceph_version: function(service) {
-	if (service.ceph_version_short) {
-	    return service.ceph_version_short;
-	}
-
-	if (service.ceph_version) {
-	    var match = service.ceph_version.match(/version (\d+(\.\d+)*)/);
-	    if (match) {
-		return match[1];
-	    }
-	}
-
-	return undefined;
-    },
-
-    compare_ceph_versions: function(a, b) {
-	if (a === b) {
-	    return 0;
-	}
-	let avers = a.toString().split('.');
-	let bvers = b.toString().split('.');
-
-	while (true) {
-	    let av = avers.shift();
-	    let bv = bvers.shift();
-
-	    if (av === undefined && bv === undefined) {
-		return 0;
-	    } else if (av === undefined)  {
-		return -1;
-	    } else if (bv === undefined) {
-		return 1;
-	    } else {
-		let diff = parseInt(av, 10) - parseInt(bv, 10);
-		if (diff != 0) return diff;
-		// else we need to look at the next parts
-	    }
-	}
-
-    },
-
-    get_ceph_icon_html: function(health, fw) {
-	var state = PVE.Utils.map_ceph_health[health];
-	var cls = PVE.Utils.get_health_icon(state);
-	if (fw) {
-	    cls += ' fa-fw';
-	}
-	return "<i class='fa " + cls + "'></i> ";
-    },
-
-    map_ceph_health: {
-	'HEALTH_OK':'good',
-	'HEALTH_OLD':'old',
-	'HEALTH_WARN':'warning',
-	'HEALTH_ERR':'critical'
-    },
-
-    render_ceph_health: function(healthObj) {
-	var state = {
-	    iconCls: PVE.Utils.get_health_icon(),
-	    text: ''
-	};
-
-	if (!healthObj || !healthObj.status) {
-	    return state;
-	}
-
-	var health = PVE.Utils.map_ceph_health[healthObj.status];
-
-	state.iconCls = PVE.Utils.get_health_icon(health, true);
-	state.text = healthObj.status;
-
-	return state;
-    },
-
-    render_zfs_health: function(value) {
-	if (typeof value == 'undefined'){
-	    return "";
-	}
-	var iconCls = 'question-circle';
-	switch (value) {
-	    case 'AVAIL':
-	    case 'ONLINE':
-		iconCls = 'check-circle good';
-		break;
-	    case 'REMOVED':
-	    case 'DEGRADED':
-		iconCls = 'exclamation-circle warning';
-		break;
-	    case 'UNAVAIL':
-	    case 'FAULTED':
-	    case 'OFFLINE':
-		iconCls = 'times-circle critical';
-		break;
-	    default: //unknown
-	}
-
-	return '<i class="fa fa-' + iconCls + '"></i> ' + value;
-
-    },
-
-    get_kvm_osinfo: function(value) {
-	var info = { base: 'Other' }; // default
-	if (value) {
-	    Ext.each(Object.keys(PVE.Utils.kvm_ostypes), function(k) {
-		Ext.each(PVE.Utils.kvm_ostypes[k], function(e) {
-		    if (e.val === value) {
-			info = { desc: e.desc, base: k };
-		    }
-		});
-	    });
-	}
-	return info;
-    },
-
-    render_kvm_ostype: function (value) {
-	var osinfo = PVE.Utils.get_kvm_osinfo(value);
-	if (osinfo.desc && osinfo.desc !== '-') {
-	    return osinfo.base + ' ' + osinfo.desc;
-	} else {
-	    return osinfo.base;
-	}
-    },
-
-    render_hotplug_features: function (value) {
-	var fa = [];
-
-	if (!value || (value === '0')) {
-	    return gettext('Disabled');
-	}
-
-	if (value === '1') {
-	    value = 'disk,network,usb';
-	}
-
-	Ext.each(value.split(','), function(el) {
-	    if (el === 'disk') {
-		fa.push(gettext('Disk'));
-	    } else if (el === 'network') {
-		fa.push(gettext('Network'));
-	    } else if (el === 'usb') {
-		fa.push('USB');
-	    } else if (el === 'memory') {
-		fa.push(gettext('Memory'));
-	    } else if (el === 'cpu') {
-		fa.push(gettext('CPU'));
-	    } else {
-		fa.push(el);
-	    }
-	});
-
-	return fa.join(', ');
-    },
-
-    render_qga_features: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText  + ')';
-	}
-	var props = PVE.Parser.parsePropertyString(value, 'enabled');
-	if (!PVE.Parser.parseBoolean(props.enabled)) {
-	    return Proxmox.Utils.disabledText;
-	}
-
-	delete props.enabled;
-	var agentstring = Proxmox.Utils.enabledText;
-
-	Ext.Object.each(props, function(key, value) {
-	    var keystring = '' ;
-	    agentstring += ', ' + key + ': ';
-
-	    if (PVE.Parser.parseBoolean(value)) {
-		agentstring += Proxmox.Utils.enabledText;
-	    } else {
-		agentstring += Proxmox.Utils.disabledText;
-	    }
-	});
-
-	return agentstring;
-    },
-
-    render_qemu_machine: function(value) {
-	return value || (Proxmox.Utils.defaultText + ' (i440fx)');
-    },
-
-    render_qemu_bios: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (SeaBIOS)';
-	} else if (value === 'seabios') {
-	    return "SeaBIOS";
-	} else if (value === 'ovmf') {
-	    return "OVMF (UEFI)";
-	} else {
-	    return value;
-	}
-    },
-
-    render_dc_ha_opts: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	} else {
-	    return PVE.Parser.printPropertyString(value);
-	}
-    },
-    render_as_property_string: function(value) {
-	return (!value) ? Proxmox.Utils.defaultText
-	    : PVE.Parser.printPropertyString(value);
-    },
-
-    render_scsihw: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (LSI 53C895A)';
-	} else if (value === 'lsi') {
-	    return 'LSI 53C895A';
-	} else if (value === 'lsi53c810') {
-	    return 'LSI 53C810';
-	} else if (value === 'megasas') {
-	    return 'MegaRAID SAS 8708EM2';
-	} else if (value === 'virtio-scsi-pci') {
-	    return 'VirtIO SCSI';
-	} else if (value === 'virtio-scsi-single') {
-	    return 'VirtIO SCSI single';
-	} else if (value === 'pvscsi') {
-	    return 'VMware PVSCSI';
-	} else {
-	    return value;
-	}
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-	//ar: 'Arabic',
-	da: 'Danish',
-	de: 'German',
-	'de-ch': 'German (Swiss)',
-	'en-gb': 'English (UK)',
-	'en-us': 'English (USA)',
-	es: 'Spanish',
-	//et: 'Estonia',
-	fi: 'Finnish',
-	//fo: 'Faroe Islands',
-	fr: 'French',
-	'fr-be': 'French (Belgium)',
-	'fr-ca': 'French (Canada)',
-	'fr-ch': 'French (Swiss)',
-	//hr: 'Croatia',
-	hu: 'Hungarian',
-	is: 'Icelandic',
-	it: 'Italian',
-	ja: 'Japanese',
-	lt: 'Lithuanian',
-	//lv: 'Latvian',
-	mk: 'Macedonian',
-	nl: 'Dutch',
-	//'nl-be': 'Dutch (Belgium)',
-	no: 'Norwegian',
-	pl: 'Polish',
-	pt: 'Portuguese',
-	'pt-br': 'Portuguese (Brazil)',
-	//ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	//th: 'Thai',
-	tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-	std: gettext('Standard VGA'),
-	vmware: gettext('VMware compatible'),
-	qxl: 'SPICE',
-	qxl2: 'SPICE dual monitor',
-	qxl3: 'SPICE three monitors',
-	qxl4: 'SPICE four monitors',
-	serial0: gettext('Serial terminal') + ' 0',
-	serial1: gettext('Serial terminal') + ' 1',
-	serial2: gettext('Serial terminal') + ' 2',
-	serial3: gettext('Serial terminal') + ' 3',
-	virtio: 'VirtIO-GPU',
-	none: Proxmox.Utils.noneText
-    },
-
-    render_kvm_language: function (value) {
-	if (!value || value === '__default__') {
-	    return Proxmox.Utils.defaultText;
-	}
-	var text = PVE.Utils.kvm_keymaps[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_keymap_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_language('')]];
-	Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_language(value)]);
-	});
-
-	return data;
-    },
-
-    console_map: {
-	'__default__': Proxmox.Utils.defaultText + ' (xterm.js)',
-	'vv': 'SPICE (remote-viewer)',
-	'html5': 'HTML5 (noVNC)',
-	'xtermjs': 'xterm.js'
-    },
-
-    render_console_viewer: function(value) {
-	value = value || '__default__';
-	if (PVE.Utils.console_map[value]) {
-	    return PVE.Utils.console_map[value];
-	}
-	return value;
-    },
-
-    console_viewer_array: function() {
-	return Ext.Array.map(Object.keys(PVE.Utils.console_map), function(v) {
-	    return [v, PVE.Utils.render_console_viewer(v)];
-	});
-    },
-
-    render_kvm_vga_driver: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	}
-	var vga = PVE.Parser.parsePropertyString(value, 'type');
-	var text = PVE.Utils.kvm_vga_drivers[vga.type];
-	if (!vga.type) {
-	    text = Proxmox.Utils.defaultText;
-	}
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_vga_driver_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_vga_driver('')]];
-	Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-	});
-
-	return data;
-    },
-
-    render_kvm_startup: function(value) {
-	var startup = PVE.Parser.parseStartup(value);
-
-	var res = 'order=';
-	if (startup.order === undefined) {
-	    res += 'any';
-	} else {
-	    res += startup.order;
-	}
-	if (startup.up !== undefined) {
-	    res += ',up=' + startup.up;
-	}
-	if (startup.down !== undefined) {
-	    res += ',down=' + startup.down;
-	}
-
-	return res;
-    },
-
-    extractFormActionError: function(action) {
-	var msg;
-	switch (action.failureType) {
-	case Ext.form.action.Action.CLIENT_INVALID:
-	    msg = gettext('Form fields may not be submitted with invalid values');
-	    break;
-	case Ext.form.action.Action.CONNECT_FAILURE:
-	    msg = gettext('Connection error');
-	    var resp = action.response;
-	    if (resp.status && resp.statusText) {
-		msg += " " + resp.status + ": " + resp.statusText;
-	    }
-	    break;
-	case Ext.form.action.Action.LOAD_FAILURE:
-	case Ext.form.action.Action.SERVER_INVALID:
-	    msg = Proxmox.Utils.extractRequestError(action.result, true);
-	    break;
-	}
-	return msg;
-    },
-
-    format_duration_short: function(ut) {
-
-	if (ut < 60) {
-	    return ut.toFixed(1) + 's';
-	}
-
-	if (ut < 3600) {
-	    var mins = ut / 60;
-	    return mins.toFixed(1) + 'm';
-	}
-
-	if (ut < 86400) {
-	    var hours = ut / 3600;
-	    return hours.toFixed(1) + 'h';
-	}
-
-	var days = ut / 86400;
-	return days.toFixed(1) + 'd';
-    },
-
-    contentTypes: {
-	'images': gettext('Disk image'),
-	'backup': gettext('VZDump backup file'),
-	'vztmpl': gettext('Container template'),
-	'iso': gettext('ISO image'),
-	'rootdir': gettext('Container'),
-	'snippets': gettext('Snippets')
-    },
-
-    storageSchema: {
-	dir: {
-	    name: Proxmox.Utils.directoryText,
-	    ipanel: 'DirInputPanel',
-	    faIcon: 'folder'
-	},
-	lvm: {
-	    name: 'LVM',
-	    ipanel: 'LVMInputPanel',
-	    faIcon: 'folder'
-	},
-	lvmthin: {
-	    name: 'LVM-Thin',
-	    ipanel: 'LvmThinInputPanel',
-	    faIcon: 'folder'
-	},
-	nfs: {
-	    name: 'NFS',
-	    ipanel: 'NFSInputPanel',
-	    faIcon: 'building'
-	},
-	cifs: {
-	    name: 'CIFS',
-	    ipanel: 'CIFSInputPanel',
-	    faIcon: 'building'
-	},
-	glusterfs: {
-	    name: 'GlusterFS',
-	    ipanel: 'GlusterFsInputPanel',
-	    faIcon: 'building'
-	},
-	iscsi: {
-	    name: 'iSCSI',
-	    ipanel: 'IScsiInputPanel',
-	    faIcon: 'building'
-	},
-	cephfs: {
-	    name: 'CephFS',
-	    ipanel: 'CephFSInputPanel',
-	    faIcon: 'building'
-	},
-	pvecephfs: {
-	    name: 'CephFS (PVE)',
-	    ipanel: 'CephFSInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	rbd: {
-	    name: 'RBD',
-	    ipanel: 'RBDInputPanel',
-	    faIcon: 'building'
-	},
-	pveceph: {
-	    name: 'RBD (PVE)',
-	    ipanel: 'RBDInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	zfs: {
-	    name: 'ZFS over iSCSI',
-	    ipanel: 'ZFSInputPanel',
-	    faIcon: 'building'
-	},
-	zfspool: {
-	    name: 'ZFS',
-	    ipanel: 'ZFSPoolInputPanel',
-	    faIcon: 'folder'
-	},
-	drbd: {
-	    name: 'DRBD',
-	    hideAdd: true
-	}
-    },
-
-    format_storage_type: function(value, md, record) {
-	if (value === 'rbd') {
-	    value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
-	} else if (value === 'cephfs') {
-	    value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
-	}
-
-	var schema = PVE.Utils.storageSchema[value];
-	if (schema) {
-	    return schema.name;
-	}
-	return Proxmox.Utils.unknownText;
-    },
-
-    format_ha: function(value) {
-	var text = Proxmox.Utils.noneText;
-
-	if (value.managed) {
-	    text = value.state || Proxmox.Utils.noneText;
-
-	    text += ', ' +  Proxmox.Utils.groupText + ': ';
-	    text += value.group || Proxmox.Utils.noneText;
-	}
-
-	return text;
-    },
-
-    format_content_types: function(value) {
-	return value.split(',').sort().map(function(ct) {
-	    return PVE.Utils.contentTypes[ct] || ct;
-	}).join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-	var data = record.data;
-	if (Ext.isNumber(data.channel) &&
-	    Ext.isNumber(data.id) &&
-	    Ext.isNumber(data.lun)) {
-	    return "CH " +
-		Ext.String.leftPad(data.channel,2, '0') +
-		" ID " + data.id + " LUN " + data.lun;
-	}
-	return data.volid.replace(/^.*:(.*\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-	return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	if (!(record.data.uptime && Ext.isNumeric(value))) {
-	    return '';
-	}
-
-	var maxcpu = record.data.maxcpu || 1;
-
-	if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-	    return '';
-	}
-
-	var per = value * 100;
-
-	return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-	/*jslint confusion: true */
-
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value);
-    },
-
-    render_bandwidth: function(value) {
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value) + '/s';
-    },
-
-    render_timestamp_human_readable: function(value) {
-	return Ext.Date.format(new Date(value * 1000), 'l d F Y H:i:s');
-    },
-
-    render_duration: function(value) {
-	if (value === undefined) {
-	    return '-';
-	}
-	return PVE.Utils.format_duration_short(value);
-    },
-
-    calculate_mem_usage: function(data) {
-	if (!Ext.isNumeric(data.mem) ||
-	    data.maxmem === 0 ||
-	    data.uptime < 1) {
-	    return -1;
-	}
-
-	return (data.mem / data.maxmem);
-    },
-
-    render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-	if (value > 1 ) {
-	    // we got no percentage but bytes
-	    var mem = value;
-	    var maxmem = record.data.maxmem;
-	    if (!record.data.uptime ||
-		maxmem === 0 ||
-		!Ext.isNumeric(mem)) {
-		return '';
-	    }
-
-	    return ((mem*100)/maxmem).toFixed(1) + " %";
-	}
-	return (value*100).toFixed(1) + " %";
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var mem = value;
-	var maxmem = record.data.maxmem;
-
-	if (!record.data.uptime) {
-	    return '';
-	}
-
-	if (!(Ext.isNumeric(mem) && maxmem)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    calculate_disk_usage: function(data) {
-
-	if (!Ext.isNumeric(data.disk) ||
-	    data.type === 'qemu' ||
-	    (data.type === 'lxc' && data.uptime === 0) ||
-	    data.maxdisk === 0) {
-	    return -1;
-	}
-
-	return (data.disk / data.maxdisk);
-    },
-
-    render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-
-	return (value * 100).toFixed(1) + " %";
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var disk = value;
-	var maxdisk = record.data.maxdisk;
-	var type = record.data.type;
-
-	if (!Ext.isNumeric(disk) ||
-	    type === 'qemu' ||
-	    maxdisk === 0 ||
-	    (type === 'lxc' && record.data.uptime === 0)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    get_object_icon_class: function(type, record) {
-	var status = '';
-	var objType = type;
-
-	if (type === 'type') {
-	    // for folder view
-	    objType = record.groupbyid;
-	} else if (record.template) {
-	    // templates
-	    objType = 'template';
-	    status = type;
-	} else {
-	    // everything else
-	    status = record.status + ' ha-' + record.hastate;
-	}
-
-	if (record.lock) {
-	    status += ' locked lock-' + record.lock;
-	}
-
-	var defaults = PVE.tree.ResourceTree.typeDefaults[objType];
-	if (defaults && defaults.iconCls) {
-	    var retVal = defaults.iconCls + ' ' + status;
-	    return retVal;
-	}
-
-	return '';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
-	var fa = '<i class="fa-fw x-grid-icon-custom ' + cls  + '"></i> ';
-	return fa + value;
-    },
-
-    render_support_level: function(value, metaData, record) {
-	return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    /* render functions for new status panel */
-
-    render_usage: function(val) {
-	return (val*100).toFixed(2) + '%';
-    },
-
-    render_cpu_usage: function(val, max) {
-	return Ext.String.format(gettext('{0}% of {1}') +
-	    ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
-    },
-
-    render_size_usage: function(val, max) {
-	if (max === 0) {
-	    return gettext('N/A');
-	}
-	return (val*100/max).toFixed(2) + '% '+ '(' +
-	    Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
-    },
-
-    /* this is different for nodes */
-    render_node_cpu_usage: function(value, record) {
-	return PVE.Utils.render_cpu_usage(value, record.cpus);
-    },
-
-    /* this is different for nodes */
-    render_node_size_usage: function(record) {
-	return PVE.Utils.render_size_usage(record.used, record.total);
-    },
-
-    render_optional_url: function(value) {
-	var match;
-	if (value && (match = value.match(/^https?:\/\//)) !== null) {
-	    return '<a target="_blank" href="' + value + '">' + value + '</a>';
-	}
-	return value;
-    },
-
-    render_san: function(value) {
-	var names = [];
-	if (Ext.isArray(value)) {
-	    value.forEach(function(val) {
-		if (!Ext.isNumber(val)) {
-		    names.push(val);
-		}
-	    });
-	    return names.join('<br>');
-	}
-	return value;
-    },
-
-    render_full_name: function(firstname, metaData, record) {
-	var first = firstname || '';
-	var last = record.data.lastname || '';
-	return Ext.htmlEncode(first + " " + last);
-    },
-
-    render_u2f_error: function(error) {
-	var ErrorNames = {
-	    '1': gettext('Other Error'),
-	    '2': gettext('Bad Request'),
-	    '3': gettext('Configuration Unsupported'),
-	    '4': gettext('Device Ineligible'),
-	    '5': gettext('Timeout')
-	};
-	return "U2F Error: "  + ErrorNames[error] || Proxmox.Utils.unknownText;
-    },
-
-    windowHostname: function() {
-	return window.location.hostname.replace(Proxmox.Utils.IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-
-    openDefaultConsoleWindow: function(consoles, vmtype, vmid, nodename, vmname, cmd) {
-	var dv = PVE.Utils.defaultViewer(consoles);
-	PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname, cmd);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname, cmd) {
-	// kvm, lxc, shell, upgrade
-
-	if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-	    throw "missing vmid";
-	}
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (viewer === 'html5') {
-	    PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'xtermjs') {
-	    Proxmox.Utils.openXtermJsViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'vv') {
-	    var url;
-	    var params = { proxy: PVE.Utils.windowHostname() };
-	    if (vmtype === 'kvm') {
-		url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'lxc') {
-		url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'shell') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'upgrade') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.upgrade = 1;
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'cmd') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.cmd = cmd;
-		PVE.Utils.openSpiceViewer(url, params);
-	    }
-	} else {
-	    throw "unknown viewer type";
-	}
-    },
-
-    defaultViewer: function(consoles) {
-
-	var allowSpice, allowXtermjs;
-
-	if (consoles === true) {
-	    allowSpice = true;
-	    allowXtermjs = true;
-	} else if (typeof consoles === 'object') {
-	    allowSpice = consoles.spice;
-	    allowXtermjs = !!consoles.xtermjs;
-	}
-	var dv = PVE.VersionInfo.console || 'xtermjs';
-	if (dv === 'vv' && !allowSpice) {
-	    dv = (allowXtermjs) ? 'xtermjs' : 'html5';
-	} else if (dv === 'xtermjs' && !allowXtermjs) {
-	    dv = (allowSpice) ? 'vv' : 'html5';
-	}
-
-	return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    novnc: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    resize: 'off',
-	    cmd: cmd
-	});
-	var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-	if (nw) {
-	    nw.focus();
-	}
-    },
-
-    openSpiceViewer: function(url, params){
-
-	var downloadWithName = function(uri, name) {
-	    var link = Ext.DomHelper.append(document.body, {
-		tag: 'a',
-		href: uri,
-		css : 'display:none;visibility:hidden;height:0px;'
-	    });
-
-	    // Note: we need to tell android the correct file name extension
-	    // but we do not set 'download' tag for other environments, because
-	    // It can have strange side effects (additional user prompt on firefox)
-	    var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-	    if (andriod) {
-		link.download = name;
-	    }
-
-	    if (link.fireEvent) {
-		link.fireEvent('onclick');
-	    } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-		link.dispatchEvent(evt);
-	    }
-	};
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    params: params,
-	    method: 'POST',
-	    failure: function(response, opts){
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, opts){
-		var raw = "[virt-viewer]\n";
-		Ext.Object.each(response.result.data, function(k, v) {
-		    raw += k + "=" + v + "\n";
-		});
-		var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-		    encodeURIComponent(raw);
-
-		downloadWithName(url, "pve-spice.vv");
-	    }
-	});
-    },
-
-    openTreeConsole: function(tree, record, item, index, e) {
-	e.stopEvent();
-	var nodename = record.data.node;
-	var vmid = record.data.vmid;
-	var vmname = record.data.name;
-	if (record.data.type === 'qemu' && !record.data.template) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    let conf = response.result.data;
-		    var consoles = {
-			spice: !!conf.spice,
-			xtermjs: !!conf.serial,
-		    };
-		    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-		}
-	    });
-	} else if (record.data.type === 'lxc' && !record.data.template) {
-	    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-	}
-    },
-
-    // test automation helper
-    call_menu_handler: function(menu, text) {
-
-	var list = menu.query('menuitem');
-
-	Ext.Array.each(list, function(item) {
-	    if (item.text === text) {
-		if (item.handler) {
-		    item.handler();
-		    return 1;
-		} else {
-		    return undefined;
-		}
-	    }
-	});
-    },
-
-    createCmdMenu: function(v, record, item, index, event) {
-	event.stopEvent();
-	if (!(v instanceof Ext.tree.View)) {
-	    v.select(record);
-	}
-	var menu;
-	var template = !!record.data.template;
-	var type = record.data.type;
-
-	if (template) {
-	    if (type === 'qemu' || type == 'lxc') {
-		menu = Ext.create('PVE.menu.TemplateMenu', {
-		    pveSelNode: record
-		});
-	    }
-	} else if (type === 'qemu' ||
-		   type === 'lxc' ||
-		   type === 'node') {
-	    menu = Ext.create('PVE.' + type + '.CmdMenu', {
-		pveSelNode: record,
-		nodename: record.data.node
-	    });
-	} else {
-	    return;
-	}
-
-	menu.showAt(event.getXY());
-	return menu;
-    },
-
-    // helper for deleting field which are set to there default values
-    delete_if_default: function(values, fieldname, default_val, create) {
-	if (values[fieldname] === '' || values[fieldname] === default_val) {
-	    if (!create) {
-		if (values['delete']) {
-		    values['delete'] += ',' + fieldname;
-		} else {
-		    values['delete'] = fieldname;
-		}
-	    }
-
-	    delete values[fieldname];
-	}
-    },
-
-    loadSSHKeyFromFile: function(file, callback) {
-	// ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-	// a user@host comment, 1420 for 8192 bits; current max is 16kbit
-	// assume: 740*8 for max. 32kbit (5920 byte file)
-	// round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
-	if (file.size > 8192) {
-	    Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
-	    return;
-	}
-	/*global
-	  FileReader
-	*/
-	var reader = new FileReader();
-	reader.onload = function(evt) {
-	    callback(evt.target.result);
-	};
-	reader.readAsText(file);
-    },
-
-    bus_counts: { ide: 4, sata: 6, scsi: 16, virtio: 16 },
-
-    // types is either undefined (all busses), an array of busses, or a single bus
-    forEachBus: function(types, func) {
-	var busses = Object.keys(PVE.Utils.bus_counts);
-	var i, j, count, cont;
-
-	if (Ext.isArray(types)) {
-	    busses = types;
-	} else if (Ext.isDefined(types)) {
-	    busses = [ types ];
-	}
-
-	// check if we only have valid busses
-	for (i = 0; i < busses.length; i++) {
-	    if (!PVE.Utils.bus_counts[busses[i]]) {
-		throw "invalid bus: '" + busses[i] + "'";
-	    }
-	}
-
-	for (i = 0; i < busses.length; i++) {
-	    count = PVE.Utils.bus_counts[busses[i]];
-	    for (j = 0; j < count; j++) {
-		cont = func(busses[i], j);
-		if (!cont && cont !== undefined) {
-		    return;
-		}
-	    }
-	}
-    },
-
-    mp_counts: { mps: 256, unused: 256 },
-
-    forEachMP: function(func, includeUnused) {
-	var i, cont;
-	for (i = 0; i < PVE.Utils.mp_counts.mps; i++) {
-	    cont = func('mp', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-
-	if (!includeUnused) {
-	    return;
-	}
-
-	for (i = 0; i < PVE.Utils.mp_counts.unused; i++) {
-	    cont = func('unused', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-    },
-
-    cleanEmptyObjectKeys: function (obj) {
-	var propName;
-	for (propName in obj) {
-	    if (obj.hasOwnProperty(propName)) {
-		if (obj[propName] === null || obj[propName] === undefined) {
-		    delete obj[propName];
-		}
-	    }
-	}
-    },
-
-    handleStoreErrorOrMask: function(me, store, regex, callback) {
-
-	me.mon(store, 'load', function (proxy, response, success, operation) {
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-	    var msg;
-
-	    if (operation.error.statusText) {
-		if (operation.error.statusText.match(regex)) {
-		    callback(me, operation.error);
-		    return;
-		} else {
-		    msg = operation.error.statusText + ' (' + operation.error.status + ')';
-		}
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    showCephInstallOrMask: function(container, msg, nodename, callback){
-	var regex = new RegExp("not (installed|initialized)", "i");
-	if (msg.match(regex)) {
-	    if (Proxmox.UserName === 'root@pam') {
-		container.el.mask();
-		if (!container.down('pveCephInstallWindow')){
-		    var isInstalled = msg.match(/not initialized/i) ? true : false;
-		    var win = Ext.create('PVE.ceph.Install', {
-			nodename: nodename
-		    });
-		    win.getViewModel().set('isInstalled', isInstalled);
-		    container.add(win);
-		    win.show();
-		    callback(win);
-		}
-	    } else {
-		container.mask(Ext.String.format(gettext('{0} not installed.') +
-		    ' ' + gettext('Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
-	    }
-	    return true;
-	} else {
-	    return false;
-	}
-    }
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-    }
-
-});
-
-// ExtJS related things
-
-Proxmox.Utils.toolkit = 'extjs';
-
-// custom PVE specific VTypes
-Ext.apply(Ext.form.field.VTypes, {
-
-    QemuStartDate: function(v) {
-	return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-    IP64AddressList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == '') {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.IP64_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    IP64AddressListText: gettext('Example') + ': 192.168.1.1,192.168.1.2',
-    IP64AddressListMask: /[A-Fa-f0-9\,\:\.\;\ ]/
-});
-
-Ext.define('PVE.form.field.Display', {
-    override: 'Ext.form.field.Display',
-
-    setSubmitValue: function(value) {
-	// do nothing, this is only to allow generalized  bindings for the:
-	// `me.isCreate ? 'textfield' : 'displayfield'` cases we have.
-    }
-});
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseACME: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-	var errors = false;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; //continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
-		res.domains = match_res[1].split(/[;, ]/);
-	    } else {
-		errors = true;
-		return false;
-	    }
-	});
-
-	if (errors || !res) {
-	    return;
-	}
-
-	return res;
-    },
-
-    parseBoolean: function(value, default_value) {
-	if (!Ext.isDefined(value)) {
-	    return default_value;
-	}
-	value = value.toLowerCase();
-	return value === '1' ||
-	       value === 'on' ||
-	       value === 'yes' ||
-	       value === 'true';
-    },
-
-    parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
-		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	});
-
-	if (error !== undefined) {
-	    console.error(error);
-	    return;
-	}
-
-	return res;
-    },
-
-    printPropertyString: function(data, defaultKey) {
-	var stringparts = [],
-	    gotDefaultKeyVal = false,
-	    defaultKeyVal;
-
-	Ext.Object.each(data, function(key, value) {
-	    if (defaultKey !== undefined && key === defaultKey) {
-		gotDefaultKeyVal = true;
-		defaultKeyVal = value;
-	    } else {
-		stringparts.push(key + '=' + value);
-	    }
-	});
-
-	stringparts = stringparts.sort();
-	if (gotDefaultKeyVal) {
-	    stringparts.unshift(defaultKeyVal);
-	}
-
-	return stringparts.join(',');
-    },
-
-    parseQemuNetwork: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-		res.model = match_res[1].toLowerCase();
-		if (match_res[3]) {
-		    res.macaddr = match_res[3];
-		}
-	    } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-		res.bridge = match_res[1];
-	    } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-		res.rate = match_res[1];
-	    } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-		res.tag = match_res[1];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		res.firewall = match_res[1];
-	    } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-		res.disconnect = match_res[1];
-	    } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-		res.queues = match_res[1];
-	    } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
-		res.trunks = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors || !res.model) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-	var netstr = net.model;
-	if (net.macaddr) {
-	    netstr += "=" + net.macaddr;
-	}
-	if (net.bridge) {
-	    netstr += ",bridge=" + net.bridge;
-	    if (net.tag) {
-		netstr += ",tag=" + net.tag;
-	    }
-	    if (net.firewall) {
-		netstr += ",firewall=" + net.firewall;
-	    }
-	}
-	if (net.rate) {
-	    netstr += ",rate=" + net.rate;
-	}
-	if (net.queues) {
-	    netstr += ",queues=" + net.queues;
-	}
-	if (net.disconnect) {
-	    netstr += ",link_down=" + net.disconnect;
-	}
-	if (net.trunks) {
-	    netstr += ",trunks=" + net.trunks;
-	}
-	return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var match_res = key.match(/^([a-z]+)(\d+)$/);
-	if (!match_res) {
-	    return;
-	}
-	res['interface'] = match_res[1];
-	res.index = match_res[2];
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    if (k === 'cache' && v === 'off') {
-		v = 'none';
-	    }
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-	var drivestr = drive.file;
-
-	Ext.Object.each(drive, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'index' || key === 'interface') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseIPConfig: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
-		res.ip = match_res[1];
-	    } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
-		res.gw = match_res[1];
-	    } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
-		res.ip6 = match_res[1];
-	    } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
-		res.gw6 = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printIPConfig: function(cfg) {
-	var c = "";
-	var str = "";
-	if (cfg.ip) {
-	    str += "ip=" + cfg.ip;
-	    c = ",";
-	}
-	if (cfg.gw) {
-	    str += c + "gw=" + cfg.gw;
-	    c = ",";
-	}
-	if (cfg.ip6) {
-	    str += c + "ip6=" + cfg.ip6;
-	    c = ",";
-	}
-	if (cfg.gw6) {
-	    str += c + "gw6=" + cfg.gw6;
-	    c = ",";
-	}
-	return str;
-    },
-
-    parseOpenVZNetIf: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(';'), function(item) {
-	    if (!item || item.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var data = {};
-	    Ext.Array.each(item.split(','), function(p) {
-		if (!p || p.match(/^\s*$/)) {
-		    return; // continue
-		}
-		var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-		if (!match_res) {
-		    errors = true;
-		    return false; // break
-		}
-		if (match_res[1] === 'bridge'){
-		    var bridgevlanf = match_res[2];
-		    var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-		    if (!bridge_res) {
-			errors = true;
-			return false; // break
-		    }
-		    data.bridge = bridge_res[1];
-		    data.tag = bridge_res[4];
-		    /*jslint confusion: true*/
-		    data.firewall = bridge_res[5] ? 1 : 0;
-		    /*jslint confusion: false*/
-		} else {
-		    data[match_res[1]] = match_res[2];
-		}
-	    });
-
-	    if (errors || !data.ifname) {
-		errors = true;
-		return false; // break
-	    }
-
-	    data.raw = item;
-
-	    res[data.ifname] = data;
-	});
-
-	return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-	var netarray = [];
-
-	Ext.Object.each(netif, function(iface, data) {
-	    var tmparray = [];
-	    Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-		var value = data[key];
-		if (key === 'bridge'){
-		    if(data.tag){
-			value = value + 'v' + data.tag;
-		    }
-		    if (data.firewall){
-			value = value + 'f';
-		    }
-		}
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-
-	    });
-	    netarray.push(tmparray.join(','));
-	});
-
-	return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var data = {};
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
-	    if (match_res) {
-		data[match_res[1]] = match_res[2];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		data.firewall = PVE.Parser.parseBoolean(match_res[1]);
-	    } else {
-		// todo: simply ignore errors ?
-		return; // continue
-	    }
-	});
-
-	return data;
-    },
-
-    printLxcNetwork: function(data) {
-	var tmparray = [];
-	Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-			'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-		var value = data[key];
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-	});
-
-	/*jslint confusion: true*/
-	if (data.rate > 0) {
-	    tmparray.push('rate=' + data.rate);
-	}
-	/*jslint confusion: false*/
-	return tmparray.join(',');
-    },
-
-    parseLxcMountPoint: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(.+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
-	if (m) {
-	    res.storage = m[1];
-	    res.type = 'volume';
-	} else if (res.file.match(/^\/dev\//)) {
-	    res.type = 'device';
-	} else {
-	    res.type = 'bind';
-	}
-
-	return res;
-    },
-
-    printLxcMountPoint: function(mp) {
-	var drivestr = mp.file;
-
-	Ext.Object.each(mp, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'type' || key === 'storage') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseStartup: function(value) {
-	if (value === undefined) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-		res.order = match_res[2];
-	    } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-		res.up = match_res[1];
-	    } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printStartup: function(startup) {
-	var arr = [];
-	if (startup.order !== undefined && startup.order !== '') {
-	    arr.push('order=' + startup.order);
-	}
-	if (startup.up !== undefined && startup.up !== '') {
-	    arr.push('up=' + startup.up);
-	}
-	if (startup.down !== undefined && startup.down !== '') {
-	    arr.push('down=' + startup.down);
-	}
-
-	return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-	var res = value.split(',').reduce(function (accumulator, currentValue) {
-	    var splitted = currentValue.split(new RegExp("=(.+)"));
-	    accumulator[splitted[0]] = splitted[1];
-	    return accumulator;
-	}, {});
-
-	if (PVE.Parser.parseBoolean(res.base64, false)) {
-	    Ext.Object.each(res, function(key, value) {
-		if (key === 'uuid') { return; }
-		res[key] = Ext.util.Base64.decode(value);
-	    });
-	}
-
-	return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-	var datastr = '';
-	var base64 = false;
-	Ext.Object.each(data, function(key, value) {
-	    if (value === '') { return; }
-	    if (key === 'uuid') {
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-	    } else {
-		// values should be base64 encoded from now on, mark config strings correspondingly
-		if (!base64) {
-		    base64 = true;
-		    datastr += (datastr !== '' ? ',' : '') + 'base64=1';
-		}
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
-	    }
-	});
-
-	return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    parseTfaType: function(value) {
-	/*jslint confusion: true*/
-	var match;
-	if (!value || !value.length) {
-	    return undefined;
-	} else if (value === 'x!oath') {
-	    return 'totp';
-	} else if (!!(match = value.match(/^x!(.+)$/))) {
-	    return match[1];
-	} else {
-	    return 1;
-	}
-    },
-
-    parseQemuCpu: function(value) {
-	if (!value) {
-	    return {};
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    if (!p.match(/\=/)) {
-		if (Ext.isDefined(res.cpu)) {
-		    errors = true;
-		    return false; // break
-		}
-		res.cputype = p;
-		return; // continue
-	    }
-
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var k = match_res[1];
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    res[k] = match_res[2];
-	});
-
-	if (errors || !res.cputype) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuCpu: function(cpu) {
-	var cpustr = cpu.cputype;
-	var optstr = '';
-
-	Ext.Object.each(cpu, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'cputype') {
-		return; // continue
-	    }
-	    optstr += ',' + key + '=' + value;
-	});
-
-	if (!cpustr) {
-	    if (optstr) {
-		return 'kvm64' + optstr;
-	    }
-	    return;
-	}
-
-	return cpustr + optstr;
-    },
-
-    parseSSHKey: function(key) {
-	//                |--- options can have quotes--|     type    key        comment
-	var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
-	var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
-
-	var m = key.match(keyre);
-	if (!m) {
-	    return null;
-	}
-	if (m.length < 3 || !m[2]) { // [2] is always either type or key
-	    return null;
-	}
-	if (m[1] && m[1].match(typere)) {
-	    return {
-		type: m[1],
-		key: m[2],
-		comment: m[3]
-	    };
-	}
-	if (m[2].match(typere)) {
-	    return {
-		options: m[1],
-		type: m[2],
-		key: m[3],
-		comment: m[4]
-	    };
-	}
-	return null;
-    }
-}});
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-	var me = this;
-
-	var changes = false;
-	var oldtext = Ext.encode(me.UIState[name]);
-	var newtext = Ext.encode(newvalue);
-	if (newtext != oldtext) {
-	    changes = true;
-	    me.UIState[name] = newvalue;
-	    //console.log("changed old " + name + " " + oldtext);
-	    //console.log("changed new " + name + " " + newtext);
-	    if (fireEvents) {
-		me.fireEvent("statechange", me, name, { value: newvalue });
-	    }
-	}
-	return changes;
-    },
-
-    // private
-    hslist: [
-	// order is important for notifications
-	// [ name, default ]
-	['view', 'server'],
-	['rid', 'root'],
-	['ltab', 'tasks'],
-	['nodetab', ''],
-	['storagetab', ''],
-	['pooltab', ''],
-	['kvmtab', ''],
-	['lxctab', ''],
-	['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-	cloudinit: 52,
-	replication: 51,
-	system: 50,
-	monitor: 49,
-	'ha-fencing': 48,
-	'ha-groups': 47,
-	'ha-resources': 46,
-	'ceph-log': 45,
-	'ceph-crushmap':44,
-	'ceph-pools': 43,
-	'ceph-osdtree': 42,
-	'ceph-disklist': 41,
-	'ceph-monlist': 40,
-	'ceph-config': 39,
-	ceph: 38,
-	'firewall-fwlog': 37,
-	'firewall-options': 36,
-	'firewall-ipset': 35,
-	'firewall-aliases': 34,
-	'firewall-sg': 33,
-	firewall: 32,
-	apt: 31,
-	members: 30,
-	snapshot: 29,
-	ha: 28,
-	support: 27,
-	pools: 26,
-	syslog: 25,
-	ubc: 24,
-	initlog: 23,
-	openvz: 22,
-	backup: 21,
-	resources: 20,
-	content: 19,
-	root: 18,
-	domains: 17,
-	roles: 16,
-	groups: 15,
-	users: 14,
-	time: 13,
-	dns: 12,
-	network: 11,
-	services: 10,
-	options: 9,
-	console: 8,
-	hardware: 7,
-	permissions: 6,
-	summary: 5,
-	tasks: 4,
-	clog: 3,
-	storage: 2,
-	folder: 1,
-	server: 0
-    },
-
-    decodeHToken: function(token) {
-	var me = this;
-
-	var state = {};
-	if (!token) {
-	    Ext.Array.each(me.hslist, function(rec) {
-		state[rec[0]] = rec[1];
-	    });
-	    return state;
-	}
-
-	// return Ext.urlDecode(token);
-
-	var items = token.split(':');
-	var prefix = items.shift();
-
-	if (prefix != me.hprefix) {
-	    return me.decodeHToken();
-	}
-
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = items.shift();
-	    if (value) {
-		if (value[0] === '=') {
-		    value = decodeURIComponent(value.slice(1));
-		} else {
-		    Ext.Object.each(me.compDict, function(key, cv) {
-			if (value == cv) {
-			    value = key;
-			    return false;
-			}
-		    });
-		}
-	    }
-	    state[rec[0]] = value;
-	});
-
-	return state;
-    },
-
-    encodeHToken: function(state) {
-	var me = this;
-
-	// return Ext.urlEncode(state);
-
-	var ctoken = me.hprefix;
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = state[rec[0]];
-	    if (!Ext.isDefined(value)) {
-		value = rec[1];
-	    }
-	    value = encodeURIComponent(value);
-	    if (!value) {
-		ctoken += ':';
-	    } else {
-		var comp = me.compDict[value];
-		if (Ext.isDefined(comp)) {
-		    ctoken += ":" + comp;
-		} else {
-		    ctoken += ":=" + value;
-		}
-	    }
-	});
-
-	return ctoken;
-    },
-
-    constructor: function(config){
-	var me = this;
-
-	me.callParent([config]);
-
-	me.UIState = me.decodeHToken(); // set default
-
-	var history_change_cb = function(token) {
-	    //console.log("HC " + token);
-	    if (!token) {
-		var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-		if (res){
-		    // process text value and close...
-		    Ext.History.back();
-		} else {
-		    Ext.History.forward();
-		}
-		return;
-	    }
-
-	    var newstate = me.decodeHToken(token);
-	    Ext.Array.each(me.hslist, function(rec) {
-		if (typeof newstate[rec[0]] == "undefined") {
-		    return;
-		}
-		me.setHV(rec[0], newstate[rec[0]], true);
-	    });
-	};
-
-	var start_token = Ext.History.getToken();
-	if (start_token) {
-	    history_change_cb(start_token);
-	} else {
-	    var htext = me.encodeHToken(me.UIState);
-	    Ext.History.add(htext);
-	}
-
-	Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-	/*jslint confusion: true */
-	var me = this;
-	var data;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    data = { value: me.UIState[name] };
-	} else {
-	    data = me.callParent(arguments);
-	    if (!data && name === 'GuiCap') {
-		data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-	    }
-	}
-
-	//console.log("GET " + name + " " + Ext.encode(data));
-	return data;
-    },
-
-    clear: function(name){
-	var me = this;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    me.UIState[name] = null;
-	}
-
-	me.callParent(arguments);
-    },
-
-    set: function(name, value, fireevent){
-        var me = this;
-
-	//console.log("SET " + name + " " + Ext.encode(value));
-	if (typeof me.UIState[name] != "undefined") {
-	    var newvalue = value ? value.value : null;
-	    if (me.setHV(name, newvalue, fireevent)) {
-		var htext = me.encodeHToken(me.UIState);
-		Ext.History.add(htext);
-	    }
-	} else {
-	    me.callParent(arguments);
-	}
-    }
-});
-Ext.define('PVE.menu.Item', {
-    extend: 'Ext.menu.Item',
-    alias: 'widget.pveMenuItem',
-
-    // set to wrap the handler callback in a confirm dialog  showing this text
-    confirmMsg: false,
-
-    // set to focus 'No' instead of 'Yes' button and show a warning symbol
-    dangerous: false,
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.handler) {
-	    me.setHandler(me.handler, me.scope);
-	}
-
-	me.callParent();
-    },
-
-    setHandler: function(fn, scope) {
-	var me = this;
-	me.scope = scope;
-	me.handler = function(button, e) {
-	    var rec, msg;
-	    if (me.confirmMsg) {
-		msg = me.confirmMsg;
-		Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: msg,
-		    buttons: Ext.Msg.YESNO,
-		    defaultFocus: me.dangerous ? 'no' : 'yes',
-		    callback: function(btn) {
-			if (btn === 'yes') {
-			    Ext.callback(fn, me.scope, [me, e], 0, me);
-			}
-		    }
-		});
-	    } else {
-		Ext.callback(fn, me.scope, [me, e], 0, me);
-	    }
-	};
-    }
-});
-Ext.define('PVE.menu.TemplateMenu', {
-    extend: 'Ext.menu.Menu',
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var guestType = me.pveSelNode.data.type;
-	if (guestType !== 'qemu' && guestType != 'lxc') {
-	    throw "invalid guest type";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var template = me.pveSelNode.data.template;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	me.title = (guestType === 'qemu' ? 'VM ' : 'CT ') + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: guestType,
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: template
-		    });
-		    win.show();
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade', 'cmd'
-
-    cmd: undefined,
-
-    consoleName: undefined,
-
-    iconCls: 'fa fa-terminal',
-
-    enableSpice: true,
-    enableXtermjs: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    text: gettext('Console'),
-
-    setEnableSpice: function(enable){
-	var me = this;
-
-	me.enableSpice = enable;
-	me.down('#spicemenu').setDisabled(!enable);
-    },
-
-    setEnableXtermJS: function(enable){
-	var me = this;
-
-	me.enableXtermjs = enable;
-	me.down('#xtermjs').setDisabled(!enable);
-    },
-
-    handler: function() {
-	var me = this;
-	var consoles = {
-	    spice: me.enableSpice,
-	    xtermjs: me.enableXtermjs
-	};
-	PVE.Utils.openDefaultConsoleWindow(consoles, me.consoleType, me.vmid,
-					   me.nodename, me.consoleName, me.cmd);
-    },
-
-    menu: [
-	{
-	    xtype:'menuitem',
-	    text: 'noVNC',
-	    iconCls: 'pve-itype-icon-novnc',
-	    type: 'html5',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    xterm: 'menuitem',
-	    itemId: 'spicemenu',
-	    text: 'SPICE',
-	    type: 'vv',
-	    iconCls: 'pve-itype-icon-virt-viewer',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    text: 'xterm.js',
-	    itemId: 'xtermjs',
-	    iconCls: 'pve-itype-icon-xtermjs',
-	    type: 'xtermjs',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- *
- *   does this for the button and every menu item
- */
-Ext.define('PVE.button.Split', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveSplitButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    handlerWrapper: function(button, event) {
-	var me = this;
-	var rec, msg;
-	if (me.selModel) {
-	    rec = me.selModel.getSelection()[0];
-	    if (!rec || (me.enableFn(rec) === false)) {
-		return;
-	    }
-	}
-
-	if (me.confirmMsg) {
-	    msg = me.confirmMsg;
-	    // confirMsg can be boolean or function
-	    /*jslint confusion: true*/
-	    if (Ext.isFunction(me.confirmMsg)) {
-		msg = me.confirmMsg(rec);
-	    }
-	    /*jslint confusion: false*/
-	    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-	    Ext.Msg.show({
-		title: gettext('Confirm'),
-		icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		msg: msg,
-		buttons: Ext.Msg.YESNO,
-		callback: function(btn) {
-		    if (btn !== 'yes') {
-			return;
-		    }
-		    me.realHandler(button, event, rec);
-		}
-	    });
-	} else {
-	    me.realHandler(button, event, rec);
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-	    me.realHandler = me.handler;
-	    me.handler = me.handlerWrapper;
-	}
-
-	if (me.menu && me.menu.items) {
-	    me.menu.items.forEach(function(item) {
-		if (item.handler) {
-		    item.realHandler = item.handler;
-		    item.handler = me.handlerWrapper;
-		}
-
-		if (item.selModel) {
-		    me.mon(item.selModel, "selectionchange", function() {
-			var rec = item.selModel.getSelection()[0];
-			if (!rec || (item.enableFn(rec) === false )) {
-			    item.setDisabled(true);
-			} else {
-			    item.setDisabled(false);
-			}
-		    });
-		}
-	    });
-	}
-
-	me.callParent();
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.controller.StorageEdit', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.storageEdit',
-    control: {
-	'field[name=content]': {
-	    change: function(field, value) {
-		var hasBackups = Ext.Array.contains(value, 'backup');
-		var maxfiles = this.lookupReference('maxfiles');
-		if (!maxfiles) {
-		    return;
-		}
-
-		if (!hasBackups) {
-		// clear values which will never be submitted
-		    maxfiles.reset();
-		}
-		maxfiles.setDisabled(!hasBackups);
-	    }
-	}
-    }
-});
-Ext.define('PVE.qemu.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'suspended':
-		stopped = false;
-		suspended = true;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = "VM " + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: running || suspended,
-		disabled: running || suspended,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-	    {
-		text: gettext('Pause'),
-		iconCls: 'fa fa-fw fa-pause',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmpause', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Hibernate'),
-		iconCls: 'fa fa-fw fa-download',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		tooltip: gettext('Suspend to disk'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmsuspend', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend', { todisk: 1 });
-		    });
-		}
-	    },
-	    {
-		text: gettext('Resume'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: !suspended,
-		handler: function() {
-		    vm_command('resume');
-		}
-	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'qemu',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'qemu');
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		hidden: !caps.vms['VM.Allocate'],
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmtemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			     url: '/nodes/' + nodename + '/qemu/' + vmid + '/template',
-			     method: 'POST',
-			     failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			     }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    Proxmox.Utils.API2Request({
-			url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-			failure: function(response, opts) {
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, opts) {
-			    var allowSpice = response.result.data.spice;
-			    var allowXtermjs = response.result.data.serial;
-			    var consoles = {
-				spice: allowSpice,
-				xtermjs: allowXtermjs
-			    };
-			    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-			}
-		    });
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no CT ID specified";
-	}
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/lxc/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = 'CT ' + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		disabled: running,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-//	    {
-//		text: gettext('Suspend'),
-//		iconCls: 'fa fa-fw fa-pause',
-//		hidde: suspended,
-//		disabled: stopped || suspended,
-//		handler: function() {
-//		    var msg = Proxmox.Utils.format_task_description('vzsuspend', vmid);
-//		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-//			if (btn !== 'yes') {
-//			    return;
-//			}
-//
-//			vm_command('suspend');
-//		    });
-//		}
-//	    },
-//	    {
-//		text: gettext('Resume'),
-//		iconCls: 'fa fa-fw fa-play',
-//		hidden: !suspended,
-//		handler: function() {
-//		    vm_command('resume');
-//		}
-//	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: standalone || !caps.vms['VM.Migrate']
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'lxc');
-		}
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'lxc',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vztemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/lxc/' + vmid + '/template',
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-    xtype: 'nodeCmdMenu',
-
-    showSeparator: false,
-
-    items: [
-	{
-	    text: gettext('Create VM'),
-	    itemId: 'createvm',
-	    iconCls: 'fa fa-desktop',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{
-	    text: gettext('Create CT'),
-	    itemId: 'createct',
-	    iconCls: 'fa fa-cube',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Bulk Start'),
-	    itemId: 'bulkstart',
-	    iconCls: 'fa fa-fw fa-play',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Start'),
-		    btnText: gettext('Start'),
-		    action: 'startall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Stop'),
-	    itemId: 'bulkstop',
-	    iconCls: 'fa fa-fw fa-stop',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Stop'),
-		    btnText: gettext('Stop'),
-		    action: 'stopall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Migrate'),
-	    itemId: 'bulkmigrate',
-	    iconCls: 'fa fa-fw fa-send-o',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Migrate'),
-		    btnText: gettext('Migrate'),
-		    action: 'migrateall'
-		});
-		win.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Shell'),
-	    itemId: 'shell',
-	    iconCls: 'fa fa-fw fa-terminal',
-	    handler: function() {
-		var me = this.up('menu');
-		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, me.nodename, undefined);
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Wake-on-LAN'),
-	    itemId: 'wakeonlan',
-	    iconCls: 'fa fa-fw fa-power-off',
-	    handler: function() {
-		var me = this.up('menu');
-		Proxmox.Utils.API2Request({
-		    param: {},
-		    url: '/nodes/' + me.nodename + '/wakeonlan',
-		    method: 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, opts) {
-			Ext.Msg.show({
-			    title: 'Success',
-			    icon: Ext.Msg.INFO,
-			    msg: Ext.String.format(gettext("Wake on LAN packet send for '{0}': '{1}'"), me.nodename, response.result.data)
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no nodename specified';
-	}
-
-	me.title = gettext('Node') + " '" + me.nodename + "'";
-	me.callParent();
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	// disable not allowed options
-	if (!caps.vms['VM.Allocate']) {
-	    me.getComponent('createct').setDisabled(true);
-	    me.getComponent('createvm').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.PowerMgmt']) {
-	    me.getComponent('bulkstart').setDisabled(true);
-	    me.getComponent('bulkstop').setDisabled(true);
-	    me.getComponent('bulkmigrate').setDisabled(true);
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.Console']) {
-	    me.getComponent('shell').setDisabled(true);
-	}
-
-	if (me.pveSelNode.data.running) {
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-    }
-});
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-
-    vmid: undefined,
-
-    cmd: undefined,
-
-    consoleType: undefined, // lxc, kvm, shell, cmd
-
-    layout: 'fit',
-
-    xtermjs: false,
-
-    border: false,
-
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.consoleType) {
-	    throw "no console type specified";
-	}
-
-	if (!me.vmid && me.consoleType !== 'shell' && me.consoleType !== 'cmd') {
-	    throw "no VM ID specified";
-	}
-
-	// always use same iframe, to avoid running several noVnc clients
-	// at same time (to avoid performance problems)
-	var box = Ext.create('Ext.ux.IFrame', { itemid : "vncconsole" });
-
-	var type = me.xtermjs ? 'xtermjs' : 'novnc';
-	Ext.apply(me, {
-	    items: box,
-	    listeners: {
-		activate: function() {
-		    var queryDict = {
-			console: me.consoleType, // kvm, lxc, upgrade or shell
-			vmid: me.vmid,
-			node: me.nodename,
-			cmd: me.cmd,
-			resize: 'scale'
-		    };
-		    queryDict[type] = 1;
-		    PVE.Utils.cleanEmptyObjectKeys(queryDict);
-		    var url = '/?' + Ext.Object.toQueryString(queryDict);
-		    box.load(url);
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.on('afterrender', function() {
-	    me.focus();
-	});
-    }
-});
-
-Ext.define('PVE.data.PermPathStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.pvePermPath',
-    fields: [ 'value' ],
-    autoLoad: false,
-    data: [
-	{'value':  '/'},
-	{'value':  '/access'},
-	{'value': '/nodes'},
-	{'value': '/pool'},
-	{'value': '/storage'},
-	{'value': '/vms'}
-    ],
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	me.callParent([config]);
-
-	me.suspendEvents();
-	PVE.data.ResourceStore.each(function(record) {
-	    switch (record.get('type')) {
-		case 'node':
-		    me.add({value: '/nodes/' + record.get('text')});
-		    break;
-
-		case 'qemu':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'lxc':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'storage':
-		    me.add({value: '/storage/' + record.get('storage')});
-		    break;
-		case 'pool':
-		    me.add({value: '/pool/' + record.get('pool')});
-		    break;
-	    }
-	});
-	me.resumeEvents();
-
-	me.fireEvent('refresh', me);
-	me.fireEvent('datachanged', me);
-
-	me.sort({
-	    property: 'value',
-	    direction: 'ASC'
-	});
-    }
-});
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-	var me = this, i;
-
-	return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-
-    // returns the cached data from all nodes
-    getNodes: function() {
-	var me = this;
-
-	var nodes = [];
-	me.each(function(record) {
-	    if (record.get('type') == "node") {
-		nodes.push( record.getData() );
-	    }
-	});
-
-	return nodes;
-    },
-
-    storageIsShared: function(storage_path) {
-	var me = this;
-
-	var index = me.findExact('id', storage_path);
-
-	return me.getAt(index).data.shared;
-    },
-
-    guestNode: function(vmid) {
-	var me = this;
-
-	var index = me.findExact('vmid', parseInt(vmid, 10));
-
-	return me.getAt(index).data.node;
-    },
-
-    constructor: function(config) {
-	// fixme: how to avoid those warnings
-	/*jslint confusion: true */
-
-	var me = this;
-
-	config = config || {};
-
-	var field_defaults = {
-	    type: {
-		header: gettext('Type'),
-		type: 'string',
-		renderer: PVE.Utils.render_resource_type,
-		sortable: true,
-		hideable: false,
-		width: 100
-	    },
-	    id: {
-		header: 'ID',
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    running: {
-		header: gettext('Online'),
-		type: 'boolean',
-		renderer: Proxmox.Utils.format_boolean,
-		hidden: true,
-		convert: function(value, record) {
-		    var info = record.data;
-		    return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-		}
-	    },
-	    text: {
-		header: gettext('Description'),
-		type: 'string',
-		sortable: true,
-		width: 200,
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-
-		    if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
-			text = String(info.vmid);
-			if (info.name) {
-			    text += " (" + info.name + ')';
-			}
-		    } else { // node, pool, storage
-			text = info[info.type] || info.id;
-			if (info.node && info.type !== 'node') {
-			    text += " (" + info.node + ")";
-			}
-		    }
-
-		    return text;
-		}
-	    },
-	    vmid: {
-		header: 'VMID',
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    name: {
-		header: gettext('Name'),
-		hidden: true,
-		sortable: true,
-		type: 'string'
-	    },
-	    disk: {
-		header: gettext('Disk usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_disk_usage,
-		sortable: true,
-		width: 100,
-		hidden: true
-	    },
-	    diskuse: {
-		header: gettext('Disk usage') + " %",
-		type: 'number',
-		sortable: true,
-		renderer: PVE.Utils.render_disk_usage_percent,
-		width: 100,
-		calculate: PVE.Utils.calculate_disk_usage,
-		sortType: 'asFloat'
-	    },
-	    maxdisk: {
-		header: gettext('Disk size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    mem: {
-		header: gettext('Memory usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_mem_usage,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    memuse: {
-		header: gettext('Memory usage') + " %",
-		type: 'number',
-		renderer: PVE.Utils.render_mem_usage_percent,
-		calculate: PVE.Utils.calculate_mem_usage,
-		sortType: 'asFloat',
-		sortable: true,
-		width: 100
-	    },
-	    maxmem: {
-		header: gettext('Memory size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		hidden: true,
-		sortable: true,
-		width: 100
-	    },
-	    cpu: {
-		header: gettext('CPU usage'),
-		type: 'float',
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100
-	    },
-	    maxcpu: {
-		header: gettext('maxcpu'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    diskread: {
-		header: gettext('Total Disk Read'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    diskwrite: {
-		header: gettext('Total Disk Write'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netin: {
-		header: gettext('Total NetIn'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netout: {
-		header: gettext('Total NetOut'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    template: {
-		header: gettext('Template'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    uptime: {
-		header: gettext('Uptime'),
-		type: 'integer',
-		renderer: Proxmox.Utils.render_uptime,
-		sortable: true,
-		width: 110
-	    },
-	    node: {
-		header: gettext('Node'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    storage: {
-		header: gettext('Storage'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    pool: {
-		header: gettext('Pool'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    hastate: {
-		header: gettext('HA State'),
-		type: 'string',
-		defaultValue: 'unmanaged',
-		hidden: true,
-		sortable: true
-	    },
-	    status: {
-		header: gettext('Status'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    lock: {
-		header: gettext('Lock'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    }
-	};
-
-	var fields = [];
-	var fieldNames = [];
-	Ext.Object.each(field_defaults, function(key, value) {
-	    var field = {name: key, type: value.type};
-	    if (Ext.isDefined(value.convert)) {
-		field.convert = value.convert;
-	    }
-
-	    if (Ext.isDefined(value.calculate)) {
-		field.calculate = value.calculate;
-	    }
-
-	    if (Ext.isDefined(value.defaultValue)) {
-		field.defaultValue = value.defaultValue;
-	    }
-
-	    fields.push(field);
-	    fieldNames.push(key);
-	});
-
-	Ext.define('PVEResources', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/resources'
-	    }
-	});
-
-	Ext.define('PVETree', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: { type: 'memory' }
-	});
-
-	Ext.apply(config, {
-	    storeid: 'PVEResources',
-	    model: 'PVEResources',
-	    defaultColumns: function() {
-		var res = [];
-		Ext.Object.each(field_defaults, function(field, info) {
-		    var fi = Ext.apply({ dataIndex: field }, info);
-		    res.push(fi);
-		});
-		return res;
-	    },
-	    fieldNames: fieldNames
-	});
-
-	me.callParent([config]);
-    }
-});
-Ext.define('pve-domains', {
-    extend: "Ext.data.Model",
-    fields: [
-	'realm', 'type', 'comment', 'default', 'tfa',
-	{
-	    name: 'descr',
-	    // Note: We use this in the RealmComboBox.js (see Bug #125)
-	    convert: function(value, record) {
-		if (value) {
-		    return value;
-		}
-
-		var info = record.data;
-		// return realm if there is no comment
-		var text = info.comment || info.realm;
-
-		if (info.tfa) {
-		    text += " (+ " + info.tfa + ")";
-		}
-
-		return Ext.String.htmlEncode(text);
-	    }
-	}
-    ],
-    idProperty: 'realm',
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/domains"
-    }
-});
-Ext.define('pve-rrd-node', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	{
-	    name:'iowait',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'loadavg',
-	'maxcpu',
-	'memtotal',
-	'memused',
-	'netin',
-	'netout',
-	'roottotal',
-	'rootused',
-	'swaptotal',
-	'swapused',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-guest', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'maxcpu',
-	'netin',
-	'netout',
-	'mem',
-	'maxmem',
-	'disk',
-	'maxdisk',
-	'diskread',
-	'diskwrite',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-storage', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'used',
-	'total',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    minValue: 1,
-	    maxValue: 4094
-	});
-
-	me.callParent();
-    }
-});
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-    comboItems: [
-	['__default__', gettext('Default')],
-	[1, gettext('Yes')],
-	[0, gettext('No')]
-    ]
-});
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['0', Proxmox.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-    valueField: 'poolid',
-    displayField: 'poolid',
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: 'poolid'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    autoSelect: false,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Pool'),
-			sortable: true,
-			dataIndex: 'poolid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-	extend: 'Ext.data.Model',
-	fields: [ 'poolid', 'comment' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/pools"
-	},
-	idProperty: 'poolid'
-    });
-
-});
-Ext.define('PVE.form.PrivilegesSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'pvePrivilegesSelector',
-
-    multiSelect: true,
-
-    initComponent: function() {
-	var me = this;
-
-	// So me.store is available.
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/roles/Administrator',
-	    method: 'GET',
-	    success: function(response, options) {
-		var data = [], key;
-		/*jslint forin: true */
-		for (key in response.result.data) {
-		    data.push([key, key]);
-		}
-		/*jslint forin: false */
-
-		me.store.setData(data);
-
-		me.store.sort({
-		    property: 'key',
-		    direction: 'ASC'
-		});
-	    },
-
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-Ext.define('pve-groups', {
-    extend: 'Ext.data.Model',
-    fields: [ 'groupid', 'comment' ],
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/groups"
-    },
-    idProperty: 'groupid'
-});
-
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveGroupSelector',
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'groupid',
-    displayField: 'groupid',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		sortable: true,
-		dataIndex: 'groupid',
-		flex: 1
-	    },
-	    {
-		header: gettext('Comment'),
-		sortable: false,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: [{
-		property: 'groupid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-Ext.define('PVE.form.UserSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'userid',
-    displayField: 'userid',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-users',
-	    sorters: [{
-		property: 'userid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('User'),
-			sortable: true,
-			dataIndex: 'userid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Name'),
-			sortable: true,
-			renderer: PVE.Utils.render_full_name,
-			dataIndex: 'firstname',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'userid', 'firstname', 'lastname' , 'email', 'comment',
-	    { type: 'boolean', name: 'enable' },
-	    { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/users"
-	},
-	idProperty: 'userid'
-    });
-
-});
-
-
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'roleid',
-    displayField: 'roleid',
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: [{
-		property: 'roleid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Role'),
-			sortable: true,
-			dataIndex: 'roleid',
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-	extend: 'Ext.data.Model',
-	fields: [ 'roleid', 'privs' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/roles"
-	},
-	idProperty: 'roleid'
-    });
-
-});
-Ext.define('PVE.form.GuestIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveGuestIDSelector',
-
-    allowBlank: false,
-
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeID: false,
-
-    guestType: undefined,
-
-    validator: function(value) {
-	var me = this;
-
-	if (!Ext.isNumeric(value) ||
-	    value < me.minValue ||
-	    value > me.maxValue) {
-	    // check is done by ExtJS
-	    return true;
-	}
-
-	if (me.validateExists === true && !me.exists) {
-	    return me.unknownID;
-	}
-
-	if (me.validateExists === false && me.exists) {
-	    return me.inUseID;
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var label = '{0} ID';
-	var unknownID = gettext('This {0} ID does not exists');
-	var inUseID = gettext('This {0} ID is already in use');
-	var type = 'CT/VM';
-
-	if (me.guestType === 'lxc') {
-	    type = 'CT';
-	} else if (me.guestType === 'qemu') {
-	    type = 'VM';
-	}
-
-	me.label = Ext.String.format(label, type);
-	me.unknownID = Ext.String.format(unknownID, type);
-	me.inUseID = Ext.String.format(inUseID, type);
-
-	Ext.apply(me, {
-	    fieldLabel: me.label,
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    if (!Ext.isDefined(me.validateExists)) {
-			return;
-		    }
-		    Proxmox.Utils.API2Request({
-			params: { vmid: newValue },
-			url: '/cluster/nextid',
-			method: 'GET',
-			success: function(response, opts) {
-			    me.exists = false;
-			    me.validate();
-			},
-			failure: function(response, opts) {
-			    me.exists = true;
-			    me.validate();
-			}
-		    });
-		}
-	    }
-	});
-
-        me.callParent();
-
-	if (me.loadNextFreeID) {
-	    Proxmox.Utils.API2Request({
-		url: '/cluster/nextid',
-		method: 'GET',
-		success: function(response, opts) {
-		    me.setRawValue(response.result.data);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    allowDecimals: false,
-
-    allowExponential: false,
-
-    computeUpDown: function(value) {
-	var me = this;
-
-	if (!me.hotplug) {
-	    return { up: value + me.step, down: value - me.step };
-	}
-	
-	var dimm_size = 512;
-	var prev_dimm_size = 0;
-	var min_size = 1024;
-	var current_size = min_size;
-	var value_up = min_size;
-	var value_down = min_size;
-	var value_start = min_size;
-
-	var i, j;
-	for (j = 0; j < 9; j++) {
-	    for (i = 0; i < 32; i++) {
-		if ((value >= current_size) && (value < (current_size + dimm_size))) {
-		    value_start = current_size;
-		    value_up = current_size + dimm_size;
-		    value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-		}
-		current_size += dimm_size;				
-	    }
-	    prev_dimm_size = dimm_size;
-	    dimm_size = dimm_size*2;
-	}
-
-	return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-	}
-    },
-
-    onSpinDown: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.hotplug) {
-	    me.minValue = 1024;
-
-	    me.on('blur', function(field) {
-		var value = me.getValue();
-		var res = me.computeUpDown(value);
-		if (value === res.start || value === res.up || value === res.down) {
-		    return;
-		}
-		field.setValue(res.up);
-	    });
-	}
-
-        me.callParent();
-    }
-});
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveNetworkCardSelector',
-    comboItems: [
-	['e1000', 'Intel E1000'],
-	['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-	['rtl8139', 'Realtek RTL8139'],
-	['vmxnet3', 'VMware vmxnet3']
-    ]
-});
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveDiskFormatSelector',
-    comboItems:  [
-	['raw', gettext('Raw disk image') + ' (raw)'],
-	['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-	['vmdk', gettext('VMware image format') + ' (vmdk)']
-    ]
-});
-Ext.define('PVE.form.DiskSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveDiskSelector',
-
-    // can be
-    // undefined: all
-    // unused: only unused
-    // journal_disk: all disks with gpt
-    diskType: undefined,
-
-    valueField: 'devpath',
-    displayField: 'devpath',
-    emptyText: gettext('No Disks unused'),
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Device'),
-		flex: 3,
-		sortable: true,
-		dataIndex: 'devpath'
-	    },
-	    {
-		header: gettext('Size'),
-		flex: 2,
-		sortable: false,
-		renderer: Proxmox.Utils.format_size,
-		dataIndex: 'size'
-	    },
-	    {
-		header: gettext('Serial'),
-		flex: 5,
-		sortable: true,
-		dataIndex: 'serial'
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    filterOnLoad: true,
-	    model: 'pve-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list",
-		extraParams: { type: me.diskType }
-	    },
-	    sorters: [
-		{
-		    property : 'devpath',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-}, function() {
-
-    Ext.define('pve-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial'],
-	idProperty: 'devpath'
-    });
-});
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveBusSelector',
-  
-    noVirtIO: false,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [['ide', 'IDE'], ['sata', 'SATA']];
-
-	if (!me.noVirtIO) {
-	    me.comboItems.push(['virtio', 'VirtIO Block']);
-	}
-
-	me.comboItems.push(['scsi', 'SCSI']);
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveControllerSelector',
-   
-    statics: {
-	maxIds: {
-	    ide: 3,
-	    sata: 5,
-	    virtio: 15,
-	    scsi: 13
-	}
-    },
-
-    noVirtIO: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    sortByPreviousUsage: function(vmconfig, controllerList) {
-
-	var usedControllers = Ext.clone(PVE.form.ControllerSelector.maxIds);
-
-	var type;
-	for (type in usedControllers) {
-	    if(usedControllers.hasOwnProperty(type)) {
-		usedControllers[type] = 0;
-	    }
-	}
-
-	var property;
-	for (property in vmconfig) {
-	    if (vmconfig.hasOwnProperty(property)) {
-		if (property.match(PVE.Utils.bus_match) && !vmconfig[property].match(/media=cdrom/)) {
-		    var foundController = property.match(PVE.Utils.bus_match)[1];
-		    usedControllers[foundController]++;
-		}
-	    }
-	}
-
-	var vmDefaults = PVE.qemu.OSDefaults[vmconfig.ostype];
-
-	var sortPriority = vmDefaults && vmDefaults.busPriority
-	    ? vmDefaults.busPriority : PVE.qemu.OSDefaults.generic;
-
-	var sortedList = Ext.clone(controllerList);
-	sortedList.sort(function(a,b) {
-	    if (usedControllers[b] == usedControllers[a]) {
-		return sortPriority[b] - sortPriority[a];
-	    }
-	    return usedControllers[b] - usedControllers[a];
-	});
-	
-	return sortedList;
-    },
-
-    setVMConfig: function(vmconfig, autoSelect) {
-	var me = this;
-
-	me.vmconfig = Ext.apply({}, vmconfig);
-
-	var clist = ['ide', 'virtio', 'scsi', 'sata'];
-	var bussel = me.down('field[name=controller]');
-	var deviceid = me.down('field[name=deviceid]');
-
-	if (autoSelect === 'cdrom') {
-	    clist = ['ide', 'scsi', 'sata'];
-	    if (!Ext.isDefined(me.vmconfig.ide2)) {
-		bussel.setValue('ide');
-		deviceid.setValue(2);
-		return;
-	    }
-	} else  {
-	    // in most cases we want to add a disk to the same controller
-	    // we previously used
-	    clist = me.sortByPreviousUsage(me.vmconfig, clist);
-	}
-
-	Ext.Array.each(clist, function(controller) {
-	    var confid, i;
-	    bussel.setValue(controller);
-	    for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
-		confid = controller + i.toString();
-		if (!Ext.isDefined(me.vmconfig[confid])) {
-		    deviceid.setValue(i);
-		    return false; // break
-		}
-	    }
-	});
-	deviceid.validate();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    fieldLabel: gettext('Bus/Device'),
-	    layout: 'hbox',
-	    defaults: {
-                hideLabel: true
-	    },
-	    items: [
-		{
-		    xtype: 'pveBusSelector',
-		    name: 'controller',
-		    value: PVE.qemu.OSDefaults.generic.busType,
-		    noVirtIO: me.noVirtIO,
-		    allowBlank: false,
-		    flex: 2,
-		    listeners: {
-			change: function(t, value) {
-			    if (!value) {
-				return;
-			    }
-			    var field = me.down('field[name=deviceid]');
-			    field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
-			    field.validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'deviceid',
-		    minValue: 0,
-		    maxValue: PVE.form.ControllerSelector.maxIds.ide,
-		    value: '0',
-		    flex: 1,
-		    allowBlank: false,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.rendered) {
-			    return;
-			}
-			var field = me.down('field[name=controller]');
-			var controller = field.getValue();
-			var confid = controller + value;
-			if (Ext.isDefined(me.vmconfig[confid])) {
-			    return "This device is already in use.";
-			}
-			return true;
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
-/*global Proxmox*/
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    view.store.on('load', this.onLoad, view);
-	},
-
-	onLoad: function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-	    var me = this;
-	    var val = me.getValue();
-	    if (!val || !me.store.findRecord('realm', val)) {
-		var def = 'pam';
-		Ext.each(records, function(rec) {
-		    if (rec.data && rec.data['default']) {
-			def = rec.data.realm;
-		    }
-		});
-		me.setValue(def);
-	    }
-	}
-    },
-
-    fieldLabel: gettext('Realm'),
-    name: 'realm',
-    queryMode: 'local',
-    allowBlank: false,
-    editable: false,
-    forceSelection: true,
-    autoSelect: false,
-    triggerAction: 'all',
-    valueField: 'realm',
-    displayField: 'descr',
-    getState: function() {
-	return { value: this.getValue() };
-    },
-    applyState : function(state) {
-	if (state && state.value) {
-	    this.setValue(state.value);
-	}
-    },
-    stateEvents: [ 'select' ],
-    stateful: true, // last chosen auth realm is saved between page reloads
-    id: 'pveloginrealm', // We need stable ids when using stateful, not autogenerated
-    stateID: 'pveloginrealm',
-
-    needOTP: function(realm) {
-	var me = this;
-	// use exact match
-	var rec = me.store.findRecord('realm', realm, 0, false, false, true);
-	return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    store: {
-	model: 'pve-domains',
-	autoLoad: true
-    }
-});
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    editable: false,
-    allowBlank: false,
-    forceSelection: true,
-    autoSelect: false,
-    valueField: 'key',
-    displayField: 'value',
-    hideLabel: true,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	var default_views = {
-	    server: {
-		text: gettext('Server View'),
-		groups: ['node']
-	    },
-	    folder: {
-		text: gettext('Folder View'),
-		groups: ['type']
-	    },
-	    storage: {
-		text: gettext('Storage View'),
-		groups: ['node'],
-		filterfn: function(node) {
-		    return node.data.type === 'storage' || node.data.type === 'node';
-		}
-	    },
-	    pool: { 
-		text: gettext('Pool View'), 
-		groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-			node.data.type === 'pool';
-                }
-	    }
-	};
-
-	var groupdef = [];
-	Ext.Object.each(default_views, function(viewname, value) {
-	    groupdef.push([viewname, value.text]);
-	});
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-            proxy: {
-		type: 'memory',
-		reader: 'array'
-            },
-	    data: groupdef,
-	    autoload: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    value: groupdef[0][0],
-	    getViewFilter: function() {
-		var view = me.getValue();
-		return Ext.apply({ id: view }, default_views[view] || default_views.server);
-	    },
-
-	    getState: function() {
-		return { value: me.getValue() };
-	    },
-
-	    applyState : function(state, doSelect) {
-		var view = me.getValue();
-		if (state && state.value && (view != state.value)) {
-		    var record = store.findRecord('key', state.value);
-		    if (record) {
-			me.setValue(state.value, true);
-			if (doSelect) {
-			    me.fireEvent('select', me, [record]);
-			}
-		    }
-		}
-	    },
-	    stateEvents: [ 'select' ],
-	    stateful: true,
-	    stateId: 'pveview',
-	    id: 'view'
-	});
-
-	me.callParent();
-
-	var statechange = function(sp, key, value) {
-	    if (key === me.id) {
-		me.applyState(value, true);
-	    }
-	};
-
-	var sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', statechange, me);
-    }
-});
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveNodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // do not allow those nodes (array)
-    disallowedNodes: undefined,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'node',
-    displayField: 'node',
-    store: {
-	    fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes'
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		},
-		{
-		    property : 'mem',
-		    direction: 'DESC'
-		}
-	    ]
-	},
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node',
-		sortable: true,
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Memory usage') + " %",
-		renderer: PVE.Utils.render_mem_usage_percent,
-		sortable: true,
-		width: 100,
-		dataIndex: 'mem'
-	    },
-	    {
-		header: gettext('CPU usage'),
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100,
-		dataIndex: 'cpu'
-	    }
-	]
-    },
-
-    validator: function(value) {
-	/*jslint confusion: true */
-	var me = this;
-	if (!me.onlineValidator || (me.allowBlank && !value)) {
-	    return true;
-	}
-
-	var offline = [];
-	var notAllowed = [];
-
-	Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-	    var rec = me.store.findRecord(me.valueField, node);
-	    if (!(rec && rec.data) || rec.data.status !== 'online') {
-		offline.push(node);
-	    } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-		notAllowed.push(node);
-	    }
-	});
-
-	if (value && notAllowed.length !== 0) {
-	    return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-	}
-
-	if (value && offline.length !== 0) {
-	    return "Node " + offline.join(', ') + " seems to be offline!";
-	}
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-        me.getStore().load();
-
-	// filter out disallowed nodes
-	me.getStore().addFilter(new Ext.util.Filter({
-	    filterFn: function(item) {
-		if (Ext.isArray(me.disallowedNodes)) {
-		    return !Ext.Array.contains(me.disallowedNodes, item.data.node);
-		} else {
-		    return true;
-		}
-	    }
-	}));
-
-	me.mon(me.getStore(), 'load', function(){
-	    me.isValid();
-	});
-    }
-});
-Ext.define('PVE.form.FileSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFileSelector',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    listeners: {
-	afterrender: function() {
-	    var me = this;
-	    if (!me.disabled) {
-		me.setStorage(me.storage, me.nodename);
-	    }
-	}
-    },
-
-    setStorage: function(storage, nodename) {
-	var me = this;
-
-	var change = false;
-	if (storage && (me.storage !== storage)) {
-	    me.storage = storage;
-	    change = true;
-	}
-
-	if (nodename && (me.nodename !== nodename)) {
-	    me.nodename = nodename;
-	    change = true;
-	}
-
-	if (!(me.storage && me.nodename && change)) {
-	    return;
-	}
-
-	var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-	if (me.storageContent) {
-	    url += '?content=' + me.storageContent;
-	}
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url
-	});
-
-	me.store.removeAll();
-	me.store.load();
-    },
-
-    setNodename: function(nodename) {
-	this.setStorage(undefined, nodename);
-    },
-
-    store: {
-	model: 'pve-storage-content'
-    },
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'volid',
-    displayField: 'text',
-
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'text',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Format'),
-		width: 60,
-		dataIndex: 'format'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 100,
-		dataIndex: 'size',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveStorageSelector',
-
-    allowBlank: false,
-    valueField: 'storage',
-    displayField: 'storage',
-    listConfig: {
-	width: 450,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'storage',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Type'),
-		width: 75,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Avail'),
-		width: 90,
-		dataIndex: 'avail',
-		renderer: Proxmox.Utils.format_size
-	    },
-	    {
-		header: gettext('Capacity'),
-		width: 90,
-		dataIndex: 'total',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    },
-
-    reloadStorageList: function() {
-	var me = this;
-	if (!me.nodename) {
-	    return;
-	}
-
-	var params = {
-	    format: 1
-	};
-	var url = '/api2/json/nodes/' + me.nodename + '/storage';
-	if (me.storageContent) {
-	    params.content = me.storageContent;
-	}
-	if (me.targetNode) {
-	    params.target = me.targetNode;
-	    params.enabled = 1; // skip disabled storages
-	}
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url,
-	    extraParams: params
-	});
-
-	me.store.load();
- 
-    },
-
-    setTargetNode: function(targetNode) {
-	var me = this;
-
-	if (!targetNode || (me.targetNode === targetNode)) {
-	    return;
-	}
-
-	me.targetNode = targetNode;
-
-	me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.reloadStorageList();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-status',
-	    sorters: {
-		property: 'storage', 
-		order: 'DESC' 
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	if (nodename) {
-	    me.setNodename(nodename);
-	}
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-	idProperty: 'storage'
-    });
-
-});
-Ext.define('PVE.form.DiskStorageSelector', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveDiskStorageSelector',
-
-    layout: 'fit',
-    defaults: {
-	margin: '0 0 5 0'
-    },
-
-    // the fieldLabel for the storageselector
-    storageLabel: gettext('Storage'),
-
-    // the content to show (e.g., images or rootdir)
-    storageContent: undefined,
-
-    // if true, selects the first available storage
-    autoSelect: false,
-
-    allowBlank: false,
-    emptyText: '',
-
-    // hides the selection field
-    // this is always hidden on creation,
-    // and only shown when the storage needs a selection and
-    // hideSelection is not true
-    hideSelection: undefined,
-
-    // hides the size field (e.g, for the efi disk dialog)
-    hideSize: false,
-
-    // sets the initial size value
-    // string because else we get a type confusion
-    defaultSize: '32',
-
-    changeStorage: function(f, value) {
-	var me = this;
-	var formatsel = me.getComponent('diskformat');
-	var hdfilesel = me.getComponent('hdimage');
-	var hdsizesel = me.getComponent('disksize');
-
-	// initial store load, and reset/deletion of the storage
-	if (!value) {
-	    hdfilesel.setDisabled(true);
-	    hdfilesel.setVisible(false);
-
-	    formatsel.setDisabled(true);
-	    return;
-	}
-
-	var rec = f.store.getById(value);
-	// if the storage is not defined, or valid,
-	// we cannot know what to enable/disable
-	if (!rec) {
-	    return;
-	}
-
-	var selectformat = false;
-	if (rec.data.format) {
-	    var format = rec.data.format[0]; // 0 is the formats, 1 the default in the backend
-	    delete format.subvol; // we never need subvol in the gui
-	    selectformat = (Ext.Object.getSize(format) > 1);
-	}
-
-	var select = !!rec.data.select_existing && !me.hideSelection;
-
-	formatsel.setDisabled(!selectformat);
-	formatsel.setValue(selectformat ? 'qcow2' : 'raw');
-
-	hdfilesel.setDisabled(!select);
-	hdfilesel.setVisible(select);
-	if (select) {
-	    hdfilesel.setStorage(value);
-	}
-
-	hdsizesel.setDisabled(select || me.hideSize);
-	hdsizesel.setVisible(!select && !me.hideSize);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-	var hdfilesel = me.getComponent('hdimage');
-
-	hdstorage.setNodename(nodename);
-	hdfilesel.setNodename(nodename);
-    },
-
-    setDisabled: function(value) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-
-	// reset on disable
-	if (value) {
-	    hdstorage.setValue();
-	}
-	hdstorage.setDisabled(value);
-
-	// disabling does not always fire this event and we do not need
-	// the value of the validity
-	hdstorage.fireEvent('validitychange');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'pveStorageSelector',
-		itemId: 'hdstorage',
-		name: 'hdstorage',
-		reference: 'hdstorage',
-		fieldLabel: me.storageLabel,
-		nodename: me.nodename,
-		storageContent: me.storageContent,
-		disabled: me.disabled,
-		autoSelect: me.autoSelect,
-		allowBlank: me.allowBlank,
-		emptyText: me.emptyText,
-		listeners: {
-		    change: {
-			fn: me.changeStorage,
-			scope: me
-		    }
-		}
-	    },
-	    {
-		xtype: 'pveFileSelector',
-		name: 'hdimage',
-		reference: 'hdimage',
-		itemId: 'hdimage',
-		fieldLabel: gettext('Disk image'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: true
-	    },
-	    {
-		xtype: 'numberfield',
-		itemId: 'disksize',
-		reference: 'disksize',
-		name: 'disksize',
-		fieldLabel: gettext('Disk size') + ' (GiB)',
-		hidden: me.hideSize,
-		disabled: me.hideSize,
-		minValue: 0.001,
-		maxValue: 128*1024,
-		decimalPrecision: 3,
-		value: me.defaultSize,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveDiskFormatSelector',
-		itemId: 'diskformat',
-		reference: 'diskformat',
-		name: 'diskformat',
-		fieldLabel: gettext('Format'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: me.storageContent === 'rootdir',
-		value: 'qcow2',
-		allowBlank: false
-	    }
-	];
-
-	// use it to disable the children but not ourself
-	me.disabled = false;
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    store: {
-	fields: [ 'iface', 'active', 'type' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	]
-    },
-    valueField: 'iface',
-    displayField: 'iface',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Bridge'),
-		dataIndex: 'iface',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Active'),
-		width: 60,
-		dataIndex: 'active',
-		renderer: Proxmox.Utils.format_boolean
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comments',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-		me.bridgeType
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-        me.callParent();
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.PCISelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pvePCISelector',
-
-    store: {
-	fields: [ 'id','vendor_name', 'device_name', 'vendor', 'device', 'iommugroup', 'mdev' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'id',
-		direction: 'ASC'
-	    }
-	]
-    },
-
-    autoSelect: false,
-    valueField: 'id',
-    displayField: 'id',
-
-    // can contain a load callback for the store
-    // useful to determine the state of the IOMMU
-    onLoadCallBack: undefined,
-
-    listConfig: {
-	width: 800,
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'id',
-		width: 80
-	    },
-	    {
-		header: gettext('IOMMU Group'),
-		dataIndex: 'iommugroup',
-		width: 50
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor_name',
-		flex: 2
-	    },
-	    {
-		header: gettext('Device'),
-		dataIndex: 'device_name',
-		flex: 6
-	    },
-	    {
-		header: gettext('Mediated Devices'),
-		dataIndex: 'mdev',
-		flex: 1,
-		renderer: function(val) {
-		    return Proxmox.Utils.format_boolean(!!val);
-		}
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined;
-
-        me.callParent();
-
-	if (me.onLoadCallBack !== undefined) {
-	    me.mon(me.getStore(), 'load', me.onLoadCallBack);
-	}
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.MDevSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveMDevSelector',
-
-    store: {
-	fields: [ 'type','available', 'description' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'type',
-		direction: 'ASC'
-	    }
-	]
-    },
-    autoSelect: false,
-    valueField: 'type',
-    displayField: 'type',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		flex: 1
-	    },
-	    {
-		header: gettext('Available'),
-		dataIndex: 'available',
-		width: 80
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'description',
-		flex: 1,
-		renderer: function(value) {
-		    if (!value) {
-			return '';
-		    }
-
-		    return value.split('\n').join('<br>');
-		}
-	    }
-	]
-    },
-
-    setPciID: function(pciid, force) {
-	var me = this;
-
-	if (!force && (!pciid || (me.pciid === pciid))) {
-	    return;
-	}
-
-	me.pciid = pciid;
-	me.updateProxy();
-    },
-
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-	me.updateProxy();
-    },
-
-    updateProxy: function() {
-	var me = this;
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci/' + me.pciid + '/mdev'
-	});
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no node name specified';
-	}
-
-        me.callParent();
-
-	if (me.pciid) {
-	    me.setPciID(me.pciid, true);
-	}
-    }
-});
-
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    valueField: 'group',
-    displayField: 'group',
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'group', 'comment' ],
-	    idProperty: 'group',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/groups"
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Security Group'),
-			dataIndex: 'group',
-			hideable: false,
-			width: 100
-		    },
-		    {
-			header: gettext('Comment'),  
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    valueField: 'ref',
-    displayField: 'ref',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-
-	var url = "/api2/json" + me.base_url;
-	if (me.ref_type) {
-	    url += "?type=" + me.ref_type;
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'type', 'name', 'ref', 'comment' ],
-	    idProperty: 'ref',
-	    proxy: {
-		type: 'proxmox',
-		url: url
-	    },
-	    sorters: {
-		property: 'ref',
-		order: 'DESC'
-	    }
-	});
-
-	var disable_query_for_ips = function(f, value) {
-	    if (value === null || 
-		value.match(/^\d/)) { // IP address starts with \d
-		f.queryDelay = 9999999999; // hack: disable with long delay
-	    } else {
-		f.queryDelay = 10;
-	    }
-	};
-
-	var columns = [];
-
-	if (!me.ref_type) {
-	    columns.push({
-		header: gettext('Type'),
-		dataIndex: 'type',
-		hideable: false,
-		width: 60
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Name'),
-		dataIndex: 'ref',
-		hideable: false,
-		width: 140
-	    },
-	    {
-		header: gettext('Comment'),  
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: { columns: columns }
-	});
-
-	me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-    valueField: 'p',
-    displayField: 'p',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'p',
-		hideable: false,
-		sortable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Number'),
-		dataIndex: 'n',
-		hideable: false,
-		sortable: false,
-		width: 50
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'd',
-		hideable: false,
-		sortable: false,
-		flex: 1
-	    }
-	]
-    },
-    store: {
-	    fields: [ 'p', 'd', 'n'],
-	    data: [
-		{ p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-		{ p: 'udp', n: 17, d: 'User Datagram Protocol' },
-		{ p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-		{ p: 'igmp', n: 2,  d: 'Internet Group Management' },
-		{ p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-		{ p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-		{ p: 'st', n: 5, d: 'ST datagram mode' },
-		{ p: 'egp', n: 8, d: 'exterior gateway protocol' },
-		{ p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-		{ p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-		{ p: 'hmp', n: 20, d: 'host monitoring protocol' },
-		{ p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-		{ p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-		{ p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-		{ p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-		{ p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-		{ p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-		{ p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-		{ p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-		{ p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-		{ p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-		{ p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-		{ p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-		{ p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-		{ p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-		{ p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-		{ p: 'skip', n: 57, d: 'SKIP' },
-		{ p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-		{ p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-		{ p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-		{ p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-		{ p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-		{ p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-		{ p: 'ax.25', n: 93, d: 'AX.25 frames' },
-		{ p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-		{ p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-		{ p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-		{ p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-		{ p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-		{ p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-		{ p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-		{ p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-		{ p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-		{ p: 'fc', n: 133, d: 'Fibre Channel' },
-		{ p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-		{ p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-		{ p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-		{ p: 'hip', n: 139, d: 'Host Identity Protocol' },
-		{ p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-		{ p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-		{ p: 'rohc', n: 142, d: 'Robust Header Compression' }
-	    ]
-	}
-});
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CPUModelSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + ' (kvm64)'],
-	['486', '486'],
-	['athlon', 'athlon'],
-	['core2duo', 'core2duo'],
-	['coreduo', 'coreduo'],
-	['kvm32', 'kvm32'],
-	['kvm64', 'kvm64'],
-	['pentium', 'pentium'],
-	['pentium2', 'pentium2'],
-	['pentium3', 'pentium3'],
-	['phenom', 'phenom'],
-	['qemu32', 'qemu32'],
-	['qemu64', 'qemu64'],
-	['Conroe', 'Conroe'],
-	['Penryn', 'Penryn'],
-	['Nehalem', 'Nehalem'],
-	['Westmere', 'Westmere'],
-	['SandyBridge', 'SandyBridge'],
-	['IvyBridge', 'IvyBridge'],
-	['Haswell', 'Haswell'],
-	['Haswell-noTSX','Haswell-noTSX'],
-	['Broadwell', 'Broadwell'],
-	['Broadwell-noTSX','Broadwell-noTSX'],
-	['Skylake-Client','Skylake-Client'],
-	['Opteron_G1', 'Opteron_G1'],
-	['Opteron_G2', 'Opteron_G2'],
-	['Opteron_G3', 'Opteron_G3'],
-	['Opteron_G4', 'Opteron_G4'],
-	['Opteron_G5', 'Opteron_G5'],
-	['EPYC', 'EPYC'],
-	['host', 'host']
-
-    ]
-});
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + " (" + gettext('No cache') + ")"],
-	['directsync', 'Direct sync'],
-	['writethrough', 'Write through'],
-	['writeback', 'Write back'],
-	['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-	['none', gettext('No cache')]
-    ]
-});
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    valueField: 'name',
-    displayField: 'name',
-
-    loadStore: function(nodename, vmid) {
-	var me = this;
-
-	if (!nodename) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-        if (!vmid) {
-	    return;
-        }
-
-	me.vmid = vmid;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid +'/snapshot'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-	if (!me.guestType) {
-	    throw "no guest type specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'name'],
-	    filterOnLoad: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Snapshot'),
-			dataIndex: 'name',
-			hideable: false,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	me.loadStore(me.nodename, me.vmid);
-    }
-});
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-
-    cts: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [];
-
-	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'snippets'];
-	}
-
-	Ext.Array.each(me.cts, function(ct) {
-	    me.comboItems.push([ct, PVE.Utils.format_content_types(ct)]);
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'Ext.form.CheckboxGroup',
-    alias: 'widget.pveHotplugFeatureSelector',
-
-    columns: 1,
-    vertical: true,
-
-    defaults: {
-	name: 'hotplug',
-	submitValue: false
-    },
-    items: [
-	{
-	    boxLabel: gettext('Disk'),
-	    inputValue: 'disk',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Network'),
-	    inputValue: 'network',
-	    checked: true
-	},
-	{
-	    boxLabel: 'USB',
-	    inputValue: 'usb',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Memory'),
-	    inputValue: 'memory'
-	},
-	{
-	    boxLabel: gettext('CPU'),
-	    inputValue: 'cpu'
-	}
-    ],
-
-    setValue: function(value) {
-	var me = this;
-	var newVal = [];
-	if (value === '1') {
-	    newVal = ['disk', 'network', 'usb'];
-	} else if (value !== '0') {
-	    newVal = value.split(',');
-	}
-	me.callParent([{ hotplug: newVal }]);
-    },
-
-    // override framework function to
-    // assemble the hotplug value
-    getSubmitData: function() {
-	var me = this,
-	boxes = me.getBoxes(),
-	data = [];
-	Ext.Array.forEach(boxes, function(box){
-	    if (box.getValue()) {
-		data.push(box.inputValue);
-	    }
-	});
-
-	/* because above is hotplug an array */
-	/*jslint confusion: true*/
-	if (data.length === 0) {
-	    return { 'hotplug':'0' };
-	} else {
-	    return { 'hotplug': data.join(',') };
-	}
-    }
-
-});
-Ext.define('PVE.form.AgentFeatureSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: ['widget.pveAgentFeatureSelector'],
-
-    initComponent: function() {
-	var me = this;
-	me.items= [
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Qemu Agent'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		listeners: {
-		    change: function(f, value, old) {
-			var gtcb = me.down('proxmoxcheckbox[name=fstrim_cloned_disks]');
-			if (value) {
-			    gtcb.setDisabled(false);
-			} else {
-			    gtcb.setDisabled(true);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Run guest-trim after clone disk'),
-		name: 'fstrim_cloned_disks',
-		disabled: true
-	    }
-	];
-	me.callParent();
-    },
-
-    onGetValues: function(values) {
-	var agentstr = PVE.Parser.printPropertyString(values, 'enabled');
-	return { agent: agentstr };
-    },
-
-    setValues: function(values) {
-	var agent = values.agent || '';
-	var res = PVE.Parser.parsePropertyString(agent, 'enabled');
-	this.callParent([res]);
-    }
-});
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-    comboItems: [
-	['comstar', 'Comstar'],
-	[ 'istgt', 'istgt'],
-	[ 'iet', 'IET'],
-	[ 'LIO', 'LIO']
-    ]
-});
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems:[],
-    initComponent: function(){
-	var me = this;
-	me.comboItems = [
-	    ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-	    ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-	    ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-	    ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-	    ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-	    ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])],
-	    ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])]
-	];
-	this.callParent();
-    }
-});
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-    comboItems: [
-	['__default__', PVE.Utils.render_scsihw('')],
-	['lsi', PVE.Utils.render_scsihw('lsi')],
-	['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-	['megasas', PVE.Utils.render_scsihw('megasas')],
-	['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-	['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-	['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-    ]
-});
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-    comboItems: [
-	    ['ACCEPT', 'ACCEPT'],
-	    ['REJECT', 'REJECT'],
-	    [ 'DROP', 'DROP']
-	]
-});
-/*
- *  This is a global search field
- *  it loads the /cluster/resources on focus
- *  and displays the result in a floating grid
- *
- *  it filters and sorts the objects by the algorithm in
- *  the customFilter function
- *
- *  also it does accept key up/down and enter for input
- *  and it opens to ctrl+shift+f and ctrl+space
- */
-Ext.define('PVE.form.GlobalSearchField', {
-    extend: 'Ext.form.field.Text',
-    alias: 'widget.pveGlobalSearchField',
-
-    emptyText: gettext('Search'),
-    enableKeyEvents: true,
-    selectOnFocus: true,
-    padding: '0 5 0 5',
-
-    grid: {
-	xtype: 'gridpanel',
-	focusOnToFront: false,
-	floating: true,
-	emptyText: Proxmox.Utils.noneText,
-	width: 600,
-	height: 400,
-	scrollable: {
-	    xtype: 'scroller',
-	    y: true,
-	    x:false
-	},
-	store: {
-	    model: 'PVEResources',
-	    proxy:{
-		type: 'proxmox',
-		url: '/api2/extjs/cluster/resources'
-	    }
-	},
-	plugins: {
-	    ptype: 'bufferedrenderer',
-	    trailingBufferZone: 20,
-	    leadingBufferZone: 20
-	},
-
-	hideMe: function() {
-	    var me = this;
-	    if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
-		return;
-	    }
-	    me.hasFocus = false;
-	    if (!me.textfield.hasFocus) {
-		me.hide();
-	    }
-	},
-
-	setFocus: function() {
-	    var me = this;
-	    me.hasFocus = true;
-	},
-
-	listeners: {
-	    rowclick: function(grid, record) {
-		var me = this;
-		me.textfield.selectAndHide(record.id);
-	    },
-	    itemcontextmenu: function(v, record, item, index, event) {
-		var me = this;
-		me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
-	    },
-	    /* because of lint */
-	    focusleave: {
-		fn: 'hideMe'
-	    },
-	    focusenter: 'setFocus'
-	},
-
-	columns: [
-	    {
-		text: gettext('Type'),
-		dataIndex: 'type',
-		width: 100,
-		renderer: PVE.Utils.render_resource_type
-	    },
-	    {
-		text: gettext('Description'),
-		flex: 1,
-		dataIndex: 'text'
-	    },
-	    {
-		text: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		text: gettext('Pool'),
-		dataIndex: 'pool'
-	    }
-	]
-    },
-
-    customFilter: function(item) {
-	var me = this;
-	var match = 0;
-	var fieldArr = [];
-	var i,j, fields;
-
-	// different types of objects have different fields to search
-	// for example, a node will never have a pool and vice versa
-	switch (item.data.type) {
-	    case 'pool': fieldArr = ['type', 'pool', 'text']; break;
-	    case 'node': fieldArr = ['type', 'node', 'text']; break;
-	    case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
-	    default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
-	}
-	if (me.filterVal === '') {
-	    item.data.relevance = 0;
-	    return true;
-	}
-
-	// all text is case insensitive and each word is
-	// searched alone
-	// for every partial match, the row gets
-	// 1 match point, for every exact match
-	// it gets 2 points
-	//
-	// results gets sorted by points (descending)
-	fields = me.filterVal.split(/\s+/);
-	for(i = 0; i < fieldArr.length; i++) {
-	    var v = item.data[fieldArr[i]];
-	    if (v !== undefined) {
-		v = v.toString().toLowerCase();
-		for(j = 0; j < fields.length; j++) {
-		    if (v.indexOf(fields[j]) !== -1) {
-			match++;
-			if(v === fields[j]) {
-			    match++;
-			}
-		    }
-		}
-	    }
-	}
-	// give the row the 'relevance' value
-	item.data.relevance = match;
-	return (match > 0);
-    },
-
-    updateFilter: function(field, newValue, oldValue) {
-	var me = this;
-	// parse input and filter store,
-	// show grid
-	me.grid.store.filterVal = newValue.toLowerCase().trim();
-	me.grid.store.clearFilter(true);
-	me.grid.store.filterBy(me.customFilter);
-	me.grid.getSelectionModel().select(0);
-    },
-
-    selectAndHide: function(id) {
-	var me = this;
-	me.tree.selectById(id);
-	me.grid.hide();
-	me.setValue('');
-	me.blur();
-    },
-
-    onKey: function(field, e) {
-	var me = this;
-	var key = e.getKey();
-
-	switch(key) {
-	    case Ext.event.Event.ENTER:
-		// go to first entry if there is one
-		if (me.grid.store.getCount() > 0) {
-		    me.selectAndHide(me.grid.getSelection()[0].data.id);
-		}
-		break;
-	    case Ext.event.Event.UP:
-		me.grid.getSelectionModel().selectPrevious();
-		break;
-	    case Ext.event.Event.DOWN:
-		me.grid.getSelectionModel().selectNext();
-		break;
-	    case Ext.event.Event.ESC:
-		me.grid.hide();
-		me.blur();
-		break;
-	}
-    },
-
-    loadValues: function(field) {
-	var me = this;
-	var records = [];
-
-	me.hasFocus = true;
-	me.grid.textfield = me;
-	me.grid.store.load();
-	me.grid.showBy(me, 'tl-bl');
-    },
-
-    hideGrid: function() {
-	var me = this;
-
-	me.hasFocus = false;
-	if (!me.grid.hasFocus) {
-	    me.grid.hide();
-	}
-    },
-
-    listeners: {
-	change: {
-	    fn: 'updateFilter',
-	    buffer: 250
-	},
-	specialkey: 'onKey',
-	focusenter: 'loadValues',
-	focusleave: {
-	    fn: 'hideGrid',
-	    delay: 100
-	}
-    },
-
-    toggleFocus: function() {
-	var me = this;
-	if (!me.hasFocus) {
-	    me.focus();
-	} else {
-	    me.blur();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.tree) {
-	    throw "no tree given";
-	}
-
-	me.grid = Ext.create(me.grid);
-
-	me.callParent();
-
-	/*jslint confusion: true*/
-	/*because shift is also a function*/
-	// bind ctrl+shift+f and ctrl+space
-	// to open/close the search
-	me.keymap = new Ext.KeyMap({
-	    target: Ext.get(document),
-	    binding: [{
-		key:'F',
-		ctrl: true,
-		shift: true,
-		fn: me.toggleFocus,
-		scope: me
-	    },{
-		key:' ',
-		ctrl: true,
-		fn: me.toggleFocus,
-		scope: me
-	    }]
-	});
-
-	// always select first item and
-	// sort by relevance after load
-	me.mon(me.grid.store, 'load', function() {
-	    me.grid.getSelectionModel().select(0);
-	    me.grid.store.sort({
-		property: 'relevance',
-		direction: 'DESC'
-	    });
-	});
-    }
-
-});
-Ext.define('PVE.form.QemuBiosSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveQemuBiosSelector'],
-
-    initComponent: function() {
-	var me = this;
-
-        me.comboItems = [
-	    ['__default__', PVE.Utils.render_qemu_bios('')],
-	    ['seabios', PVE.Utils.render_qemu_bios('seabios')],
-	    ['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-/* filter is a javascript builtin, but extjs calls it also filter */
-Ext.define('PVE.form.VMSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    allowBlank: true,
-    selectAll: false,
-    isFormField: true,
-
-    plugins: 'gridfilters',
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-    columns: [
-	{
-	    header: 'ID',
-	    dataIndex: 'vmid',
-	    width: 80,
-	    filter: {
-		type: 'number'
-	    }
-	},
-	{
-	    header: gettext('Node'),
-	    dataIndex: 'node'
-	},
-	{
-	    header: gettext('Status'),
-	    dataIndex: 'status',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1,
-	    filter: {
-		type: 'string'
-	    }
-	},
-	{
-	    header: gettext('Pool'),
-	    dataIndex: 'pool',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Type'),
-	    dataIndex: 'type',
-	    width: 120,
-	    renderer: function(value) {
-		if (value === 'qemu') {
-		    return gettext('Virtual Machine');
-		} else if (value === 'lxc') {
-		    return gettext('LXC Container');
-		}
-
-		return '';
-	    },
-	    filter: {
-		type: 'list',
-		store: {
-		    data: [
-			{id: 'qemu', text: gettext('Virtual Machine')},
-			{id: 'lxc', text: gettext('LXC Container')}
-		    ],
-		    // due to EXTJS-18711
-		    // we have to do a static list via a store
-		    // but to avoid creating an object,
-		    // we have to have a pseudo un function
-		    un: function(){}
-		}
-	    }
-	},
-	{
-	    header: 'HA ' + gettext('Status'),
-	    dataIndex: 'hastate',
-	    flex: 1,
-	    filter: {
-		type: 'list'
-	    }
-	}
-    ],
-
-    selModel: {
-	selType: 'checkboxmodel',
-	mode: 'SIMPLE'
-    },
-
-    checkChangeEvents: [
-	'selectionchange',
-	'change'
-    ],
-
-    listeners: {
-	selectionchange: function() {
-	    // to trigger validity and error checks
-	    this.checkChange();
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	var selection = sm.getSelection();
-	var values = [];
-	var store = me.getStore();
-	selection.forEach(function(item) {
-	    // only add if not filtered
-	    if (store.findExact('vmid', item.data.vmid) !== -1) {
-		values.push(item.data.vmid);
-	    }
-	});
-	return values;
-    },
-
-    setValue: function(value) {
-	console.log(value);
-	var me = this;
-	var sm = me.getSelectionModel();
-	if (!Ext.isArray(value)) {
-	    value = value.split(',');
-	}
-	var selection = [];
-	var store = me.getStore();
-
-	value.forEach(function(item) {
-	    var rec = store.findRecord('vmid',item, 0, false, true, true);
-	    console.log(store);
-
-	    if (rec) {
-		console.log(rec);
-		selection.push(rec);
-	    }
-	});
-
-	sm.select(selection);
-
-	return me.mixins.field.setValue.call(me, value);
-    },
-
-    getErrors: function(value) {
-	var me = this;
-	if (me.allowBlank ===  false &&
-	    me.getSelectionModel().getCount() === 0) {
-	    me.addBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	    return [gettext('No VM selected')];
-	}
-
-	me.removeBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	return [];
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.nodename) {
-	    me.store.filters.add({
-		property: 'node',
-		exactMatch: true,
-		value: me.nodename
-	    });
-	}
-
-	// only show the relevant guests by default
-	if (me.action) {
-	    var statusfilter = '';
-	    switch (me.action) {
-		case 'startall':
-		    statusfilter = 'stopped';
-		    break;
-		case 'stopall':
-		    statusfilter = 'running';
-		    break;
-	    }
-	    if (statusfilter !== '') {
-		me.store.filters.add({
-		    property: 'template',
-		    value: 0
-		},{
-		    id: 'x-gridfilter-status',
-		    operator: 'in',
-		    property: 'status',
-		    value: [statusfilter]
-		});
-	    }
-	}
-
-	var store = me.getStore();
-	var sm = me.getSelectionModel();
-
-	if (me.selectAll) {
-	    me.mon(store,'load', function(){
-		me.getSelectionModel().selectAll(false);
-	    });
-	}
-    }
-});
-
-
-Ext.define('PVE.form.VMComboSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.vmComboSelector',
-
-    valueField: 'vmid',
-    displayField: 'vmid',
-
-    autoSelect: false,
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-
-    listConfig: {
-	width: 600,
-	plugins: 'gridfilters',
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'vmid',
-		width: 80,
-		filter: {
-		    type: 'number'
-		}
-	    },
-	    {
-		header: gettext('Name'),
-		dataIndex: 'name',
-		flex: 1,
-		filter: {
-		    type: 'string'
-		}
-	    },
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		header: gettext('Status'),
-		dataIndex: 'status',
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Pool'),
-		dataIndex: 'pool',
-		hidden: true,
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		width: 120,
-		renderer: function(value) {
-		    if (value === 'qemu') {
-			return gettext('Virtual Machine');
-		    } else if (value === 'lxc') {
-			return gettext('LXC Container');
-		    }
-
-		    return '';
-		},
-		filter: {
-		    type: 'list',
-		    store: {
-			data: [
-			    {id: 'qemu', text: gettext('Virtual Machine')},
-			    {id: 'lxc', text: gettext('LXC Container')}
-			],
-			un: function(){} // due to EXTJS-18711
-		    }
-		}
-	    },
-	    {
-		header: 'HA ' + gettext('Status'),
-		dataIndex: 'hastate',
-		hidden: true,
-		flex: 1,
-		filter: {
-		    type: 'list'
-		}
-	    }
-	]
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.form.VMCPUFlagSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmcpuflagselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    disableSelection: true,
-    columnLines: false,
-    selectable: false,
-    hideHeaders: true,
-
-    scrollable: 'y',
-    height: 200,
-
-    unkownFlags: [],
-
-    store: {
-	type: 'store',
-	fields: ['flag', { name: 'state', defaultValue: '=' }, 'desc'],
-	data: [
-	    // FIXME: let qemu-server host this and autogenerate or get from API call??
-	    { flag: 'md-clear', desc: 'Required to let the guest OS know if MDS is mitigated correctly' },
-	    { flag: 'pcid', desc: 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs' },
-	    { flag: 'spec-ctrl', desc: 'Allows improved Spectre mitigation with Intel CPUs' },
-	    { flag: 'ssbd', desc: 'Protection for "Speculative Store Bypass" for Intel models' },
-	    { flag: 'ibpb', desc: 'Allows improved Spectre mitigation with AMD CPUs' },
-	    { flag: 'virt-ssbd', desc: 'Basis for "Speculative Store Bypass" protection for AMD models' },
-	    { flag: 'amd-ssbd', desc: 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"' },
-	    { flag: 'amd-no-ssb', desc: 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs' },
-	    { flag: 'pdpe1gb', desc: 'Allow guest OS to use 1GB size pages, if host HW supports it' }
-	],
-	listeners: {
-	    update: function() {
-		this.commitChanges();
-	    }
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var store = me.getStore();
-	var flags = '';
-
-	// ExtJS does not has a nice getAllRecords interface for stores :/
-	store.queryBy(Ext.returnTrue).each(function(rec) {
-	    var s = rec.get('state');
-	    if (s && s !== '=') {
-		var f = rec.get('flag');
-		if (flags === '') {
-		    flags = s + f;
-		} else {
-		    flags += ';' + s + f;
-		}
-	    }
-	});
-
-	flags += me.unkownFlags.join(';');
-
-	return flags;
-    },
-
-    setValue: function(value) {
-	var me = this;
-	var store = me.getStore();
-
-	me.value = value || '';
-
-	me.unkownFlags = [];
-
-	me.getStore().queryBy(Ext.returnTrue).each(function(rec) {
-	    rec.set('state', '=');
-	});
-
-	var flags = value ? value.split(';') : [];
-	flags.forEach(function(flag) {
-	    var sign = flag.substr(0, 1);
-	    flag = flag.substr(1);
-
-	    var rec = store.findRecord('flag', flag);
-	    if (rec !== null) {
-		rec.set('state', sign);
-	    } else {
-		me.unkownFlags.push(flag);
-	    }
-	});
-	store.reload();
-
-	var res = me.mixins.field.setValue.call(me, value);
-
-	return res;
-    },
-    columns: [
-	{
-	    dataIndex: 'state',
-	    renderer: function(v) {
-		switch(v) {
-		    case '=': return 'Default';
-		    case '-': return 'Off';
-		    case '+': return 'On';
-		    default: return 'Unknown';
-		}
-	    },
-	    width: 65
-	},
-	{
-	    xtype: 'widgetcolumn',
-	    dataIndex: 'state',
-	    width: 95,
-	    onWidgetAttach: function (column, widget, record) {
-		var val = record.get('state') || '=';
-		widget.down('[inputValue=' + val + ']').setValue(true);
-		// TODO: disable if selected CPU model and flag are incompatible
-	    },
-	    widget: {
-		xtype: 'radiogroup',
-		hideLabel: true,
-		layout: 'hbox',
-		validateOnChange: false,
-		value: '=',
-		listeners: {
-		    change: function(f, value) {
-			var v = Object.values(value)[0];
-			f.getWidgetRecord().set('state', v);
-
-			var view = this.up('grid');
-			view.dirty = view.getValue() !== view.originalValue;
-			view.checkDirty();
-			//view.checkChange();
-		    }
-		},
-		items: [
-		    {
-			boxLabel: '-',
-			boxLabelAlign: 'before',
-			inputValue: '-'
-		    },
-		    {
-			checked: true,
-			inputValue: '='
-		    },
-		    {
-			boxLabel: '+',
-			inputValue: '+'
-		    }
-		]
-	    }
-	},
-	{
-	    dataIndex: 'flag',
-	    width: 100
-	},
-	{
-	    dataIndex: 'desc',
-	    cellWrap: true,
-	    flex: 1
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	// static class store, thus gets not recreated, so ensure defaults are set!
-	me.getStore().data.forEach(function(v) {
-	    v.state = '=';
-	});
-
-	me.value = me.originalValue = '';
-
-	me.callParent(arguments);
-    }
-});
-Ext.define('PVE.form.USBSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUSBSelector'],
-    allowBlank: false,
-    autoSelect: false,
-    displayField: 'usbid',
-    valueField: 'usbid',
-    editable: true,
-
-    getUSBValue: function() {
-	var me = this;
-	var rec = me.store.findRecord('usbid', me.value);
-	var val = 'host='+ me.value;
-	if (rec && rec.data.speed === "5000") {
-	    val = 'host=' + me.value + ",usb3=1";
-	}
-	return val;
-    },
-
-    validator: function(value) {
-	var me = this;
-	if (me.type === 'device') {
-	    return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
-	} else if (me.type === 'port') {
-	    return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
-	}
-	return false;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (me.type !== 'device' && me.type !== 'port') {
-	    throw "no valid type specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-usb-' + me.type,
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/scan/usb"
-	    },
-	    filters: [
-		function (item) {
-		    return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: (me.type === 'device')?gettext('Device'):gettext('Port'),
-			sortable: true,
-			dataIndex: 'usbid',
-			width: 80
-		    },
-		    {
-			header: gettext('Manufacturer'),
-			sortable: true,
-			dataIndex: 'manufacturer',
-			width: 100
-		    },
-		    {
-			header: gettext('Product'),
-			sortable: true,
-			dataIndex: 'product',
-			flex: 1
-		    },
-		    {
-			header: gettext('Speed'),
-			width: 70,
-			sortable: true,
-			dataIndex: 'speed',
-			renderer: function(value) {
-			    if (value === "5000") {
-				return "USB 3.0";
-			    } else if (value === "480") {
-				return "USB 2.0";
-			    } else {
-				return "USB 1.x";
-			    }
-			}
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-usb-device', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val, data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('vendid') + ':' + data.get('prodid');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-
-    Ext.define('pve-usb-port', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val,data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('busnum') + '-' + data.get('usbpath');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-});
-Ext.define('PVE.form.CalendarEvent', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pveCalendarEvent',
-
-    editable: true,
-
-    valueField: 'value',
-    displayField: 'text',
-    queryMode: 'local',
-
-    store: {
-	field: [ 'value', 'text'],
-	data: [
-	    { value: '*/30', text: Ext.String.format(gettext("Every {0} minutes"), 30) },
-	    { value: '*/2:00', text: gettext("Every two hours")},
-	    { value: '2,22:30', text: gettext("Every day") + " 02:30, 22:30"},
-	    { value: 'mon..fri', text: gettext("Monday to Friday") + " 00:00"},
-	    { value: 'mon..fri */1:00', text: gettext("Monday to Friday") + ': ' +  gettext("hourly")},
-	    { value: 'sun 01:00', text: gettext("Sunday") + " 01:00"}
-	]
-    },
-
-    tpl: [
-	'<ul class="x-list-plain"><tpl for=".">',
-	    '<li role="option" class="x-boundlist-item">{text}</li>',
-	'</tpl></ul>'
-    ],
-
-    displayTpl: [
-	'<tpl for=".">',
-	'{value}',
-	'</tpl>'
-    ]
-
-});
-Ext.define('PVE.form.CephPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephPoolSelector',
-
-    allowBlank: false,
-    valueField: 'pool_name',
-    displayField: 'pool_name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/pools'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.form.PermPathSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pvePermPathSelector',
-
-    valueField: 'value',
-    displayField: 'value',
-    typeAhead: true,
-    queryMode: 'local',
-    store: {
-	type: 'pvePermPath'
-    }
-});
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-	var me = this;
-
-	var taskstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-tasks',
-	    model: 'proxmox-tasks',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/tasks'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: taskstore,
-	    sortAfterUpdate: true,
-	    appendAtStart: true,
-	    sorters: [
-		{
-		    property : 'pid',
-		    direction: 'DESC'
-		},
-		{
-		    property : 'starttime',
-		    direction: 'DESC'
-		}
-	    ]
-
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 150,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type == "vncproxy" ||
-				record.data.type == "vncshell" ||
-				record.data.type == "spiceproxy") {
-				metaData.tdCls =  "x-grid-row-console";
-			    } else {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type != "vncproxy") {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return Proxmox.Utils.errorText + ': ' + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		show: taskstore.startUpdate,
-		destroy: taskstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-	var me = this;
-
-	var logstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-log',
-	    model: 'proxmox-cluster-log',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/log'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: logstore,
-	    appendAtStart: true 
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true,
- 
-		getRowClass: function(record, index) {
-		    var pri = record.get('pri');
-
-		    if (pri && pri <= 3) {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{ 
-		    header: gettext("Time"), 
-		    dataIndex: 'time',
-		    width: 150,
-		    renderer: function(value) { 
-			return Ext.Date.format(value, "M d H:i:s"); 
-		    }
-		},
-		{ 
-		    header: gettext("Node"), 
-		    dataIndex: 'node',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Service"), 
-		    dataIndex: 'tag',
-		    width: 100
-		},
-		{ 
-		    header: "PID", 
-		    dataIndex: 'pid',
-		    width: 100 
-		},
-		{ 
-		    header: gettext("User name"), 
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Severity"), 
-		    dataIndex: 'pri',
-		    renderer: PVE.Utils.render_serverity,
-		    width: 100 
-		},
-		{ 
-		    header: gettext("Message"), 
-		    dataIndex: 'msg',
-		    flex: 1	  
-		}
-	    ],
-	    listeners: {
-		activate: logstore.startUpdate,
-		deactivate: logstore.stopUpdate,
-		destroy: logstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = 'ltab';
-	var sp = Ext.state.Manager.getProvider();
-
-	var state = sp.get(stateid);
-	if (state && state.value) {
-	    me.activeTab = state.value;
-	}
-
-	Ext.apply(me, {
-	    listeners: {
-		tabchange: function() {
-		    var atab = me.getActiveTab().itemId;
-		    var state = { value: atab };
-		    sp.set(stateid, state);
-		}
-	    },
-	    items: [
-		{
-		    itemId: 'tasks',
-		    title: gettext('Tasks'),
-		    xtype: 'pveClusterTasks'
-		},
-		{
-		    itemId: 'clog',
-		    title: gettext('Cluster log'),
-		    xtype: 'pveClusterLog'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.items.get(0).fireEvent('show', me.items.get(0));
-
-	var statechange = function(sp, key, state) {
-	    if (key === stateid) {
-		var atab = me.getActiveTab().itemId;
-		var ntab = state.value;
-		if (state && ntab && (atab != ntab)) {
-		    me.setActiveTab(ntab);
-		}
-	    }
-	};
-
-	sp.on('statechange', statechange);
-	me.on('destroy', function() {
-	    sp.un('statechange', statechange);		    
-	});
-
-    }
-});
-Ext.define('PVE.panel.StatusView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStatusView',
-
-    layout: {
-	type: 'column'
-    },
-
-    title: gettext('Status'),
-
-    getRecordValue: function(key, store) {
-	if (!key) {
-	    throw "no key given";
-	}
-	var me = this;
-
-	if (store === undefined) {
-	    store = me.getStore();
-	}
-
-	var rec = store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-
-	return '';
-    },
-
-    fieldRenderer: function(val,max) {
-	if (max === undefined) {
-	    return val;
-	}
-
-	if (!Ext.isNumeric(max) || max === 1) {
-	    return PVE.Utils.render_usage(val);
-	}
-	return PVE.Utils.render_size_usage(val,max);
-    },
-
-    fieldCalculator: function(used, max) {
-	if (!Ext.isNumeric(max) && Ext.isNumeric(used)) {
-	    return used;
-	} else if(!Ext.isNumeric(used)) {
-	    /* we come here if the field is from a node
-	     * where the records are not mem and maxmem
-	     * but mem.used and mem.total
-	     */
-	    if (used.used !== undefined &&
-		used.total !== undefined) {
-		return used.used/used.total;
-	    }
-	}
-
-	return used/max;
-    },
-
-    updateField: function(field) {
-	var me = this;
-	var text = '';
-	var renderer = me.fieldRenderer;
-	if (Ext.isFunction(field.renderer)) {
-	    renderer = field.renderer;
-	}
-	if (field.multiField === true) {
-	    field.updateValue(renderer.call(field, me.getStore().getRecord()));
-	} else if (field.textField !== undefined) {
-	    field.updateValue(renderer.call(field, me.getRecordValue(field.textField)));
-	} else if(field.valueField !== undefined) {
-	    var used = me.getRecordValue(field.valueField);
-	    /*jslint confusion: true*/
-	    /* string and int */
-	    var max = field.maxField !== undefined ? me.getRecordValue(field.maxField) : 1;
-
-	    var calculate = me.fieldCalculator;
-
-	    if (Ext.isFunction(field.calculate)) {
-		calculate = field.calculate;
-	    }
-	    field.updateValue(renderer.call(field, used,max), calculate(used,max));
-	}
-    },
-
-    getStore: function() {
-	var me = this;
-	if (!me.rstore) {
-	    throw "there is no rstore";
-	}
-
-	return me.rstore;
-    },
-
-    updateTitle: function() {
-	var me = this;
-	me.setTitle(me.getRecordValue('name'));
-    },
-
-    updateValues: function(store, records, success) {
-	if (!success) {
-	    return; // do not update if store load was not successful
-	}
-	var me = this;
-	var itemsToUpdate = me.query('pveInfoWidget');
-
-	itemsToUpdate.forEach(me.updateField, me);
-
-	me.updateTitle(store);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	if (!me.title) {
-	    throw "no title given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', 'updateValues');
-    }
-
-});
-Ext.define('PVE.panel.GuestStatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveGuestStatusView',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    height: 300,
-
-    cbindData: function (initialConfig) {
-	var me = this;
-	return {
-	    isQemu: me.pveSelNode.data.type === 'qemu',
-	    isLxc: me.pveSelNode.data.type === 'lxc'
-	};
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'status',
-	    title: gettext('Status'),
-	    iconCls: 'fa fa-info fa-fw',
-	    printBar: false,
-	    multiField: true,
-	    renderer: function(record) {
-		var me = this;
-		var text = record.data.status;
-		var qmpstatus = record.data.qmpstatus;
-		if (qmpstatus && qmpstatus !== record.data.status) {
-		    text += ' (' + qmpstatus + ')';
-		}
-		return text;
-	    }
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    xtype: 'pveInfoWidget',
-	    itemId: 'node',
-	    iconCls: 'fa fa-building fa-fw',
-	    title: gettext('Node'),
-	    cbind: {
-		text: '{pveSelNode.data.node}'
-	    },
-	    printBar: false
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpus',
-	    renderer: PVE.Utils.render_cpu_usage,
-	    // in this specific api call
-	    // we already have the correct value for the usage
-	    calculate: Ext.identityFn
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory usage'),
-	    valueField: 'mem',
-	    maxField: 'maxmem'
-	},
-	{
-	    itemId: 'swap',
-	    xtype: 'pveInfoWidget',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'maxswap',
-	    cbind: {
-		hidden: '{isQemu}',
-		disabled: '{isQemu}'
-	    }
-	},
-	{
-	    itemId: 'rootfs',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    valueField: 'disk',
-	    maxField: 'maxdisk',
-	    printBar: false,
-	    renderer: function(used, max) {
-		var me = this;
-		me.setPrintBar(used > 0);
-		if (used === 0) {
-		    return PVE.Utils.render_size(max);
-		} else {
-		    return PVE.Utils.render_size_usage(used,max);
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'ips',
-	    xtype: 'pveAgentIPView',
-	    cbind: {
-		rstore: '{rstore}',
-		pveSelNode: '{pveSelNode}',
-		hidden: '{isLxc}',
-		disabled: '{isLxc}'
-	    }
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = me.getRecordValue('uptime');
-
-	var text = "";
-	if (Number(uptime) > 0) {
-	    text = " (" + gettext('Uptime') + ': ' + Proxmox.Utils.format_duration_long(uptime)
-		+ ')';
-	}
-
-	me.setTitle(me.getRecordValue('name') + text);
-    }
-});
-/*
- * This is a running chart widget
- * you add time datapoints to it,
- * and we only show the last x of it
- * used for ceph performance charts
- */
-Ext.define('PVE.widget.RunningChart', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveRunningChart',
-
-    layout: {
-	type: 'hbox',
-	align: 'center'
-    },
-    items: [
-	{
-	    width: 80,
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}:</h3>'
-	},
-	{
-	    flex: 1,
-	    xtype: 'cartesian',
-	    height: '100%',
-	    itemId: 'chart',
-	    border: false,
-	    axes: [
-		{
-		    type: 'numeric',
-		    position: 'left',
-		    hidden: true,
-		    minimum: 0
-		},
-		{
-		    type: 'numeric',
-		    position: 'bottom',
-		    hidden: true
-		}
-	    ],
-
-	    store: {
-		data: {}
-	    },
-
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '0 B/s',
-		textAlign: 'end',
-		textBaseline: 'middle',
-		fontSize: 14
-	    }],
-
-	    series: [{
-		type: 'line',
-		xField: 'time',
-		yField: 'val',
-		fill: 'true',
-		colors: ['#cfcfcf'],
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function( tooltip, record, ctx) {
-			var me = this.getChart();
-			var date = new Date(record.data.time);
-			var value = me.up().renderer(record.data.val);
-			tooltip.setHtml(
-			    me.up().title + ': ' + value + '<br />' +
-			    Ext.Date.format(date, 'H:i:s')
-			);
-		    }
-		},
-		style: {
-		    lineWidth: 1.5,
-		    opacity: 0.60
-		},
-		marker: {
-		    opacity: 0,
-		    scaling: 0.01,
-		    fx: {
-			duration: 200,
-			easing: 'easeOut'
-		    }
-		},
-		highlightCfg: {
-		    opacity: 1,
-		    scaling: 1.5
-		}
-	    }]
-	}
-    ],
-
-    // the renderer for the tooltip and last value,
-    // default just the value
-    renderer: Ext.identityFn,
-
-    // show the last x seconds
-    // default is 5 minutes
-    timeFrame: 5*60,
-
-    addDataPoint: function(value, time) {
-	var me = this.chart;
-	var panel = me.up();
-	var now = new Date();
-	var begin = new Date(now.getTime() - (1000*panel.timeFrame));
-
-	me.store.add({
-	    time: time || now.getTime(),
-	    val: value || 0
-	});
-
-	// delete all old records when we have 20 times more datapoints
-	// than seconds in our timeframe (so even a subsecond graph does
-	// not trigger this often)
-	//
-	// records in the store do not take much space, but like this,
-	// we prevent a memory leak when someone has the site open for a long time
-	// with minimal graphical glitches
-	if (me.store.count() > panel.timeFrame * 20) {
-	    var oldData = me.store.getData().createFiltered(function(item) {
-		return item.data.time < begin.getTime();
-	    });
-
-	    me.store.remove(oldData.getRange());
-	}
-
-	me.timeaxis.setMinimum(begin.getTime());
-	me.timeaxis.setMaximum(now.getTime());
-	me.valuesprite.setText(panel.renderer(value || 0).toString());
-	me.valuesprite.setAttributes({
-	    x: me.getWidth() - 15,
-	    y: me.getHeight()/2
-	}, true);
-	me.redraw();
-    },
-
-    setTitle: function(title) {
-	this.title = title;
-	var me = this.getComponent('title');
-	me.update({title: title});
-    },
-
-    initComponent: function(){
-	var me = this;
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.chart = me.getComponent('chart');
-	me.chart.timeaxis = me.chart.getAxes()[1];
-	me.chart.valuesprite = me.chart.getSurface('chart').get('valueSprite');
-	if (me.color) {
-	    me.chart.series[0].setStyle({
-		fill: me.color,
-		stroke: me.color
-	    });
-	}
-    }
-});
-Ext.define('PVE.widget.Info',{
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveInfoWidget',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    value: 0,
-    maximum: 1,
-    printBar: true,
-    items: [
-	{
-	    xtype: 'component',
-	    itemId: 'label',
-	    data: {
-		title: '',
-		usage: '',
-		iconCls: undefined
-	    },
-	    tpl: [
-		'<div class="left-aligned">',
-		'<tpl if="iconCls">',
-		'<i class="{iconCls}"></i> ',
-		'</tpl>',
-		'{title}</div>&nbsp;<div class="right-aligned">{usage}</div>'
-	    ]
-	},
-	{
-	    height: 2,
-	    border: 0
-	},
-	{
-	    xtype: 'progressbar',
-	    itemId: 'progress',
-	    height: 5,
-	    value: 0,
-	    animate: true
-	}
-    ],
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-
-    setPrintBar: function(enable) {
-	var me = this;
-	me.printBar = enable;
-	me.getComponent('progress').setVisible(enable);
-    },
-
-    setIconCls: function(iconCls) {
-	var me = this;
-	me.getComponent('label').data.iconCls = iconCls;
-    },
-
-    updateValue: function(text, usage) {
-	var me = this;
-	var label = me.getComponent('label');
-	label.update(Ext.apply(label.data, {title: me.title, usage:text}));
-
-	if (usage !== undefined &&
-	    me.printBar &&
-	    Ext.isNumeric(usage) &&
-	    usage >= 0) {
-	    var progressBar = me.getComponent('progress');
-	    progressBar.updateProgress(usage, '');
-	    if (usage > me.criticalThreshold) {
-		progressBar.removeCls('warning');
-		progressBar.addCls('critical');
-	    } else if (usage > me.warningThreshold) {
-		progressBar.removeCls('critical');
-		progressBar.addCls('warning');
-	    } else {
-		progressBar.removeCls('warning');
-		progressBar.removeCls('critical');
-	    }
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.title) {
-	    throw "no title defined";
-	}
-
-	me.callParent();
-
-	me.getComponent('progress').setVisible(me.printBar);
-
-	me.updateValue(me.text, me.value);
-	me.setIconCls(me.iconCls);
-    }
-
-});
-Ext.define('PVE.panel.TemplateStatusView',{
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveTemplateStatusView',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	printBar: false,
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    itemId: 'node',
-	    iconCls: 'fa fa-fw fa-building',
-	    title: gettext('Node')
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'cpus',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('Processors'),
-	    textField: 'cpus'
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory'),
-	    textField: 'maxmem',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'swap',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('Swap'),
-	    textField: 'maxswap',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'disk',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    textField: 'maxdisk',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var name = me.pveSelNode.data.name;
-	if (!name) {
-	    throw "no name specified";
-	}
-
-	me.title = name;
-
-	me.callParent();
-	if (me.pveSelNode.data.type !== 'lxc') {
-	    me.remove(me.getComponent('swap'));
-	}
-	me.getComponent('node').updateValue(me.pveSelNode.data.node);
-    }
-});
-Ext.define('PVE.widget.HealthWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveHealthWidget',
-
-    data: {
-	iconCls: PVE.Utils.get_health_icon(undefined, true),
-	text: '',
-	title: ''
-    },
-
-    style: {
-	'text-align':'center'
-    },
-
-    tpl: [
-	'<h3>{title}</h3>',
-	'<i class="fa fa-5x {iconCls}"></i>',
-	'<br /><br/>',
-	'{text}'
-    ],
-
-    updateHealth: function(data) {
-	var me = this;
-	me.update(Ext.apply(me.data, data));
-    },
-
-    initComponent: function(){
-	var me = this;
-
-	if (me.title) {
-	    me.config.data.title = me.title;
-	}
-
-	me.callParent();
-    }
-
-});
-/*global u2f*/
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onLogon: function() {
-	    var me = this;
-
-	    var form = this.lookupReference('loginForm');
-	    var unField = this.lookupReference('usernameField');
-	    var saveunField = this.lookupReference('saveunField');
-	    var view = this.getView();
-
-	    if (!form.isValid()) {
-		return;
-	    }
-
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
-	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
-
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
-
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
-
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
-			} else {
-			    me.perform_otp();
-			}
-		    } else {
-			me.success(data);
-		    }
-		}
-	    });
-
-	},
-	failure: function(resp) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.unmask();
-	    var handler = function() {
-		var uf = me.lookupReference('usernameField');
-		uf.focus(true, true);
-	    };
-
-	    Ext.MessageBox.alert(gettext('Error'),
-				 gettext("Login failed. Please try again"),
-				 handler);
-	},
-	success: function(data) {
-	    var me = this;
-	    var view = me.getView();
-	    var handler = view.handler || Ext.emptyFn;
-	    handler.call(me, data);
-	    view.close();
-	},
-
-	perform_otp: function() {
-	    var me = this;
-	    var win = Ext.create('PVE.window.TFALoginWindow', {
-		onLogin: function(value) {
-		    me.finish_tfa(value);
-		},
-		onCancel: function() {
-		    Proxmox.LoggedOut = false;
-		    Proxmox.Utils.authClear();
-		    me.getView().show();
-		}
-	    });
-	    win.show();
-	},
-
-	perform_u2f: function(data) {
-	    var me = this;
-	    // Show the message:
-	    var msg = Ext.Msg.show({
-		title: 'U2F: '+gettext('Verification'),
-		message: gettext('Please press the button on your U2F Device'),
-		buttons: []
-	    });
-	    var chlg = data.U2FChallenge;
-	    var key = {
-		version: chlg.version,
-		keyHandle: chlg.keyHandle
-	    };
-	    u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
-		msg.close();
-		if (res.errorCode) {
-		    Proxmox.Utils.authClear();
-		    Ext.Msg.alert(gettext('Error'), PVE.Utils.render_u2f_error(res.errorCode));
-		    return;
-		}
-		delete res.errorCode;
-		me.finish_tfa(JSON.stringify(res));
-	    });
-	},
-	finish_tfa: function(res) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-	    var params = { response: res };
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'POST',
-		timeout: 5000, // it'll delay both success & failure
-		success: function(resp, opts) {
-		    view.el.unmask();
-		    // Fill in what we copy over from the 1st factor:
-		    var data = resp.result.data;
-		    data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-		    data.username = Proxmox.UserName;
-		    // Finish logging in:
-		    me.success(data);
-		},
-		failure: function(resp, opts) {
-		    Proxmox.Utils.authClear();
-		    me.failure(resp);
-		}
-	    });
-	},
-
-	control: {
-	    'field[name=username]': {
-		specialkey: function(f, e) {
-		    if (e.getKey() === e.ENTER) {
-			var pf = this.lookupReference('passwordField');
-			if (!pf.getValue()) {
-			    pf.focus(false);
-			}
-		    }
-		}
-	    },
-	    'field[name=lang]': {
-		change: function(f, value) {
-		    var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-		    Ext.util.Cookies.set('PVELangCookie', value, dt);
-		    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
-		    window.location.reload();
-		}
-	    },
-            'button[reference=loginButton]': {
-		click: 'onLogon'
-            },
-	    '#': {
-		show: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var checkboxField = this.lookupReference('saveunField');
-		    var unField = this.lookupReference('usernameField');
-
-		    var checked = sp.get(checkboxField.getStateId());
-		    checkboxField.setValue(checked);
-
-		    if(checked === true) {
-			var username = sp.get(unField.getStateId());
-			unField.setValue(username);
-			var pwField = this.lookupReference('passwordField');
-			pwField.focus();
-		    }
-		}
-	    }
-	}
-    },
-
-    width: 400,
-
-    modal: true,
-
-    border: false,
-
-    draggable: true,
-
-    closable: false,
-
-    resizable: false,
-
-    layout: 'auto',
-
-    title: gettext('Proxmox VE Login'),
-
-    defaultFocus: 'usernameField',
-
-    defaultButton: 'loginButton',
-
-    items: [{
-	xtype: 'form',
-	layout: 'form',
-	url: '/api2/extjs/access/ticket',
-	reference: 'loginForm',
-
-	fieldDefaults: {
-	    labelAlign: 'right',
-	    allowBlank: false
-	},
-
-	items: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('User name'),
-		name: 'username',
-		itemId: 'usernameField',
-		reference: 'usernameField',
-		stateId: 'login-username'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		fieldLabel: gettext('Password'),
-		name: 'password',
-		reference: 'passwordField'
-	    },
-	    {
-		xtype: 'pveRealmComboBox',
-		name: 'realm'
-	    },
-	    {
-		xtype: 'proxmoxLanguageSelector',
-		fieldLabel: gettext('Language'),
-		value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
-		name: 'lang',
-		reference: 'langField',
-		submitValue: false
-	    }
-	],
-	buttons: [
-	    {
-		xtype: 'checkbox',
-		fieldLabel: gettext('Save User name'),
-		name: 'saveusername',
-		reference: 'saveunField',
-		stateId: 'login-saveusername',
-		labelWidth: 'auto',
-		labelAlign: 'right',
-		submitValue: false
-	    },
-	    {
-		text: gettext('Login'),
-		reference: 'loginButton'
-	    }
-	]
-    }]
- });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	login: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onLogin(me.lookup('otpField').getValue());
-	    view.close();
-	},
-	cancel: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onCancel();
-	    view.close();
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Please enter your OTP verification code:'),
-	    name: 'otp',
-	    itemId: 'otpField',
-	    reference: 'otpField',
-	    allowBlank: false
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Login'),
-	    reference: 'loginButton',
-	    handler: 'login'
-	},
-	{
-	    text: gettext('Cancel'),
-	    handler: 'cancel'
-	}
-    ]
-});
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-
-    activeTitle: '', // used for automated testing
-
-    width: 700,
-    height: 510,
-
-    modal: true,
-    border: false,
-
-    draggable: true,
-    closable: true,
-    resizable: false,
-
-    layout: 'border',
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var tabs = me.items || [];
-	delete me.items;
-	
-	/* 
-	 * Items may have the following functions:
-	 * validator(): per tab custom validation
-	 * onSubmit(): submit handler
-	 * onGetValues(): overwrite getValues results
-	 */
-
-	Ext.Array.each(tabs, function(tab) {
-	    tab.disabled = true;
-	});
-	tabs[0].disabled = false;
-
-	var maxidx = 0;
-	var curidx = 0;
-
-	var check_card = function(card) {
-	    var valid = true;
-	    var fields = card.query('field, fieldcontainer');
-	    if (card.isXType('fieldcontainer')) {
-		fields.unshift(card);
-	    }
-	    Ext.Array.each(fields, function(field) {
-		// Note: not all fielcontainer have isValid()
-		if (Ext.isFunction(field.isValid) && !field.isValid()) {
-		    valid = false;
-		}
-	    });
-
-	    if (Ext.isFunction(card.validator)) {
-		return card.validator();
-	    }
-
-	    return valid;
-	};
-
-	var disable_at = function(card) {
-	    var tp = me.down('#wizcontent');
-	    var idx = tp.items.indexOf(card);
-	    for(;idx < tp.items.getCount();idx++) {
-		var nc = tp.items.getAt(idx);
-		if (nc) {
-		    nc.disable();
-		}
-	    }
-	};
-
-	var tabchange = function(tp, newcard, oldcard) {
-	    if (newcard.onSubmit) {
-		me.down('#next').setVisible(false);
-		me.down('#submit').setVisible(true); 
-	    } else {
-		me.down('#next').setVisible(true);
-		me.down('#submit').setVisible(false); 
-	    }
-	    var valid = check_card(newcard);
-	    me.down('#next').setDisabled(!valid);    
-	    me.down('#submit').setDisabled(!valid);    
-	    me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-	    var idx = tp.items.indexOf(newcard);
-	    if (idx > maxidx) {
-		maxidx = idx;
-	    }
-	    curidx = idx;
-
-	    var next = idx + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (valid && ntab && !newcard.onSubmit) {
-		ntab.enable();
-	    }
-	};
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, true, false);
-	}
-
-	var sp = Ext.state.Manager.getProvider();
-	var advchecked = sp.get('proxmox-advanced-cb');
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'form',
-		    region: 'center',
-		    layout: 'fit',
-		    border: false,
-		    margins: '5 5 0 5',
-		    fieldDefaults: {
-			labelWidth: 100,
-			anchor: '100%'
-		    },
-		    items: [{
-			itemId: 'wizcontent',
-			xtype: 'tabpanel',
-			activeItem: 0,
-			bodyPadding: 10,
-			listeners: {
-			    afterrender: function(tp) {
-				var atab = this.getActiveTab();
-				tabchange(tp, atab);
-			    },
-			    tabchange: function(tp, newcard, oldcard) {
-				tabchange(tp, newcard, oldcard);
-			    }
-			},
-			items: tabs
-		    }]
-		}
-	    ],
-	    fbar: [
-		{
-		    xtype: 'proxmoxHelpButton',
-		    itemId: 'help'
-		},
-		'->',
-		{
-		    xtype: 'proxmoxcheckbox',
-		    boxLabelAlign: 'before',
-		    boxLabel: gettext('Advanced'),
-		    value: advchecked,
-		    listeners: {
-			change: function(cb, val) {
-			    var tp = me.down('#wizcontent');
-			    tp.query('inputpanel').forEach(function(ip) {
-				ip.setAdvancedVisible(val);
-			    });
-
-			    sp.set('proxmox-advanced-cb', val);
-			}
-		    }
-		},
-		{
-		    text: gettext('Back'),
-		    disabled: true,
-		    itemId: 'back',
-		    minWidth: 60,
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			var prev = tp.items.indexOf(atab) - 1;
-			if (prev < 0) {
-			    return;
-			}
-			var ntab = tp.items.getAt(prev);
-			if (ntab) {
-			    tp.setActiveTab(ntab);
-			}
-		    }
-		},
-		{
-		    text: gettext('Next'),
-		    disabled: true,
-		    itemId: 'next',
-		    minWidth: 60,
-		    handler: function() {
-
-			var form = me.down('form').getForm();
-
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			if (!check_card(atab)) {
-			    return;
-			}
-
-			var next = tp.items.indexOf(atab) + 1;
-			var ntab = tp.items.getAt(next);
-			if (ntab) {
-			    ntab.enable();
-			    tp.setActiveTab(ntab);
-			}
-
-		    }
-		},
-		{
-		    text: gettext('Finish'),
-		    minWidth: 60,
-		    hidden: true,
-		    itemId: 'submit',
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			atab.onSubmit();
-		    }
-		}
-	    ]
-	});
-	me.callParent();
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setAdvancedVisible(advchecked);
-	});
-
-	Ext.Array.each(me.query('field'), function(field) {
-	    var validcheck = function() {
-		var tp = me.down('#wizcontent');
-
-		// check tabs from current to the last enabled for validity
-		// since we might have changed a validity on a later one
-		var i;
-		for (i = curidx; i <= maxidx && i < tp.items.getCount(); i++) {
-		    var tab = tp.items.getAt(i);
-		    var valid = check_card(tab);
-
-		    // only set the buttons on the current panel
-		    if (i === curidx) {
-			me.down('#next').setDisabled(!valid);
-			me.down('#submit').setDisabled(!valid);
-		    }
-
-		    // if a panel is invalid, then disable it and all following,
-		    // else enable it and go to the next
-		    var ntab = tp.items.getAt(i + 1);
-		    if (!valid) {
-			disable_at(ntab);
-			return;
-		    } else if (ntab && !tab.onSubmit) {
-			ntab.enable();
-		    }
-		}
-	    };
-	    field.on('change', validcheck);
-	    field.on('validitychange', validcheck);
-	});
-    }
-});
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    title: gettext('Notes'),
-	    width: 600,
-	    height: '400px',
-	    resizable: true,
-	    layout: 'fit',
-	    defaultButton: undefined,
-	    items: {
-		xtype: 'textarea',
-		name: 'description',
-		height: '100%',
-		value: '',
-		hideLabel: true
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: me.storage,
-	    fieldLabel: gettext('Storage'),
-	    storageContent: 'backup',
-	    allowBlank: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		storagesel,
-		{
-		    xtype: 'pveBackupModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    value: 'snapshot',
-		    name: 'mode'
-		},
-		{
-		    xtype: 'pveCompressionSelector',
-		    name: 'compress',
-		    value: 'lzo',
-		    fieldLabel: gettext('Compression')
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Send email to'),
-		    name: 'mailto',
-		    emptyText: Proxmox.Utils.noneText
-		}
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Backup'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid,
-		    mode: values.mode,
-		    remove: 0
-		};
-
-		if ( values.mailto ) {
-		    params.mailto = values.mailto;
-		}
-
-		if (values.compress) {
-		    params.compress = values.compress;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/vzdump',
-		    params: params,
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			// close later so we reload the grid
-			// after the task has completed
-			me.hide();
-
-			var upid = response.result.data;
-			
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				close: function() {
-				    me.close();
-				}
-			    }
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var helpBtn = Ext.create('Proxmox.button.Help', {
-	    onlineHelp: 'chapter_vzdump',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	});
-
-	var title = gettext('Backup') + " " + 
-	    ((me.vmtype === 'lxc') ? "CT" : "VM") +
-	    " " + me.vmid;
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 350,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ helpBtn, '->', submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: Proxmox.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.volid) {
-	    throw "no volume ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no vmtype specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: '',
-	    fieldLabel: gettext('Storage'),
-	    storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-	    allowBlank: true
-	});
-
-	var IDfield;
-	if (me.vmid) {
-	    IDfield = Ext.create('Ext.form.field.Display', {
-		name: 'vmid',
-		value: me.vmid,
-		fieldLabel: (me.vmtype === 'lxc') ? 'CT' : 'VM'
-	    });
-	} else {
-	    IDfield = Ext.create('PVE.form.GuestIDSelector', {
-		name: 'vmid',
-		guestType: me.vmtype,
-		loadNextFreeID: true,
-		validateExists: false
-	    });
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		value: me.volidText || me.volid,
-		fieldLabel: gettext('Source')
-	    },
-	    storagesel,
-	    IDfield,
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'bwlimit',
-		fieldLabel: gettext('Read Limit (MiB/s)'),
-		minValue: 0,
-		emptyText: gettext('Defaults to target storage restore limit'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext("Use '0' to disable all bandwidth limits.")
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'unique',
-		fieldLabel: gettext('Unique'),
-		hidden: !!me.vmid,
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext('Autogenerate unique properties, e.g., MAC addresses')
-		},
-		checked: false
-	    }
-	];
-
-	/*jslint confusion: true*/
-	if (me.vmtype === 'lxc') {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'unprivileged',
-		value: true,
-		fieldLabel: gettext('Unprivileged container')
-	    });
-	}
-	/*jslint confusion: false*/
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doRestore = function(url, params) {
-	    Proxmox.Utils.API2Request({
-		url: url,
-		params: params,
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.close();
-		}
-	    });
-	};
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Restore'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid || values.vmid,
-		    force: me.vmid ? 1 : 0
-		};
-		if (values.unique) { params.unique = 1; }
-
-		if (values.bwlimit !== undefined) {
-		    params.bwlimit = values.bwlimit * 1024;
-		}
-
-		var url;
-		var msg;
-		if (me.vmtype === 'lxc') {
-		    url = '/nodes/' + me.nodename + '/lxc';
-		    params.ostemplate = me.volid;
-		    params.restore = 1;
-		    if (values.unprivileged) { params.unprivileged = 1; }
-		    msg = Proxmox.Utils.format_task_description('vzrestore', params.vmid);
-		} else if (me.vmtype === 'qemu') {
-		    url = '/nodes/' + me.nodename + '/qemu';
-		    params.archive = me.volid;
-		    msg = Proxmox.Utils.format_task_description('qmrestore', params.vmid);
-		} else {
-		    throw 'unknown VM type';
-		}
-
-		if (me.vmid) {
-		    msg += '. ' + gettext('This will permanently erase current VM data.');
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRestore(url, params);
-		    });
-		} else {
-		    doRestore(url, params);
-		}
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-	var title =  gettext('Restore') + ": " + (
-	    (me.vmtype === 'lxc') ? 'CT' : 'VM');
-
-	if (me.vmid) {
-	    title += " " + me.vmid;
-	}
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 500,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-/* Popup a message window
- * where the user has to manually enter the resource ID
- * to enable the destroy button
- */
-Ext.define('PVE.window.SafeDestroy', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSafeDestroy',
-
-    title: gettext('Confirm'),
-    modal: true,
-    buttonAlign: 'center',
-    bodyPadding: 10,
-    width: 450,
-    layout: { type:'hbox' },
-    defaultFocus: 'confirmField',
-    showProgress: false,
-
-    config: {
-	item: {
-	    id: undefined,
-	    type: undefined
-	},
-	url: undefined,
-	params: {}
-    },
-
-    getParams: function() {
-	var me = this;
-	if (Ext.Object.isEmpty(me.params)) {
-	    return '';
-	}
-	return '?' + Ext.Object.toQueryString(me.params);
-    },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=confirm]': {
-		change: function(f, value) {
-		    var view = this.getView();
-		    var removeButton = this.lookupReference('removeButton');
-		    if (value === view.getItem().id.toString()) {
-			removeButton.enable();
-		    } else {
-			removeButton.disable();
-		    }
-		},
-		specialkey: function (field, event) {
-		    var removeButton = this.lookupReference('removeButton');
-		    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
-			removeButton.fireEvent('click', removeButton, event);
-		    }
-		}
-	    },
-           'button[reference=removeButton]': {
-		click: function() {
-		    var view = this.getView();
-		    Proxmox.Utils.API2Request({
-			url: view.getUrl() + view.getParams(),
-			method: 'DELETE',
-			waitMsgTarget: view,
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var hasProgressBar = view.showProgress &&
-				response.result.data ? true : false;
-
-			    if (hasProgressBar) {
-				// stay around so we can trigger our close events
-				// when background action is completed
-				view.hide();
-
-				var upid = response.result.data;
-				var win = Ext.create('Proxmox.window.TaskProgress', {
-				    upid: upid,
-				    listeners: {
-					destroy: function () {
-					    view.close();
-					}
-				    }
-				});
-				win.show();
-			    } else {
-				view.close();
-			    }
-			}
-		    });
-		}
-            }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    cls: [ Ext.baseCSSPrefix + 'message-box-icon',
-		   Ext.baseCSSPrefix + 'message-box-warning',
-		   Ext.baseCSSPrefix + 'dlg-icon']
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    xtype: 'component',
-		    reference: 'messageCmp'
-		},
-		{
-		    itemId: 'confirmField',
-		    reference: 'confirmField',
-		    xtype: 'textfield',
-		    name: 'confirm',
-		    labelWidth: 300,
-		    hideTrigger: true,
-		    allowBlank: false
-		}
-	    ]
-	}
-    ],
-    buttons: [
-	{
-	    reference: 'removeButton',
-	    text: gettext('Remove'),
-	    disabled: true
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	var item = me.getItem();
-
-	if (!Ext.isDefined(item.id)) {
-	    throw "no ID specified";
-	}
-
-	if (!Ext.isDefined(item.type)) {
-	    throw "no VM type specified";
-	}
-
-	var messageCmp = me.lookupReference('messageCmp');
-	var msg;
-
-	if (item.type === 'VM') {
-	    msg = Proxmox.Utils.format_task_description('qmdestroy', item.id);
-	} else if (item.type === 'CT') {
-	    msg = Proxmox.Utils.format_task_description('vzdestroy', item.id);
-	} else if (item.type === 'CephPool') {
-	    msg = Proxmox.Utils.format_task_description('cephdestroypool', item.id);
-	} else if (item.type === 'Image') {
-	    msg = Proxmox.Utils.format_task_description('unknownimgdel', item.id);
-	} else {
-	    throw "unknown item type specified";
-	}
-
-	messageCmp.setHtml(msg);
-
-	var confirmField = me.lookupReference('confirmField');
-	msg = gettext('Please enter the ID to confirm') +
-	    ' (' + item.id + ')';
-	confirmField.setFieldLabel(msg);
-    }
-});
-Ext.define('PVE.window.BackupConfig', {
-    extend: 'Ext.window.Window',
-    title: gettext('Configuration'),
-    width: 600,
-    height: 400,
-    layout: 'fit',
-    modal: true,
-    items: {
-	xtype: 'component',
-	itemId: 'configtext',
-	autoScroll: true,
-	style: {
-	    'background-color': 'white',
-	    'white-space': 'pre',
-	    'font-family': 'monospace',
-	    padding: '5px'
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.volume) {
-	    throw "no volume specified";
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + nodename + "/vzdump/extractconfig",
-	    method: 'GET',
-	    params: {
-		volume: me.volume
-	    },
-	    failure: function(response, opts) {
-		me.close();
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response,options) {
-		me.show();
-		me.down('#configtext').update(Ext.htmlEncode(response.result.data));
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.Settings', {
-    extend: 'Ext.window.Window',
-
-    width: '800px',
-    title: gettext('My Settings'),
-    iconCls: 'fa fa-gear',
-    modal: true,
-    bodyPadding: 10,
-    resizable: false,
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    onlineHelp: 'gui_my_settings',
-	    hidden: false
-	},
-	'->',
-	{
-	    text: gettext('Close'),
-	    handler: function() {
-		this.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    var me = this;
-	    var sp = Ext.state.Manager.getProvider();
-
-	    var username = sp.get('login-username') || Proxmox.Utils.noneText;
-	    me.lookupReference('savedUserName').setValue(username);
-
-	    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-	    settings.forEach(function(setting) {
-		var val = localStorage.getItem('pve-xterm-' + setting);
-		if (val !== undefined && val !== null) {
-		    var field = me.lookup(setting);
-		    field.setValue(val);
-		    field.resetOriginalValue();
-		}
-	    });
-	},
-
-	set_button_status: function() {
-	    var me = this;
-
-	    var form = me.lookup('xtermform');
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-
-	    var hasvalues = false;
-	    var values = form.getValues();
-	    Ext.Object.eachValue(values, function(value) {
-		if (value) {
-		    hasvalues = true;
-		    return false;
-		}
-	    });
-
-	    me.lookup('xtermsave').setDisabled(!dirty || !valid);
-	    me.lookup('xtermreset').setDisabled(!hasvalues);
-	},
-
-	control: {
-	    '#xtermjs form': {
-		dirtychange: 'set_button_status',
-		validitychange: 'set_button_status'
-	    },
-	    '#xtermjs button': {
-		click: function(button) {
-		    var me = this;
-		    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-		    settings.forEach(function(setting) {
-			var field = me.lookup(setting);
-			if (button.reference === 'xtermsave') {
-			    var value = field.getValue();
-			    if (value) {
-				localStorage.setItem('pve-xterm-' + setting, value);
-			    } else {
-				localStorage.removeItem('pve-xterm-' + setting);
-			    }
-			} else if (button.reference === 'xtermreset') {
-			    field.setValue(undefined);
-			    localStorage.removeItem('pve-xterm-' + setting);
-			}
-			field.resetOriginalValue();
-		    });
-		    me.set_button_status();
-		}
-	    },
-	    'button[name=reset]': {
-		click: function () {
-		    var blacklist = ['GuiCap', 'login-username', 'dash-storages'];
-		    var sp = Ext.state.Manager.getProvider();
-		    var state;
-		    for (state in sp.state) {
-			if (sp.state.hasOwnProperty(state)) {
-			    if (blacklist.indexOf(state) !== -1) {
-				continue;
-			    }
-
-			    sp.clear(state);
-			}
-		    }
-
-		    window.location.reload();
-		}
-	    },
-	    'button[name=clear-username]': {
-		click: function () {
-		    var me = this;
-		    var usernamefield = me.lookupReference('savedUserName');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    usernamefield.setValue(Proxmox.Utils.noneText);
-		    sp.clear('login-username');
-		}
-	    },
-	    'grid[reference=dashboard-storages]': {
-		selectionchange: function(grid, selected) {
-		    var me = this;
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // saves the selected storageids as
-		    // "id1,id2,id3,..."
-		    // or clears the variable
-		    if (selected.length > 0) {
-			sp.set('dash-storages',
-			    Ext.Array.pluck(selected, 'id').join(','));
-		    } else {
-			sp.clear('dash-storages');
-		    }
-		},
-		afterrender: function(grid) {
-		    var me = grid;
-		    var sp = Ext.state.Manager.getProvider();
-		    var store = me.getStore();
-		    var items = [];
-		    me.suspendEvent('selectionchange');
-		    var storages = sp.get('dash-storages') || '';
-		    storages.split(',').forEach(function(storage){
-			// we have to get the records
-			// to be able to select them
-			if (storage !== '') {
-			    var item = store.getById(storage);
-			    if (item) {
-				items.push(item);
-			    }
-			}
-		    });
-		    me.getSelectionModel().select(items);
-		    me.resumeEvent('selectionchange');
-		}
-	    }
-	}
-    },
-
-    items: [{
-	    xtype: 'fieldset',
-	    width: '50%',
-	    title: gettext('Webinterface Settings'),
-	    margin: '5',
-	    layout: {
-		type: 'vbox',
-		align: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Dashboard Storages'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'grid',
-		    maxHeight: 150,
-		    reference: 'dashboard-storages',
-		    selModel: {
-			selType: 'checkboxmodel'
-		    },
-		    columns: [{
-			header: gettext('Name'),
-			dataIndex: 'storage',
-			flex: 1
-		    },{
-			header: gettext('Node'),
-			dataIndex: 'node',
-			flex: 1
-		    }],
-		    store: {
-			type: 'diff',
-			field: ['type', 'storage', 'id', 'node'],
-			rstore: PVE.data.ResourceStore,
-			filters: [{
-			    property: 'type',
-			    value: 'storage'
-			}],
-			sorters: [ 'node','storage']
-		    }
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Saved User name'),
-		    labelAlign: 'left',
-		    labelWidth: '50%',
-		    stateId: 'login-username',
-		    reference: 'savedUserName',
-		    value: ''
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Clear User name'),
-		    width: 'auto',
-		    name: 'clear-username'
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Layout'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Reset Layout'),
-		    width: 'auto',
-		    name: 'reset'
-		}
-	    ]
-    },{
-	xtype: 'fieldset',
-	itemId: 'xtermjs',
-	width: '50%',
-	margin: '5',
-	title: gettext('xterm.js Settings'),
-	items: [{
-	    xtype: 'form',
-	    reference: 'xtermform',
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		algin: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'textfield',
-		    name: 'fontFamily',
-		    reference: 'fontFamily',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Font-Family')
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    emptyText: Proxmox.Utils.defaultText,
-		    name: 'fontSize',
-		    reference: 'fontSize',
-		    minValue: 1,
-		    fieldLabel: gettext('Font-Size')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'letterSpacing',
-		    reference: 'letterSpacing',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Letter Spacing')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'lineHeight',
-		    minValue: 0.1,
-		    reference: 'lineHeight',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Line Height')
-		},
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'hbox',
-			pack: 'end'
-		    },
-		    items: [
-			{
-			    xtype: 'button',
-			    reference: 'xtermreset',
-			    disabled: true,
-			    text: gettext('Reset')
-			},
-			{
-			    xtype: 'button',
-			    reference: 'xtermsave',
-			    disabled: true,
-			    text: gettext('Save')
-			}
-		    ]
-		}
-	    ]
-	}]
-    }],
-
-    onShow: function() {
-	var me = this;
-	me.callParent();
-    }
-});
-Ext.define('PVE.panel.StartupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'qm_startup_and_shutdown',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = PVE.Parser.printStartup(values);
-
-	if (res === undefined || res === '') {
-	    return { 'delete': 'startup' };
-	}
-
-	return { startup: res };
-    },
-
-    setStartup: function(value) {
-	var me = this;
-
-	var startup = PVE.Parser.parseStartup(value);
-	if (startup) {
-	    me.setValues(startup);
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		name: 'order',
-		defaultValue: '',
-		emptyText: 'any',
-		fieldLabel: gettext('Start/Shutdown order')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'up',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Startup delay')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'down',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Shutdown timeout')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.window.StartupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveWindowStartupEdit',
-    onlineHelp: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-	var ipanelConfig = me.onlineHelp ? {onlineHelp: me.onlineHelp} : {};
-	var ipanel = Ext.create('PVE.panel.StartupInputPanel', ipanelConfig);
-
-	Ext.applyIf(me, {
-	    subject: gettext('Start/Shutdown order'),
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		ipanel.setStartup(me.vmconfig.startup);		    
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.Install', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveCephInstallWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 220,
-    header: false,
-    resizable: false,
-    draggable: false,
-    modal: true,
-    nodename: undefined,
-    shadow: false,
-    border: false,
-    bodyBorder: false,
-    closable: false,
-    cls: 'install-mask',
-    bodyCls: 'install-mask',
-    layout: {
-        align: 'stretch',
-        pack: 'center',
-	type: 'vbox'
-    },
-    viewModel: {
-	data: {
-	      cephVersion: 'nautilus',
-	      isInstalled: false
-	},
-	formulas: {
-	    buttonText: function (get){
-		if (get('isInstalled')) {
-		    return gettext('Configure Ceph');
-		} else {
-		    return gettext('Install Ceph-') + get('cephVersion');
-		}
-	    },
-	    windowText: function (get) {
-		if (get('isInstalled')) {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not initialized.'), 'Ceph') + ' '+
-		    gettext('You need to create a initial config once.') + '</p>';
-		} else {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '<br>' +
-		    gettext('Would you like to install it now?') + '</p>';
-		}
-	    }
-	}
-    },
-    items: [
-	{
-	    bind: {
-		html: '{windowText}'
-	    },
-	    border: false,
-	    padding: 5,
-	    bodyCls: 'install-mask'
-
-	},
-	{
-	    xtype: 'button',
-	    bind: {
-		text: '{buttonText}'
-	    },
-	    viewModel: {},
-	    cbind: {
-		nodename: '{nodename}'
-	    },
-	    handler: function() {
-		var me = this.up('pveCephInstallWindow');
-		var win = Ext.create('PVE.ceph.CephInstallWizard',{
-		    nodename: me.nodename
-		});
-		win.getViewModel().set('isInstalled', this.getViewModel().get('isInstalled'));
-		win.show();
-		me.mon(win,'beforeClose', function(){
-		    me.fireEvent("cephInstallWindowClosed");
-		    me.close();
-		});
-
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallEnableEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveFirewallEnableEdit'],
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    subject: gettext('Firewall'),
-    cbindData: {
-	defaultValue: 0
-    },
-    width: 350,
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    uncheckedValue: 0,
-	    cbind: {
-		defaultValue: '{defaultValue}',
-		checked: '{defaultValue}'
-	    },
-	    deleteDefaultValue: false,
-	    fieldLabel: gettext('Firewall')
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'warning',
-	    userCls: 'pve-hint',
-	    value: gettext('Warning: Firewall still disabled at datacenter level!'),
-	    hidden: true
-	}
-    ],
-
-    beforeShow: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/cluster/firewall/options',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		if (!response.result.data.enable) {
-		    me.down('displayfield[name=warning]').setVisible(true);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallLograteInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveFirewallLograteInputPanel',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    reference: 'enable',
-	    fieldLabel: gettext('Enable'),
-	    value: true
-	},
-	{
-	    layout: 'hbox',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'numberfield',
-		    name: 'rate',
-		    fieldLabel: gettext('Log rate limit'),
-		    minValue: 1,
-		    maxValue: 99,
-		    allowBlank: false,
-		    flex: 2,
-		    value: 1
-		},
-		{
-		    xtype: 'box',
-		    html: '<div style="margin: auto; padding: 2.5px;"><b>/</b></div>'
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    name: 'unit',
-		    comboItems: [['second', 'second'], ['minute', 'minute'],
-			['hour', 'hour'], ['day', 'day']],
-		    allowBlank: false,
-		    flex: 1,
-		    value: 'second'
-		}
-	    ]
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'burst',
-	    fieldLabel: gettext('Log burst limit'),
-	    minValue: 1,
-	    maxValue: 99,
-	    value: 5
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var vals = {};
-	vals.enable = values.enable !== undefined ? 1 : 0;
-	vals.rate = values.rate + '/' + values.unit;
-	vals.burst = values.burst;
-	var properties = PVE.Parser.printPropertyString(vals, undefined);
-	if (properties == '') {
-	    return { 'delete': 'log_ratelimit' };
-	}
-	return { log_ratelimit: properties };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var properties = {};
-	if (values.log_ratelimit !== undefined) {
-	    properties = PVE.Parser.parsePropertyString(values.log_ratelimit, 'enable');
-	    if (properties.rate) {
-		var matches = properties.rate.match(/^(\d+)\/(second|minute|hour|day)$/);
-		if (matches) {
-		    properties.rate = matches[1];
-		    properties.unit = matches[2];
-		}
-	    }
-	}
-	me.callParent([properties]);
-    }
-});
-
-Ext.define('PVE.FirewallLograteEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveFirewallLograteEdit',
-
-    subject: gettext('Log rate limit'),
-
-    items: [{
-	xtype: 'pveFirewallLograteInputPanel'
-    }],
-    autoLoad: true
-});
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNotesView',
-
-    title: gettext("Notes"),
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 10,
-    scrollable: true,
-
-    tbar: {
-	itemId: 'tbar',
-	hidden: true,
-	items: [
-	    {
-		text: gettext('Edit'),
-		handler: function() {
-		    var me = this.up('panel');
-		    me.run_editor();
-		}
-	    }
-	]
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create('PVE.window.NotesEdit', {
-	    pveSelNode: me.pveSelNode,
-	    url: me.url
-	});
-	win.show();
-	win.on('destroy', me.load, me);
-    },
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data.description || '';
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    listeners: {
-	render: function(c) {
-	    var me = this;
-	    me.getEl().on('dblclick', me.run_editor, me);
-	}
-    },
-
-    tools: [{
-	type: 'gear',
-	handler: function() {
-	    var me = this.up('panel');
-	    me.run_editor();
-	}
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	if (!Ext.Array.contains(['node', 'qemu', 'lxc'], type)) {
-	    throw 'invalid type specified';
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid && type !== 'node') {
-	    throw "no VM ID specified";
-	}
-
-	me.url = '/api2/extjs/nodes/' + nodename + '/';
-
-	// add the type specific path if qemu/lxc
-	if (type === 'qemu' || type === 'lxc') {
-	    me.url += type + '/' + vmid + '/';
-	}
-
-	me.url += 'config';
-
-	me.callParent();
-	if (type === 'node') {
-	    me.down('#tbar').setVisible(true);
-	}
-	me.load();
-    }
-});
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    border: false,
-    defaultSorter: {
-	property: 'type',
-	direction: 'ASC'
-    },
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	var coldef = rstore.defaultColumns();
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: me.defaultSorter,
-	    proxy: { type: 'memory' }
-	});
-
-	var textfilter = '';
-
-	var textfilter_match = function(item) {
-	    var match = false;
-	    Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-		var v = item.data[field];
-		if (v !== undefined) {
-		    v = v.toLowerCase();
-		    if (v.indexOf(textfilter) >= 0) {
-			match = true;
-			return false;
-		    }
-		}
-	    });
-	    return match;
-	};
-
-	var updateGrid = function() {
-
-	    var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-	    
-	    //console.log("START GRID UPDATE " +  me.viewFilter);
-
-	    store.suspendEvents();
-
-	    var nodeidx = {};
-	    var gather_child_nodes = function(cn) {
-		if (!cn) {
-		    return;
-		}
-                var cs = cn.childNodes;
-		if (!cs) {
-		    return;
-		}
-		var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-		    var child = cs[i];
-		    var orgnode = rstore.data.get(child.data.id);
-		    if (orgnode) {
-			if ((!filterfn || filterfn(child)) &&
-			    (!textfilter || textfilter_match(child))) {
-			    nodeidx[child.data.id] = orgnode;
-			}
-		    }
-		    gather_child_nodes(child);
-		}
-	    };
-	    gather_child_nodes(me.pveSelNode);
-
-	    // remove vanished items
-	    var rmlist = [];
-	    store.each(function(olditem) {
-		var item = nodeidx[olditem.data.id];
-		if (!item) {
-		    //console.log("GRID REM UID: " + olditem.data.id);
-		    rmlist.push(olditem);
-		}
-	    });
-
-	    if (rmlist.length) {
-		store.remove(rmlist);
-	    }
-
-	    // add new items
-	    var addlist = [];
-	    var key;
-	    for (key in nodeidx) {
-		if (nodeidx.hasOwnProperty(key)) {
-		    var item = nodeidx[key];
-		
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var olditem = store.getById(item.data.id);
-		    var olditem = store.data.get(item.data.id);
-
-		    if (!olditem) {
-			//console.log("GRID ADD UID: " + item.data.id);
-			var info = Ext.apply({}, item.data);
-			var child = Ext.create(store.model, info);
-			addlist.push(item);
-			continue;
-		    }
-		    // try to detect changes
-		    var changes = false;
-		    var fieldkeys = PVE.data.ResourceStore.fieldNames;
-		    var fieldcount = fieldkeys.length;
-		    var fieldind;
-		    for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-			var field = fieldkeys[fieldind];
-			if (field != 'id' && item.data[field] != olditem.data[field]) {
-			    changes = true;
-			    //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-			    olditem.beginEdit();
-			    olditem.set(field, item.data[field]);
-			}
-		    }
-		    if (changes) {
-			olditem.endEdit(true);
-			olditem.commit(true); 
-		    }
-		}
-	    }
-
-	    if (addlist.length) {
-		store.add(addlist);
-	    }
-
-	    store.sort();
-
-	    store.resumeEvents();
-
-	    store.fireEvent('refresh', store);
-
-	    //console.log("END GRID UPDATE");
-	};
-
-	var filter_task = new Ext.util.DelayedTask(function(){
-	    updateGrid();
-	});
-
-	var load_cb = function() { 
-	    updateGrid(); 
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-resource',
-	    tbar: [
-		'->', 
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: textfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    var v = field.getValue();
-			    textfilter = v.toLowerCase();
-			    filter_task.delay(500);
-			}
-		    }
-		}
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		destroy: function() {
-		    rstore.un("load", load_cb);
-		}
-	    },
-            columns: coldef
-	});
-	me.callParent();
-	updateGrid();
-	rstore.on("load", load_cb);
-    }
-});
-Ext.define('PVE.pool.AddVM', {
-    extend: 'Proxmox.window.Edit',
-    width: 600,
-    height: 400,
-    isAdd: true,
-    isCreate: true,
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	var vmsField = Ext.create('Ext.form.field.Text', {
-	    name: 'vms',
-	    hidden: true,
-	    allowBlank: false
-	});
-
-	var vmStore = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property: 'vmid',
-		    order: 'ASC'
-		}
-	    ],
-	    filters: [
-		function(item) {
-		    return ((item.data.type === 'lxc' || item.data.type === 'qemu') && item.data.pool === '');
-		}
-	    ]
-	});
-
-	var vmGrid = Ext.create('widget.grid',{
-	    store: vmStore,
-	    border: true,
-	    height: 300,
-	    scrollable: true,
-	    selModel: {
-		selType: 'checkboxmodel',
-		mode: 'SIMPLE',
-		listeners: {
-		    selectionchange: function(model, selected, opts) {
-			var selectedVms = [];
-			selected.forEach(function(vm) {
-			    selectedVms.push(vm.data.vmid);
-			});
-			vmsField.setValue(selectedVms);
-		    }
-		}
-	    },
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-	Ext.apply(me, {
-	    subject: gettext('Virtual Machine'),
-	    items: [ vmsField, vmGrid ]
-	});
-
-	me.callParent();
-	vmStore.load();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.isCreate = true;
-	me.isAdd = true;
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	Ext.apply(me, {
-	    subject: gettext('Storage'),
-	    width: 350,
-	    items: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'storage',
-		    nodename: 'localhost',
-		    autoSelect: false,
-		    value:  '',
-		    fieldLabel: gettext("Storage")
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    stateful: true,
-    stateId: 'grid-pool-members',
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property : 'type',
-		    direction: 'ASC'
-		}
-	    ],
-	    proxy: {
-		type: 'proxmox',
-		root: 'data.members',
-		url: "/api2/json/pools/" + me.pool
-	    }
-	});
-
-	var coldef = PVE.data.ResourceStore.defaultColumns();
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		var params = { 'delete': 1 };
-		if (rec.data.type === 'storage') {
-		    params.storage = rec.data.storage;
-		} else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-		    params.vms = rec.data.vmid;
-		} else {
-		    throw "unknown resource type";
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/pools/' + me.pool,
-		    method: 'PUT',
-		    params: params,
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Virtual Machine'),
-				iconCls: 'pve-itype-icon-qemu',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Storage'),
-				iconCls: 'pve-itype-icon-storage',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-            columns: coldef,
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-    allowBlank: true,
-    autoSelect: false,
-    valueField: 'macro',
-    displayField: 'macro',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Description'),
-		renderer: Ext.String.htmlEncode,
-		flex: 1,
-		dataIndex: 'descr'
-	    }
-	]
-    },
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'macro', 'descr' ],
-	    idProperty: 'macro',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/macros"
-	    },
-	    sorters: {
-		property: 'macro',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	// hack: editable ComboGrid returns nothing when empty, so we need to set ''
-	// Also, disabled text fields return nothing, so we need to set ''
-
-	Ext.Array.each(['source', 'dest', 'macro', 'proto', 'sport', 'dport', 'log'], function(key) {
-	    if (values[key] === undefined) {
-		values[key] = '';
-	    }
-	});
-
-	delete values.modified_marker;
- 
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.column1 = [
-	    {
-		// hack: we use this field to mark the form 'dirty' when the
-		// record has errors- so that the user can safe the unmodified 
-		// form again.
-		xtype: 'hiddenfield',
-		name: 'modified_marker',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'type',
-		value: 'in',
-		comboItems: [['in', 'in'], ['out', 'out']],
-		fieldLabel: gettext('Direction'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'action',
-		value: 'ACCEPT',
-		comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-		fieldLabel: gettext('Action'),
-		allowBlank: false
-	    }
-        ];
-
-	if (me.allow_iface) {
-	    me.column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		fieldLabel: '',
-		value: ''
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'source',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Source')
-
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'dest',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Destination')
-	    }
-	);
-
-	
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    },
-	    {
-		xtype: 'pveFWMacroSelector',
-		name: 'macro',
-		fieldLabel: gettext('Macro'),
-		editable: true,
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-                        if (value === null) {
-			    me.down('field[name=proto]').setDisabled(false);
-			    me.down('field[name=sport]').setDisabled(false);
-			    me.down('field[name=dport]').setDisabled(false);
-                        } else {
-			    me.down('field[name=proto]').setDisabled(true);
-			    me.down('field[name=proto]').setValue('');
-			    me.down('field[name=sport]').setDisabled(true);
-			    me.down('field[name=sport]').setValue('');
-			    me.down('field[name=dport]').setDisabled(true);
-			    me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-	    },
-	    {
-		xtype: 'pveIPProtocolSelector',
-		name: 'proto',
-		autoSelect: false,
-		editable: true,
-		value: '',
-		fieldLabel: gettext('Protocol')
-	    },
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'sport',
-		value: '',
-		fieldLabel: gettext('Source port')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'dport',
-		value: '',
-		fieldLabel: gettext('Dest. port')
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'pveFirewallLogLevels'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.FirewallRulePanel', {
-	    isCreate: me.isCreate,
-	    list_refs_url: me.list_refs_url,
-	    allow_iface: me.allow_iface,
-	    rule_pos: me.rule_pos
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		    if (values.errors) {
-			var field = me.query('[isFormField][name=modified_marker]')[0];
-			field.setValue(1);
-			Ext.Function.defer(function() {
-			    var form = ipanel.up('form').getForm();
-			    form.markInvalid(values.errors);
-			}, 100);
-		    }
-		}
-	    });
-	} else if (me.rec) {
-	    ipanel.setValues(me.rec.data);
-	}
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: 'group'
-	    },
-	    {
-		xtype: 'pveSecurityGroupsSelector',
-		name: 'action',
-		value: '',
-		fieldLabel: gettext('Security Group'),
-		allowBlank: false
-	    }
-	];
-
-	if (me.allow_iface) {
-	    column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'enable',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: gettext('Enable')
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    onlineHelp: 'chapter_pve_firewall',
-
-    stateful: true,
-    stateId: 'grid-firewall-rules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(true);
-	    }
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(false);
-	    }
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + "/" + from,
-	    method: 'PUT',
-	    params: { moveto: to },
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	rule.enable = rule.enable ? 1 : 0;
-
-	var pos = rule.pos;
-	delete rule.pos;
-	delete rule.errors;
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + '/' + pos.toString(),
-	    method: 'PUT',
-	    params: rule,
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-fw-rule'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-	    var editor;
-	    if (type === 'in' || type === 'out') {
-		editor = 'PVE.FirewallRuleEdit';
-	    } else if (type === 'group') {
-		editor = 'PVE.FirewallGroupRuleEdit';
-	    } else {
-		return;
-	    }
-
-	    var win = Ext.create(editor, {
-		digest: rec.data.digest,
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rule_pos: rec.data.pos
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallRuleEdit', {
-		    allow_iface: me.allow_iface,
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var run_copy_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-
-	    if (!(type === 'in' || type === 'out')) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallRuleEdit', {
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rec: rec
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.copyBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Copy'),
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return (rec.data.type === 'in' || rec.data.type === 'out');
-	    },
-	    disabled: true,
-	    handler: run_copy_editor
-	});
-
-	if (me.allow_groups) {
-	    me.groupBtn =  Ext.create('Ext.Button', {
-		text: gettext('Insert') + ': ' + 
-		    gettext('Security Group'),
-		disabled: true,
-		handler: function() {
-		    var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-			allow_iface: me.allow_iface,
-			base_url: me.base_url
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    confirmMsg: false,
-	    getRecordName: function(rec) {
-		var rule = rec.data;
-		return rule.pos.toString() +
-		    '?digest=' + encodeURIComponent(rule.digest);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-
-	var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-	tbar.push(me.addBtn, me.copyBtn);
-	if (me.groupBtn) {
-	    tbar.push(me.groupBtn);
-	}
-	tbar.push(me.removeBtn, me.editBtn);
-
-	var render_errors = function(name, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors && errors[name]) {
-		metaData.tdCls = 'proxmox-invalid-row';
-		var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-		metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-		    html.replace(/\"/g,'&quot;') + '"';
-	    }
-	    return value;
-	};
-
-	var columns = [
-	    {
-		// similar to xtype: 'rownumberer',
-		dataIndex: 'pos',
-		resizable: false,
-		width: 23,
-		sortable: false,
-		align: 'right',
-		hideable: false,
-		menuDisabled: true,
-		renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-		    metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-		    if (value >= 0) {
-			return value;
-		    }
-		    return '';
-		}
-	    },
-	    {
-		xtype: 'checkcolumn',
-		header: gettext('Enable'),
-		dataIndex: 'enable',
-		listeners: {
-		    checkchange: function(column, recordIndex, checked) {
-			var record = me.getStore().getData().items[recordIndex];
-			record.commit();
-			var data = {};
-			Ext.Array.forEach(record.getFields(), function(field) {
-			    data[field.name] = record.get(field.name);
-			});
-			if (!me.allow_iface || !data.iface) {
-			    delete data.iface;
-			}
-			me.updateRule(data);
-		    }
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		renderer: function(value, metaData, record) {
-		    return render_errors('type', value, metaData, record);
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Action'),
-		dataIndex: 'action',
-		renderer: function(value, metaData, record) {
-		    return render_errors('action', value, metaData, record);
-		},
-		width: 80
-	    },
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		renderer: function(value, metaData, record) {
-		    return render_errors('macro', value, metaData, record);
-		},
-		width: 80
-	    }
-	];
-
-	if (me.allow_iface) {
-	    columns.push({
-		header: gettext('Interface'),
-		dataIndex: 'iface',
-		renderer: function(value, metaData, record) {
-		    return render_errors('iface', value, metaData, record);
-		},
-		width: 80
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Source'),
-		dataIndex: 'source',
-		renderer: function(value, metaData, record) {
-		    return render_errors('source', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Destination'),
-		dataIndex: 'dest',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dest', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'proto',
-		renderer: function(value, metaData, record) {
-		    return render_errors('proto', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Dest. port'),
-		dataIndex: 'dport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Source port'),
-		dataIndex: 'sport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('sport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Log level'),
-		dataIndex: 'log',
-		renderer: function(value, metaData, record) {
-		    return render_errors('log', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comment',
-		flex: 1,
-		renderer: function(value, metaData, record) {
-		    return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-		}
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-            viewConfig: {
-		plugins: [
-		    {
-			ptype: 'gridviewdragdrop',
-			dragGroup: 'FWRuleDDGroup',
-			dropGroup: 'FWRuleDDGroup'
-		    }
-		],
-		listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-			if (!dropRec) {
-			    return false; // empty view
-			}
-			var moveto = dropRec.get('pos');
-			if (dropPosition === 'after') {
-			    moveto++;
-			}
-			var pos = data.records[0].get('pos');
-			me.moveRule(pos, moveto);
-			return 0;
-                    },
-		    itemdblclick: run_editor
-		}
-	    },
-	    sortableColumns: false,
-	    columns: columns
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'enable', type: 'boolean' },
-		  'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-		  'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-	idProperty: 'pos'
-    });
-
-});
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    
-    alias_name: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.alias_name === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-            me.method = 'PUT';
-        }
-
-	var items =  [
-	    {
-		xtype: 'textfield',
-		name: me.isCreate ? 'name' : 'rename',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'cidr',
-		fieldLabel: gettext('IP/CIDR'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    items: items
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Alias'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    values.rename = values.name;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('pve-fw-aliases', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'name', 'cidr', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    onlineHelp: 'pve_firewall_ip_aliases',
-
-    stateful: true,
-    stateId: 'grid-firewall-aliases',
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-aliases',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallAliasEdit', {
-		base_url: me.base_url,
-		alias_name: rec.data.name
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallAliasEdit', {
-		    base_url: me.base_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Name'), dataIndex: 'name', width: 100 },
-		{ header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-	me.on('activate', reload);
-    }
-});
-Ext.define('PVE.FirewallOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-	    if (me.fwtype === 'node') {
-		me.cwidth1 = 250;
-	    }
-	} else {
-	    throw "unknown firewall option type";
-	}
-
-	me.rows = {};
-
-	var add_boolean_row = function(name, text, defaultValue) {
-	    me.add_boolean_row(name, text, { defaultValue: defaultValue });
-	};
-	var add_integer_row = function(name, text, minValue, labelWidth) {
-	    me.add_integer_row(name, text, {
-		minValue: minValue,
-		deleteEmpty: true,
-		labelWidth: labelWidth,
-		renderer: function(value) {
-		    if (value === undefined) {
-			return Proxmox.Utils.defaultText;
-		    }
-
-		    return value;
-		}
-	    });
-	};
-
-	var add_log_row = function(name, labelWidth) {
-	    me.rows[name] = {
-		header: name,
-		required: true,
-		defaultValue: 'nolog',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: name,
-		    fieldDefaults: { labelWidth: labelWidth || 100 },
-		    items: {
-			xtype: 'pveFirewallLogLevels',
-			name: name,
-			fieldLabel: name
-		    }
-		}
-	    };
-	};
-
-	if (me.fwtype === 'node') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 1,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 1
-		}
-	    };
-	    add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-	    add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 32768, 120);
-	    add_integer_row('nf_conntrack_tcp_timeout_established',
-			    'nf_conntrack_tcp_timeout_established', 7875, 250);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	    add_log_row('tcp_flags_log_level', 120);
-	    add_log_row('smurf_log_level');
-	} else if (me.fwtype === 'vm') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 0,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 0
-		}
-	    };
-	    add_boolean_row('dhcp', 'DHCP', 1);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_boolean_row('radv', gettext('Router Advertisement'), 0);
-	    add_boolean_row('macfilter', gettext('MAC filter'), 1);
-	    add_boolean_row('ipfilter', gettext('IP filter'), 0);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	} else if (me.fwtype === 'dc') {
-	    add_boolean_row('enable', gettext('Firewall'), 0);
-	    add_boolean_row('ebtables', 'ebtables', 1);
-	    me.rows.log_ratelimit = {
-		header: gettext('Log rate limit'),
-		required: true,
-		defaultValue: gettext('Default') + ' (enable=1,rate1/second,burst=5)',
-		editor: {
-		    xtype: 'pveFirewallLograteEdit',
-		    defaultValue: 'enable=1'
-		}
-	    };
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-	    me.rows.policy_in = {
-		header: gettext('Input Policy'),
-		required: true,
-		defaultValue: 'DROP',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Input Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_in',
-			value: 'DROP',
-			fieldLabel: gettext('Input Policy')
-		    }
-		}
-	    };
-
-	    me.rows.policy_out = {
-		header: gettext('Output Policy'),
-		required: true,
-		defaultValue: 'ACCEPT',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Output Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_out',
-			value: 'ACCEPT',
-			fieldLabel: gettext('Output Policy')
-		    }
-		}
-	    };
-	}
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = me.rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json" + me.base_url,
-	    tbar: [ edit_btn ],
-	    editorConfig: {
-		url: '/api2/extjs/' + me.base_url
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-
-
-Ext.define('PVE.FirewallLogLevels', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallLogLevels'],
-
-    name: 'log',
-    fieldLabel: gettext('Log level'),
-    value: 'nolog',
-    comboItems: [['nolog', 'nolog'], ['emerg', 'emerg'], ['alert', 'alert'],
-	['crit', 'crit'], ['err', 'err'], ['warning', 'warning'],
-	['notice', 'notice'], ['info', 'info'], ['debug', 'debug']]
-});
-/*
- * Left Treepanel, containing all the resources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-	typeDefaults: {
-	    node: { 
-		iconCls: 'fa fa-building',
-		text: gettext('Nodes')
-	    },
-	    pool: { 
-		iconCls: 'fa fa-tags',
-		text: gettext('Resource Pool')
-	    },
-	    storage: {
-		iconCls: 'fa fa-database',
-		text: gettext('Storage')
-	    },
-	    qemu: {
-		iconCls: 'fa fa-desktop',
-		text: gettext('Virtual Machine')
-	    },
-	    lxc: {
-		//iconCls: 'x-tree-node-lxc',
-		iconCls: 'fa fa-cube',
-		text: gettext('LXC Container')
-	    },
-	    template: {
-		iconCls: 'fa fa-file-o'
-	    }
-	}
-    },
-
-    useArrows: true,
-
-    // private
-    nodeSortFn: function(node1, node2) {
-	var n1 = node1.data;
-	var n2 = node2.data;
-
-	if ((n1.groupbyid && n2.groupbyid) ||
-	    !(n1.groupbyid || n2.groupbyid)) {
-
-	    var tcmp;
-
-	    var v1 = n1.type;
-	    var v2 = n2.type;
-
-	    if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		return tcmp;
-	    }
-
-	    // numeric compare for VM IDs
-	    // sort templates after regular VMs
-	    if (v1 === 'qemu' || v1 === 'lxc') {
-		if (n1.template && !n2.template) {
-		    return 1;
-		} else if (n2.template && !n1.template) {
-		    return -1;
-		}
-		v1 = n1.vmid;
-		v2 = n2.vmid;
-		if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		    return tcmp;
-		}
-	    }
-
-	    return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
-	} else if (n1.groupbyid) {
-	    return -1;
-	} else if (n2.groupbyid) {
-	    return 1;
-	}
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-	var me = this;
-
-	var diff = end - start;
-
-	var mid = start + (diff>>1);
-
-	if (diff <= 0) {
-	    return start;
-	}
-
-	var res = me.nodeSortFn(child, node.childNodes[mid]);
-	if (res <= 0) {
-	    return me.findInsertIndex(node, child, start, mid);
-	} else {
-	    return me.findInsertIndex(node, child, mid + 1, end);
-	}
-    },
-
-    setIconCls: function(info) {
-	var me = this;
-
-	var cls = PVE.Utils.get_object_icon_class(info.type, info);
-
-	if (cls !== '') {
-	    info.iconCls = cls;
-	}
-    },
-
-    // add additional elements to text
-    // at the moment only the usage indicator for storages
-    setText: function(info) {
-	var me = this;
-
-	var status = '';
-	if (info.type === 'storage') {
-	    var maxdisk = info.maxdisk;
-	    var disk = info.disk;
-	    var usage = disk/maxdisk;
-	    var cls = '';
-	    if (usage <= 1.0 && usage >= 0.0) {
-		var height = (usage*100).toFixed(0);
-		var neg_height = (100-usage*100).toFixed(0);
-		status = '<div class="usage-wrapper">';
-		status += '<div class="usage-negative" style="height: ';
-		status += neg_height + '%"></div>';
-		status += '<div class="usage" style="height: '+ height +'%"></div>';
-		status += '</div> ';
-	    }
-	}
-
-	info.text = status + info.text;
-    },
-
-    setToolTip: function(info) {
-	if (info.type === 'pool' || info.groupbyid !== undefined) {
-	    return;
-	}
-
-	var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
-	if (info.lock) {
-	    qtips.push('Config locked (' + info.lock + ')');
-	}
-	if (info.hastate != 'unmanaged') {
-	    qtips.push(gettext('HA State') + ": " + info.hastate);
-	}
-
-	info.qtip = qtips.join(', ');
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-	var me = this;
-
-	me.setIconCls(info);
-	me.setText(info);
-	me.setToolTip(info);
-
-	var defaults;
-	if (info.groupbyid) {
-	    info.text = info.groupbyid;
-	    if (info.type === 'type') {
-		defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-		if (defaults && defaults.text) {
-		    info.text = defaults.text;
-		}
-	    }
-	}
-	var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-	var pos;
-	if (cs) {
-	    pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-	}
-
-	node.insertBefore(child, pos);
-
-	return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-	var me = this;
-
-	var groupby = groups[level];
-	var v = info[groupby];
-
-	if (v) {
-            var group = node.findChild('groupbyid', v);
-	    if (!group) {
-		var groupinfo;
-		if (info.type === groupby) {
-		    groupinfo = info;
-		} else {
-		    groupinfo = {
-			type: groupby,
-			id : groupby + "/" + v
-		    };
-		    if (groupby !== 'type') {
-			groupinfo[groupby] = v;
-		    }
-		}
-		groupinfo.leaf = false;
-		groupinfo.groupbyid = v; 
-		group = me.addChildSorted(node, groupinfo);
-	    }
-	    if (info.type === groupby) {
-		return group;
-	    }
-	    if (group) {
-		return me.groupChild(group, info, groups, level + 1);
-	    }
-	}
-
-	return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	if (!me.viewFilter) {
-	    me.viewFilter = {};
-	}
-
-	var pdata = {
-	    dataIndex: {},
-	    updateCount: 0
-	};
-
-	var store = Ext.create('Ext.data.TreeStore', {
-	    model: 'PVETree',
-	    root: {
-		expanded: true,
-		id: 'root',
-		text: gettext('Datacenter'),
-		iconCls: 'fa fa-server'
-	    }
-	});
-
-	var stateid = 'rid';
-
-	var updateTree = function() {
-	    var tmp;
-
-	    store.suspendEvents();
-
-	    var rootnode = me.store.getRootNode();
-	    // remember selected node (and all parents)
-	    var sm = me.getSelectionModel();
-
-	    var lastsel = sm.getSelection()[0];
-	    var reselect = false;
-	    var parents = [];
-	    var p = lastsel;
-	    while (p && !!(p = p.parentNode)) {
-		parents.push(p);
-	    }
-
-	    var index = pdata.dataIndex;
-
-	    var groups = me.viewFilter.groups || [];
-	    var filterfn = me.viewFilter.filterfn;
-
-	    // remove vanished or moved items
-	    // update in place changed items
-	    var key;
-	    for (key in index) {
-		if (index.hasOwnProperty(key)) {
-		    var olditem = index[key];
-
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var item = rstore.getById(olditem.data.id);
-		    var item = rstore.data.get(olditem.data.id);
-
-		    var changed = false;
-		    var moved = false;
-		    if (item) {
-			// test if any grouping attributes changed
-			// this will also catch migrated nodes
-			// in server view
-			var i, len;
-			for (i = 0, len = groups.length; i < len; i++) {
-			    var attr = groups[i];
-			    if (item.data[attr] != olditem.data[attr]) {
-				//console.log("changed " + attr);
-				moved = true;
-				break;
-			    }
-			}
-
-			// explicitly check for node, since
-			// in some views, node is not a grouping
-			// attribute
-			if (!moved && item.data.node !== olditem.data.node) {
-			    moved = true;
-			}
-
-			// tree item has been updated
-			var fields = [
-			    'text', 'running', 'template', 'status',
-			    'qmpstatus', 'hastate', 'lock'
-			];
-
-			var field;
-			for (i = 0; i < fields.length; i++) {
-			    field = fields[i];
-			    if (item.data[field] !== olditem.data[field]) {
-				changed = true;
-				break;
-			    }
-			}
-
-			// fixme: also test filterfn()?
-		    }
-
-		    if (changed) {
-			olditem.beginEdit();
-			//console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-			var info = olditem.data;
-			Ext.apply(info, item.data);
-			me.setIconCls(info);
-			me.setText(info);
-			me.setToolTip(info);
-			olditem.commit();
-		    }
-		    if ((!item || moved) && olditem.isLeaf()) {
-			//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-			delete index[key];
-			var parentNode = olditem.parentNode;
-			// when the selected item disappears,
-			// we have to deselect it here, and reselect it
-			// later
-			if (lastsel && olditem.data.id === lastsel.data.id) {
-			    reselect = true;
-			    sm.deselect(olditem);
-			}
-			// since the store events are suspended, we
-			// manually remove the item from the store also
-			store.remove(olditem);
-			parentNode.removeChild(olditem, true);
-		    }
-		}
-	    }
-
-	    // add new items
-            rstore.each(function(item) {
-		var olditem = index[item.data.id];
-		if (olditem) {
-		    return;
-		}
-
-		if (filterfn && !filterfn(item)) {
-		    return;
-		}
-
-		//console.log("ADD UID: " + item.data.id);
-
-		var info = Ext.apply({ leaf: true }, item.data);
-
-		var child = me.groupChild(rootnode, info, groups, 0);
-		if (child) {
-		    index[item.data.id] = child;
-		}
-	    });
-
-	    store.resumeEvents();
-	    store.fireEvent('refresh', store);
-
-	    // select parent node is selection vanished
-	    if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-		lastsel = rootnode;
-		while (!!(p = parents.shift())) {
-		    if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-			lastsel = tmp;
-			break;
-		    }
-		}
-		me.selectById(lastsel.data.id);
-	    } else if (lastsel && reselect) {
-		me.selectById(lastsel.data.id);
-	    }
-
-	    // on first tree load set the selection from the stateful provider
-	    if (!pdata.updateCount) {
-		rootnode.expand();
-		me.applyState(sp.get(stateid));
-	    }
-
-	    pdata.updateCount++;
-	};
-
-	var statechange = function(sp, key, value) {
-	    if (key === stateid) {
-		me.applyState(value);
-	    }
-	};
-
-	sp.on('statechange', statechange);
-
-	Ext.apply(me, {
-	    allowSelection: true,
-	    store: store,
-	    viewConfig: {
-		// note: animate cause problems with applyState
-		animate: false
-	    },
-	    //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		destroy: function() {
-		    rstore.un("load", updateTree);
-		},
-		beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
-		    var sm = me.getSelectionModel();
-		    // disable selection when right clicking
-		    // except the record is already selected
-		    me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
-		},
-		beforeselect: function (tree, record, index, eopts) {
-		    var allow = me.allowSelection;
-		    me.allowSelection = true;
-		    return allow;
-		},
-		itemdblclick: PVE.Utils.openTreeConsole
-	    },
-	    setViewFilter: function(view) {
-		me.viewFilter = view;
-		me.clearTree();
-		updateTree();
-	    },
-	    setDatacenterText: function(clustername) {
-		var rootnode = me.store.getRootNode();
-
-		var rnodeText = gettext('Datacenter');
-		if (clustername !== undefined) {
-		    rnodeText += ' (' + clustername + ')';
-		}
-
-		rootnode.beginEdit();
-		rootnode.data.text = rnodeText;
-		rootnode.commit();
-	    },
-	    clearTree: function() {
-		pdata.updateCount = 0;
-		var rootnode = me.store.getRootNode();
-		rootnode.collapse();
-		rootnode.removeAll();
-		pdata.dataIndex = {};
-		me.getSelectionModel().deselectAll();
-	    },
-	    selectExpand: function(node) {
-		var sm = me.getSelectionModel();
-		if (!sm.isSelected(node)) {
-		    sm.select(node);
-		    var cn = node;
-		    while (!!(cn = cn.parentNode)) {
-			if (!cn.isExpanded()) {
-			    cn.expand();
-			}
-		    }
-		    me.getView().focusRow(node);
-		}
-	    },
-	    selectById: function(nodeid) {
-		var rootnode = me.store.getRootNode();
-		var sm = me.getSelectionModel();
-		var node;
-		if (nodeid === 'root') {
-		    node = rootnode;
-		} else {
-		    node = rootnode.findChild('id', nodeid, true);
-		}
-		if (node) {
-		    me.selectExpand(node);
-		}
-		return node;
-	    },
-	    applyState : function(state) {
-		var sm = me.getSelectionModel();
-		if (state && state.value) {
-		    me.selectById(state.value);
-		} else {
-		    sm.deselectAll();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	var sm = me.getSelectionModel();
-	sm.on('select', function(sm, n) {		    
-	    sp.set(stateid, { value: n.data.id});
-	});
-
-	rstore.on("load", updateTree);
-	rstore.startUpdate();
-	//rstore.stopUpdate();
-    }
-
-});
-Ext.define('pve-fw-ipsets', {
-    extend: 'Ext.data.Model',
-    fields: [ 'name', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsetlist',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-
-        var me = this;
-
-	if (me.ipset_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-ipsets',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('Proxmox.window.Edit', {
-		subject: "IPSet '" + rec.data.name + "'",
-		url: me.base_url,
-		method: 'POST',
-		digest: rec.data.digest,
-		items: [
-		    {
-			xtype: 'hiddenfield',
-			name: 'rename',
-			value: rec.data.name
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'name',
-			value: rec.data.name,
-			fieldLabel: gettext('Name'),
-			allowBlank: false
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'comment',
-			value: rec.data.comment,
-			fieldLabel: gettext('Comment')
-		    }
-		]
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('Proxmox.window.Edit', {
-		    subject: 'IPSet',
-		    url: me.base_url,
-		    method: 'POST',
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'name',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'textfield',
-			    name: 'comment',
-			    value: '',
-			    fieldLabel: gettext('Comment')
-			}
-		    ]
-		});
-		win.show();
-		win.on('destroy', reload);
-
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: 'IPSet', dataIndex: 'name', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = me.base_url + '/' + rec.data.name;
-		    me.ipset_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.ipset_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.cidr === undefined);
-
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-	var column1 = [];
-
-	if (me.isCreate) {
-	    if (!me.list_refs_url) {
-		throw "no alias_base_url specified";
-	    }
-
-	    column1.push({
-		xtype: 'pveIPRefSelector',
-		name: 'cidr',
-		ref_type: 'alias',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	} else {
-	    column1.push({
-		xtype: 'displayfield',
-		name: 'cidr',
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'nomatch',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: 'nomatch'
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('IP/CIDR'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsets',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no1 list_refs_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ipset'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.IPSetCidrEdit', {
-		base_url: me.base_url,
-		cidr: rec.data.cidr
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		if (!me.base_url) {
-		    return;
-		}
-		var win = Ext.create('PVE.IPSetCidrEdit', {
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	var render_errors = function(value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors.cidr || errors.nomatch;
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	Ext.apply(me, {
-	    tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    store: store,
-	    selModel: sm,
-	    listeners: {
-		itemdblclick: run_editor
-	    },
-	    columns: [
-		{
-		    xtype: 'rownumberer'
-		},
-		{
-		    header: gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			value = render_errors(value, metaData, record);
-			if (record.data.nomatch) {
-			    return '<b>! </b>' + value;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    flex: 1,
-		    renderer: function(value) {
-			return Ext.util.Format.htmlEncode(value);
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'nomatch', type: 'boolean' },
-		  'cidr', 'comment', 'errors' ],
-	idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    onlineHelp: 'pve_firewall_ip_sets',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-	    region: 'center',
-	    list_refs_url: me.list_refs_url,
-	    border: false
-	});
-
-	var ipset_list = Ext.createWidget('pveIPSetList', {
-	    region: 'west',
-	    ipset_panel: ipset_panel,
-	    base_url: me.base_url,
-	    width: '50%',
-	    border: false,
-	    split: true
-	});
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-	    listeners: {
-		show: function() {
-		    ipset_list.fireEvent('show', ipset_list);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Base class for all the multitab config panels
- *
- * How to use this:
- *
- * You create a subclass of this, and then define your wanted tabs
- * as items like this:
- *
- * items: [{
- *  title: "myTitle",
- *  xytpe: "somextype",
- *  iconCls: 'fa fa-icon',
- *  groups: ['somegroup'],
- *  expandedOnInit: true,
- *  itemId: 'someId'
- * }]
- *
- * this has to be in the declarative syntax, else we
- * cannot save them for later
- * (so no Ext.create or Ext.apply of an item in the subclass)
- *
- * the groups array expects the itemids of the items
- * which are the parents, which have to come before they
- * are used
- *
- * if you want following the tree:
- *
- * Option1
- * Option2
- *   -> SubOption1
- *	-> SubSubOption1
- *
- * the suboption1 group array has to look like this:
- * groups: ['itemid-of-option2']
- *
- * and of subsuboption1:
- * groups: ['itemid-of-option2', 'itemid-of-suboption1']
- *
- * setting the expandedOnInit determines if the item/group is expanded
- * initially (false by default)
- */
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    showSearch: true, // add a resource grid with a search button as first tab
-    viewFilter: undefined, // a filter to pass to that resource grid
-
-    tbarSpacing: true, // if true, adds a spacer after the title in tbar
-
-    dockedItems: [{
-	// this is needed for the overflow handler
-	xtype: 'toolbar',
-	overflowHandler: 'scroller',
-	dock: 'left',
-	style: {
-	    backgroundColor: '#f5f5f5',
-	    padding: 0,
-	    margin: 0
-	},
-	items: {
-	    xtype: 'treelist',
-	    itemId: 'menu',
-	    ui: 'nav',
-	    expanderOnly: true,
-	    expanderFirst: false,
-	    animation: false,
-	    singleExpand: false,
-	    listeners: {
-		selectionchange: function(treeList, selection) {
-		    var me = this.up('panel');
-		    me.suspendLayout = true;
-		    me.activateCard(selection.data.id);
-		    me.suspendLayout = false;
-		    me.updateLayout();
-		},
-		itemclick: function(treelist, info) {
-		    var olditem = treelist.getSelection();
-		    var newitem = info.node;
-
-		    // when clicking on the expand arrow,
-		    // we don't select items, but still want
-		    // the original behaviour
-		    if (info.select === false) {
-			return;
-		    }
-
-		    // if you click on a different item which is open,
-		    // leave it open
-		    // else toggle the clicked item
-		    if (olditem.data.id !== newitem.data.id &&
-			newitem.data.expanded === true) {
-			info.toggle = false;
-		    } else {
-			info.toggle = true;
-		    }
-		}
-	    }
-	}
-    },
-    {
-	xtype: 'toolbar',
-	itemId: 'toolbar',
-	dock: 'top',
-	height: 36,
-	overflowHandler: 'scroller'
-    }],
-
-    firstItem: '',
-    layout: 'card',
-    border: 0,
-
-    // used for automated test
-    selectById: function(cardid) {
-	var me = this;
-
-	var root = me.store.getRoot();
-	var selection = root.findChild('id', cardid, true);
-
-	if (selection) {
-	    selection.expand();
-	    var menu = me.down('#menu');
-	    menu.setSelection(selection);
-	    return cardid;
-	}
-    },
-
-    activateCard: function(cardid) {
-	var me = this;
-	if (me.savedItems[cardid]) {
-	    var curcard = me.getLayout().getActiveItem();
-	    var newcard = me.add(me.savedItems[cardid]);
-	    me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp);
-	    if (curcard) {
-		me.setActiveItem(cardid);
-		me.remove(curcard, true);
-
-		// trigger state change
-
-		var ncard = cardid;
-		// Note: '' is alias for first tab.
-		// First tab can be 'search' or something else
-		if (cardid === me.firstItem) {
-		    ncard = '';
-		}
-		if (me.hstateid) {
-		   me.sp.set(me.hstateid, { value: ncard });
-		}
-	    }
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = me.hstateid;
-
-	me.sp = Ext.state.Manager.getProvider();
-
-	var activeTab; // leaving this undefined means items[0] will be the default tab
-
-	if (stateid) {
-	    var state = me.sp.get(stateid);
-	    if (state && state.value) {
-		// if this tab does not exists, it chooses the first
-		activeTab = state.value;
-	    }
-	}
-
-	// get title
-	var title = me.title || me.pveSelNode.data.text;
-	me.title = undefined;
-
-	// create toolbar
-	var tbar = me.tbar || [];
-	me.tbar = undefined;
-
-	if (!me.onlineHelp) {
-	    switch(me.pveSelNode.data.id) {
-		case 'type/storage':me.onlineHelp = 'chapter-pvesm.html'; break;
-		case 'type/qemu':me.onlineHelp = 'chapter-qm.html'; break;
-		case 'type/lxc':me.onlineHelp = 'chapter-pct.html'; break;
-		case 'type/pool':me.onlineHelp = 'chapter-pveum.html#_pools'; break;
-		case 'type/node':me.onlineHelp = 'chapter-sysadmin.html'; break;
-	    }
-	}
-
-	if (me.tbarSpacing) {
-	    tbar.unshift('->');
-	}
-	tbar.unshift({
-	    xtype: 'tbtext',
-	    text: title,
-	    baseCls: 'x-panel-header-text'
-	});
-
-	me.helpButton = Ext.create('Proxmox.button.Help', {
-	    hidden: false,
-	    listenToGlobalEvent: false,
-	    onlineHelp: me.onlineHelp || undefined
-	});
-
-	tbar.push(me.helpButton);
-
-	me.dockedItems[1].items = tbar;
-
-	// include search tab
-	me.items = me.items || [];
-	if (me.showSearch) {
-	    me.items.unshift({
-		itemId: 'search',
-		title: gettext('Search'),
-		iconCls: 'fa fa-search',
-		xtype: 'pveResourceGrid',
-		pveSelNode: me.pveSelNode
-	    });
-	}
-
-	me.savedItems = {};
-	/*jslint confusion:true*/
-	if (me.items[0]) {
-	    me.firstItem = me.items[0].itemId;
-	}
-	/*jslint confusion:false*/
-
-	me.store = Ext.create('Ext.data.TreeStore', {
-	    root: {
-		expanded: true
-	    }
-	});
-	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
-
-	delete me.items;
-	me.defaults = me.defaults || {};
-	Ext.apply(me.defaults, {
-	    pveSelNode: me.pveSelNode,
-	    viewFilter: me.viewFilter,
-	    workspace: me.workspace,
-	    border: 0
-	});
-
-	me.callParent();
-
-	var menu = me.down('#menu');
-	var selection = root.findChild('id', activeTab, true) || root.firstChild;
-	var node = selection;
-	while (node !== root) {
-	    node.expand();
-	    node = node.parentNode;
-	}
-	menu.setStore(me.store);
-	menu.setSelection(selection);
-
-	// on a state change,
-	// select the new item
-	var statechange = function(sp, key, state) {
-	    // it the state change is for this panel
-	    if (stateid && (key === stateid) && state) {
-		// get active item
-		var acard = me.getLayout().getActiveItem().itemId;
-		// get the itemid of the new value
-		var ncard = state.value || me.firstItem;
-		if (ncard && (acard != ncard)) {
-		    // select the chosen item
-		    menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
-		}
-	    }
-	};
-
-	if (stateid) {
-	    me.mon(me.sp, 'statechange', statechange);
-	}
-    }
-});
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    stateful: true,
-    stateId: 'grid-guest-backup',
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmtype = me.pveSelNode.data.type;
-	if (!vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var vmtypeFilter;
-	if (vmtype === 'openvz') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-openvz-');
-	    };
-	} else if (vmtype === 'lxc') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-lxc-');
-	    };
-	} else if (vmtype === 'qemu') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-qemu-');
-	    };
-	} else {
-	    throw "unsupported VM type '" + vmtype + "'";
-	}
-
-	var searchFilter = {
-	    property: 'volid',
-	// on initial store display only our vmid backups
-	// surround with minus sign to prevent the 2016 VMID bug
-	    value: vmtype + '-' + vmid + '-',
-	    anyMatch: true,
-	    caseSensitive: false
-	};
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-content',
-	    sorters: { 
-		property: 'volid', 
-		order: 'DESC' 
-	    },
-	    filters: [
-	        vmtypeFilter,
-		searchFilter
-		]
-	});
-
-	var reload = Ext.Function.createBuffered(function() {
-	    if (me.store) {
-		me.store.load();
-	    }
-	}, 100);
-
-	var setStorage = function(storage) {
-	    var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-	    url += '?content=backup';
-
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: url
-	    });
-
-	    reload();
-	};
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    setStorage(value);
-		}
-	    }
-	});
-
-	var storagefilter = Ext.create('Ext.form.field.Text', {
-	    fieldLabel: gettext('Search'),
-	    labelWidth: 50,
-	    labelAlign: 'right',
-	    enableKeyEvents: true,
-	    value: searchFilter.value,
-	    listeners: {
-		buffer: 500,
-		keyup: function(field) {
-		    me.store.clearFilter(true);
-		    searchFilter.value = field.getValue();
-		    me.store.filter([
-			vmtypeFilter,
-			searchFilter
-		    ]);
-		}
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var backup_btn = Ext.create('Ext.button.Button', {
-	    text: gettext('Backup now'),
-	    handler: function() {
-		var win = Ext.create('PVE.window.Backup', { 
-		    nodename: nodename,
-		    vmid: vmid,
-		    vmtype: vmtype,
-		    storage: storagesel.getValue(),
-		    listeners : {
-			close: function() {
-			    reload();
-			}
-		    }
-		});
-		win.show();
-	    }
-	});
-
-	var restore_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Restore'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var volid = rec.data.volid;
-
-		var win = Ext.create('PVE.window.Restore', {
-		    nodename: nodename,
-		    vmid: vmid,
-		    volid: rec.data.volid,
-		    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-		    vmtype: vmtype
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var delete_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.volid + "'");
-		msg += " " + gettext('This will permanently erase all data.');
-
-		return msg;
-	    },
-	    getUrl: function(rec) {
-		var storage = storagesel.getValue();
-		return '/nodes/' + nodename + '/storage/' + storage + '/content/' + rec.data.volid;
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	var config_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show Configuration'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var storage = storagesel.getValue();
-		if (!storage) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.window.BackupConfig', {
-		    volume: rec.data.volid,
-		    pveSelNode: me.pveSelNode
-		});
-
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    tbar: [ backup_btn, restore_btn, delete_btn,config_btn, '->', storagesel, storagefilter ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'volid'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.CephCreateService', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateService',
-
-    showProgress: true,
-
-    setNode: function(nodename) {
-        var me = this;
-
-	me.nodename = nodename;
-        me.url = "/nodes/" + nodename + "/ceph/" + me.type + "/" + nodename;
-    },
-
-    method: 'POST',
-    isCreate: true,
-
-    items: [
-	{
-	    xtype: 'pveNodeSelector',
-	    submitValue: false,
-	    fieldLabel: gettext('Host'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    var me = this.up('pveCephCreateService');
-		    me.setNode(value);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.type) {
-	    throw "no type specified";
-	}
-
-	me.setNode(me.nodename);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephServiceList', {
-    extend: 'Ext.grid.GridPanel',
-    xtype: 'pveNodeCephServiceList',
-
-    onlineHelp: 'chapter_pveceph',
-    emptyText: gettext('No such service configured.'),
-
-    stateful: true,
-
-    // will be called when the store loads
-    storeLoadCallback: Ext.emptyFn,
-
-    // if set to true, does shows the ceph install mask if needed
-    showCephInstallMask: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    if (view.pveSelNode) {
-		view.nodename = view.pveSelNode.data.node;
-	    }
-	    if (!view.nodename) {
-		throw "no node name specified";
-	    }
-
-	    if (!view.type) {
-		throw "no type specified";
-	    }
-
-	    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-		autoLoad: true,
-		autoStart: true,
-		interval: 3000,
-		storeid: 'ceph-' + view.type + '-list' + view.nodename,
-		model: 'ceph-service-list',
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + view.nodename + "/ceph/" + view.type
-		}
-	    });
-
-	    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-		rstore: view.rstore,
-		sorters: [{ property: 'name' }]
-	    }));
-
-	    if (view.storeLoadCallback) {
-		view.rstore.on('load', view.storeLoadCallback, this);
-	    }
-	    view.on('destroy', view.rstore.stopUpdate);
-
-	    if (view.showCephInstallMask) {
-		var regex = new RegExp("not (installed|initialized)", "i");
-		PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error) {
-		    view.rstore.stopUpdate();
-		    PVE.Utils.showCephInstallOrMask(view.ownerCt, error.statusText, view.nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', function(){
-				view.rstore.startUpdate();
-			    });
-			}
-		    );
-		});
-	    }
-	},
-
-	service_cmd: function(rec, cmd) {
-	    var view = this.getView();
-	    if (!rec.data.host) {
-		Ext.Msg.alert(gettext('Error'), "entry has no host");
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		method: 'POST',
-		params: { service: view.type + '.' + rec.data.name },
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: function() {
-			    view.rstore.load();
-			}
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-	onChangeService: function(btn) {
-	    var me = this;
-	    var view = this.getView();
-	    var cmd = btn.action;
-	    var rec = view.getSelection()[0];
-	    me.service_cmd(rec, cmd);
-	},
-
-	showSyslog: function() {
-	    var view = this.getView();
-	    var rec = view.getSelection()[0];
-	    var servicename = 'ceph-' + view.type + '@' + rec.data.name;
-	    var url = "/api2/extjs/nodes/" + rec.data.host + "/syslog?service=" +  encodeURIComponent(servicename);
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + servicename,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: [{
-		    xtype: 'proxmoxLogView',
-		    url: url,
-		    log_select_timespan: 1
-		}]
-	    });
-	    win.show();
-	},
-
-	onCreate: function() {
-	    var view = this.getView();
-	    var win = Ext.create('PVE.CephCreateService', {
-		autoShow: true,
-		nodename: view.nodename,
-		subject: view.getTitle(),
-		type: view.type,
-		taskDone: function() {
-		    view.rstore.load();
-		}
-	    });
-	}
-    },
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Start'),
-	    iconCls: 'fa fa-play',
-	    action: 'start',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state === 'stopped' ||
-		  rec.data.state === 'unknown';
-	    },
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Stop'),
-	    iconCls: 'fa fa-stop',
-	    action: 'stop',
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    disabled: true,
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Restart'),
-	    iconCls: 'fa fa-refresh',
-	    action: 'restart',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    handler: 'onChangeService'
-	},
-	'-',
-	{
-	    text: gettext('Create'),
-	    reference: 'createButton',
-	    handler: 'onCreate'
-	},
-	{
-	    text: gettext('Destroy'),
-	    xtype: 'proxmoxStdRemoveButton',
-	    getUrl: function(rec) {
-		var view = this.up('grid');
-		if (!rec.data.host) {
-		    Ext.Msg.alert(gettext('Error'), "entry has no host");
-		    return;
-		}
-		return "/nodes/" + rec.data.host + "/ceph/" + view.type + "/" + rec.data.name;
-	    },
-	    callback: function(options, success, response) {
-		var view = this.up('grid');
-		if (!success) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    return;
-		}
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', {
-		    upid: upid,
-		    taskDone: function() {
-			view.rstore.load();
-		    }
-		});
-		win.show();
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: 'showSyslog'
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return this.type + '.' + v;
-	    },
-	    dataIndex: 'name'
-	},
-	{
-	    header: gettext('Host'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'host'
-	},
-	{
-	    header: gettext('Status'),
-	    flex: 1,
-	    sortable: false,
-	    dataIndex: 'state'
-	},
-	{
-	    header: gettext('Address'),
-	    flex: 3,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'addr'
-	},
-	{
-	    header: gettext('Version'),
-	    flex: 3,
-	    sortable: true,
-	    dataIndex: 'version'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.additionalColumns) {
-	    me.columns = me.columns.concat(me.additionalColumns);
-	}
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('ceph-service-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'addr', 'name', 'rank', 'host', 'quorum', 'state',
-	    'ceph_version', 'ceph_version_short',
-	    { type: 'string', name: 'version', calculate: function(data) {
-		return PVE.Utils.parse_ceph_version(data);
-	    } }
-	],
-	idProperty: 'name'
-    });
-});
-/*jslint confusion: true */
-Ext.define('PVE.CephCreateFS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateFS',
-
-    showTaskViewer: true,
-    onlineHelp: 'pveceph_fs_create',
-
-    subject: 'Ceph FS',
-    isCreate: true,
-    method: 'POST',
-
-    setFSName: function(fsName) {
-	var me = this;
-
-	if (fsName === '' || fsName === undefined) {
-	    fsName = 'cephfs';
-	}
-
-	me.url = "/nodes/" + me.nodename + "/ceph/fs/" + fsName;
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    value: 'cephfs',
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateFS').setFSName(value);
-		}
-	    },
-	    submitValue: false, // already encoded in apicall URL
-	    emptyText: 'cephfs'
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'Placement Groups',
-	    name: 'pg_num',
-	    value: 128,
-	    emptyText: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add-storage',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new CephFS to the cluster storage configuration.'),
-	    },
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setFSName();
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.NodeCephFSPanel', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNodeCephFSPanel',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    title: gettext('CephFS'),
-    onlineHelp: 'pveceph_fs',
-
-    border: false,
-    defaults: {
-	border: false,
-	cbind: {
-	    nodename: '{nodename}'
-	}
-    },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    cephfsConfigured: false,
-	    mdsCount: 0
-	},
-	formulas: {
-	    canCreateFS: function(get) {
-		return (!get('cephfsConfigured') && get('mdsCount') > 0);
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'CephFS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-fs',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/' + view.nodename + '/ceph/fs'
-			},
-			model: 'pve-ceph-fs'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'name',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateFS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!(success && records && records.length > 0)) {
-			vm.set('cephfsConfigured', false);
-			return;
-		    }
-		    vm.set('cephfsConfigured', true);
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create CephFS'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			// only one CephFS per Ceph cluster makes sense for now
-			disabled: '{!canCreateFS}'
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: 'Data Pool',
-		    flex: 1,
-		    dataIndex: 'data_pool'
-		},
-		{
-		    header: 'Metadata Pool',
-		    flex: 1,
-		    dataIndex: 'metadata_pool'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    title: gettext('Metadata Servers'),
-	    stateId: 'grid-ceph-mds',
-	    type: 'mds',
-	    storeLoadCallback: function(store, records, success) {
-		var vm = this.getViewModel();
-		if (!success || !records) {
-		    vm.set('mdsCount', 0);
-		    return;
-		}
-		vm.set('mdsCount', records.length);
-	    },
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-}, function() {
-    Ext.define('pve-ceph-fs', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'data_pool', 'metadata_pool' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/fs"
-	},
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.CephCreatePool', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreatePool',
-
-    showProgress: true,
-    onlineHelp: 'pve_ceph_pools',
-
-    subject: 'Ceph Pool',
-    isCreate: true,
-    method: 'POST',
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Size'),
-	    name: 'size',
-	    value: 3,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Min. Size'),
-	    name: 'min_size',
-	    value: 2,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'pveCephRuleSelector',
-	    fieldLabel: 'Crush Rule', // do not localize
-	    name: 'crush_rule',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'pg_num',
-	    name: 'pg_num',
-	    value: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add_storages',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new pool to the cluster storage configuration.'),
-	    },
-	}
-    ],
-    initComponent : function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.apply(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/pools",
-	    defaults: {
-		nodename: me.nodename
-	    }
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephPoolList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeCephPoolList',
-
-    onlineHelp: 'chapter_pveceph',
-
-    stateful: true,
-    stateId: 'grid-ceph-pools',
-    bufferedRenderer: false,
-
-    features: [ { ftype: 'summary'} ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    width: 120,
-	    sortable: true,
-	    dataIndex: 'pool_name'
-	},
-	{
-	    header: gettext('Size') + '/min',
-	    width: 100,
-	    align: 'right',
-	    renderer: function(v, meta, rec) {
-		return v + '/' + rec.data.min_size;
-	    },
-	    dataIndex: 'size'
-	},
-	{
-	    text: '# Placement Groups', // pg_num',
-	    width: 180,
-	    align: 'right',
-	    dataIndex: 'pg_num'
-	},
-	{
-	    text: 'CRUSH Rule',
-	    columns: [
-		{
-		    text: 'ID',
-		    align: 'right',
-		    width: 50,
-		    dataIndex: 'crush_rule'
-		},
-		{
-		    text: gettext('Name'),
-		    width: 150,
-		    dataIndex: 'crush_rule_name',
-		},
-	    ]
-	},
-	{
-	    text: gettext('Used'),
-	    columns: [
-		{
-		    text: '%',
-		    width: 100,
-		    sortable: true,
-		    align: 'right',
-		    renderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		    dataIndex: 'percent_used',
-		    summaryType: 'sum',
-		    summaryRenderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		},
-		{
-		    text: gettext('Total'),
-		    width: 100,
-		    sortable: true,
-		    renderer: PVE.Utils.render_size,
-		    align: 'right',
-		    dataIndex: 'bytes_used',
-		    summaryType: 'sum',
-		    summaryRenderer: PVE.Utils.render_size
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-pool-list' + nodename,
-	    model: 'ceph-pool-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/pools"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		var win = Ext.create('PVE.CephCreatePool', {
-                    nodename: nodename
-		});
-		win.show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	var destroy_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Destroy'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.pool_name) {
-		    return;
-		}
-		var base_url = '/nodes/' + nodename + '/ceph/pools/' +
-		    rec.data.pool_name;
-
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    showProgress: true,
-		    url: base_url,
-		    params: {
-			remove_storages: 1
-		    },
-		    item: { type: 'CephPool', id: rec.data.pool_name }
-		}).show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ create_btn, destroy_btn ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-pool-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'pool_name',
-		  { name: 'pool', type: 'integer'},
-		  { name: 'size', type: 'integer'},
-		  { name: 'min_size', type: 'integer'},
-		  { name: 'pg_num', type: 'integer'},
-		  { name: 'bytes_used', type: 'integer'},
-		  { name: 'percent_used', type: 'number'},
-		  { name: 'crush_rule', type: 'integer'},
-		  { name: 'crush_rule_name', type: 'string'}
-		],
-	idProperty: 'pool_name'
-    });
-});
-
-Ext.define('PVE.form.CephRuleSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephRuleSelector',
-
-    allowBlank: false,
-    valueField: 'name',
-    displayField: 'name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/rules'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.CephCreateOsd', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateOsd',
-
-    subject: 'Ceph OSD',
-
-    showProgress: true,
-
-    onlineHelp: 'pve_ceph_osds',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			Object.keys(values || {}).forEach(function(name) {
-			    if (values[name] === '') {
-				delete values[name];
-			    }
-			});
-
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'dev',
-			    nodename: me.nodename,
-			    diskType: 'unused',
-			    fieldLabel: gettext('Disk'),
-			    allowBlank: false
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'db_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('DB Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=db_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'db_size',
-			    fieldLabel: gettext('DB size') + ' (GiB)',
-			    minValue: 1,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ],
-		    advancedColumn1: [
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'encrypted',
-			    fieldLabel: gettext('Encrypt OSD')
-			},
-		    ],
-		    advancedColumn2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'wal_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('WAL Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD/DB disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=wal_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'wal_size',
-			    fieldLabel: gettext('WAL size') + ' (GiB)',
-			    minValue: 0.5,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pve-hint',
-		    value: 'Note: Ceph is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_pveceph') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.CephRemoveOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephRemoveOsd'],
-
-    isRemove: true,
-
-    showProgress: true,
-    method: 'DELETE',
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cleanup',
-	    checked: true,
-	    labelWidth: 130,
-	    fieldLabel: gettext('Cleanup Disks')
-	}
-    ],
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (me.osdid === undefined || me.osdid < 0) {
-	    throw "no osdid specified";
-	}
-
-	me.isCreate = true;
-
-	me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephOsdTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveNodeCephOsdTree'],
-    onlineHelp: 'chapter_pveceph',
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    flags: [],
-	    maxversion: '0',
-	    versions: {},
-	    isOsd: false,
-	    downOsd: false,
-	    upOsd: false,
-	    inOsd: false,
-	    outOsd: false,
-	    osdid: '',
-	    osdhost: '',
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	reload: function() {
-	    var me = this.getView();
-	    var vm = this.getViewModel();
-	    var nodename = vm.get('nodename');
-	    var sm = me.getSelectionModel();
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + nodename + "/ceph/osd",
-		waitMsgTarget: me,
-		method: 'GET',
-		failure: function(response, opts) {
-		    var msg = response.htmlStatus;
-		    PVE.Utils.showCephInstallOrMask(me, msg, nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', this.reload);
-			}
-		    );
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-		    var selected = me.getSelection();
-		    var name;
-		    if (selected.length) {
-			name = selected[0].data.name;
-		    }
-		    vm.set('versions', data.versions);
-		    // extract max version
-		    var maxversion = vm.get('maxversion');
-		    Object.values(data.versions || {}).forEach(function(version) {
-			if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-			    maxversion = version;
-			}
-		    });
-		    vm.set('maxversion', maxversion);
-		    sm.deselectAll();
-		    me.setRootNode(data.root);
-		    me.expandAll();
-		    if (name) {
-			var node = me.getRootNode().findChild('name', name, true);
-			if (node) {
-			    me.setSelection([node]);
-			}
-		    }
-
-		    var flags = data.flags.split(',');
-		    vm.set('flags', flags);
-		    var noout = flags.includes('noout');
-		    me.down('#nooutBtn').setText(noout ? gettext("Unset noout") : gettext("Set noout"));
-		}
-	    });
-	},
-
-	osd_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd;
-	    var params = comp.params || {};
-	    var osdid = vm.get('osdid');
-
-	    var doRequest = function() {
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + vm.get('osdhost') + "/ceph/osd/" + osdid + '/' + cmd,
-		    waitMsgTarget: me.getView(),
-		    method: 'POST',
-		    params: params,
-		    success: () => { me.reload(); },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    };
-
-	    if (cmd === 'scrub') {
-		Ext.MessageBox.defaultButton = params.deep === 1 ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: params.deep === 1 ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: params.deep !== 1 ?
-		       Ext.String.format(gettext("Scrub OSD.{0}"), osdid) :
-		       Ext.String.format(gettext("Deep Scrub OSD.{0}"), osdid) +
-			   "<br>Caution: This can reduce performance while it is running.",
-		    buttons: Ext.Msg.YESNO,
-		    callback: function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRequest();
-		    }
-		});
-	    } else {
-		doRequest();
-	    }
-	},
-
-	create_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephCreateOsd', {
-		nodename: vm.get('nodename'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	destroy_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephRemoveOsd', {
-		nodename: vm.get('osdhost'),
-		osdid: vm.get('osdid'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	set_flag: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var flags = vm.get('flags');
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + vm.get('nodename') + "/ceph/flags/noout",
-		waitMsgTarget: me.getView(),
-		method: flags.includes('noout') ? 'DELETE' : 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: () => { me.reload(); }
-	    });
-	},
-
-	service_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd || comp;
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + vm.get('osdhost') + "/ceph/" + cmd,
-		params: { service: "osd." + vm.get('osdid') },
-		waitMsgTarget: me.getView(),
-		method: 'POST',
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: () => { me.reload(); }
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	set_selection_status: function(tp, selection) {
-	    if (selection.length < 1) {
-		return;
-	    }
-	    var rec = selection[0];
-	    var vm = this.getViewModel();
-
-	    var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
-
-	    vm.set('isOsd', isOsd);
-	    vm.set('downOsd', isOsd && rec.data.status === 'down');
-	    vm.set('upOsd', isOsd && rec.data.status !== 'down');
-	    vm.set('inOsd', isOsd && rec.data.in);
-	    vm.set('outOsd', isOsd && !rec.data.in);
-	    vm.set('osdid', isOsd ? rec.data.id : undefined);
-	    vm.set('osdhost', isOsd ? rec.data.host : undefined);
-	},
-
-	render_status: function(value, metaData, rec) {
-	    if (!value) {
-		return value;
-	    }
-	    var inout = rec.data['in'] ? 'in' : 'out';
-	    var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
-		'critical fa-arrow-circle-down';
-
-	    var inouticon = rec.data['in'] ? 'good fa-circle' :
-		'warning fa-circle-o';
-
-	    var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
-		inout + ' <i class="fa ' + inouticon + '"></i>';
-
-	    return text;
-	},
-
-	render_wal: function(value, metaData, rec) {
-	    if (!value &&
-		rec.data.osdtype === 'bluestore' &&
-		rec.data.type === 'osd') {
-		return 'N/A';
-	    }
-	    return value;
-	},
-
-	render_version: function(value, metadata, rec) {
-	    var vm = this.getViewModel();
-	    var versions = vm.get('versions');
-	    var icon = "";
-	    var version = value || "";
-	    if (value && value != vm.get('maxversion')) {
-		icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
-	    }
-
-	    if (!value && rec.data.type == 'host') {
-		version = versions[rec.data.name] || Proxmox.Utils.unknownText;
-	    }
-
-	    return icon + version;
-	},
-
-	render_osd_val: function(value, metaData, rec) {
-	    return (rec.data.type === 'osd') ? value : '';
-	},
-	render_osd_weight: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    return Ext.util.Format.number(value, '0.00###');
-	},
-
-	render_osd_latency: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    let commit_ms = rec.data.commit_latency_ms,
-	        apply_ms = rec.data.apply_latency_ms;
-	    return apply_ms + ' / ' + commit_ms;
-	},
-
-	render_osd_size: function(value, metaData, rec) {
-	    return this.render_osd_val(PVE.Utils.render_size(value), metaData, rec);
-	},
-
-	control: {
-	    '#': {
-		selectionchange: 'set_selection_status'
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-
-	    if (!view.pveSelNode.data.node) {
-		throw "no node name specified";
-	    }
-
-	    vm.set('nodename', view.pveSelNode.data.node);
-
-	    me.callParent();
-	    me.reload();
-	}
-    },
-
-    stateful: true,
-    stateId: 'grid-ceph-osd',
-    rootVisible: false,
-    useArrows: true,
-
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: 'Name',
-	    dataIndex: 'name',
-	    width: 150
-	},
-	{
-	    text: 'Type',
-	    dataIndex: 'type',
-	    hidden: true,
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: gettext("Class"),
-	    dataIndex: 'device_class',
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: "OSD Type",
-	    dataIndex: 'osdtype',
-	    align: 'right',
-	    width: 100
-	},
-	{
-	    text: "Bluestore Device",
-	    dataIndex: 'blfsdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "DB Device",
-	    dataIndex: 'dbdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "WAL Device",
-	    dataIndex: 'waldev',
-	    align: 'right',
-	    renderer: 'render_wal',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: 'Status',
-	    dataIndex: 'status',
-	    align: 'right',
-	    renderer: 'render_status',
-	    width: 120
-	},
-	{
-	    text: gettext('Version'),
-	    dataIndex: 'version',
-	    align: 'right',
-	    renderer: 'render_version'
-	},
-	{
-	    text: 'weight',
-	    dataIndex: 'crush_weight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: 'reweight',
-	    dataIndex: 'reweight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: gettext('Used') + ' (%)',
-	    dataIndex: 'percent_used',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return Ext.util.Format.number(value, '0.00');
-	    },
-	    width: 100
-	},
-	{
-	    text: gettext('Total'),
-	    dataIndex: 'total_space',
-	    align: 'right',
-	    renderer: 'render_osd_size',
-	    width: 100
-	},
-	{
-	    text: 'Apply/Commit<br>Latency (ms)',
-	    dataIndex: 'apply_latency_ms',
-	    align: 'right',
-	    renderer: 'render_osd_latency',
-	    width: 120
-	}
-    ],
-
-
-    tbar: {
-	items: [
-	    {
-		text: gettext('Reload'),
-		iconCls: 'fa fa-refresh',
-		handler: 'reload'
-	    },
-	    '-',
-	    {
-		text: gettext('Create') + ': OSD',
-		handler: 'create_osd',
-	    },
-	    {
-		text: gettext('Set noout'),
-		itemId: 'nooutBtn',
-		handler: 'set_flag',
-	    },
-	    '->',
-	    {
-		xtype: 'tbtext',
-		data: {
-		    osd: undefined
-		},
-		bind: {
-		    data: {
-			osd: "{osdid}"
-		    }
-		},
-		tpl: [
-		    '<tpl if="osd">',
-		    'osd.{osd}:',
-		    '<tpl else>',
-		    gettext('No OSD selected'),
-		    '</tpl>'
-		]
-	    },
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-play',
-		disabled: true,
-		bind: {
-		    disabled: '{!downOsd}'
-		},
-		cmd: 'start',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-stop',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'stop',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Restart'),
-		iconCls: 'fa fa-refresh',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'restart',
-		handler: 'service_cmd'
-	    },
-	    '-',
-	    {
-		text: 'Out',
-		iconCls: 'fa fa-circle-o',
-		disabled: true,
-		bind: {
-		    disabled: '{!inOsd}'
-		},
-		cmd: 'out',
-		handler: 'osd_cmd'
-	    },
-	    {
-		text: 'In',
-		iconCls: 'fa fa-circle',
-		disabled: true,
-		bind: {
-		    disabled: '{!outOsd}'
-		},
-		cmd: 'in',
-		handler: 'osd_cmd'
-	    },
-	    '-',
-	    {
-		text: gettext('More'),
-		iconCls: 'fa fa-bars',
-		disabled: true,
-		bind: {
-		    disabled: '{!isOsd}'
-		},
-		menu: [
-		    {
-			text: gettext('Scrub'),
-			iconCls: 'fa fa-shower',
-			cmd: 'scrub',
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Deep Scrub'),
-			iconCls: 'fa fa-bath',
-			cmd: 'scrub',
-			params: {
-			    deep: 1,
-			},
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Destroy'),
-			itemId: 'remove',
-			iconCls: 'fa fa-fw fa-trash-o',
-			bind: {
-			    disabled: '{!downOsd}'
-			},
-			handler: 'destroy_osd'
-		    }
-		],
-	    }
-	]
-    },
-
-    fields: [
-	'name', 'type', 'status', 'host', 'in', 'id' ,
-	{ type: 'number', name: 'reweight' },
-	{ type: 'number', name: 'percent_used' },
-	{ type: 'integer', name: 'bytes_used' },
-	{ type: 'integer', name: 'total_space' },
-	{ type: 'integer', name: 'apply_latency_ms' },
-	{ type: 'integer', name: 'commit_latency_ms' },
-	{ type: 'string', name: 'device_class' },
-	{ type: 'string', name: 'osdtype' },
-	{ type: 'string', name: 'blfsdev' },
-	{ type: 'string', name: 'dbdev' },
-	{ type: 'string', name: 'waldev' },
-	{ type: 'string', name: 'version', calculate: function(data) {
-	    return PVE.Utils.parse_ceph_version(data);
-	} },
-	{ type: 'string', name: 'iconCls', calculate: function(data) {
-	    var iconMap = {
-		host: 'fa-building',
-		osd: 'fa-hdd-o',
-		root: 'fa-server',
-	    };
-	    return 'fa x-fa-tree ' + iconMap[data.type];
-	} },
-	{ type: 'number', name: 'crush_weight' }
-    ],
-});
-Ext.define('PVE.node.CephMonMgrList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveNodeCephMonMgr',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    onlineHelp: 'chapter_pveceph',
-
-    defaults: {
-	border: false,
-	onlineHelp: 'chapter_pveceph',
-	flex: 1
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    items: [
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    type: 'mon',
-	    additionalColumns: [
-		{
-		    header: gettext('Quorum'),
-		    width: 70,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'quorum'
-		}
-	    ],
-	    stateId: 'grid-ceph-monitor',
-	    showCephInstallMask: true,
-	    title: gettext('Monitor')
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    type: 'mgr',
-	    stateId: 'grid-ceph-manager',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    title: gettext('Manager')
-	}
-    ]
-});
-Ext.define('PVE.node.CephCrushMap', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveNodeCephCrushMap'],
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    stateful: true,
-    stateId: 'layout-ceph-crush',
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/crush',
-
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.node.CephStatus', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephStatus',
-
-    onlineHelp: 'chapter_pveceph',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: {
-	type: 'column'
-    },
-
-    defaults: {
-	padding: 5
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Health'),
-	    bodyPadding: 10,
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    minHeight: 230,
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    minHeight: 500,
-		    columnWidth: 0.5
-		}
-	    },
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    itemId: 'overallhealth',
-		    xtype: 'pveHealthWidget',
-		    title: gettext('Status')
-		},
-		{
-		    flex: 2,
-		    itemId: 'warnings',
-		    stateful: true,
-		    stateId: 'ceph-status-warnings',
-		    xtype: 'grid',
-		    // since we load the store manually,
-		    // to show the emptytext, we have to
-		    // specify an empty store
-		    store: { data:[] },
-		    emptyText: gettext('No Warnings/Errors'),
-		    columns: [
-			{
-			    dataIndex: 'severity',
-			    header: gettext('Severity'),
-			    align: 'center',
-			    width: 70,
-			    renderer: function(value) {
-				var health = PVE.Utils.map_ceph_health[value];
-				var classes = PVE.Utils.get_health_icon(health);
-
-				return '<i class="fa fa-fw ' + classes + '"></i>';
-			    },
-			    sorter: {
-				sorterFn: function(a,b) {
-				    var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-				    return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-				}
-			    }
-			},
-			{
-			    dataIndex: 'summary',
-			    header: gettext('Summary'),
-			    flex: 1
-			},
-			{
-			    xtype: 'actioncolumn',
-			    width: 40,
-			    align: 'center',
-			    tooltip: gettext('Detail'),
-			    items: [
-				{
-				    iconCls: 'x-fa fa-info-circle',
-				    handler: function(grid, rowindex, colindex, item, e, record) {
-					var win = Ext.create('Ext.window.Window', {
-					    title: gettext('Detail'),
-					    resizable: true,
-					    modal: true,
-					    width: 650,
-					    height: 400,
-					    layout: {
-						type: 'fit'
-					    },
-					    items: [{
-						scrollable: true,
-						padding: 10,
-						xtype: 'box',
-						html: [
-						    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-						    '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-						]
-					    }]
-					});
-					win.show();
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveCephStatusDetail',
-	    itemId: 'statusdetail',
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 250
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 300
-		}
-	    },
-	    title: gettext('Status')
-	},
-	{
-	    title: gettext('Services'),
-	    xtype: 'pveCephServices',
-	    itemId: 'services',
-	    plugins: 'responsive',
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 200
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 200
-		}
-	    }
-	},
-	{
-	    xtype: 'panel',
-	    title: gettext('Performance'),
-	    columnWidth: 1,
-	    bodyPadding: 5,
-	    layout: {
-		type: 'hbox',
-		align: 'center'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    xtype: 'proxmoxGauge',
-		    itemId: 'space',
-		    title: gettext('Usage')
-		},
-		{
-		    flex: 2,
-		    xtype: 'container',
-		    defaults: {
-			padding: 0,
-			height: 100
-		    },
-		    items: [
-			{
-			    itemId: 'reads',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Reads'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'writes',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Writes'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'iops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS', // do not localize
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'readiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Reads'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'writeiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Writes'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			}
-		    ]
-		}
-	    ]
-	}
-    ],
-
-    generateCheckData: function(health) {
-	var result = [];
-	var checks = health.checks || {};
-	var keys = Ext.Object.getKeys(checks).sort();
-
-	Ext.Array.forEach(keys, function(key) {
-	    var details = checks[key].detail || [];
-	    result.push({
-		id: key,
-		summary: checks[key].summary.message,
-		detail: Ext.Array.reduce(
-			    checks[key].detail,
-			    function(first, second) {
-				return first + '\n' + second.message;
-			    },
-			    ''
-			),
-		severity: checks[key].severity
-	    });
-	});
-
-	return result;
-    },
-
-    updateAll: function(store, records, success) {
-	if (!success || records.length === 0) {
-	    return;
-	}
-
-	var me = this;
-	var rec = records[0];
-	me.status = rec.data;
-
-	// add health panel
-	me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
-	// add errors to gridstore
-	me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
-
-	// update services
-	me.getComponent('services').updateAll(me.metadata || {}, rec.data);
-
-	// update detailstatus panel
-	me.getComponent('statusdetail').updateAll(me.metadata || {}, rec.data);
-
-	// add performance data
-	var used = rec.data.pgmap.bytes_used;
-	var total = rec.data.pgmap.bytes_total;
-
-	var text = Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(used),
-	    PVE.Utils.render_size(total)
-	);
-
-	// update the usage widget
-	me.down('#space').updateValue(used/total, text);
-
-	// TODO: logic for jewel (iops split in read/write)
-
-	var iops = rec.data.pgmap.op_per_sec;
-	var readiops = rec.data.pgmap.read_op_per_sec;
-	var writeiops = rec.data.pgmap.write_op_per_sec;
-	var reads = rec.data.pgmap.read_bytes_sec || 0;
-	var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-	if (iops !== undefined && me.version !== 'hammer') {
-	    me.change_version('hammer');
-	} else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-	    me.change_version('jewel');
-	}
-	// update the graphs
-	me.reads.addDataPoint(reads);
-	me.writes.addDataPoint(writes);
-	me.iops.addDataPoint(iops);
-	me.readiops.addDataPoint(readiops);
-	me.writeiops.addDataPoint(writeiops);
-    },
-
-    change_version: function(version) {
-	var me = this;
-	me.version = version;
-	me.sp.set('ceph-version', version);
-	me.iops.setVisible(version === 'hammer');
-	me.readiops.setVisible(version === 'jewel');
-	me.writeiops.setVisible(version === 'jewel');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	me.callParent();
-	var baseurl = '/api2/json' + (nodename ? '/nodes/' + nodename : '/cluster') + '/ceph';
-	me.store = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-status-' + (nodename || 'cluster'),
-	    interval: 5000,
-	    proxy: {
-		type: 'proxmox',
-		url: baseurl + '/status'
-	    }
-	});
-
-	me.metadatastore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-metadata-' + (nodename || 'cluster'),
-	    interval: 15*1000,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/ceph/metadata'
-	    }
-	});
-
-	// save references for the updatefunction
-	me.iops = me.down('#iops');
-	me.readiops = me.down('#readiops');
-	me.writeiops = me.down('#writeiops');
-	me.reads = me.down('#reads');
-	me.writes = me.down('#writes');
-
-	// get ceph version
-	me.sp = Ext.state.Manager.getProvider();
-	me.version = me.sp.get('ceph-version');
-	me.change_version(me.version);
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-	    me.store.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, (nodename || 'localhost'),
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.mon(me.store, 'load', me.updateAll, me);
-	me.mon(me.metadatastore, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    var rec = records[0];
-	    me.metadata = rec.data;
-
-	    // update services
-	    me.getComponent('services').updateAll(rec.data, me.status || {});
-
-	    // update detailstatus panel
-	    me.getComponent('statusdetail').updateAll(rec.data, me.status || {});
-
-	}, me);
-
-	me.on('destroy', me.store.stopUpdate);
-	me.on('destroy', me.metadatastore.stopUpdate);
-	me.store.startUpdate();
-	me.metadatastore.startUpdate();
-    }
-
-});
-Ext.define('PVE.ceph.StatusDetail', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephStatusDetail',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [{
-	flex: 1,
-	itemId: 'osds',
-	maxHeight: 250,
-	scrollable: true,
-	padding: '0 10 5 10',
-	data: {
-	    total: 0,
-	    upin: 0,
-	    upout: 0,
-	    downin: 0,
-	    downout: 0,
-	    oldosds: []
-	},
-	tpl: [
-	    '<h3>' + 'OSDs' + '</h3>',
-	    '<table class="osds">',
-	    '<tr><td></td>',
-	    '<td><i class="fa fa-fw good fa-circle"></i>',
-	    gettext('In'),
-	    '</td>',
-	    '<td><i class="fa fa-fw warning fa-circle-o"></i>',
-	    gettext('Out'),
-	    '</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
-	    gettext('Up'),
-	    '</td>',
-	    '<td>{upin}</td>',
-	    '<td>{upout}</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
-	    gettext('Down'),
-	    '</td>',
-	    '<td>{downin}</td>',
-	    '<td>{downout}</td>',
-	    '</tr>',
-	    '</table>',
-	    '<br /><div>',
-	    gettext('Total'),
-	    ': {total}',
-	    '</div><br />',
-	    '<tpl if="oldosds.length &gt; 0">',
-	    '<i class="fa fa-refresh warning"></i> ' + gettext('Outdated OSDs') + "<br>",
-	    '<div class="osds">',
-	    '<tpl for="oldosds">',
-	    '<div class="left-aligned">osd.{id}:</div>',
-	    '<div class="right-aligned">{version}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>',
-	    '</div>',
-	    '</tpl>'
-	]
-    },
-    {
-	flex: 1,
-	border: false,
-	itemId: 'pgchart',
-	xtype: 'polar',
-	height: 184,
-	innerPadding: 5,
-	insetPadding: 5,
-	colors: [
-	    '#CFCFCF',
-	    '#21BF4B',
-	    '#FFCC00',
-	    '#FF6C59'
-	],
-	store: { },
-	series: [
-	    {
-		type: 'pie',
-		donut: 60,
-		angleField: 'count',
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function(tooltip, record, ctx) {
-			var html = record.get('text');
-			html += '<br>';
-			record.get('states').forEach(function(state) {
-			    html += '<br>' +
-				state.state_name + ': ' + state.count.toString();
-			});
-			tooltip.setHtml(html);
-		    }
-		},
-		subStyle: {
-		    strokeStyle: false
-		}
-	    }
-	]
-    },
-    {
-	flex: 1.6,
-	itemId: 'pgs',
-	padding: '0 10',
-	maxHeight: 250,
-	scrollable: true,
-	data: {
-	    states: []
-	},
-	tpl: [
-	    '<h3>' + 'PGs' + '</h3>',
-	    '<tpl for="states">',
-	    '<div class="left-aligned"><i class ="fa fa-circle {cls}"></i> {state_name}:</div>',
-	    '<div class="right-aligned">{count}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>'
-	]
-    }],
-
-    // similar to mgr dashboard
-    pgstates: {
-	// clean
-	clean: 1,
-	active: 1,
-
-	// working
-	activating: 2,
-	backfill_wait: 2,
-	backfilling: 2,
-	creating: 2,
-	deep: 2,
-	degraded: 2,
-	forced_backfill: 2,
-	forced_recovery: 2,
-	peered: 2,
-	peering: 2,
-	recovering: 2,
-	recovery_wait: 2,
-	repair: 2,
-	scrubbing: 2,
-	snaptrim: 2,
-	snaptrim_wait: 2,
-
-	// error
-	backfill_toofull: 3,
-	backfill_unfound: 3,
-	down: 3,
-	incomplete: 3,
-	inconsistent: 3,
-	recovery_toofull: 3,
-	recovery_unfound: 3,
-	remapped: 3,
-	snaptrim_error: 3,
-	stale: 3,
-	undersized: 3
-    },
-
-    statecategories: [
-	{
-	    text: gettext('Unknown'),
-	    count: 0,
-	    states: [],
-	    cls: 'faded'
-	},
-	{
-	    text: gettext('Clean'),
-	    cls: 'good'
-	},
-	{
-	    text: gettext('Working'),
-	    cls: 'warning'
-	},
-	{
-	    text: gettext('Error'),
-	    cls: 'critical'
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var maxversion = "0";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-
-	var oldosds = [];
-
-	if (metadata.osd) {
-	    metadata.osd.forEach(function(osd) {
-		var version = PVE.Utils.parse_ceph_version(osd);
-		if (version != maxversion) {
-		    oldosds.push({
-			id: osd.id,
-			version: version
-		    });
-		}
-	    });
-	}
-
-	var pgmap = status.pgmap || {};
-	var health = status.health || {};
-	var osdmap = status.osdmap || { osdmap: {} };
-
-
-	// update pgs sorted
-	var pgs_by_state = pgmap.pgs_by_state || [];
-	pgs_by_state.sort(function(a,b){
-	    return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
-	});
-
-	me.statecategories.forEach(function(cat) {
-	    cat.count = 0;
-	    cat.states = [];
-	});
-
-	pgs_by_state.forEach(function(state) {
-	    var i;
-	    var states = state.state_name.split(/[^a-z]+/);
-	    var result = 0;
-	    for (i = 0; i < states.length; i++) {
-		if (me.pgstates[states[i]] > result) {
-		    result = me.pgstates[states[i]];
-		}
-	    }
-	    // for the list
-	    state.cls = me.statecategories[result].cls;
-
-	    me.statecategories[result].count += state.count;
-	    me.statecategories[result].states.push(state);
-	});
-
-	me.getComponent('pgchart').getStore().setData(me.statecategories);
-	me.getComponent('pgs').update({states: pgs_by_state});
-
-	var downinregex = /(\d+) osds down/;
-	var downin_osds = 0;
-
-	// we collect monitor/osd information from the checks
-	Ext.Object.each(health.checks, function(key, value, obj) {
-	    var found = null;
-	    if (key === 'OSD_DOWN') {
-		found = value.summary.message.match(downinregex);
-		if (found !== null) {
-		    downin_osds = parseInt(found[1],10);
-		}
-	    }
-	});
-
-	// update osds counts
-
-	var total_osds = osdmap.osdmap.num_osds || 0;
-	var in_osds = osdmap.osdmap.num_in_osds || 0;
-	var up_osds = osdmap.osdmap.num_up_osds || 0;
-	var out_osds = total_osds - in_osds;
-	var down_osds = total_osds - up_osds;
-
-	var downout_osds = down_osds - downin_osds;
-	var upin_osds = in_osds - downin_osds;
-	var upout_osds = up_osds - upin_osds;
-	var osds = {
-	    total: total_osds,
-	    upin: upin_osds,
-	    upout: upout_osds,
-	    downin: downin_osds,
-	    downout: downout_osds,
-	    oldosds: oldosds
-	};
-	var osdcomponent = me.getComponent('osds');
-	osdcomponent.update(Ext.apply(osdcomponent.data, osds));
-
-	me.suspendLayout = false;
-	me.updateLayout();
-    }
-});
-
-Ext.define('PVE.ceph.Services', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephServices',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5 20',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mons',
-	    title: gettext('Monitors')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mgrs',
-	    title: gettext('Managers')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mdss',
-	    title: gettext('Meta Data Servers')
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-
-	var healthstates = {
-	    'HEALTH_UNKNOWN': 0,
-	    'HEALTH_ERR': 1,
-	    'HEALTH_WARN': 2,
-	    'HEALTH_OLD': 3,
-	    'HEALTH_OK': 4
-	};
-	var healthmap = [
-	    'HEALTH_UNKNOWN',
-	    'HEALTH_ERR',
-	    'HEALTH_WARN',
-	    'HEALTH_OLD',
-	    'HEALTH_OK'
-	];
-	var reduceFn = function(first, second) {
-	    return first + '\n' + second.message;
-	};
-	var services = ['mon','mgr','mds'];
-	var maxversion = "00.0.00";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-	var i;
-	var quorummap = (status && status.quorum_names) ? status.quorum_names : [];
-	var monmessages = {};
-	var mgrmessages = {};
-	var mdsmessages = {};
-	if (status) {
-	    if (status.health) {
-		Ext.Object.each(status.health.checks, function(key, value, obj) {
-		    if (!Ext.String.startsWith(key, "MON_")) {
-			return;
-		    }
-
-		    var i;
-		    for (i = 0; i < value.detail.length; i++) {
-			var match = value.detail[i].message.match(/mon.([a-zA-Z0-9\-\.]+)/);
-			if (!match) {
-			    continue;
-			}
-			var monid = match[1];
-
-			if (!monmessages[monid]) {
-			    monmessages[monid] = {
-				worstSeverity: healthstates.HEALTH_OK,
-				messages: []
-			    };
-			}
-
-
-			monmessages[monid].messages.push(
-							 PVE.Utils.get_ceph_icon_html(value.severity, true) +
-							 Ext.Array.reduce(value.detail, reduceFn, '')
-			);
-			if (healthstates[value.severity] < monmessages[monid].worstSeverity) {
-			    monmessages[monid].worstSeverity = healthstates[value.severity];
-			}
-		    }
-		});
-	    }
-
-	    if (status.mgrmap) {
-		mgrmessages[status.mgrmap.active_name] = "active";
-		status.mgrmap.standbys.forEach(function(mgr) {
-		    mgrmessages[mgr.name] = "standby";
-		});
-	    }
-
-	    if (status.fsmap) {
-		status.fsmap.by_rank.forEach(function(mds) {
-		    mdsmessages[mds.name] = 'rank: ' + mds.rank + "; " + mds.status;
-		});
-	    }
-	}
-
-	var checks = {
-	    mon: function(mon) {
-		if (quorummap.indexOf(mon.name) !== -1) {
-		    mon.health = healthstates.HEALTH_OK;
-		} else {
-		    mon.health = healthstates.HEALTH_ERR;
-		}
-		if (monmessages[mon.name]) {
-		    if (monmessages[mon.name].worstSeverity < mon.health) {
-			mon.health = monmessages[mon.name].worstSeverity;
-		    }
-		    Array.prototype.push.apply(mon.messages, monmessages[mon.name].messages);
-		}
-		return mon;
-	    },
-	    mgr: function(mgr) {
-		if (mgrmessages[mgr.name] === 'active') {
-		    mgr.title = '<b>' + mgr.title + '</b>';
-		    mgr.statuses.push(gettext('Status') + ': <b>active</b>');
-		} else if (mgrmessages[mgr.name] === 'standby') {
-		    mgr.statuses.push(gettext('Status') + ': standby');
-		} else if (mgr.health > healthstates.HEALTH_WARN) {
-		    mgr.health = healthstates.HEALTH_WARN;
-		}
-
-		return mgr;
-	    },
-	    mds: function(mds) {
-		if (mdsmessages[mds.name]) {
-		    mds.title = '<b>' + mds.title + '</b>';
-		    mds.statuses.push(gettext('Status') + ': <b>' + mdsmessages[mds.name]+"</b>");
-		} else if (mds.addr !== Proxmox.Utils.unknownText) {
-		    mds.statuses.push(gettext('Status') + ': standby');
-		}
-
-		return mds;
-	    }
-	};
-
-	for (i = 0; i < services.length; i++) {
-	    var type = services[i];
-	    var ids = Object.keys(metadata[type] || {});
-	    me[type] = {};
-
-	    var j;
-	    for (j = 0; j < ids.length; j++) {
-		var id = ids[j];
-		var tmp = id.split('@');
-		var name = tmp[0];
-		var host = tmp[1];
-		var result = {
-		    id: id,
-		    health: healthstates.HEALTH_OK,
-		    statuses: [],
-		    messages: [],
-		    name: name,
-		    title: metadata[type][id].name || name,
-		    host: host,
-		    version: PVE.Utils.parse_ceph_version(metadata[type][id]),
-		    service: metadata[type][id].service,
-		    addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText
-		};
-
-		result.statuses = [
-		    gettext('Host') + ": " + result.host,
-		    gettext('Address') + ": " + result.addr
-		];
-
-		if (checks[type]) {
-		    result = checks[type](result);
-		}
-
-		if (result.service && !result.version) {
-		    result.messages.push(
-			PVE.Utils.get_ceph_icon_html('HEALTH_UNKNOWN', true) +
-			gettext('Stopped')
-		    );
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (!result.version && result.addr === Proxmox.Utils.unknownText) {
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (result.version) {
-		    result.statuses.push(gettext('Version') + ": " + result.version);
-
-		    if (result.version != maxversion) {
-			if (result.health > healthstates.HEALTH_OLD) {
-			    result.health = healthstates.HEALTH_OLD;
-			}
-			result.messages.push(
-			    PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) +
-			    gettext('Not Current Version, please upgrade')
-			);
-		    }
-		}
-
-		result.statuses.push(''); // empty line
-		result.text = result.statuses.concat(result.messages).join('<br>');
-
-		result.health = healthmap[result.health];
-
-		me[type][id] = result;
-	    }
-	}
-
-	me.getComponent('mons').updateAll(Object.values(me.mon));
-	me.getComponent('mgrs').updateAll(Object.values(me.mgr));
-	me.getComponent('mdss').updateAll(Object.values(me.mds));
-    }
-});
-
-Ext.define('PVE.ceph.ServiceList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCephServiceList',
-
-    style: {
-	'text-align':'center'
-    },
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	}
-    ],
-
-    updateAll: function(list) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var i;
-	list.sort(function(a,b) {
-	    return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
-	});
-	var ids = {};
-	if (me.ids) {
-	    me.ids.forEach(function(id) {
-		ids[id] = true;
-	    });
-	}
-	for (i = 0; i < list.length; i++) {
-	    var service = me.getComponent(list[i].id);
-	    if (!service) {
-		// since services are already sorted, and
-		// we always have a sorted list
-		// we can add it at the service+1 position (because of the title)
-		service = me.insert(i+1, {
-		    xtype: 'pveCephServiceWidget',
-		    itemId: list[i].id
-		});
-		if (!me.ids) {
-		    me.ids = [];
-		}
-		me.ids.push(list[i].id);
-	    } else {
-		delete ids[list[i].id];
-	    }
-	    service.updateService(list[i].title, list[i].text, list[i].health);
-	}
-
-	Object.keys(ids).forEach(function(id) {
-	    me.remove(id);
-	});
-	me.suspendLayout = false;
-	me.updateLayout();
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getComponent('title').update({
-	    title: me.title
-	});
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.ServiceWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveCephServiceWidget',
-
-    userCls: 'monitor inline-block',
-    data: {
-	title: '0',
-	health: 'HEALTH_ERR',
-	text: '',
-	iconCls: PVE.Utils.get_health_icon()
-    },
-
-    tpl: [
-	'{title}: ',
-	'<i class="fa fa-fw {iconCls}"></i>'
-    ],
-
-    updateService: function(title, text, health) {
-	var me = this;
-
-	me.update(Ext.apply(me.data, {
-	    health: health,
-	    text: text,
-	    title: title,
-	    iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[health])
-	}));
-
-	if (me.tooltip) {
-	    me.tooltip.setHtml(text);
-	}
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    if (me.tooltip) {
-		me.tooltip.destroy();
-		delete me.tooltip;
-	    }
-	},
-	mouseenter: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (!me) {
-		    return;
-		}
-		if (!me.tooltip) {
-		    me.tooltip = Ext.create('Ext.tip.ToolTip', {
-			target: me.el,
-			trackMouse: true,
-			dismissDelay: 0,
-			renderTo: Ext.getBody(),
-			html: me.data.text
-		    });
-		}
-		me.tooltip.show();
-	    }
-	},
-	mouseleave: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (me.tooltip) {
-		    me.tooltip.destroy();
-		    delete me.tooltip;
-		}
-	    }
-	}
-    }
-});
-Ext.define('PVE.node.CephConfigDb', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveNodeCephConfigDb',
-
-    border: false,
-    store: {
-	proxy: {
-	    type: 'proxmox'
-	}
-    },
-
-    columns: [
-	{
-	    dataIndex: 'section',
-	    text: 'WHO',
-	    width: 100,
-	},
-	{
-	    dataIndex: 'mask',
-	    text: 'MASK',
-	    hidden: true,
-	    width: 80,
-	},
-	{
-	    dataIndex: 'level',
-	    hidden: true,
-	    text: 'LEVEL',
-	},
-	{
-	    dataIndex: 'name',
-	    flex: 1,
-	    text: 'OPTION',
-	},
-	{
-	    dataIndex: 'value',
-	    flex: 1,
-	    text: 'VALUE',
-	},
-	{
-	    dataIndex: 'can_update_at_runtime',
-	    text: 'Runtime Updatable',
-	    hidden: true,
-	    width: 80,
-	    renderer: Proxmox.Utils.format_boolean
-	},
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store.proxy.url = '/api2/json/nodes/' + nodename + '/ceph/configdb';
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore());
-	me.getStore().load();
-    }
-});
-Ext.define('PVE.node.CephConfig', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfig',
-
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/config',
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.CephConfigCrush', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfigCrush',
-
-    onlineHelp: 'chapter_pveceph',
-
-    layout: 'border',
-    items: [{
-	    title: gettext('Configuration'),
-	    xtype: 'pveNodeCephConfig',
-	    region: 'center'
-	},
-	{
-	    title: 'Crush Map', // do not localize
-	    xtype: 'pveNodeCephCrushMap',
-	    region: 'east',
-	    split: true,
-	    width: '50%'
-	},
-	{
-	    title: gettext('Configuration Database'),
-	    xtype: 'pveNodeCephConfigDb',
-	    region: 'south',
-	    split: true,
-	    weight: -30,
-	    height: '50%'
-    }],
-
-    initComponent: function() {
-	var me = this;
-	me.defaults = {
-	    pveSelNode: me.pveSelNode
-	};
-	me.callParent();
-    }
-});
-Ext.define('PVE.ceph.Log', {
-    extend: 'Proxmox.panel.LogView',
-    xtype: 'cephLogView',
-    nodename: undefined,
-    failCallback: function(response) {
-	var me = this;
-	var msg = response.htmlStatus;
-	var windowShow = PVE.Utils.showCephInstallOrMask(me, msg, me.nodename,
-	    function(win){
-		me.mon(win, 'cephInstallWindowClosed', function(){
-		    me.loadTask.delay(200);
-		});
-	    }
-	);
-	if (!windowShow) {
-	    Proxmox.Utils.setErrorMask(me, msg);
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.CephInstallWizard', {
-	extend: 'PVE.window.Wizard',
-	alias: 'widget.pveCephInstallWizard',
-	mixins: ['Proxmox.Mixin.CBind'],
-	resizable: false,
-	nodename: undefined,
-	viewModel: {
-	    data: {
-		nodename: '',
-		configuration: true,
-		isInstalled: false
-	    }
-	},
-	cbindData: {
-	    nodename: undefined
-	},
-	title: gettext('Setup'),
-	navigateNext: function() {
-	    var tp = this.down('#wizcontent');
-	    var atab = tp.getActiveTab();
-
-	    var next = tp.items.indexOf(atab) + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (ntab) {
-		ntab.enable();
-		tp.setActiveTab(ntab);
-	    }
-	},
-	setInitialTab: function (index) {
-	    var tp = this.down('#wizcontent');
-	    var initialTab = tp.items.getAt(index);
-	    initialTab.enable();
-	    tp.setActiveTab(initialTab);
-	},
-	onShow: function() {
-		this.callParent(arguments);
-		var isInstalled = this.getViewModel().get('isInstalled');
-		if (isInstalled) {
-		    this.getViewModel().set('configuration', false);
-		    this.setInitialTab(2);
-		}
-	},
-	items: [
-	    {
-		title: gettext('Info'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'chapter_pveceph',
-		html: '<h3>Ceph?</h3>'+
-		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
-		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
-		' This wizard will guide you through the necessary steps, after the initial installation you will be offered to create an initial configuration.'+
-		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
-		'<p>Please take a look at our documentation, by clicking the help button below, before starting the installation, '+
-		'if you want to gain deeper knowledge about Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#back').hide(true);
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Start installation'));
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
-		    }
-		}
-	    },
-	    {
-		title: gettext('Installation'),
-		xtype: 'panel',
-		layout: 'fit',
-		cbind:{
-		    nodename: '{nodename}'
-		},
-		viewModel: {}, // needed to inherit parent viewModel data
-		listeners: {
-		    afterrender: function() {
-			var me = this;
-			if (this.getViewModel().get('isInstalled')) {
-			    this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
-			} else {
-			    me.down('pveNoVncConsole').fireEvent('activate');
-			}
-		    },
-		    activate: function() {
-			var me = this;
-			var nodename = me.nodename;
-			me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
-				storeid: 'ceph-status-' + nodename,
-				interval: 1000,
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + nodename + '/ceph/status'
-				},
-				listeners: {
-				    load: function(rec, response, success, operation) {
-
-					if (success) {
-					    me.updateStore.stopUpdate();
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("not initialized", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("rados_connect failed", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
-					    me.down('textfield').setValue('success');
-					} else if (!operation.error.statusText.match("not installed", "i")) {
-					    Proxmox.Utils.setErrorMask(me, operation.error.statusText);
-					}
-				    }
-				}
-			});
-			me.updateStore.startUpdate();
-		    },
-		    destroy: function() {
-			var me = this;
-			if (me.updateStore) {
-			    me.updateStore.stopUpdate();
-			}
-		    }
-		},
-		items: [
-		    {
-			itemId: 'jsconsole',
-			consoleType: 'cmd',
-			xtermjs: true,
-			xtype: 'pveNoVncConsole',
-			cbind:{
-			    nodename: '{nodename}'
-			},
-			cmd: 'ceph_install'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'installSuccess',
-			value: '',
-			allowBlank: false,
-			submitValue: false,
-			hidden: true
-		    }
-		]
-	    },
-	    {
-		xtype: 'inputpanel',
-		title: gettext('Configuration'),
-		onlineHelp: 'chapter_pveceph',
-		cbind: {
-		    nodename: '{nodename}'
-		},
-		viewModel: {
-		    data: {
-			replicas: undefined,
-			minreplicas: undefined
-		    }
-		},
-		listeners: {
-		    activate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
-		    },
-		    beforeshow: function() {
-			if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			    this.mask("Coniguration already initialized",['pve-static-mask']);
-			} else {
-			    this.unmask();
-			}
-		    },
-		    deactivate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
-		    }
-		},
-		column1: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('Ceph cluster configuration') + ':'
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'network',
-			value: '',
-			fieldLabel: 'Public Network IP/CIDR',
-			bind: {
-			    allowBlank: '{configuration}'
-			}
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'cluster-network',
-			fieldLabel: 'Cluster Network IP/CIDR',
-			allowBlank: true,
-			autoSelect: false,
-			emptyText: gettext('Same as Public Network')
-		    }
-		    // FIXME: add hint about cluster network and/or reference user to docs??
-		],
-		column2: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('First Ceph monitor') + ':'
-		    },
-		    {
-			xtype: 'pveNodeSelector',
-			fieldLabel: gettext('Monitor node'),
-			name: 'mon-node',
-			selectCurNode: true,
-			allowBlank: false
-		    },
-		    {
-			xtype: 'displayfield',
-			value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
-			userCls: 'pve-hint'
-		    }
-		],
-		advancedColumn1: [
-		    {
-			xtype: 'numberfield',
-			name: 'size',
-			fieldLabel: 'Number of replicas',
-			bind: {
-			    value: '{replicas}'
-			},
-			maxValue: 7,
-			minValue: 2,
-			emptyText: '3'
-		    },
-		    {
-			xtype: 'numberfield',
-			name: 'min_size',
-			fieldLabel: 'Minimum replicas',
-			bind: {
-			    maxValue: '{replicas}',
-			    value: '{minreplicas}'
-			},
-			minValue: 2,
-			maxValue: 3,
-			setMaxValue: function(value) {
-			    this.maxValue = Ext.Number.from(value, 2);
-			    // allow enough to avoid split brains with max 'size', but more makes simply no sense
-			    if (this.maxValue > 4) {
-				this.maxValue = 4;
-			    }
-			    this.toggleSpinners();
-			    this.validate();
-			},
-			emptyText: '2'
-		    }
-		],
-		onGetValues: function(values) {
-		    ['cluster-network', 'size', 'min_size'].forEach(function(field) {
-			if (!values[field]) {
-			    delete values[field];
-			}
-		    });
-		    return values;
-		},
-		onSubmit: function() {
-		    var me = this;
-		    if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			var wizard = me.up('window');
-			var kv = wizard.getValues();
-			delete kv['delete'];
-			var monNode = kv['mon-node'];
-			delete kv['mon-node'];
-			var nodename = me.nodename;
-			delete kv.nodename;
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/ceph/init',
-			    waitMsgTarget: wizard,
-			    method: 'POST',
-			    params: kv,
-			    success: function() {
-				Proxmox.Utils.API2Request({
-				    url: '/nodes/' + monNode + '/ceph/mon/' + monNode,
-				    waitMsgTarget: wizard,
-				    method: 'POST',
-				    success: function() {
-					me.up('pveCephInstallWizard').navigateNext();
-				    },
-				    failure: function(response, opts) {
-					Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				    }
-				});
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-
-		    } else {
-			me.up('pveCephInstallWizard').navigateNext();
-		    }
-		}
-	    },
-	    {
-		title: gettext('Success'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'pve_ceph_install',
-		html: '<h3>Installation successful!</h3>'+
-		'<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
-		    '<ol><li>Install Ceph on other nodes</li>'+
-		    '<li>Create additional Ceph Monitors</li>'+
-		    '<li>Create Ceph OSDs</li>'+
-		    '<li>Create Ceph Pools</li></ol>'+
-		'<p>To learn more click on the help button below.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-
-			var tp = this.up('#wizcontent');
-			var idx = tp.items.indexOf(this)-1;
-			for(;idx >= 0;idx--) {
-			    var nc = tp.items.getAt(idx);
-			    if (nc) {
-				nc.disable();
-			    }
-			}
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-		    }
-		},
-		onSubmit: function() {
-		    var wizard = this.up('pveCephInstallWizard');
-		    wizard.close();
-		}
-	    }
-	]
-    });
-Ext.define('PVE.node.DiskList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeDiskList',
-
-    emptyText: gettext('No Disks found'),
-
-    stateful: true,
-    stateId: 'grid-node-disks',
-
-    columns: [
-	{
-	    header: gettext('Device'),
-	    width: 150,
-	    sortable: true,
-	    dataIndex: 'devpath'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 80,
-	    sortable: true,
-	    dataIndex: 'type',
-	    renderer: function(v) {
-		if (v === 'ssd') {
-		    return 'SSD';
-		} else if (v === 'hdd') {
-		    return 'Hard Disk';
-		} else if (v === 'usb'){
-		    return 'USB';
-		} else {
-		    return gettext('Unknown');
-		}
-	    }
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 150,
-	    sortable: false,
-	    renderer: function(v, metaData, rec) {
-		if (rec) {
-		    if (rec.data.osdid >= 0) {
-			var bluestore = '';
-			if (rec.data.bluestore === 1) {
-			    bluestore = ' (Bluestore)';
-			}
-			return "Ceph osd." + rec.data.osdid.toString() + bluestore;
-		    }
-
-		    var types = [];
-		    if (rec.data.journals > 0) {
-			types.push('Journal');
-		    }
-
-		    if (rec.data.db > 0) {
-			types.push('DB');
-		    }
-
-		    if (rec.data.wal > 0) {
-			types.push('WAL');
-		    }
-
-		    if (types.length > 0) {
-			return 'Ceph (' + types.join(', ') + ')';
-		    }
-		}
-
-		return v || Proxmox.Utils.noText;
-	    },
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'GPT',
-	    width: 60,
-	    align: 'right',
-	    renderer: Proxmox.Utils.format_boolean,
-	    dataIndex: 'gpt'
-	},
-	{
-	    header: gettext('Vendor'),
-	    width: 100,
-	    sortable: true,
-	    hidden: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'vendor'
-	},
-	{
-	    header: gettext('Model'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'model'
-	},
-	{
-	    header: gettext('Serial'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'serial'
-	},
-	{
-	    header: 'S.M.A.R.T.',
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'health'
-	},
-	{
-	    header: 'Wearout',
-	    width: 90,
-	    sortable: true,
-	    align: 'right',
-	    dataIndex: 'wearout',
-	    renderer: function(value) {
-		if (Ext.isNumeric(value)) {
-		    return (100 - value).toString() + '%';
-		}
-		return 'N/A';
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var store = Ext.create('Ext.data.Store', {
-	    storeid: 'node-disk-list' + nodename,
-	    model: 'node-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list"
-	    },
-	    sorters: [
-		{
-		    property : 'dev',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reloadButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reload'),
-	    handler: function() {
-		me.store.load();
-	    }
-	});
-
-	var smartButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show S.M.A.R.T. values'),
-	    selModel: sm,
-	    enableFn: function() {
-		return !!sm.getSelection().length;
-	    },
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.DiskSmartWindow', {
-                    nodename: nodename,
-		    dev: rec.data.devpath
-		});
-		win.show();
-	    }
-	});
-
-	var initButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Initialize Disk with GPT'),
-	    selModel: sm,
-	    enableFn: function() {
-		var selection = sm.getSelection();
-
-		if (!selection.length || selection[0].data.used) {
-		    return false;
-		} else {
-		    return true;
-		}
-	    },
-	    disabled: true,
-
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
-		    waitMsgTarget: me,
-		    method: 'POST',
-		    params: { disk: rec.data.devpath},
-		    failure: function(response, options) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    upid: upid
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	me.loadCount = 1; // avoid duplicate loadmask
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ reloadButton, smartButton, initButton ],
-	    listeners: {
-		itemdblclick: function() {
-		    var rec = sm.getSelection()[0];
-
-		    var win = Ext.create('PVE.DiskSmartWindow', {
-			nodename: nodename,
-			dev: rec.data.devpath
-		    });
-		    win.show();
-		}
-	    }
-	});
-
-
-	me.callParent();
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('node-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
-	idProperty: 'devpath'
-    });
-});
-
-Ext.define('PVE.DiskSmartWindow', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSmartWindow',
-
-    modal: true,
-
-    items: [
-	{
-	    xtype: 'gridpanel',
-	    layout: {
-		type: 'fit'
-	    },
-	    emptyText: gettext('No S.M.A.R.T. Values'),
-	    scrollable: true,
-	    flex: 1,
-	    itemId: 'smarts',
-	    reserveScrollbar: true,
-	    columns: [
-	    { text: 'ID', dataIndex: 'id', width: 50 },
-	    { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Normalized'), dataIndex: 'value', width: 60},
-	    { text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
-	    { text: gettext('Worst'), dataIndex: 'worst', width: 60},
-	    { text: gettext('Flags'), dataIndex: 'flags'},
-	    { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
-	    ]
-	},
-	{
-	    xtype: 'component',
-	    itemId: 'text',
-	    layout: {
-		type: 'fit'
-	    },
-	    hidden: true,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Reload'),
-	    name: 'reload',
-	    handler: function() {
-		var me = this;
-		me.up('window').store.reload();
-	    }
-	},
-	{
-	    text: gettext('Close'),
-	    name: 'close',
-	    handler: function() {
-		var me = this;
-		me.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    width: 800,
-    height: 500,
-    minWidth: 600,
-    minHeight: 400,
-    bodyPadding: 5,
-    title: gettext('S.M.A.R.T. Values'),
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var dev = me.dev;
-	if (!dev) {
-	    throw "no device specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'disk-smart',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
-	    }
-	});
-
-	me.callParent();
-	var grid = me.down('#smarts');
-	var text = me.down('#text');
-
-	Proxmox.Utils.monStoreErrors(grid, me.store);
-	me.mon(me.store, 'load', function(s, records, success) {
-	    if (success && records.length > 0) {
-		var rec = records[0];
-		switch (rec.data.type) {
-		    case 'text':
-			grid.setVisible(false);
-			text.setVisible(true);
-			text.setHtml(Ext.String.htmlEncode(rec.data.text));
-			break;
-		    default:
-			// includes 'ata'
-			// cannot use empty case because
-			// of jslint
-			grid.setVisible(true);
-			text.setVisible(false);
-			grid.setStore(rec.attributes());
-			break;
-		}
-	    }
-	});
-
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('disk-smart', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'health'},
-	    { name:'type'},
-	    { name:'text'}
-	],
-	hasMany: {model: 'smart-attribute', name: 'attributes'}
-    });
-    Ext.define('smart-attribute', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
-	]
-    });
-});
-Ext.define('PVE.node.CreateLVM', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVM',
-
-    subject: 'LVM Volume Group',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMList', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveLVMList',
-    emptyText: gettext('No Volume Groups found'),
-    stateful: true,
-    stateId: 'grid-node-lvm',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Number of LVs'),
-	    dataIndex: 'lvcount',
-	    width: 150,
-	    align: 'right'
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Volume Group',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVM', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'size', 'free',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			txt += (data.leaf) ? 'hdd-o' : 'object-group';
-			return txt;
-		    }
-		},
-		{
-		    type: 'number',
-		    name: 'usage',
-		    calculate: function(data) {
-			return ((data.size-data.free)/data.size);
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateLVMThin', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVMThin',
-
-    subject: 'LVM Thinpool',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvmthin",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMThinList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveLVMThinList',
-
-    emptyText: gettext('No thinpools found'),
-    stateful: true,
-    stateId: 'grid-node-lvmthin',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'lv',
-	    flex: 1
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'lv_size'
-	},
-	{
-	    header: gettext('Used'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Metadata Usage'),
-	    width: 120,
-	    dataIndex: 'metadata_usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Metadata Size'),
-	    width: 120,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_size'
-	},
-	{
-	    header: gettext('Metadata Used'),
-	    width: 125,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_used'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Thinpool',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVMThin', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['lv', 'lv_size', 'used', 'metadata_size', 'metadata_used',
-		    {
-			type: 'number',
-			name: 'usage',
-			calculate: function(data) {
-			    return data.used/data.lv_size;
-			}
-		    },
-		    {
-			type: 'number',
-			name: 'metadata_usage',
-			calculate: function(data) {
-			    return data.metadata_used/data.metadata_size;
-			}
-		    }
-		],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/lvmthin'
-		},
-		sorters: 'lv'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateDirectory', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateDirectory',
-
-    subject: Proxmox.Utils.directoryText,
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/directory",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    comboItems: [
-			['ext4', 'ext4'],
-			['xfs', 'xfs']
-		    ],
-		    fieldLabel: gettext('Filesystem'),
-		    name: 'filesystem',
-		    value: '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.Directorylist', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveDirectoryList',
-
-    stateful: true,
-    stateId: 'grid-node-directory',
-    columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 100,
-	    dataIndex: 'type'
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options'
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateDirectory', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['path', 'device', 'type', 'options', 'unitfile' ],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/directory'
-		},
-		sorters: 'path'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.node.CreateZFS', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateZFS',
-
-    subject: 'ZFS',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_zfs',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-	var update_disklist = function() {
-	    var grid = me.down('#disklist');
-	    var disks = grid.getSelection();
-
-	    var val = [];
-	    disks.sort(function(a,b) {
-		var aorder = a.get('order') || 0;
-		var border = b.get('order') || 0;
-		return (aorder - border);
-	    });
-
-	    disks.forEach(function(disk) {
-		val.push(disk.get('devpath'));
-	    });
-
-	    me.down('field[name=devices]').setValue(val.join(','));
-	};
-
-	Ext.apply(me, {
-	    url: '/nodes/' + me.nodename + '/disks/zfs',
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'textfield',
-			    hidden: true,
-			    name: 'devices',
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxtextfield',
-			    name: 'name',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'add_storage',
-			    fieldLabel: gettext('Add Storage'),
-			    value: '1'
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('RAID Level'),
-			    name: 'raidlevel',
-			    value: 'single',
-			    comboItems: [
-				['single', gettext('Single Disk')],
-				['mirror', 'Mirror'],
-				['raid10', 'RAID10'],
-				['raidz', 'RAIDZ'],
-				['raidz2', 'RAIDZ2'],
-				['raidz3', 'RAIDZ3']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('Compression'),
-			    name: 'compression',
-			    value: 'on',
-			    comboItems: [
-				['on', 'on'],
-				['off', 'off'],
-				['gzip', 'gzip'],
-				['lz4', 'lz4'],
-				['lzjb', 'lzjb'],
-				['zle', 'zle']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    fieldLabel: gettext('ashift'),
-			    minValue: 9,
-			    maxValue: 16,
-			    value: '12',
-			    name: 'ashift'
-			}
-		    ],
-		    columnB: [
-			{
-			    xtype: 'grid',
-			    height: 200,
-			    emptyText: gettext('No Disks unused'),
-			    itemId: 'disklist',
-			    selModel: 'checkboxmodel',
-			    listeners: {
-				selectionchange: update_disklist
-			    },
-			    store: {
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + me.nodename + '/disks/list?type=unused'
-				}
-			    },
-			    columns: [
-				{
-				    text: gettext('Device'),
-				    dataIndex: 'devpath',
-				    flex: 1
-				},
-				{
-				    text: gettext('Serial'),
-				    dataIndex: 'serial'
-				},
-				{
-				    text: gettext('Size'),
-				    dataIndex: 'size',
-				    renderer: PVE.Utils.render_size
-				},
-				{
-				    header: gettext('Order'),
-				    xtype: 'widgetcolumn',
-				    dataIndex: 'order',
-				    sortable: true,
-				    widget: {
-					xtype: 'proxmoxintegerfield',
-					minValue: 1,
-					isFormField: false,
-					listeners: {
-					    change: function(numberfield, value, old_value) {
-						var record = numberfield.getWidgetRecord();
-						record.set('order', value);
-						update_disklist(record);
-					    }
-					}
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pve-hint',
-		    value: 'Note: ZFS is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_zfs') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-        me.callParent();
-	me.down('#disklist').getStore().load();
-    }
-});
-
-Ext.define('PVE.node.ZFSDevices', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveZFSDevices',
-    stateful: true,
-    stateId: 'grid-node-zfsstatus',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'state'
-	},
-	{
-	    text: 'READ',
-	    dataIndex: 'read'
-	},
-	{
-	    text: 'WRITE',
-	    dataIndex: 'write'
-	},
-	{
-	    text: 'CKSUM',
-	    dataIndex: 'cksum'
-	},
-	{
-	    text: gettext('Message'),
-	    dataIndex: 'msg'
-	}
-    ],
-
-    rootVisible: true,
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/zfs/" + me.zpool,
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'status',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			if (data.leaf) {
-			    return txt + 'hdd-o';
-			}
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSStatus', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveZFSStatus',
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/disks/zfs/" + me.zpool;
-
-	me.rows = {
-	    scan: {
-		header: gettext('Scan')
-	    },
-	    status: {
-		header: gettext('Status')
-	    },
-	    action: {
-		header: gettext('Action')
-	    },
-	    errors: {
-		header: gettext('Errors')
-	    }
-	};
-
-	me.callParent();
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveZFSList',
-
-    stateful: true,
-    stateId: 'grid-node-zfs',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    header: gettext('Size'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	},
-	{
-	    header: gettext('Allocated'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'alloc'
-	},
-	{
-	    header: gettext('Fragmentation'),
-	    renderer: function(value) {
-		return value.toString() + '%';
-	    },
-	    dataIndex: 'frag'
-	},
-	{
-	    header: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'health'
-	},
-	{
-	    header: gettext('Deduplication'),
-	    hidden: true,
-	    renderer: function(value) {
-		return value.toFixed(2).toString() + 'x';
-	    },
-	    dataIndex: 'dedup'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': ZFS',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateZFS', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	},
-	{
-	    text: gettext('Detail'),
-	    itemId: 'detailbtn',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('panel');
-		var selection = me.getSelection();
-		if (selection.length < 1) {
-		    return;
-		}
-		me.show_detail(selection[0].get('name'));
-	    }
-	}
-    ],
-
-    show_detail: function(zpool) {
-	var me = this;
-
-	var detailsgrid = Ext.create('PVE.node.ZFSStatus', {
-	    layout: 'fit',
-	    nodename: me.nodename,
-	    flex: 0,
-	    zpool: zpool
-	});
-
-	var devicetree = Ext.create('PVE.node.ZFSDevices', {
-	    title: gettext('Devices'),
-	    nodename: me.nodename,
-	    flex: 1,
-	    zpool: zpool
-	});
-
-
-	var win = Ext.create('Ext.window.Window', {
-	    modal: true,
-	    width: 800,
-	    height: 400,
-	    resizable: true,
-	    layout: 'fit',
-	    title: gettext('Status') + ': ' + zpool,
-	    items:[{
-		xtype: 'panel',
-		region: 'center',
-		layout: {
-		    type: 'vbox',
-		    align: 'stretch'
-		},
-		items: [detailsgrid, devicetree],
-		tbar: [{
-		    text: gettext('Reload'),
-		    iconCls: 'fa fa-refresh',
-		    handler: function() {
-
-			devicetree.reload();
-			detailsgrid.reload();
-		    }
-		}]
-	    }]
-	}).show();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var selection = me.getSelection();
-	me.down('#detailbtn').setDisabled(selection.length === 0);
-    },
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	},
-	selectionchange: function() {
-	    this.set_button_status();
-	},
-	itemdblclick: function(grid, record) {
-	    var me = this;
-	    me.show_detail(record.get('name'));
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/zfs'
-		},
-		sorters: 'name'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveNodeStatus',
-
-    height: 300,
-    bodyPadding: '20 15 20 15',
-
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 15 5 15'
-    },
-
-    items: [
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpuinfo',
-	    renderer: PVE.Utils.render_node_cpu_usage
-	},
-	{
-	    itemId: 'wait',
-	    iconCls: 'fa fa-fw fa-clock-o',
-	    title: gettext('IO delay'),
-	    valueField: 'wait',
-	    rowspan: 2
-	},
-	{
-	    itemId: 'load',
-	    iconCls: 'fa fa-fw fa-tasks',
-	    title: gettext('Load average'),
-	    printBar: false,
-	    textField: 'loadavg'
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    itemId: 'memory',
-	    title: gettext('RAM usage'),
-	    valueField: 'memory',
-	    maxField: 'memory',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    itemId: 'ksm',
-	    printBar: false,
-	    title: gettext('KSM sharing'),
-	    textField: 'ksm',
-	    renderer: function(record) {
-		return PVE.Utils.render_size(record.shared);
-	    },
-	    padding: '0 15 10 15'
-	},
-	{
-	    iconCls: 'fa fa-fw fa-hdd-o',
-	    itemId: 'rootfs',
-	    title: gettext('HD space') + '(root)',
-	    valueField: 'rootfs',
-	    maxField: 'rootfs',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    iconCls: 'fa fa-fw fa-refresh',
-	    itemId: 'swap',
-	    printSize: true,
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'swap',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    itemId: 'cpus',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('CPU(s)'),
-	    textField: 'cpuinfo',
-	    renderer: function(cpuinfo) {
-		return cpuinfo.cpus + " x " + cpuinfo.model + " (" +
-		cpuinfo.sockets.toString() + " " +
-		(cpuinfo.sockets > 1 ?
-		    gettext('Sockets') :
-		    gettext('Socket')
-		) + ")";
-	    },
-	    value: ''
-	},
-	{
-	    itemId: 'kversion',
-	    colspan: 2,
-	    title: gettext('Kernel Version'),
-	    printBar: false,
-	    textField: 'kversion',
-	    value: ''
-	},
-	{
-	    itemId: 'version',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('PVE Manager Version'),
-	    textField: 'pveversion',
-	    value: ''
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
-	me.setTitle(me.pveSelNode.data.node + ' (' + gettext('Uptime') + ': ' + uptime + ')');
-    }
-
-});
-Ext.define('PVE.node.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    showVersions: function() {
-	var me = this;
-
-	// Note: we use simply text/html here, because ExtJS grid has problems
-	// with cut&paste
-
-	var nodename = me.pveSelNode.data.node;
-
-	var view = Ext.createWidget('component', {
-	    autoScroll: true,
-	    padding: 5,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	});
-
-	var win = Ext.create('Ext.window.Window', {
-	    title: gettext('Package versions'),
-	    width: 600,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [ view ]
-	});
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: "/nodes/" + nodename + "/apt/versions",
-	    method: 'GET',
-	    failure: function(response, opts) {
-		win.close();
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		win.show();
-		var text = '';
-
-		Ext.Array.each(response.result.data, function(rec) {
-		    var version = "not correctly installed";
-		    var pkg = rec.Package;
-		    if (rec.OldVersion && rec.CurrentState === 'Installed') {
-			version = rec.OldVersion;
-		    }
-		    if (rec.RunningKernel) {
-			text += pkg + ': ' + version + ' (running kernel: ' +
-			    rec.RunningKernel + ')\n';
-		    } else if (rec.ManagerVersion) {
-			text += pkg + ': ' + version + ' (running version: ' +
-			    rec.ManagerVersion + ')\n';
-		    } else {
-			text += pkg + ': ' + version + '\n';
-		    }
-		});
-
-		view.update(Ext.htmlEncode(text));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var rstore = me.statusStore;
-
-	var version_btn = new Ext.Button({
-	    text: gettext('Package versions'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { me.showVersions(); });
-	    }
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl: "/api2/json/nodes/" + nodename + "/rrddata",
-	    model: 'pve-rrd-node'
-	});
-
-	Ext.apply(me, {
-	    tbar: [version_btn, '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: 'column',
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: [
-			{
-			    xtype: 'pveNodeStatus',
-			    rstore: rstore,
-			    width: 770,
-			    pveSelNode: me.pveSelNode
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('CPU usage'),
-			    fields: ['cpu','iowait'],
-			    fieldTitles: [gettext('CPU usage'), gettext('IO delay')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Server load'),
-			    fields: ['loadavg'],
-			    fieldTitles: [gettext('Load average')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Memory usage'),
-			    fields: ['memtotal','memused'],
-			    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Network traffic'),
-			    fields: ['netin','netout'],
-			    store: rrdstore
-			}
-		    ]
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*global Blob*/
-Ext.define('PVE.node.SubscriptionKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-    title: gettext('Upload Subscription Key'),
-    width: 300,
-    items: {
-	xtype: 'textfield',
-	name: 'key',
-	value: '',
-	fieldLabel: gettext('Subscription Key')
-    },
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.Subscription', {
-    extend: 'Proxmox.grid.ObjectGrid',
-
-    alias: ['widget.pveNodeSubscription'],
-
-    onlineHelp: 'getting_help',
-
-    viewConfig: {
-	enableTextSelection: true
-    },
-
-    showReport: function() {
-	var me = this;
-	var nodename = me.pveSelNode.data.node;
-
-	var getReportFileName = function() {
-	    var now = Ext.Date.format(new Date(), 'D-d-F-Y-G-i');
-	    return me.nodename + '-report-'  + now + '.txt';
-	};
-
-	var view = Ext.createWidget('component', {
-	    itemId: 'system-report-view',
-	    scrollable: true,
-	    style: {
-		'background-color': '#23272a',
-		'white-space': 'pre',
-		'font-family': 'monospace',
-		padding: '5px'
-	    }
-	});
-
-	var reportWindow = Ext.create('Ext.window.Window', {
-	    title: gettext('System Report'),
-	    width: 1024,
-	    height: 600,
-	    layout: 'fit',
-	    modal: true,
-	    buttons: [
-		        '->',
-			{
-			    text: gettext('Download'),
-			    handler: function() {
-				var fileContent = reportWindow.getComponent('system-report-view').html;
-				var fileName = getReportFileName();
-
-				// Internet Explorer
-				if (window.navigator.msSaveOrOpenBlob) {
-				    navigator.msSaveOrOpenBlob(new Blob([fileContent]), fileName);
-				} else {
-				    var element = document.createElement('a');
-				    element.setAttribute('href', 'data:text/plain;charset=utf-8,'
-				      + encodeURIComponent(fileContent));
-				    element.setAttribute('download', fileName);
-				    element.style.display = 'none';
-				    document.body.appendChild(element);
-				    element.click();
-				    document.body.removeChild(element);
-				}
-			    }
-			}
-		],
-	    items: view
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/nodes/' + me.nodename + '/report',
-	    method: 'GET',
-	    waitMsgTarget: me,
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var report = Ext.htmlEncode(response.result.data);
-		reportWindow.show();
-		view.update(report);
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = '/nodes/' + me.nodename + '/subscription';
-
-	var render_status = function(value) {
-
-	    var message = me.getObjectValue('message');
-
-	    if (message) {
-		return value + ": " + message;
-	    }
-	    return value;
-	};
-
-	var rows = {
-	    productname: {
-		header: gettext('Type')
-	    },
-	    key: {
-		header: gettext('Subscription Key')
-	    },
-	    status: {
-		header: gettext('Status'),
-		renderer: render_status
-	    },
-	    message: {
-		visible: false
-	    },
-	    serverid: {
-		header: gettext('Server ID')
-	    },
-	    sockets: {
-		header: gettext('Sockets')
-	    },
-	    checktime: {
-		header: gettext('Last checked'),
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    nextduedate: {
-		header: gettext('Next due date')
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json' + baseurl,
-	    cwidth1: 170,
-	    tbar: [ 
-		{
-		    text: gettext('Upload Subscription Key'),
-		    handler: function() {
-			var win = Ext.create('PVE.node.SubscriptionKeyEdit', {
-			    url: '/api2/extjs/' + baseurl 
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		{
-		    text: gettext('Check'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    params: { force: 1 },
-			    url: baseurl,
-			    method: 'POST',
-			    waitMsgTarget: me,
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    },
-			    callback: reload
-			});
-		    }
-		},
-		{
-		    text: gettext('System Report'),
-		    handler: function() {
-			Proxmox.Utils.checked_command(function (){ me.showReport(); });
-		    }
-		}
-	    ],
-	    rows: rows,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CertificateView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCertificatesView',
-
-    onlineHelp: 'sysadmin_certificate_management',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    items: [
-	{
-	    xtype: 'pveCertView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveACMEView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.CertificateViewer', {
-    extend: 'Proxmox.window.Edit',
-
-    title: gettext('Certificate'),
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-    width: 800,
-    resizable: true,
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'filename'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Fingerprint'),
-	    name: 'fingerprint'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Issuer'),
-	    name: 'issuer'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject'),
-	    name: 'subject'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Valid Since'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notbefore'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Expires'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notafter'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject Alternative Names'),
-	    name: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    xtype: 'textarea',
-	    editable: false,
-	    grow: true,
-	    growMax: 200,
-	    fieldLabel: gettext('Certificate'),
-	    name: 'pem'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.cert) {
-	    throw "no cert given";
-	}
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/info';
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		if (Ext.isArray(response.result.data)) {
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.filename === me.cert) {
-			    me.setValues(item);
-			    return false;
-			}
-		    });
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CertUpload', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCertUpload',
-
-    title: gettext('Upload Custom Certificate'),
-    resizable: false,
-    isCreate: true,
-    submitText: gettext('Upload'),
-    method: 'POST',
-    width: 600,
-
-    apiCallDone: function(success, response, options) {
-	if (!success) {
-	    return;
-	}
-
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    items: [
-	{
-	    fieldLabel: gettext('Private Key (Optional)'),
-	    labelAlign: 'top',
-	    emptyText: gettext('No change'),
-	    name: 'key',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=key]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    autoEl: 'hr'
-	},
-	{
-	    fieldLabel: gettext('Certificate Chain'),
-	    labelAlign: 'top',
-	    allowBlank: false,
-	    name: 'certificates',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=certificates]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'restart',
-	    value: '1'
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'force',
-	    value: '1'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/custom';
-
-	me.callParent();
-    }
-});
-
-Ext.define('pve-certificate', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san' ],
-    idProperty: 'filename'
-});
-
-Ext.define('PVE.node.Certificates', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveCertView',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    text: gettext('Upload Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.CertUpload', {
-		    nodename: me.nodename
-		});
-		win.show();
-		win.on('destroy', me.reload, me);
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'deletebtn',
-	    text: gettext('Delete Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/certificates/custom?restart=1',
-		    method: 'DELETE',
-		    success: function(response, opt) {
-			var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-			Ext.getBody().mask(txt, ['pve-static-mask']);
-			// reload after 10 seconds automatically
-			Ext.defer(function() {
-			    window.location.reload(true);
-			}, 10000);
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    itemId: 'viewbtn',
-	    disabled: true,
-	    text: gettext('View Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		me.view_certificate();
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('File'),
-	    width: 150,
-	    dataIndex: 'filename'
-	},
-	{
-	    header: gettext('Issuer'),
-	    flex: 1,
-	    dataIndex: 'issuer'
-	},
-	{
-	    header: gettext('Subject'),
-	    flex: 1,
-	    dataIndex: 'subject'
-	},
-	{
-	    header: gettext('Valid Since'),
-	    width: 150,
-	    dataIndex: 'notbefore',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Expires'),
-	    width: 150,
-	    dataIndex: 'notafter',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Subject Alternative Names'),
-	    flex: 1,
-	    dataIndex: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    header: gettext('Fingerprint'),
-	    dataIndex: 'fingerprint',
-	    hidden: true
-	},
-	{
-	    header: gettext('PEM'),
-	    dataIndex: 'pem',
-	    hidden: true
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var rec = me.rstore.getById('pveproxy-ssl.pem');
-
-	me.down('#deletebtn').setDisabled(!rec);
-    },
-
-    view_certificate: function() {
-	var me = this;
-	var selection = me.getSelection();
-	if (!selection || selection.length < 1) {
-	    return;
-	}
-	var win = Ext.create('PVE.node.CertificateViewer', {
-	    cert: selection[0].data.filename,
-	    nodename : me.nodename
-	});
-	win.show();
-    },
-
-    listeners: {
-	itemdblclick: 'view_certificate'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'certs-' + me.nodename,
-	    model: 'pve-certificate',
-	    proxy: {
-		type: 'proxmox',
-		    url: '/api2/json/nodes/' + me.nodename + '/certificates/info'
-	    }
-	});
-
-	me.store = {
-	    type: 'diff',
-	    rstore: me.rstore
-	};
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-    }
-});
-Ext.define('PVE.node.ACMEEditor', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveACMEEditor',
-
-    subject: gettext('Domains'),
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    items: [
-		{
-		    xtype: 'textarea',
-		    fieldLabel: gettext('Domains'),
-		    emptyText: "domain1.example.com\ndomain2.example.com",
-		    name: 'domains'
-		}
-	    ],
-	    onGetValues: function(values) {
-		if (!values.domains) {
-		    return {
-			'delete': 'acme'
-		    };
-		}
-		var domains = values.domains.split(/\n/).join(';');
-		return {
-		    'acme': 'domains=' + domains
-		};
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		var res = PVE.Parser.parseACME(response.result.data.acme);
-		if (res) {
-		    res.domains = res.domains.join(' ');
-		    me.setValues(res);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACMEAccountCreate', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-    title: gettext('Register Account'),
-    isCreate: true,
-    method: 'POST',
-    submitText: gettext('Register'),
-    url: '/cluster/acme/account',
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'proxmoxComboGrid',
-	    name: 'directory',
-	    allowBlank: false,
-	    valueField: 'url',
-	    displayField: 'name',
-	    fieldLabel: gettext('ACME Directory'),
-	    store: {
-		autoLoad: true,
-		fields: ['name', 'url'],
-		idProperty: ['name'],
-		proxy: {
-		    type: 'proxmox',
-		    url: '/api2/json/cluster/acme/directories'
-		},
-		sorters: {
-		    property: 'name',
-		    order: 'ASC'
-		}
-	    },
-	    listConfig: {
-		columns: [
-		    {
-			header: gettext('Name'),
-			dataIndex: 'name',
-			flex: 1
-		    },
-		    {
-			header: gettext('URL'),
-			dataIndex: 'url',
-			flex: 1
-		    }
-		]
-	    },
-	    listeners: {
-		change: function(combogrid, value) {
-		    var me = this;
-		    if (!value) {
-			return;
-		    }
-
-		    var disp = me.up('window').down('#tos_url_display');
-		    var field = me.up('window').down('#tos_url');
-		    var checkbox = me.up('window').down('#tos_checkbox');
-
-		    disp.setValue(gettext('Loading'));
-		    field.setValue(undefined);
-		    checkbox.setValue(undefined);
-
-		    Proxmox.Utils.API2Request({
-			url: '/cluster/acme/tos',
-			method: 'GET',
-			params: {
-			    directory: value
-			},
-			success: function(response, opt) {
-			    me.up('window').down('#tos_url').setValue(response.result.data);
-			    me.up('window').down('#tos_url_display').setValue(response.result.data);
-			},
-			failure: function(response, opt) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-		}
-	    }
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'tos_url_display',
-	    fieldLabel: gettext('Terms of Service'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos_url_display'
-	},
-	{
-	    xtype: 'hidden',
-	    itemId: 'tos_url',
-	    name: 'tos_url'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'tos_checkbox',
-	    fieldLabel: gettext('Accept TOS'),
-	    submitValue: false,
-	    validateValue: function(value) {
-		if (value && this.checked) {
-		    return true;
-		}
-		return false;
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'contact',
-	    vtype: 'email',
-	    allowBlank: false,
-	    fieldLabel: gettext('E-Mail')
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.ACMEAccountView', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 600,
-    fieldDefaults: {
-	labelWidth: 140
-    },
-
-    title: gettext('Account'),
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('E-Mail'),
-	    name: 'email'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Created'),
-	    name: 'createdAt'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Status'),
-	    name: 'status'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Directory'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'directory'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Terms of Services'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.accountname) {
-	    throw "no account name defined";
-	}
-
-	me.url = '/cluster/acme/account/' + me.accountname;
-
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		var data = response.result.data;
-		data.email = data.account.contact[0];
-		data.createdAt = data.account.createdAt;
-		data.status = data.account.status;
-		me.setValues(data);
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACME', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveACMEView',
-
-    margin: '10 0 0 0',
-    title: 'ACME',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    itemId: 'edit',
-	    text: gettext('Edit Domains'),
-	    handler: function() {
-		this.up('grid').run_editor();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'createaccount',
-	    text: gettext('Register Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountCreate', {
-		    taskDone: function() {
-			me.load_account();
-			me.reload();
-		    }
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'viewaccount',
-	    text: gettext('View Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountView', {
-		    accountname: 'default'
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'order',
-	    text: gettext('Order Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-
-		Proxmox.Utils.API2Request({
-		    method: 'POST',
-		    params: {
-			force: 1
-		    },
-		    url: '/nodes/' + me.nodename + '/certificates/acme/certificate',
-		    success: function(response, opt) {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: response.result.data,
-			    taskDone: function(success) {
-				me.certificate_order_finished(success);
-			    }
-			});
-			win.show();
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ],
-
-    certificate_order_finished: function(success) {
-	if (!success) {
-	    return;
-	}
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    set_button_status: function() {
-	var me = this;
-
-	var account = !!me.account;
-	var acmeObj = PVE.Parser.parseACME(me.getObjectValue('acme'));
-	var domains = acmeObj ? acmeObj.domains.length : 0;
-
-	var order = me.down('#order');
-	order.setVisible(account);
-	order.setDisabled(!account || !domains);
-
-	me.down('#createaccount').setVisible(!account);
-	me.down('#viewaccount').setVisible(account);
-    },
-
-    load_account: function() {
-	var me = this;
-
-	// for now we only use the 'default' account
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/acme/account/default',
-	    success: function(response, opt) {
-		me.account = response.result.data;
-		me.set_button_status();
-	    },
-	    failure: function(response, opt) {
-		me.account = undefined;
-		me.set_button_status();
-	    }
-	});
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create(me.rows.acme.editor, me.editorConfig);
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    listeners: {
-	itemdblclick: 'run_editor'
-    },
-
-    // account data gets loaded here
-    account: undefined,
-
-    disableSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/api2/json/nodes/' + me.nodename + '/config';
-
-	me.editorConfig = {
-	    url: '/api2/extjs/nodes/' + me.nodename + '/config'
-	};
-	/*jslint confusion: true*/
-	/*acme is a string above*/
-	me.rows = {
-	    acme: {
-		defaultValue: '',
-		header: gettext('Domains'),
-		editor: 'PVE.node.ACMEEditor',
-		renderer: function(value) {
-		    var acmeObj = PVE.Parser.parseACME(value);
-		    if (acmeObj) {
-			return acmeObj.domains.join('<br>');
-		    }
-		    return Proxmox.Utils.noneText;
-		}
-	    }
-	};
-	/*jslint confusion: false*/
-
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-	me.load_account();
-    }
-});
-Ext.define('PVE.node.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.node.Config',
-
-    onlineHelp: 'chapter_system_administration',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/status",
-	    interval: 1000
-	});
-
-	var node_command = function(cmd) {
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/status',
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var actionBtn = Ext.create('Ext.Button', {
-	    text: gettext('Bulk Actions'),
-	    iconCls: 'fa fa-fw fa-ellipsis-v',
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    menu: new Ext.menu.Menu({
-		items: [
-		    {
-			text: gettext('Bulk Start'),
-			iconCls: 'fa fa-fw fa-play',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Start'),
-				btnText: gettext('Start'),
-				action: 'startall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Stop'),
-			iconCls: 'fa fa-fw fa-stop',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Stop'),
-				btnText: gettext('Stop'),
-				action: 'stopall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Migrate'),
-			iconCls: 'fa fa-fw fa-send-o',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Migrate'),
-				btnText: gettext('Migrate'),
-				action: 'migrateall'
-			    });
-			    win.show();
-			}
-		    }
-		]
-	    })
-	});
-
-	var restartBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reboot'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Reboot node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('reboot');
-	    },
-	    iconCls: 'fa fa-undo'
-	});
-
-	var shutdownBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Shutdown node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('shutdown');
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var shellBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.nodes['Sys.Console'],
-	    text: gettext('Shell'),
-	    consoleType: 'shell',
-	    nodename: nodename
-	});
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext('Node') + " '" + nodename + "'",
-	    hstateid: 'nodetab',
-	    defaults: { statusStore: me.statusStore },
-	    tbar: [ restartBtn, shutdownBtn, shellBtn, actionBtn]
-	});
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary',
-		    xtype: 'pveNodeSummary'
-		},
-		{
-		    title: gettext('Notes'),
-		    iconCls: 'fa fa-sticky-note-o',
-		    itemId: 'notes',
-		    xtype: 'pveNotesView'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Console']) {
-	    me.items.push(
-		{
-		    title: gettext('Shell'),
-		    iconCls: 'fa fa-terminal',
-		    itemId: 'jsconsole',
-		    xtype: 'pveNoVncConsole',
-		    consoleType: 'shell',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('System'),
-		    iconCls: 'fa fa-cogs',
-		    itemId: 'services',
-		    expandedOnInit: true,
-		    startOnlyServices: {
-			'pveproxy': true,
-			'pvedaemon': true,
-			'pve-cluster': true
-		    },
-		    nodename: nodename,
-		    onlineHelp: 'pve_service_daemons',
-		    xtype: 'proxmoxNodeServiceView'
-		},
-		{
-		    title: gettext('Network'),
-		    iconCls: 'fa fa-exchange',
-		    itemId: 'network',
-		    groups: ['services'],
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeNetworkView'
-		},
-		{
-		    title: gettext('Certificates'),
-		    iconCls: 'fa fa-certificate',
-		    itemId: 'certificates',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'pveCertificatesView'
-		},
-		{
-		    title: gettext('DNS'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'dns',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeDNSView'
-		},
-		{
-		    title: gettext('Hosts'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'hosts',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeHostsView'
-		},
-		{
-		    title: gettext('Time'),
-		    itemId: 'time',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'proxmoxNodeTimeView',
-		    iconCls: 'fa fa-clock-o'
-		});
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push({
-		title: 'Syslog',
-		iconCls: 'fa fa-list',
-		groups: ['services'],
-		disabled: !caps.nodes['Sys.Syslog'],
-		itemId: 'syslog',
-		xtype: 'proxmoxJournalView',
-		url: "/api2/extjs/nodes/" + nodename + "/journal"
-	    });
-
-	    if (caps.nodes['Sys.Modify']) {
-		me.items.push({
-		    title: gettext('Updates'),
-		    iconCls: 'fa fa-refresh',
-		    disabled: !caps.nodes['Sys.Console'],
-		    // do we want to link to system updates instead?
-		    itemId: 'apt',
-		    xtype: 'proxmoxNodeAPT',
-		    upgradeBtn: {
-			xtype: 'pveConsoleButton',
-			disabled: Proxmox.UserName !== 'root@pam',
-			text: gettext('Upgrade'),
-			consoleType: 'upgrade',
-			nodename: nodename
-		    },
-		    nodename: nodename
-		});
-	    }
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    iconCls: 'fa fa-shield',
-		    title: gettext('Firewall'),
-		    allow_iface: true,
-		    base_url: '/nodes/' + nodename + '/firewall/rules',
-		    list_refs_url: '/cluster/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    title: gettext('Options'),
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_host_specific_configuration',
-		    groups: ['firewall'],
-		    base_url: '/nodes/' + nodename + '/firewall/options',
-		    fwtype: 'node',
-		    itemId: 'firewall-options'
-		});
-	}
-
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Disks'),
-		    itemId: 'storage',
-		    expandedOnInit: true,
-		    iconCls: 'fa fa-hdd-o',
-		    xtype: 'pveNodeDiskList'
-		},
-		{
-		    title: 'LVM',
-		    itemId: 'lvm',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square',
-		    groups: ['storage'],
-		    xtype: 'pveLVMList'
-		},
-		{
-		    title: 'LVM-Thin',
-		    itemId: 'lvmthin',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square-o',
-		    groups: ['storage'],
-		    xtype: 'pveLVMThinList'
-		},
-		{
-		    title: Proxmox.Utils.directoryText,
-		    itemId: 'directory',
-		    onlineHelp: 'chapter_storage',
-		    iconCls: 'fa fa-folder',
-		    groups: ['storage'],
-		    xtype: 'pveDirectoryList'
-		},
-		{
-		    title: 'ZFS',
-		    itemId: 'zfs',
-		    onlineHelp: 'chapter_zfs',
-		    iconCls: 'fa fa-th-large',
-		    groups: ['storage'],
-		    xtype: 'pveZFSList'
-		},
-		{
-		    title: 'Ceph',
-		    itemId: 'ceph',
-		    iconCls: 'fa fa-ceph',
-		    xtype: 'pveNodeCephStatus'
-		},
-		{
-		    xtype: 'pveReplicaView',
-		    iconCls: 'fa fa-retweet',
-		    title: gettext('Replication'),
-		    itemId: 'replication'
-		},
-		{
-		    xtype: 'pveNodeCephConfigCrush',
-		    title: gettext('Configuration'),
-		    iconCls: 'fa fa-gear',
-		    groups: ['ceph'],
-		    itemId: 'ceph-config'
-		},
-		{
-		    xtype: 'pveNodeCephMonMgr',
-		    title: gettext('Monitor'),
-		    iconCls: 'fa fa-tv',
-		    groups: ['ceph'],
-		    itemId: 'ceph-monlist'
-		},
-		{
-		    xtype: 'pveNodeCephOsdTree',
-		    title: 'OSD',
-		    iconCls: 'fa fa-hdd-o',
-		    groups: ['ceph'],
-		    itemId: 'ceph-osdtree'
-		},
-		{
-		    xtype: 'pveNodeCephFSPanel',
-		    title: 'CephFS',
-		    iconCls: 'fa fa-folder',
-		    groups: ['ceph'],
-		    nodename: nodename,
-		    itemId: 'ceph-cephfspanel'
-		},
-		{
-		    xtype: 'pveNodeCephPoolList',
-		    title: 'Pools',
-		    iconCls: 'fa fa-sitemap',
-		    groups: ['ceph'],
-		    itemId: 'ceph-pools'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push(
-		{
-		    xtype: 'proxmoxLogView',
-		    title: gettext('Log'),
-		    iconCls: 'fa fa-list',
-		    groups: ['firewall'],
-		    onlineHelp: 'chapter_pve_firewall',
-		    url: '/api2/extjs/nodes/' + nodename + '/firewall/log',
-		    itemId: 'firewall-fwlog'
-		},
-		{
-		    title: gettext('Log'),
-		    itemId: 'ceph-log',
-		    iconCls: 'fa fa-list',
-		    groups: ['ceph'],
-		    onlineHelp: 'chapter_pveceph',
-		    xtype: 'cephLogView',
-		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
-		    nodename: nodename
-		});
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Task History'),
-		iconCls: 'fa fa-list',
-		itemId: 'tasks',
-		nodename: nodename,
-		xtype: 'proxmoxNodeTasks'
-	    },
-	    {
-		title: gettext('Subscription'),
-		iconCls: 'fa fa-support',
-		itemId: 'support',
-		xtype: 'pveNodeSubscription',
-		nodename: nodename
-	    }
-	);
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var uptimerec = s.data.get('uptime');
-	    var powermgmt = uptimerec ? uptimerec.data.value : false;
-	    if (!caps.nodes['Sys.PowerMgmt']) {
-		powermgmt = false;
-	    }
-	    restartBtn.setDisabled(!powermgmt);
-	    shutdownBtn.setDisabled(!powermgmt);
-	    shellBtn.setDisabled(!powermgmt);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    vmtype: undefined,
-    nodename: undefined,
-    vmid: undefined,
-
-    viewModel: {
-	data: {
-	    vmid: undefined,
-	    nodename: undefined,
-	    vmtype: undefined,
-	    running: false,
-	    qemu: {
-		onlineHelp: 'qm_migration',
-		commonName: 'VM'
-	    },
-	    lxc: {
-		onlineHelp: 'pct_migration',
-		commonName: 'CT'
-	    },
-	    migration: {
-		possible: true,
-		preconditions: [],
-		'with-local-disks': 0,
-		mode: undefined,
-		allowedNodes: undefined
-	    }
-
-	},
-
-	formulas: {
-	    setMigrationMode: function(get) {
-		if (get('running')){
-		    if (get('vmtype') === 'qemu') {
-			return gettext('Online');
-		    } else {
-			return gettext('Restart Mode');
-		    }
-		} else {
-		    return gettext('Offline');
-		}
-	    },
-	    setStorageselectorHidden: function(get) {
-		    if (get('migration.with-local-disks') && get('running')) {
-			return false;
-		    } else {
-			return true;
-		    }
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=formPanel]': {
-		validityChange: function(panel, isValid) {
-		    this.getViewModel().set('migration.possible', isValid);
-		    this.checkMigratePreconditions();
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this,
-		vm = view.getViewModel();
-
-	    if (!view.nodename) {
-		throw "missing custom view config: nodename";
-	    }
-	    vm.set('nodename', view.nodename);
-
-	    if (!view.vmid) {
-		throw "missing custom view config: vmid";
-	    }
-	    vm.set('vmid', view.vmid);
-
-	    if (!view.vmtype) {
-		throw "missing custom view config: vmtype";
-	    }
-	    vm.set('vmtype', view.vmtype);
-
-
-	    view.setTitle(
-		Ext.String.format('{0} {1}{2}', gettext('Migrate'), vm.get(view.vmtype).commonName, view.vmid)
-	    );
-	    me.lookup('proxmoxHelpButton').setHelpConfig({
-		onlineHelp: vm.get(view.vmtype).onlineHelp
-	    });
-	    me.checkMigratePreconditions();
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	onTargetChange: function (nodeSelector) {
-	    //Always display the storages of the currently seleceted migration target
-	    this.lookup('pveDiskStorageSelector').setNodename(nodeSelector.value);
-	    this.checkMigratePreconditions();
-	},
-
-	startMigration: function() {
-	    var me = this,
-		view = me.getView(),
-		vm = me.getViewModel();
-
-	    var values = me.lookup('formPanel').getValues();
-	    var params = {
-		target: values.target
-	    };
-
-	    if (vm.get('migration.mode')) {
-		params[vm.get('migration.mode')] = 1;
-	    }
-	    if (vm.get('migration.with-local-disks')) {
-		params['with-local-disks'] = 1;
-	    }
-	    //only submit targetstorage if vm is running, storage migration to different storage is only possible online
-	    if (vm.get('migration.with-local-disks') && vm.get('running')) {
-		params.targetstorage = values.targetstorage;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		waitMsgTarget: view,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var extraTitle = Ext.String.format(' ({0} ---> {1})', vm.get('nodename'), params.target);
-
-		    Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid,
-			extraTitle: extraTitle
-		    }).show();
-
-		    view.close();
-		}
-	    });
-
-	},
-
-	checkMigratePreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel();
-
-
-	    var vmrec = PVE.data.ResourceStore.findRecord('vmid', vm.get('vmid'),
-			0, false, false, true);
-	    if (vmrec && vmrec.data && vmrec.data.running) {
-		vm.set('running', true);
-	    }
-
-	    if (vm.get('vmtype') === 'qemu') {
-		me.checkQemuPreconditions();
-	    } else {
-		me.checkLxcPreconditions();
-	    }
-	    me.lookup('pveNodeSelector').disallowedNodes = [vm.get('nodename')];
-
-	    // Only allow nodes where the local storage is available in case of offline migration
-	    // where storage migration is not possible
-	    me.lookup('pveNodeSelector').allowedNodes = vm.get('migration.allowedNodes');
-
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	checkQemuPreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel(),
-		migrateStats;
-
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'online');
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		method: 'GET',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    migrateStats = response.result.data;
-		    if (migrateStats.running) {
-			vm.set('running', true);
-		    }
-		    // Get migration object from viewmodel to prevent
-		    // to many bind callbacks
-		    var migration = vm.get('migration');
-		    migration.preconditions = [];
-
-		    if (migrateStats.allowed_nodes) {
-			migration.allowedNodes = migrateStats.allowed_nodes;
-			var target = me.lookup('pveNodeSelector').value;
-			if (target.length && !migrateStats.allowed_nodes.includes(target)) {
-			    let disallowed = migrateStats.not_allowed_nodes[target];
-			    let missing_storages = disallowed.unavailable_storages.join(', ');
-
-			    migration.possible = false;
-			    migration.preconditions.push({
-				text: 'Storage (' + missing_storages + ') not available on selected target. ' +
-				  'Start VM to use live storage migration or select other target node',
-				severity: 'error'
-			    });
-			}
-		    }
-
-		    if (migrateStats.local_resources.length) {
-			migration.possible = false;
-			migration.preconditions.push({
-			    text: 'Can\'t migrate VM with local resources: '+ migrateStats.local_resources.join(', '),
-			    severity: 'error'
-			});
-		    }
-
-		    if (migrateStats.local_disks.length) {
-
-			migrateStats.local_disks.forEach(function (disk) {
-			    if (disk.cdrom && disk.cdrom === 1) {
-				migration.possible = false;
-				migration.preconditions.push({
-				    text: "Can't migrate VM with local CD/DVD",
-				    severity: 'error'
-				});
-
-			    } else if (!disk.referenced_in_config) {
-				migration.possible = false;
-				migration.preconditions.push({
-				    text: 'Found not referenced/unused disk via storage: '+ disk.volid,
-				    severity: 'error'
-				});
-			    } else {
-				migration['with-local-disks'] = 1;
-				migration.preconditions.push({
-				    text:'Migration with local disk might take long: ' + disk.volid
-					+' (' + PVE.Utils.render_size(disk.size) + ')',
-				    severity: 'warning'
-				});
-			    }
-			});
-
-		    }
-
-		    vm.set('migration', migration);
-
-		}
-	    });
-	},
-	checkLxcPreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel();
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'restart');
-	    }
-	}
-
-
-    },
-
-    width: 600,
-    modal: true,
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    border: false,
-    items: [
-	{
-	    xtype: 'form',
-	    reference: 'formPanel',
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'column'
-	    },
-	    items: [
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'displayfield',
-			name: 'source',
-			fieldLabel: gettext('Source node'),
-			bind: {
-			    value: '{nodename}'
-			}
-		    },
-		    {
-			xtype: 'displayfield',
-			reference: 'migrationMode',
-			fieldLabel: gettext('Mode'),
-			bind: {
-			    value: '{setMigrationMode}'
-			}
-		    }]
-		},
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'pveNodeSelector',
-			reference: 'pveNodeSelector',
-			name: 'target',
-			fieldLabel: gettext('Target node'),
-			allowBlank: false,
-			disallowedNodes: undefined,
-			onlineValidator: true,
-			listeners: {
-			    change: 'onTargetChange'
-			}
-		    },
-		    {
-			    xtype: 'pveStorageSelector',
-			    reference: 'pveDiskStorageSelector',
-			    name: 'targetstorage',
-			    fieldLabel: gettext('Target storage'),
-			    storageContent: 'images',
-			    bind: {
-				hidden: '{setStorageselectorHidden}'
-			    }
-		    }]
-		}
-	    ]
-	},
-	{
-	    xtype: 'gridpanel',
-	    reference: 'preconditionGrid',
-	    selectable: false,
-	    flex: 1,
-	    columns: [{
-		text: '',
-		dataIndex: 'severity',
-		renderer: function(v) {
-		    switch (v) {
-			case 'warning':
-			    return '<i class="fa fa-exclamation-triangle warning"></i> ';
-			case 'error':
-			    return '<i class="fa fa-times critical"></i>';
-			default:
-			    return v;
-		    }
-		},
-		width: 35
-	    },
-	    {
-		text: 'Info',
-		dataIndex: 'text',
-		cellWrap: true,
-		flex: 1
-	    }],
-	    bind: {
-		hidden: '{!migration.preconditions.length}',
-		store: {
-		    fields: ['severity','text'],
-		    data: '{migration.preconditions}'
-		}
-	    }
-	}
-
-    ],
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    reference: 'proxmoxHelpButton',
-	    onlineHelp: 'pct_migration',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	},
-	'->',
-	{
-	    xtype: 'button',
-	    reference: 'submitButton',
-	    text: gettext('Migrate'),
-	    handler: 'startMigration',
-	    bind: {
-		disabled: '{!migration.possible}'
-	    }
-	}
-    ]
-});
-Ext.define('PVE.window.BulkAction', {
-    extend: 'Ext.window.Window',
-
-    resizable: true,
-    width: 800,
-    modal: true,
-    layout: {
-	type: 'fit'
-    },
-    border: false,
-
-    // the action to be set
-    // currently there are
-    // startall
-    // migrateall
-    // stopall
-    action: undefined,
-
-    submit: function(params) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.action,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		me.hide();
-		win.on('destroy', function() {
-		    me.close();
-		});
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.action) {
-	    throw "no action specified";
-	}
-
-	if (!me.btnText) {
-	    throw "no button text specified";
-	}
-
-	if (!me.title) {
-	    throw "no title specified";
-	}
-
-	var items = [];
-
-	if (me.action === 'migrateall') {
-	    /*jslint confusion: true*/
-	    /*value is string and number*/
-	    items.push(
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'target',
-		    disallowedNodes: [me.nodename],
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'maxworkers',
-		    minValue: 1,
-		    maxValue: 100,
-		    value: 1,
-		    fieldLabel: gettext('Parallel jobs'),
-		    allowBlank: false
-		},
-		{
-		    itemId: 'lxcwarning',
-		    xtype: 'displayfield',
-		    userCls: 'pve-hint',
-		    value: 'Warning: Running CTs will be migrated in Restart Mode.',
-		    hidden: true // only visible if running container chosen
-		}
-	    );
-	    /*jslint confusion: false*/
-	} else if (me.action === 'startall') {
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'force',
-		value: 1
-	    });
-	}
-
-	items.push({
-	    xtype: 'vmselector',
-	    itemId: 'vms',
-	    name: 'vms',
-	    flex: 1,
-	    height: 300,
-	    selectAll: true,
-	    allowBlank: false,
-	    nodename: me.nodename,
-	    action: me.action,
-	    listeners: {
-		selectionchange: function(vmselector, records) {
-		    if (me.action == 'migrateall') {
-			var showWarning = records.some(function(item) {
-			    return (item.data.type == 'lxc' &&
-				item.data.status == 'running');
-			});
-			me.down('#lxcwarning').setVisible(showWarning);
-		    }
-		}
-	    }
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    fieldDefaults: {
-		labelWidth: 300,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: me.btnText,
-	    handler: function() {
-		form.isValid();
-		me.submit(form.getValues());
-	    }
-	});
-
-	Ext.apply(me, {
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-
-	form.on('validitychange', function() {
-	    var valid = form.isValid();
-	    submitBtn.setDisabled(!valid);
-	});
-	form.isValid();
-    }
-});
-Ext.define('PVE.window.Clone', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    isTemplate: false,
-
-    onlineHelp: 'qm_copy_and_clone',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=cloneform]': {
-		validitychange: 'disableSubmit'
-	    }
-	},
-	disableSubmit: function(form) {
-	    this.lookupReference('submitBtn').setDisabled(!form.isValid());
-	}
-    },
-
-    statics: {
-	// display a snapshot selector only if needed
-	wrap: function(nodename, vmid, isTemplate, guestType) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var snapshotList = response.result.data;
-		    var hasSnapshots = snapshotList.length === 1 &&
-			snapshotList[0].name === 'current' ? false : true;
-
-		    Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: isTemplate,
-			hasSnapshots: hasSnapshots
-		    }).show();
-		}
-	    });
-	}
-    },
-
-    create_clone: function(values) {
-	var me = this;
-
-	var params = { newid: values.newvmid };
-
-	if (values.snapname && values.snapname !== 'current') {
-	    params.snapname = values.snapname;
-	}
-
-	if (values.pool) {
-	    params.pool = values.pool;
-	}
-
-	if (values.name) {
-	    if (me.guestType === 'lxc') {
-		params.hostname = values.name;
-	    } else {
-		params.name = values.name;
-	    }
-	}
-
-	if (values.target) {
-	    params.target = values.target;
-	}
-
-	if (values.clonemode === 'copy') {
-	    params.full = 1;
-	    if (values.hdstorage) {
-		params.storage = values.hdstorage;
-		if (values.diskformat && me.guestType !== 'lxc') {
-		    params.format = values.diskformat;
-		}
-	    }
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/clone',
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-
-    },
-
-    // disable the Storage selector when clone mode is linked clone
-    updateVisibility: function() {
-	var me = this;
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-	var disksel = me.lookup('diskselector');
-	disksel.setDisabled(clonemode === 'clone');
-    },
-
-    // add to the list of valid nodes each node where
-    // all the VM disks are available
-    verifyFeature: function() {
-	var me = this;
-
-	var snapname = me.lookupReference('snapshotsel').getValue();
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-
-	var params = { feature: clonemode };
-	if (snapname !== 'current') {
-	    params.snapname = snapname;
-	}
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/feature',
-	    params: params,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		me.lookupReference('submitBtn').setDisabled(true);
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var res = response.result.data;
-
-		me.lookupReference('targetsel').allowedNodes = res.nodes;
-		me.lookupReference('targetsel').validate();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.snapname) {
-	    me.snapname = 'current';
-	}
-
-	if (!me.guestType) {
-	    throw "no Guest Type specified";
-	}
-
-	var titletext = me.guestType === 'lxc' ? 'CT' : 'VM';
-	if (me.isTemplate) {
-	    titletext += ' Template';
-	}
-	me.title = "Clone " + titletext + " " + me.vmid;
-
-	var col1 = [];
-	var col2 = [];
-
-	col1.push({
-	    xtype: 'pveNodeSelector',
-	    name: 'target',
-	    reference: 'targetsel',
-	    fieldLabel: gettext('Target node'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    onlineValidator: true,
-	    listeners: {
-		change: function(f, value) {
-		    me.lookupReference('hdstorage').setTargetNode(value);
-		}
-	    }
-	});
-
-	var modelist = [['copy', gettext('Full Clone')]];
-	if (me.isTemplate) {
-	    modelist.push(['clone', gettext('Linked Clone')]);
-	}
-
-	col1.push({
-	    xtype: 'pveGuestIDSelector',
-	    name: 'newvmid',
-	    guestType: me.guestType,
-	    value: '',
-	    loadNextFreeID: true,
-	    validateExists: false
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'name',
-	    allowBlank: true,
-	    fieldLabel: me.guestType === 'lxc' ? gettext('Hostname') : gettext('Name')
-	},
-	{
-	    xtype: 'pvePoolSelector',
-	    fieldLabel: gettext('Resource Pool'),
-	    name: 'pool',
-	    value: '',
-	    allowBlank: true
-	}
-	);
-
-	col2.push({
-	    xtype: 'proxmoxKVComboBox',
-	    fieldLabel: gettext('Mode'),
-	    name: 'clonemode',
-	    reference: 'clonemodesel',
-	    allowBlank: false,
-	    hidden: !me.isTemplate,
-	    value: me.isTemplate ? 'clone' : 'copy',
-		    comboItems: modelist,
-		    listeners: {
-			change: function(t, value) {
-			    me.updateVisibility();
-			    me.verifyFeature();
-			}
-		    }
-	},
-	{
-	    xtype: 'PVE.form.SnapshotSelector',
-	    name: 'snapname',
-	    reference: 'snapshotsel',
-	    fieldLabel: gettext('Snapshot'),
-	    nodename: me.nodename,
-	    guestType: me.guestType,
-	    vmid: me.vmid,
-	    hidden: me.isTemplate || !me.hasSnapshots ? true : false,
-	    disabled: false,
-	    allowBlank: false,
-	    value : me.snapname,
-	    listeners: {
-		change: function(f, value) {
-		    me.verifyFeature();
-		}
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    reference: 'diskselector',
-	    nodename: me.nodename,
-	    autoSelect: false,
-	    hideSize: true,
-	    hideSelection: true,
-	    storageLabel: gettext('Target Storage'),
-	    allowBlank: true,
-	    storageContent: me.guestType === 'qemu' ? 'images' : 'rootdir',
-	    emptyText: gettext('Same as source'),
-	    disabled: me.isTemplate ? true : false // because default mode is clone for templates
-	});
-
-	var formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    reference: 'cloneform',
-	    border: false,
-	    layout: 'column',
-	    defaultType: 'container',
-	    columns: 2,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: col1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: col2
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 600,
-	    height: 250,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ {
-		xtype: 'proxmoxHelpButton',
-		listenToGlobalEvent: false,
-		hidden: false,
-		onlineHelp: me.onlineHelp
-	    },
-	    '->',
-	    {
-		reference: 'submitBtn',
-		text: gettext('Clone'),
-		disabled: true,
-		handler: function() {
-		    var cloneForm = me.lookupReference('cloneform');
-		    if (cloneForm.isValid()) {
-			me.create_clone(cloneForm.getValues());
-		    }
-		}
-	    } ],
-	    items: [ formPanel ]
-	});
-
-	me.callParent();
-
-	me.verifyFeature();
-    }
-});
-Ext.define('PVE.qemu.Monitor', {
-    extend: 'Ext.panel.Panel',
-
-    alias: 'widget.pveQemuMonitor',
-
-    maxLines: 500,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var history = [];
-	var histNum = -1;
-	var lines = [];
-
-	var textbox = Ext.createWidget('panel', {
-	    region: 'center',
-	    xtype: 'panel',
-	    autoScroll: true,
-	    border: true,
-	    margins: '5 5 5 5',
-	    bodyStyle: 'font-family: monospace;'
-	});
-
-	var scrollToEnd = function() {
-	    var el = textbox.getTargetEl();
-	    var dom = Ext.getDom(el);
-
-	    var clientHeight = dom.clientHeight;
-	    // BrowserBug: clientHeight reports 0 in IE9 StrictMode
-            // Instead we are using offsetHeight and hardcoding borders
-            if (Ext.isIE9 && Ext.isStrict) {
-		clientHeight = dom.offsetHeight + 2;
-            }
-	    dom.scrollTop = dom.scrollHeight - clientHeight;
-	};
-
-	var refresh = function() {
-	    textbox.update('<pre>' + lines.join('\n') + '</pre>');
-	    scrollToEnd();
-	};
-
-	var addLine = function(line) {
-	    lines.push(line);
-	    if (lines.length > me.maxLines) {
-		lines.shift();
-	    }
-	};
-
-	var executeCmd = function(cmd) {
-	    addLine("# " + Ext.htmlEncode(cmd));
-	    if (cmd) {
-		history.unshift(cmd);
-		if (history.length > 20) {
-		    history.splice(20);
-		}
-	    }
-	    histNum = -1;
-
-	    refresh();
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor",
-		method: 'POST',
-		waitMsgTarget: me,
-		success: function(response, opts) {
-		    var res = response.result.data; 
-		    Ext.Array.each(res.split('\n'), function(line) {
-			addLine(Ext.htmlEncode(line));
-		    });
-		    refresh();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		textbox,
-		{
-		    region: 'south',
-		    margins:'0 5 5 5',
-		    border: false,
-		    xtype: 'textfield',
-		    name: 'cmd',
-		    value: '',
-		    fieldStyle: 'font-family: monospace;',
-		    allowBlank: true,
-		    listeners: {
-			afterrender: function(f) {
-			    f.focus(false);
-			    addLine("Type 'help' for help.");
-			    refresh();
-			},
-			specialkey: function(f, e) {
-			    var key = e.getKey();
-			    switch (key) {
-				case e.ENTER:
-				    var cmd = f.getValue();
-				    f.setValue('');
-				    executeCmd(cmd);
-				    break;
-				case e.PAGE_UP:
-				    textbox.scrollBy(0, -0.9*textbox.getHeight(), false);
-				    break;
-				case e.PAGE_DOWN:
-				    textbox.scrollBy(0, 0.9*textbox.getHeight(), false);
-				    break;
-				case e.UP:
-				    if (histNum + 1 < history.length) {
-					f.setValue(history[++histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				case e.DOWN:
-				    if (histNum > 0) {
-					f.setValue(history[--histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				default:
-				    break;
-			    }
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		show: function() {
-		    var field = me.query('textfield[name="cmd"]')[0];
-		    field.focus(false, true);
-		}
-	    }
-	});		
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveQemuSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 330,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 330,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.qemu.OSTypeInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuOSTypePanel',
-    onlineHelp: 'qm_os_settings',
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'combobox[name=osbase]': {
-		change: 'onOSBaseChange'
-	    },
-	    'combobox[name=ostype]': {
-		afterrender: 'onOSTypeChange',
-		change: 'onOSTypeChange'
-	    }
-	},
-	onOSBaseChange: function(field, value) {
-	    this.lookup('ostype').getStore().setData(PVE.Utils.kvm_ostypes[value]);
-	},
-	onOSTypeChange: function(field) {
-	    var me = this, ostype = field.getValue();
-	    if (!me.getView().insideWizard) {
-		return;
-	    }
-	    var targetValues = PVE.qemu.OSDefaults.getDefaults(ostype);
-
-	    me.setWidget('pveBusSelector', targetValues.busType);
-	    me.setWidget('pveNetworkCardSelector', targetValues.networkCard);
-	    var scsihw = targetValues.scsihw || '__default__';
-	    this.getViewModel().set('current.scsihw', scsihw);
-	},
-	setWidget: function(widget, newValue) {
-	    // changing a widget is safe only if ComponentQuery.query returns us
-	    // a single value array
-	    var widgets = Ext.ComponentQuery.query('pveQemuCreateWizard ' + widget);
-	    if (widgets.length === 1) {
-		widgets[0].setValue(newValue);
-	    } else {
-		throw 'non unique widget :' + widget + ' in Wizard';
-	    }
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	/*jslint confusion: true */
-	me.items = [
-	    {
-		xtype: 'displayfield',
-		value: gettext('Guest OS') + ':',
-		hidden: !me.insideWizard
-	    },
-	    {
-		xtype: 'combobox',
-		submitValue: false,
-		name: 'osbase',
-		fieldLabel: gettext('Type'),
-		editable: false,
-		queryMode: 'local',
-		value: 'Linux',
-		store: Object.keys(PVE.Utils.kvm_ostypes)
-	    },
-	    {
-		xtype: 'combobox',
-		name: 'ostype',
-		reference: 'ostype',
-		fieldLabel: gettext('Version'),
-		value: 'l26',
-		allowBlank : false,
-		editable: false,
-		queryMode: 'local',
-		valueField: 'val',
-		displayField: 'desc',
-		store: {
-		    fields: ['desc', 'val'],
-		    data: PVE.Utils.kvm_ostypes.Linux,
-		    listeners: {
-			datachanged: function (store) {
-			    var ostype = me.lookup('ostype');
-			    var old_val = ostype.getValue();
-			    if (!me.insideWizard && old_val && store.find('val', old_val) != -1) {
-				ostype.setValue(old_val);
-			    } else {
-				ostype.setValue(store.getAt(0));
-			    }
-			}
-		    }
-		}
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.OSTypeEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: 'OS Type',
-
-    items: [{ xtype: 'pveQemuOSTypePanel' }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var value = response.result.data.ostype || 'other';
-		var osinfo = PVE.Utils.get_kvm_osinfo(value);
-		me.setValues({ ostype: value, osbase: osinfo.base });
-	    }
-	});
-    }
-});
-/*
- * This class holds performance *recommended* settings for the PVE Qemu wizards
- * the *mandatory* settings are set in the PVE::QemuServer
- * config_to_command sub
- * We store this here until we get the data from the API server
-*/
-
-// this is how you would add an hypothetic FreeBSD > 10 entry
-//
-//virtio-blk is stable but virtIO net still
-//   problematic as of 10.3
-// see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059
-//	addOS({
-//	    parent: 'generic', // inherits defaults
-//	    pveOS: 'freebsd10', // must match a radiofield in OSTypeEdit.js
-//	    busType: 'virtio' // must match a pveBusController value
-//			    // networkCard muss match a pveNetworkCardSelector
-
-
-Ext.define('PVE.qemu.OSDefaults', {
-    singleton: true, // will also force creation when loaded
-
-    constructor: function() {
-	var me = this;
-
-	var addOS = function(settings) {
-		if (me.hasOwnProperty(settings.parent)) {
-		    var child = Ext.clone(me[settings.parent]);
-		    me[settings.pveOS] = Ext.apply(child, settings);
-
-		} else {
-		    throw("Could not find your genitor");
-		}
-	    };
-
-	// default values
-	me.generic = {
-	    busType: 'ide',
-	    networkCard: 'e1000',
-	    busPriority: {
-		    ide: 4,
-		    sata: 3,
-		    scsi: 2,
-		    virtio: 1
-	    },
-	    scsihw: 'virtio-scsi-pci'
-	};
-
-       // virtio-net is in kernel since 2.6.25
-       // virtio-scsi since 3.2 but backported in RHEL with 2.6 kernel
-	addOS({
-	    pveOS: 'l26',
-	    parent : 'generic',
-	    busType: 'scsi',
-	    busPriority: {
-		    scsi: 4,
-		    virtio: 3,
-		    sata: 2,
-		    ide: 1
-	    },
-	    networkCard: 'virtio'
-	});
-
-	// recommandation from http://wiki.qemu.org/Windows2000
-	addOS({
-	    pveOS: 'w2k',
-	    parent : 'generic',
-	    networkCard: 'rtl8139',
-	    scsihw: ''
-	});
-	// https://pve.proxmox.com/wiki/Windows_XP_Guest_Notes
-	addOS({
-	    pveOS: 'wxp',
-	    parent : 'w2k'
-	});
-
-	me.getDefaults = function(ostype) {
-	    if (PVE.qemu.OSDefaults[ostype]) {
-		return PVE.qemu.OSDefaults[ostype];
-	    } else {
-		return PVE.qemu.OSDefaults.generic;
-	    }
-	};
-    }
-});
-Ext.define('PVE.qemu.ProcessorInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuProcessorPanel',
-    onlineHelp: 'qm_cpu',
-
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateCores: function() {
-	    var me = this.getView();
-	    var sockets = me.down('field[name=sockets]').getValue();
-	    var cores = me.down('field[name=cores]').getValue();
-	    me.down('field[name=totalcores]').setValue(sockets*cores);
-	    var vcpus = me.down('field[name=vcpus]');
-	    vcpus.setMaxValue(sockets*cores);
-	    vcpus.setEmptyText(sockets*cores);
-	    vcpus.validate();
-	},
-
-	control: {
-	    'field[name=sockets]': {
-		change: 'updateCores'
-	    },
-	    'field[name=cores]': {
-		change: 'updateCores'
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (Array.isArray(values['delete'])) {
-	    values['delete'] = values['delete'].join(',');
-	}
-
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	// build the cpu options:
-	me.cpu.cputype = values.cputype;
-
-	if (values.flags) {
-	    me.cpu.flags = values.flags;
-	} else {
-	    delete me.cpu.flags;
-	}
-
-	delete values.cputype;
-	delete values.flags;
-	var cpustring = PVE.Parser.printQemuCpu(me.cpu);
-
-	// remove cputype delete request:
-	var del = values['delete'];
-	delete values['delete'];
-	if (del) {
-	    del = del.split(',');
-	    Ext.Array.remove(del, 'cputype');
-	} else {
-	    del = [];
-	}
-
-	if (cpustring) {
-	    values.cpu = cpustring;
-	} else {
-	    del.push('cpu');
-	}
-
-	var delarr = del.join(',');
-	if (delarr) {
-	    values['delete'] = delarr;
-	}
-
-	return values;
-    },
-
-    cpu: {},
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'sockets',
-	    minValue: 1,
-	    maxValue: 4,
-	    value: '1',
-	    fieldLabel: gettext('Sockets'),
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cores',
-	    minValue: 1,
-	    maxValue: 128,
-	    value: '1',
-	    fieldLabel: gettext('Cores'),
-	    allowBlank: false
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'CPUModelSelector',
-	    name: 'cputype',
-	    value: '__default__',
-	    fieldLabel: gettext('Type')
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Total cores'),
-	    name: 'totalcores',
-	    value: '1'
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'vcpus',
-	    minValue: 1,
-	    maxValue: 1,
-	    value: '',
-	    fieldLabel: gettext('VCPUs'),
-	    deleteEmpty: true,
-	    allowBlank: true,
-	    emptyText: '1'
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    maxValue: 128, // api maximum
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    minValue: 8,
-	    maxValue: 500000,
-	    value: '1024',
-	    deleteEmpty: true,
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Enable NUMA'),
-	    name: 'numa',
-	    uncheckedValue: 0
-	}
-    ],
-    advancedColumnB: [
-	{
-	    xtype: 'label',
-	    text: 'Extra CPU Flags:'
-	},
-	{
-	    xtype: 'vmcpuflagselector',
-	    name: 'flags'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.ProcessorEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 700,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.ProcessorInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Processors'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		var value = data.cpu;
-		if (value) {
-		    var cpu = PVE.Parser.parseQemuCpu(value);
-		    ipanel.cpu = cpu;
-		    data.cputype = cpu.cputype;
-		    if (cpu.flags) {
-			data.flags = cpu.flags;
-		    }
-		}
-		me.setValues(data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuBootOrderPanel',
-    vmconfig: {}, // store loaded vm config
-
-    bootdisk: undefined,
-    selection: [],
-    list: [],
-    comboboxes: [],
-
-    isBootDisk: function(value) {
-	return PVE.Utils.bus_match.test(value);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-	var order = me.vmconfig.boot || 'cdn';
-	me.bootdisk = me.vmconfig.bootdisk || undefined;
-
-	// get the first 3 characters
-	// ignore the rest (there should never be more than 3)
-	me.selection = order.split('').slice(0,3);
-
-	// build bootdev list
-	me.list = [];
-	Ext.Object.each(me.vmconfig, function(key, value) {
-	    if (me.isBootDisk(key) &&
-		!(/media=cdrom/).test(value)) {
-		me.list.push([key, "Disk '" + key + "'"]);
-	    }
-	});
-
-	me.list.push(['d', 'CD-ROM']);
-	me.list.push(['n', gettext('Network')]);
-	me.list.push(['__none__', Proxmox.Utils.noneText]);
-
-	me.recomputeList();
-
-	me.comboboxes.forEach(function(box) {
-	    box.resetOriginalValue();
-	});
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var order = me.selection.join('');
-	var res = { boot: order };
-
-	if  (me.bootdisk && order.indexOf('c') !== -1) {
-	    res.bootdisk = me.bootdisk;
-	} else {
-	    res['delete'] = 'bootdisk';
-	}
-
-	return res;
-    },
-
-    recomputeSelection: function(combobox, newVal, oldVal) {
-	var me = this.up('#inputpanel');
-	me.selection = [];
-	me.comboboxes.forEach(function(item) {
-	    var val = item.getValue();
-
-	    // when selecting an already selected item,
-	    // switch it around
-	    if ((val === newVal || (me.isBootDisk(val) && me.isBootDisk(newVal))) &&
-		item.name !== combobox.name &&
-		newVal !== '__none__') {
-		// swap items
-		val = oldVal;
-	    }
-
-	    // push 'c','d' or 'n' in the array
-	    if (me.isBootDisk(val)) {
-		me.selection.push('c');
-		me.bootdisk = val;
-	    } else if (val === 'd' ||
-		       val === 'n') {
-		me.selection.push(val);
-	    }
-	});
-
-	me.recomputeList();
-    },
-
-    recomputeList: function(){
-	var me = this;
-	// set the correct values in the kvcomboboxes
-	var cnt = 0;
-	me.comboboxes.forEach(function(item) {
-	    if (cnt === 0) {
-		// never show 'none' on first combobox
-		item.store.loadData(me.list.slice(0, me.list.length-1));
-	    } else {
-		item.store.loadData(me.list);
-	    }
-	    item.suspendEvent('change');
-	    if (cnt < me.selection.length) {
-		item.setValue((me.selection[cnt] !== 'c')?me.selection[cnt]:me.bootdisk);
-	    } else if (cnt === 0){
-		item.setValue('');
-	    } else {
-		item.setValue('__none__');
-	    }
-	    cnt++;
-	    item.resumeEvent('change');
-	    item.validate();
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	// this has to be done here, because of
-	// the way our inputPanel class handles items
-	me.comboboxes = [
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 1",
-		labelWidth: 120,
-		name: 'bd1',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 2",
-		labelWidth: 120,
-		name: 'bd2',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 3",
-		labelWidth: 120,
-		name: 'bd3',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    })
-	];
-	Ext.apply(me, { items: me.comboboxes });
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    items: [{
-	xtype: 'pveQemuBootOrderPanel',
-	itemId: 'inputpanel'
-    }],
-
-    subject: gettext('Boot Order'),
-
-    initComponent : function() {
-	var me = this;
-	me.callParent();
-	me.load({
-	    success: function(response, options) {
-		me.down('#inputpanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuMemoryPanel',
-    onlineHelp: 'qm_memory',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = {};
-
-	res.memory = values.memory;
-	res.balloon = values.balloon;
-
-	if (!values.ballooning) {
-	    res.balloon = 0;
-	    res['delete'] = 'shares';
-	} else if (values.memory === values.balloon) {
-	    delete res.balloon;
-	    res['delete'] = 'balloon,shares';
-	} else if (Ext.isDefined(values.shares) && (values.shares !== "")) {
-	    res.shares = values.shares;
-	} else {
-	    res['delete'] = "shares";
-	}
-
-	return res;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var labelWidth = 160;
-
-	me.items= [
-	    {
-		xtype: 'pveMemoryField',
-		labelWidth: labelWidth,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		name: 'memory',
-		minValue: 1,
-		step: 32,
-		hotplug: me.hotplug,
-		listeners: {
-		    change: function(f, value, old) {
-			var bf = me.down('field[name=balloon]');
-			var balloon = bf.getValue();
-			bf.setMaxValue(value);
-			if (balloon === old) {
-			    bf.setValue(value);
-			}
-			bf.validate();
-		    }
-		}
-	    }
-	];
-
-	me.advancedItems= [
-	    {
-		xtype: 'pveMemoryField',
-		name: 'balloon',
-		minValue: 1,
-		step: 32,
-		fieldLabel: gettext('Minimum memory') + ' (MiB)',
-		hotplug: me.hotplug,
-		labelWidth: labelWidth,
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			var memory = me.down('field[name=memory]').getValue();
-			var shares = me.down('field[name=shares]');
-			shares.setDisabled(value === memory);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'shares',
-		disabled: true,
-		minValue: 0,
-		maxValue: 50000,
-		value: '',
-		step: 10,
-		fieldLabel: gettext('Shares'),
-		labelWidth: labelWidth,
-		allowBlank: true,
-		emptyText: Proxmox.Utils.defaultText + ' (1000)',
-		submitEmptyText: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		labelWidth: labelWidth,
-		value: '1',
-		name: 'ballooning',
-		fieldLabel: gettext('Ballooning Device'),
-		listeners: {
-		    change: function(f, value) {
-			var bf = me.down('field[name=balloon]');
-			var shares = me.down('field[name=shares]');
-			var memory = me.down('field[name=memory]');
-			bf.setDisabled(!value);
-			shares.setDisabled(!value || (bf.getValue() === memory.getValue()));
-		    }
-		}
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = me.items;
-	    me.items = undefined;
-	    me.advancedColumn1 = me.advancedItems;
-	    me.advancedItems = undefined;
-	}
-	me.callParent();
-    }
-
-});
-
-Ext.define('PVE.qemu.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent: function() {
-	var me = this;
-
-	var memoryhotplug;
-	if(me.hotplug) {
-	    Ext.each(me.hotplug.split(','), function(el) {
-		if (el === 'memory') {
-		    memoryhotplug = 1;
-	        }
-	    });
-	}
-
-	var ipanel = Ext.create('PVE.qemu.MemoryInputPanel', {
-	    hotplug: memoryhotplug
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: [ ipanel ],
-	    // uncomment the following to use the async configiguration API
-	    // backgroundDelay: 5, 
-	    width: 400
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-
-		var values = {
-		    ballooning: data.balloon === 0 ? '0' : '1',
-		    shares: data.shares,
-		    memory: data.memory || '512',
-		    balloon: data.balloon > 0 ? data.balloon : (data.memory || '512')
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuNetworkInputPanel',
-    onlineHelp: 'qm_network_device',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	me.network.model = values.model;
-	if (values.nonetwork) {
-	    return {};
-	} else {
-	    me.network.bridge = values.bridge;
-	    me.network.tag = values.tag;
-	    me.network.firewall = values.firewall;
-	}
-	me.network.macaddr = values.macaddr;
-	me.network.disconnect = values.disconnect;
-	me.network.queues = values.queues;
-
-	if (values.rate) {
-	    me.network.rate = values.rate;
-	} else {
-	    delete me.network.rate;
-	}
-
-	var params = {};
-
-	params[me.confid] = PVE.Parser.printQemuNetwork(me.network);
-
-	return params;
-    },
-
-    setNetwork: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data) {
-	    data.networkmode = data.bridge ? 'bridge' : 'nat';
-	} else {
-	    data = {};
-	    data.networkmode = 'bridge';
-	}
-	me.network = data;
-	
-	me.setValues(me.network);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.bridgesel.setNodename(nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.network = {};
-	me.confid = 'net0';
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.bridgesel = Ext.create('PVE.form.BridgeSelector', {
-	    name: 'bridge',
-	    fieldLabel: gettext('Bridge'),
-	    nodename: me.nodename,
-	    autoSelect: true,
-	    allowBlank: false
-	});
-
-	me.column1 = [
-	    me.bridgesel,
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		checked: (me.insideWizard || me.isCreate)
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Disconnect'),
-		name: 'disconnect'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1.unshift({
-		xtype: 'checkbox',
-		name: 'nonetwork',
-		inputValue: 'none',
-		boxLabel: gettext('No network device'),
-		listeners: {
-		    change: function(cb, value) {
-			var fields = [
-			    'disconnect',
-			    'bridge',
-			    'tag',
-			    'firewall',
-			    'model',
-			    'macaddr',
-			    'rate',
-			    'queues'
-			];
-			fields.forEach(function(fieldname) {
-			    me.down('field[name='+fieldname+']').setDisabled(value);
-			});
-			me.down('field[name=bridge]').validate();
-		    }
-		}
-	    });
-	    me.column2.unshift({
-		xtype: 'displayfield'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'pveNetworkCardSelector',
-		name: 'model',
-		fieldLabel: gettext('Model'),
-		value: PVE.qemu.OSDefaults.generic.networkCard,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'macaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		allowBlank: true,
-		emptyText: 'auto'
-	    });
-	me.advancedColumn2 = [
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: '',
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'queues',
-		fieldLabel: 'Multiqueue',
-		minValue: 1,
-		maxValue: 8,
-		value: '',
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";	    
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.NetworkInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: me.isCreate
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Device'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		if (!me.isCreate) {
-		    var value = me.vmconfig[me.confid];
-		    var network = PVE.Parser.parseQemuNetwork(me.confid, value);
-		    if (!network) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse network options');
-			me.close();
-			return;
-		    }
-		    ipanel.setNetwork(me.confid, network);
-		} else {
-		    for (i = 0; i < 100; i++) {
-			confid = 'net' + i.toString();
-			if (!Ext.isDefined(me.vmconfig[confid])) {
-			    me.confid = confid;
-			    break;
-			}
-		    }
-		    ipanel.setNetwork(me.confid);		    
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Smbios1InputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.PVE.qemu.Smbios1InputPanel',
-
-    insideWizard: false,
-
-    smbios1: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {
-	    smbios1: PVE.Parser.printQemuSmbios1(values)
-	};
-
-	return params;
-    },
-
-    setSmbios1: function(data) {
-	var me = this;
-
-	me.smbios1 = data;
-	
-	me.setValues(me.smbios1);
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: 'UUID',
-	    regex: /^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$/,
-	    name: 'uuid'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Manufacturer'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'manufacturer'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Product'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'product'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Version'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'version'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Serial'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'serial'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: 'SKU',
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'sku'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Family'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'family'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.Smbios1Edit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.Smbios1InputPanel', {});
-
-	Ext.applyIf(me, {
-	    subject: gettext('SMBIOS settings (type1)'),
-	    width: 450,
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		var value = me.vmconfig.smbios1;
-		if (value) {
-		    var data = PVE.Parser.parseQemuSmbios1(value);
-		    if (!data) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse smbios options');
-			me.close();
-			return;
-		    }
-		    ipanel.setSmbios1(data);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.CDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuCDInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || (values.controller + values.deviceid);
-	
-	me.drive.media = 'cdrom';
-	if (values.mediaType === 'iso') {
-	    me.drive.file = values.cdimage;
-	} else if (values.mediaType === 'cdrom') {
-	    me.drive.file = 'cdrom';
-	} else {
-	    me.drive.file = 'none';
-	}
-
-	var params = {};
-		
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	
-	return params;	
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig, 'cdrom');
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	var values = {};
-	if (drive.file === 'cdrom') {
-	    values.mediaType = 'cdrom';
-	} else if (drive.file === 'none') {
-	    values.mediaType = 'none';
-	} else {
-	    values.mediaType = 'iso';
-	    var match = drive.file.match(/^([^:]+):/);
-	    if (match) {
-		values.cdstorage = match[1];
-		values.cdimage = drive.file;
-	    }
-	}
-
-	me.drive = drive;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.cdstoragesel.setNodename(nodename);
-	me.cdfilesel.setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	var items = [];
-
-	if (!me.confid) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		noVirtIO: true
-	    });
-	    items.push(me.bussel);
-	}
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'iso',
-	    boxLabel: gettext('Use CD/DVD disc image file (iso)'),
-	    checked: true,
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=cdstorage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').validate();
-		}
-	    }
-	});
-
-	me.cdfilesel = Ext.create('PVE.form.FileSelector', {
-	    name: 'cdimage',
-	    nodename: me.nodename,
-	    storageContent: 'iso',
-	    fieldLabel: gettext('ISO image'),
-	    labelAlign: 'right',
-	    allowBlank: false
-	});
-	
-	me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
-	    name: 'cdstorage',
-	    nodename: me.nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'iso',
-	    allowBlank: false,
-	    autoSelect: me.insideWizard,
-	    listeners: {
-		change: function(f, value) {
-		    me.cdfilesel.setStorage(value);
-		}
-	    }
-	});
-
-	items.push(me.cdstoragesel);
-	items.push(me.cdfilesel);
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'cdrom',
-	    boxLabel: gettext('Use physical CD/DVD Drive')
-	});
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'none',
-	    boxLabel: gettext('Do not use any media')
-	});
-
-	me.items = items;
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.CDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'CD/DVD Drive',
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-	
-	me.load({
-	    success:  function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert('Error', 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-/* 'change' property is assigned a string and then a function */
-Ext.define('PVE.qemu.HDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuHDInputPanel',
-    onlineHelp: 'qm_hard_disk',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onControllerChange: function(field) {
-	    var value = field.getValue();
-
-	    var allowIOthread = value.match(/^(virtio|scsi)/);
-	    this.lookup('iothread').setDisabled(!allowIOthread);
-	    if (!allowIOthread) {
-		this.lookup('iothread').setValue(false);
-	    }
-
-	    var virtio = value.match(/^virtio/);
-	    this.lookup('discard').setDisabled(virtio);
-	    this.lookup('ssd').setDisabled(virtio);
-	    if (virtio) {
-		this.lookup('discard').setValue(false);
-		this.lookup('ssd').setValue(false);
-	    }
-
-	    this.lookup('scsiController').setVisible(value.match(/^scsi/));
-	},
-
-	control: {
-	    'field[name=controller]': {
-		change: 'onControllerChange',
-		afterrender: 'onControllerChange'
-	    },
-	    'field[name=iothread]' : {
-		change: function(f, value) {
-		    if (!this.getView().insideWizard) {
-			return;
-		    }
-		    var vmScsiType = value ? 'virtio-scsi-single': 'virtio-scsi-pci';
-		    this.lookupReference('scsiController').setValue(vmScsiType);
-		}
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {};
-	var confid = me.confid || (values.controller + values.deviceid);
-
-	if (me.unused) {
-	    me.drive.file = me.vmconfig[values.unusedId];
-	    confid = values.controller + values.deviceid;
-	} else if (me.isCreate) {
-	    if (values.hdimage) {
-		me.drive.file = values.hdimage;
-	    } else {
-		me.drive.file = values.hdstorage + ":" + values.disksize;
-	    }
-	    me.drive.format = values.diskformat;
-	}
-
-	if (values.nobackup) {
-	    me.drive.backup = 'no';
-	} else {
-	    delete me.drive.backup;
-	}
-
-	if (values.noreplicate) {
-	    me.drive.replicate = 'no';
-	} else {
-	    delete me.drive.replicate;
-	}
-
-	if (values.discard) {
-	    me.drive.discard = 'on';
-	} else {
-	    delete me.drive.discard;
-	}
-
-	if (values.ssd) {
-	    me.drive.ssd = 'on';
-	} else {
-	    delete me.drive.ssd;
-	}
-
-	if (values.iothread) {
-	    me.drive.iothread = 'on';
-	} else {
-	    delete me.drive.iothread;
-	}
-
-	if (values.cache) {
-	    me.drive.cache = values.cache;
-	} else {
-	    delete me.drive.cache;
-	}
-
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            if (values[name]) {
-                me.drive[name] = values[name];
-            } else {
-                delete me.drive[name];
-            }
-            var burst_name = name + '_max';
-            if (values[burst_name] && values[name]) {
-                me.drive[burst_name] = values[burst_name];
-            } else {
-                delete me.drive[burst_name];
-            }
-        });
-
-
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
-	return params;
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	me.vmconfig = vmconfig;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig);
-	    me.scsiController.setValue(vmconfig.scsihw);
-	}
-	if (me.unusedDisks) {
-	    var disklist = [];
-	    Ext.Object.each(vmconfig, function(key, value) {
-		if (key.match(/^unused\d+$/)) {
-		    disklist.push([key, value]);
-		}
-	    });
-	    me.unusedDisks.store.loadData(disklist);
-	    me.unusedDisks.setValue(me.confid);
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	me.drive = drive;
-
-	var values = {};
-	var match = drive.file.match(/^([^:]+):/);
-	if (match) {
-	    values.hdstorage = match[1];
-	}
-
-	values.hdimage = drive.file;
-	values.nobackup = !PVE.Parser.parseBoolean(drive.backup, 1);
-	values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
-	values.diskformat = drive.format || 'raw';
-	values.cache = drive.cache || '__default__';
-	values.discard = (drive.discard === 'on');
-	values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-	values.iothread = PVE.Parser.parseBoolean(drive.iothread);
-
-	values.mbps_rd = drive.mbps_rd;
-	values.mbps_wr = drive.mbps_wr;
-	values.iops_rd = drive.iops_rd;
-	values.iops_wr = drive.iops_wr;
-	values.mbps_rd_max = drive.mbps_rd_max;
-	values.mbps_wr_max = drive.mbps_wr_max;
-	values.iops_rd_max = drive.iops_rd_max;
-	values.iops_wr_max = drive.iops_wr_max;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var labelWidth = 140;
-
-	me.drive = {};
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.advancedColumn1 = [];
-	me.advancedColumn2 = [];
-
-	if (!me.confid || me.unused) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
-	    });
-	    me.column1.push(me.bussel);
-
-	    me.scsiController = Ext.create('Ext.form.field.Display', {
-		fieldLabel: gettext('SCSI Controller'),
-		reference: 'scsiController',
-		bind: me.insideWizard ? {
-		    value: '{current.scsihw}'
-		} : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		submitValue: false,
-		hidden: true
-	    });
-	    me.column1.push(me.scsiController);
-	}
-
-	if (me.unused) {
-	    me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
-		name: 'unusedId',
-		fieldLabel: gettext('Disk image'),
-		matchFieldWidth: false,
-		listConfig: {
-		    width: 350
-		},
-		data: [],
-		allowBlank: false
-	    });
-	    me.column1.push(me.unusedDisks);
-	} else if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveDiskStorageSelector',
-		storageContent: 'images',
-		name: 'disk',
-		nodename: me.nodename,
-		autoSelect: me.insideWizard
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'textfield',
-		disabled: true,
-		submitValue: false,
-		fieldLabel: gettext('Disk image'),
-                name: 'hdimage'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'CacheTypeSelector',
-		name: 'cache',
-		value: '__default__',
-		fieldLabel: gettext('Cache')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Discard'),
-		disabled: me.confid && me.confid.match(/^virtio/),
-		reference: 'discard',
-		name: 'discard'
-	    }
-	);
-
-	me.advancedColumn1.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && me.confid.match(/^virtio/),
-		fieldLabel: gettext('SSD emulation'),
-		labelWidth: labelWidth,
-		name: 'ssd',
-		reference: 'ssd'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && !me.confid.match(/^(virtio|scsi)/),
-		fieldLabel: 'IO thread',
-		labelWidth: labelWidth,
-		reference: 'iothread',
-		name: 'iothread'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    }
-	);
-
-	me.advancedColumn2.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('No backup'),
-		labelWidth: labelWidth,
-		name: 'nobackup'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Skip replication'),
-		labelWidth: labelWidth,
-		name: 'noreplicate'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-/*jslint confusion: false */
-
-Ext.define('PVE.qemu.HDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    backgroundDelay: 5,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    me.subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
-	} else {
-           me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
-	}
-
-	me.items = [ ipanel ];
-
-	me.callParent();
-	/*jslint confusion: true*/
-	/* 'data' is assigned an empty array in same file, and here we
-	 * use it like an object
-	 */
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-	/*jslint confusion: false*/
-    }
-});
-Ext.define('PVE.window.HDResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 140,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 250,
-	    height: 150,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-Ext.define('PVE.window.HDMove', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-
-    move_disk: function(disk, storage, format, delete_disk) {
-	var me = this;
-	var qemu = (me.type === 'qemu');
-	var params = {};
-	params.storage = storage;
-	params[qemu ? 'disk':'volume'] = disk;
-
-	if (format && qemu) {
-	    params.format = format;
-	}
-
-	if (delete_disk) {
-	    params['delete'] = 1;
-	}
-
-	var url = '/nodes/' + me.nodename + '/' + me.type + '/' + me.vmid + '/';
-	url += qemu ? 'move_disk' : 'move_volume';
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: url,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		win.on('destroy', function() { me.close(); });
-	    }
-	});
-
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var diskarray = [];
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    me.type = 'qemu';
-	}
-
-	var qemu = (me.type === 'qemu');
-
-        var items = [
-            {
-                xtype: 'displayfield',
-                name: qemu ? 'disk' : 'volume',
-                value: me.disk,
-                fieldLabel: qemu ? gettext('Disk') : gettext('Mount Point'),
-                vtype: 'StorageId',
-                allowBlank: false
-            }
-        ];
-
-	items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    storageLabel: gettext('Target Storage'),
-	    nodename: me.nodename,
-	    storageContent: qemu ? 'images' : 'rootdir',
-	    hideSize: true
-	});
-
-	items.push({
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Delete source'),
-	    name: 'deleteDisk',
-	    uncheckedValue: 0,
-	    checked: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = qemu ? gettext("Move disk") : gettext('Move Volume');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: me.title,
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.move_disk(me.disk, values.hdstorage, values.diskformat,
-				 values.deleteDisk);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 350,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	me.mon(me.formPanel, 'validitychange', function(fp, isValid) {
-	    submitBtn.setDisabled(!isValid);
-	});
-
-	me.formPanel.isValid();
-    }
-});
-Ext.define('PVE.qemu.EFIDiskInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveEFIDiskInputPanel',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = 'efidisk0';
-
-	if (values.hdimage) {
-	    me.drive.file = values.hdimage;
-	} else {
-	    // we use 1 here, because for efi the size gets overridden from the backend
-	    me.drive.file = values.hdstorage + ":1";
-	}
-
-	me.drive.format = values.diskformat;
-	var params = {};
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items= [];
-
-	me.items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    nodename: me.nodename,
-	    hideSize: true
-	});
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.EFIDiskEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-    subject: gettext('EFI Disk'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveEFIDiskInputPanel',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: true
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.DisplayInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveDisplayInputPanel',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values, 'type');
-	if (ret === '') {
-	    return {
-		'delete': 'vga'
-	    };
-	}
-	return {
-	    vga: ret
-	};
-    },
-
-    items: [{
-	name: 'type',
-	xtype: 'proxmoxKVComboBox',
-	value: '__default__',
-	deleteEmpty: false,
-	fieldLabel: gettext('Graphic card'),
-	comboItems: PVE.Utils.kvm_vga_driver_array(),
-	validator: function() {
-	    var v = this.getValue();
-	    var cfg = this.up('proxmoxWindowEdit').vmconfig || {};
-
-	    if (v.match(/^serial\d+$/) && (!cfg[v] || cfg[v] !== 'socket')) {
-		var fmt = gettext("Serial interface '{0}' is not correctly configured.");
-		return Ext.String.format(fmt, v);
-	    }
-	    return true;
-	},
-	listeners: {
-	    change: function(cb, val) {
-		var me = this.up('panel');
-		if (!val) {
-		    return;
-		}
-		var disable = false;
-		var emptyText = Proxmox.Utils.defaultText;
-		switch (val) {
-		    case "cirrus":
-			emptyText = "4";
-			break;
-		    case "std":
-			emptyText = "16";
-			break;
-		    case "qxl":
-		    case "qxl2":
-		    case "qxl3":
-		    case "qxl4":
-			emptyText = "16";
-			break;
-		    case "vmware":
-			emptyText = "16";
-			break;
-		    case "none":
-		    case "serial0":
-		    case "serial1":
-		    case "serial2":
-		    case "serial3":
-			emptyText = 'N/A';
-			disable = true;
-			break;
-		    case "virtio":
-			emptyText = "256";
-			break;
-		    default:
-			break;
-		}
-		var memoryfield = me.down('field[name=memory]');
-		memoryfield.setEmptyText(emptyText);
-		memoryfield.setDisabled(disable);
-	    }
-	}
-    },{
-	xtype: 'proxmoxintegerfield',
-	emptyText: Proxmox.Utils.defaultText,
-	fieldLabel: gettext('Memory') + ' (MiB)',
-	minValue: 4,
-	maxValue: 512,
-	step: 4,
-	name: 'memory'
-    }]
-});
-
-Ext.define('PVE.qemu.DisplayEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Display'),
-    width: 350,
-
-    items: [{
-	xtype: 'pveDisplayInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-		var vga = me.vmconfig.vga || '__default__';
-		me.setValues(PVE.Parser.parsePropertyString(vga, 'type'));
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.KeyboardEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('Keyboard Layout'),
-	    items: {
-		xtype: 'VNCKeyboardSelector',
-		name: 'keyboard',
-		value: '__default__',
-		fieldLabel: gettext('Keyboard Layout')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.HardwareView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.HardwareView'],
-
-    onlineHelp: 'qm_virtual_machines_settings',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-	var iconCls = rowdef.iconCls;
-	var icon = '';
-	var txt = (rowdef.header || key);
-
-	metaData.tdAttr = "valign=middle";
-
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') { 
-		var value = me.getObjectValue(key, '', false);
-		if (value === '') {
-		    value = me.getObjectValue(key, '', true);
-		}
-		if (value.match(/vm-.*-cloudinit/)) {
-		    metaData.tdCls = 'pve-itype-icon-cloud';
-		    return rowdef.cloudheader;
-		} else if (value.match(/media=cdrom/)) {
-		    metaData.tdCls = 'pve-itype-icon-cdrom';
-		    return rowdef.cdheader;
-		}
-	    }
-	} else if (iconCls) {
-	    icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
-	    metaData.tdCls += " pve-itype-fa";
-	}
-	return icon + txt;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	/*jslint confusion: true */
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
-		never_delete: true,
-		defaultValue: '512',
-		tdCls: 'pve-itype-icon-memory',
-		group: 2,
-		multiKey: ['memory', 'balloon', 'shares'],
-		renderer: function(value, metaData, record, ri, ci, store, pending) {
-		    var res = '';
-
-		    var max = me.getObjectValue('memory', 512, pending);
-		    var balloon =  me.getObjectValue('balloon', undefined, pending);
-		    var shares = me.getObjectValue('shares', undefined, pending);
-
-		    res  = Proxmox.Utils.format_size(max*1024*1024);
-
-		    if (balloon !== undefined && balloon > 0) {
-			res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
-
-			if (shares) {
-			    res += ' [shares=' + shares +']';
-			}
-		    } else if (balloon === 0) {
-			res += ' [balloon=0]';
-		    }
-		    return res;
-		}
-	    },
-	    sockets: {
-		header: gettext('Processors'),
-		never_delete: true,
-		editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? 
-		    'PVE.qemu.ProcessorEdit' : undefined,
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		defaultValue: '1',
-		multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
-		renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
-
-		    var sockets = me.getObjectValue('sockets', 1, pending);
-		    var model = me.getObjectValue('cpu', undefined, pending);
-		    var cores = me.getObjectValue('cores', 1, pending);
-		    var numa = me.getObjectValue('numa', undefined, pending);
-		    var vcpus = me.getObjectValue('vcpus', undefined, pending);
-		    var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
-		    var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
-
-		    var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
-			sockets*cores, sockets, cores);
-
-		    if (model) {
-			res += ' [' + model + ']';
-		    }
-
-		    if (numa) {
-			res += ' [numa=' + numa +']';
-		    }
-
-		    if (vcpus) {
-			res += ' [vcpus=' + vcpus +']';
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit +']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits +']';
-		    }
-
-		    return res;
-		}
-	    },
-	    bios: {
-		header: 'BIOS',
-		group: 4,
-		never_delete: true,
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.BiosEdit' : undefined,
-		defaultValue: '',
-		iconCls: 'microchip',
-		renderer: PVE.Utils.render_qemu_bios
-	    },
-	    vga: {
-		header: gettext('Display'),
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
-		never_delete: true,
-		tdCls: 'pve-itype-icon-display',
-		group:5,
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_vga_driver		
-	    },
-	    machine: {
-		header: gettext('Machine'),
-		editor: caps.vms['VM.Config.HWType'] ?  {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Machine'),
-		    width: 350,
-		    items: [{
-			xtype: 'proxmoxKVComboBox',
-			name: 'machine',
-			value: '__default__',
-			fieldLabel: gettext('Machine'),
-			comboItems: [
-			    ['__default__', PVE.Utils.render_qemu_machine('')],
-			    ['q35', 'q35']
-			]
-		    }]} : undefined,
-		iconCls: 'cogs',
-		never_delete: true,
-		group: 6,
-		defaultValue: '',
-		renderer: PVE.Utils.render_qemu_machine
-	    },
-	    scsihw: {
-		header: gettext('SCSI Controller'),
-		iconCls: 'database',
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.ScsiHwEdit' : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		group: 7,
-		never_delete: true,
-		defaultValue: ''
-	    },
-	    cores: {
-		visible: false
-	    },
-	    cpu: {
-		visible: false
-	    },
-	    numa: {
-		visible: false
-	    },
-	    balloon: {
-		visible: false
-	    },
-	    hotplug: {
-		visible: false
-	    },
-	    vcpus: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    shares: {
-		visible: false
-	    }
-	};
-	/*jslint confusion: false */
-
-	PVE.Utils.forEachBus(undefined, function(type, id) {
-	    var confid = type + id;
-	    rows[confid] = {
-		group: 10,
-		tdCls: 'pve-itype-icon-storage',
-		editor: 'PVE.qemu.HDEdit',
-		never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-		header: gettext('Hard Disk') + ' (' + confid +')',
-		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
-		cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
-	    };
-	});
-	for (i = 0; i < 32; i++) {
-	    confid = "net" + i.toString();
-	    rows[confid] = {
-		group: 15,
-		order: i,
-		tdCls: 'pve-itype-icon-network',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
-		never_delete: caps.vms['VM.Config.Network'] ? false : true,
-		header: gettext('Network Device') + ' (' + confid +')'
-	    };
-	}
-	rows.efidisk0 = {
-	    group: 20,
-	    tdCls: 'pve-itype-icon-storage',
-	    editor: null,
-	    never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-	    header: gettext('EFI Disk')
-	};
-	for (i = 0; i < 5; i++) {
-	    confid = "usb" + i.toString();
-	    rows[confid] = {
-		group: 25,
-		order: i,
-		tdCls: 'pve-itype-icon-usb',
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('USB Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "hostpci" + i.toString();
-	    rows[confid] = {
-		group: 30,
-		order: i,
-		tdCls: 'pve-itype-icon-pci',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
-		header: gettext('PCI Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "serial" + i.toString();
-	    rows[confid] = {
-		group: 35,
-		order: i,
-		tdCls: 'pve-itype-icon-serial',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('Serial Port') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 256; i++) {
-	    rows["unused" + i.toString()] = {
-		group: 99,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
-		header: gettext('Unused Disk') + ' ' + i.toString()
-	    };
-	}
-
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-	    
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var editor = rowdef.editor;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') {
-		var value = me.getObjectValue(rec.data.key, '', true); 
-		if (value.match(/vm-.*-cloudinit/)) {
-		    return;
-		} else if (value.match(/media=cdrom/)) {
-		    editor = 'PVE.qemu.CDEdit';
-		} else if (!diskCap) {
-		    return;
-		}
-	    }
-
-	    var win;
-
-	    if (Ext.isString(editor)) {
-		win = Ext.create(editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var run_resize = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var run_move = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_editor
-        });
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_move
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    defaultText: gettext('Remove'),
-	    altText: gettext('Detach'),
-	    selModel: sm,
-	    disabled: true,
-	    dangerous: true,
-	    RESTMethod: 'PUT',
-	    confirmMsg: function(rec) {
-		var warn = gettext('Are you sure you want to remove entry {0}');
-		if (this.text === this.altText) {
-		    warn = gettext('Are you sure you want to detach entry {0}');
-		}
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		if (entry.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: function(b, e, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: b.RESTMethod,
-		    params: {
-			'delete': rec.data.key
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			if (b.RESTMethod === 'POST') {
-			    var upid = response.result.data;
-			    var win = Ext.create('Proxmox.window.TaskProgress', {
-				upid: upid,
-				listeners: {
-				    destroy: function () {
-					me.reload();
-				    }
-				}
-			    });
-			    win.show();
-			}
-		    }
-		});
-	    },
-	    listeners: {
-		render: function(btn) {
-		    // hack: calculate an optimal button width on first display
-		    // to prevent the whole toolbar to move when we switch
-		    // between the "Remove" and "Detach" labels
-		    var def = btn.getSize().width;
-
-		    btn.setText(btn.altText);
-		    var alt = btn.getSize().width;
-
-		    btn.setText(btn.defaultText);
-
-		    var optimal = alt > def ? alt : def;
-		    btn.setSize({ width: optimal });
-		}
-	    }
-	});
-
-	var revert_btn = new Proxmox.button.Button({
-	    text: gettext('Revert'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(b, e, rec) {
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: {
-			'revert': revert
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var efidisk_menuitem = Ext.create('Ext.menu.Item',{
-	    text: gettext('EFI Disk'),
-	    iconCls: 'pve-itype-icon-storage',
-	    disabled: !caps.vms['VM.Config.Disk'],
-	    handler: function() {
-
-		var rstoredata = me.rstore.getData().map;
-		// check if ovmf is configured
-		if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') {
-		    var win = Ext.create('PVE.qemu.EFIDiskEdit', {
-			url: '/api2/extjs/' + baseurl,
-			pveSelNode: me.pveSelNode
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		} else {
-		    Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
-		}
-
-	    }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    // disable button when we have an efidisk already
-	    // disable is ok in this case, because you can instantly
-	    // see that there is already one
-	    efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined);
-	    // en/disable usb add button
-	    var usbcount = 0;
-	    var pcicount = 0;
-	    var hasCloudInit = false;
-	    me.rstore.getData().items.forEach(function(item){
-		if (/^usb\d+/.test(item.id)) {
-		    usbcount++;
-		} else if (/^hostpci\d+/.test(item.id)) {
-		    pcicount++;
-		}
-		if (!hasCloudInit && /vm-.*-cloudinit/.test(item.data.value)) {
-		    hasCloudInit = true;
-		}
-	    });
-
-	    // heuristic only for disabling some stuff, the backend has the final word.
-	    var noSysConsolePerm = !caps.nodes['Sys.Console'];
-
-	    me.down('#addusb').setDisabled(noSysConsolePerm || (usbcount >= 5));
-	    me.down('#addpci').setDisabled(noSysConsolePerm || (pcicount >= 4));
-	    me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
-
-	    if (!rec) {
-		remove_btn.disable();
-		edit_btn.disable();
-		resize_btn.disable();
-		move_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isCDRom = (value && !!value.toString().match(/media=cdrom/));
-	    var isUnusedDisk = key.match(/^unused\d+/);
-	    var isUsedDisk = !isUnusedDisk &&
-		rowdef.tdCls == 'pve-itype-icon-storage' &&
-		!isCDRom;
-
-	    var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
-
-	    var isEfi = (key === 'efidisk0');
-
-	    remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true) || (isUnusedDisk && !diskCap));
-	    remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
-	    remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
-
-	    edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit || (!isCDRom && !diskCap));
-
-	    resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    move_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    revert_btn.setDisabled(!pending);
-
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
-	    interval: 5000,
-	    selModel: sm,
-	    run_editor: run_editor,
-	    tbar: [ 
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Hard Disk'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.HDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CD/DVD Drive'),
-				iconCls: 'pve-itype-icon-cdrom',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Network Device'),
-				iconCls: 'pve-itype-icon-network',
-				disabled: !caps.vms['VM.Config.Network'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.NetworkEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode,
-					isCreate: true
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    efidisk_menuitem,
-			    {
-				text: gettext('USB Device'),
-				itemId: 'addusb',
-				iconCls: 'pve-itype-icon-usb',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.USBEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('PCI Device'),
-				itemId: 'addpci',
-				iconCls: 'pve-itype-icon-pci',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.PCIEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Serial Port'),
-				itemId: 'addserial',
-				iconCls: 'pve-itype-icon-serial',
-				disabled: !caps.vms['VM.Config.Options'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.SerialEdit', {
-					url: '/api2/extjs/' + baseurl
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CloudInit Drive'),
-				itemId: 'addci',
-				iconCls: 'pve-itype-icon-cloud',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CIDriveEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn,
-		edit_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-	me.mon(me.rstore, 'refresh', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.qemu.ScsiHwEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('SCSI Controller Type'),
-	    items: {
-		xtype: 'pveScsiHwSelector',
-		name: 'scsihw',
-		value: '__default__',
-		fieldLabel: gettext('Type')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.BiosEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveQemuBiosEdit',
-
-    initComponent : function() {
-	var me = this;
-
-	var EFIHint = Ext.createWidget({
-	    xtype: 'displayfield', //submitValue is false, so we don't get submitted
-	    userCls: 'pve-hint',
-	    value: 'You need to add an EFI disk for storing the ' +
-	    'EFI settings. See the online help for details.',
-	    hidden: true
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'BIOS',
-	    items: [ {
-		xtype: 'pveQemuBiosSelector',
-		onlineHelp: 'qm_bios_and_uefi',
-		name: 'bios',
-		value: '__default__',
-		fieldLabel: 'BIOS',
-		listeners: {
-		    'change' : function(field, newValue) {
-			if (newValue == 'ovmf') {
-			    Proxmox.Utils.API2Request({
-				url : me.url,
-				method : 'GET',
-				failure : function(response, opts) {
-				    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				},
-				success : function(response, opts) {
-				    var vmConfig = response.result.data;
-				    // there can be only one
-				    if (!vmConfig.efidisk0) {
-					EFIHint.setVisible(true);
-				    }
-				}
-			    });
-			} else {
-			    if (EFIHint.isVisible()) {
-				EFIHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    EFIHint
-	    ] });
-
-	me.callParent();
-
-	me.load();
-
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.Options'],
-
-    onlineHelp: 'qm_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    name: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Name'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Name'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    xtype: 'textfield',
-			    name: 'name',
-			    vtype: 'DnsName',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: true
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.name === undefined ||
-				values.name === null ||
-				values.name === '') {
-				params = { 'delete':'name'};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ?
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'qm_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.OSTypeEdit' : undefined,
-		renderer: PVE.Utils.render_kvm_ostype,
-		defaultValue: 'other'
-	    },
-	    bootdisk: {
-		visible: false
-	    },
-	    boot: {
-		header: gettext('Boot Order'),
-		defaultValue: 'cdn',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.BootOrderEdit' : undefined,
-		multiKey: ['boot', 'bootdisk'],
-		renderer: function(order, metaData, record, rowIndex, colIndex, store, pending) {
-		    var i;
-		    var text = '';
-		    var bootdisk = me.getObjectValue('bootdisk', undefined, pending);
-		    order = order || 'cdn';
-		    for (i = 0; i < order.length; i++) {
-			var sel = order.substring(i, i + 1);
-			if (text) {
-			    text += ', ';
-			}
-			if (sel === 'c') {
-			    if (bootdisk) {
-				text += "Disk '" + bootdisk + "'";
-			    } else {
-				text += "Disk";
-			    }
-			} else if (sel === 'n') {
-			    text += 'Network';
-			} else if (sel === 'a') {
-			    text += 'Floppy';
-			} else if (sel === 'd') {
-			    text += 'CD-ROM';
-			} else {
-			    text += sel;
-			}
-		    }
-		    return text;
-		}
-	    },
-	    tablet: {
-		header: gettext('Use tablet for pointer'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use tablet for pointer'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'tablet',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hotplug: {
-		header: gettext('Hotplug'),
-		defaultValue: 'disk,network,usb',
-		renderer:  PVE.Utils.render_hotplug_features,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hotplug'),
-		    items: {
-			xtype: 'pveHotplugFeatureSelector',
-			name: 'hotplug',
-			value: '',
-			multiSelect: true,
-			fieldLabel: gettext('Hotplug'),
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    acpi: {
-		header: gettext('ACPI support'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('ACPI support'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'acpi',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    kvm: {
-		header: gettext('KVM hardware virtualization'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('KVM hardware virtualization'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'kvm',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    freeze: {
-		header: gettext('Freeze CPU at startup'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.PowerMgmt'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Freeze CPU at startup'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'freeze',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Freeze CPU at startup')
-		    }
-		} : undefined
-	    },
-	    localtime: {
-		header: gettext('Use local time for RTC'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use local time for RTC'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'localtime',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Use local time for RTC')
-		    }
-		} : undefined
-	    },
-	    startdate: {
-		header: gettext('RTC start date'),
-		defaultValue: 'now',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('RTC start date'),
-		    items: {
-			xtype: 'proxmoxtextfield',
-			name: 'startdate',
-			deleteEmpty: true,
-			value: 'now',
-			fieldLabel: gettext('RTC start date'),
-			vtype: 'QemuStartDate',
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    smbios1: {
-		header: gettext('SMBIOS settings (type1)'),
-		defaultValue: '',
-		renderer: Ext.String.htmlEncode,
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.Smbios1Edit' : undefined
-	    },
-	    agent: {
-		header: gettext('Qemu Agent'),
-		defaultValue: false,
-		renderer: PVE.Utils.render_qga_features,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Qemu Agent'),
-		    items: {
-			xtype: 'pveAgentFeatureSelector',
-			name: 'agent'
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-        var revert_btn = new Proxmox.button.Button({
-            text: gettext('Revert'),
-            disabled: true,
-            handler: function() {
-		var sm = me.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-
-                Proxmox.Utils.API2Request({
-                    url: '/api2/extjs/' + baseurl,
-                    waitMsgTarget: me,
-                    method: 'PUT',
-                    params: {
-                        'revert': revert
-                    },
-                    callback: function() {
-                        me.reload();
-                    },
-                    failure: function (response, opts) {
-                        Ext.Msg.alert('Error',response.htmlStatus);
-                    }
-                });
-            }
-        });
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/pending",
-	    interval: 5000,
-	    cwidth1: 250,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.rstore.on('datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-
-Ext.define('PVE.window.Snapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname, vmstate: vmstate ? 1 : 0 };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	} else {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'vmstate',
-		uncheckedValue: 0,
-		defaultValue: 0,
-		checked: 1,
-		fieldLabel: gettext('Include RAM')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description, values.vmstate);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}	 
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveQemuSnapshotTree'],
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-qemu-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-        var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-        Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-            method: 'GET',
-            success: function(response, options) {
-                var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-            }
-        });
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) { 
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		return Proxmox.Utils.format_task_description('qmrollback', me.vmid) +
-		    " '" +  rec.data.name + "'";
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', { 
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [ 
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-		{
-		    text: gettext('RAM'),
-		    align: 'center',
-		    resizable: false,
-		    dataIndex: 'vmstate',
-		    width: 50,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name !== 'current') {
-			    return Proxmox.Utils.format_boolean(value);
-			}
-		    }
-		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{ 
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true, // will work in 4.1?
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-
-Ext.define('PVE.qemu.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.qemu.Config',
-
-    onlineHelp: 'chapter_virtual_machines',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + "/qemu/" + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + '/status/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var resumeBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resume'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    hidden: true,
-	    handler: function() {
-		vm_command('resume');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'qemu',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    itemId: 'removeBtn',
-		    disabled: !caps.vms['VM.Allocate'],
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'VM', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items: [{
-		    text: gettext('Pause'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid),
-		    handler: function() {
-			vm_command("suspend");
-		    },
-		    iconCls: 'fa fa-pause'
-		},{
-		    text: gettext('Hibernate'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid),
-		    tooltip: gettext('Suspend to disk'),
-		    handler: function() {
-			vm_command("suspend", { todisk: 1 });
-		    },
-		    iconCls: 'fa fa-download'
-		},{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    dangerous: true,
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid),
-		    handler: function() {
-			vm_command("stop", { timeout: 30 });
-		    },
-		    iconCls: 'fa fa-stop'
-		},{
-		    text: gettext('Reset'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid),
-		    handler: function() {
-			vm_command("reset");
-		    },
-		    iconCls: 'fa fa-bolt'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    hidden: template,
-	    consoleType: 'kvm',
-	    consoleName: vm.name,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'kvmtab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveQemuSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push({
-		title: gettext('Console'),
-		itemId: 'console',
-		iconCls: 'fa fa-terminal',
-		xtype: 'pveNoVncConsole',
-		vmid: vmid,
-		consoleType: 'kvm',
-		nodename: nodename
-	    });
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Hardware'),
-		itemId: 'hardware',
-		iconCls: 'fa fa-desktop',
-		xtype: 'PVE.qemu.HardwareView'
-	    },
-	    {
-		title: 'Cloud-Init',
-		itemId: 'cloudinit',
-		iconCls: 'fa fa-cloud',
-		xtype: 'pveCiPanel'
-	    },
-	    {
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options',
-		xtype: 'PVE.qemu.Options'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		xtype: 'proxmoxNodeTasks',
-		iconCls: 'fa fa-list',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Monitor'] && !template) {
-	    me.items.push({
-		title: gettext('Monitor'),
-		iconCls: 'fa fa-eye',
-		itemId: 'monitor',
-		xtype: 'pveQemuMonitor'
-	    });
-	}
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveQemuSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-        me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var qmpstatus;
-	    var spice = false;
-	    var xtermjs = false;
-	    var lock;
-
-	    if (!success) {
-		status = qmpstatus = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('qmpstatus');
-		qmpstatus = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-
-		spice = s.data.get('spice') ? true : false;
-		xtermjs = s.data.get('serial') ? true : false;
-
-	    }
-
-	    if (template) {
-		return;
-	    }
-
-	    var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1);
-
-	    if (resume || lock === 'suspended') {
-		startBtn.setVisible(false);
-		resumeBtn.setVisible(true);
-	    } else {
-		startBtn.setVisible(true);
-		resumeBtn.setVisible(false);
-	    }
-
-	    consoleBtn.setEnableSpice(spice);
-	    consoleBtn.setEnableXtermJS(xtermjs);
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-   }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    alias: 'widget.pveQemuCreateWizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    current: {
-		scsihw: ''
-	    }
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('Virtual Machine'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'qm_general_settings',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid',
-		    guestType: 'qemu',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'name',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: true
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		}
-	    ],
-	    advancedColumn1: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'onboot',
-		    uncheckedValue: 0,
-		    defaultValue: 0,
-		    deleteDefaultValue: true,
-		    fieldLabel: gettext('Start at boot')
-		}
-	    ],
-	    advancedColumn2: [
-		{
-		    xtype: 'textfield',
-		    name: 'order',
-		    defaultValue: '',
-		    emptyText: 'any',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Start/Shutdown order')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'up',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Startup delay')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'down',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Shutdown timeout')
-		}
-	    ],
-	    onGetValues: function(values) {
-
-		['name', 'pool', 'onboot', 'agent'].forEach(function(field) {
-		    if (!values[field]) {
-			delete values[field];
-		    }
-		});
-
-		var res = PVE.Parser.printStartup({
-		    order: values.order,
-		    up: values.up,
-		    down: values.down
-		});
-
-		if (res) {
-		    values.startup = res;
-		}
-
-		delete values.order;
-		delete values.up;
-		delete values.down;
-
-		return values;
-	    }
-	},
-	{
-	    xtype: 'container',
-	    layout: 'hbox',
-	    defaults: {
-		flex: 1,
-		padding: '0 10'
-	    },
-	    title: gettext('OS'),
-	    items: [
-		{
-		    xtype: 'pveQemuCDInputPanel',
-		    bind: {
-			nodename: '{nodename}'
-		    },
-		    confid: 'ide2',
-		    insideWizard: true
-		},
-		{
-		    xtype: 'pveQemuOSTypePanel',
-		    insideWizard: true
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveQemuSystemPanel',
-	    title: gettext('System'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuHDInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Hard Disk'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuProcessorPanel',
-	    insideWizard: true,
-	    title: gettext('CPU')
-	},
-	{
-	    xtype: 'pveQemuMemoryPanel',
-	    insideWizard: true,
-	    title: gettext('Memory')
-	},
-	{
-	    xtype: 'pveQemuNetworkInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Network'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-			    property : 'key',
-			    direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var kv = this.up('window').getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete') { // ignore
-			    return;
-			}
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/qemu',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response){
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-
-Ext.define('PVE.qemu.USBInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    autoComplete: false,
-    onlineHelp: 'qm_usb_passthrough',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=usb]': {
-		change: function(field, newValue, oldValue) {
-		    var hwidfield = this.lookupReference('hwid');
-		    var portfield = this.lookupReference('port');
-		    var usb3field = this.lookupReference('usb3');
-		    if (field.inputValue === 'hostdevice') {
-			hwidfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'port') {
-			portfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'spice') {
-			usb3field.setDisabled(newValue);
-		    }
-		}
-	    },
-	    'pveUSBSelector': {
-		change: function(field, newValue, oldValue) {
-		    var usbval = field.getUSBValue();
-		    var usb3field = this.lookupReference('usb3');
-		    var usb3 = /usb3/.test(usbval);
-		    if(usb3 && !usb3field.isDisabled()) {
-			usb3field.savedVal = usb3field.getValue();
-			usb3field.setValue(true);
-			usb3field.setDisabled(true);
-		    } else if(!usb3 && usb3field.isDisabled()){
-			var val = (usb3field.savedVal === undefined)?usb3field.originalValue:usb3field.savedVal;
-			usb3field.setValue(val);
-			usb3field.setDisabled(false);
-		    }
-		}
-	    }
-	}
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 6; i++) {
-		if (!me.vmconfig['usb' +  i.toString()]) {
-		    me.confid = 'usb' + i.toString();
-		    break;
-		}
-	    }
-	}
-	var val = "";
-	var type = me.down('radiofield').getGroupValue();
-	switch (type) {
-	    case 'spice':
-		val = 'spice'; break;
-	    case 'hostdevice':
-	    case 'port':
-		val = me.down('pveUSBSelector[name=' + type + ']').getUSBValue();
-		if (!/usb3/.test(val) && me.down('field[name=usb3]').getValue() === true) {
-		    val += ',usb3=1';
-		}
-		break;
-	    default:
-		throw "invalid type selected";
-	}
-
-	values[me.confid] = val;
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'fieldcontainer',
-	    defaultType: 'radiofield',
-	    items:[
-		{
-		    name: 'usb',
-		    inputValue: 'spice',
-		    boxLabel: gettext('Spice Port'),
-		    submitValue: false,
-		    checked: true
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'hostdevice',
-		    boxLabel: gettext('Use USB Vendor/Device ID'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    type: 'device',
-		    name: 'hostdevice',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    reference: 'hwid',
-		    allowBlank: false,
-		    fieldLabel: 'Choose Device',
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'port',
-		    boxLabel: gettext('Use USB Port'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    name: 'port',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    type: 'port',
-		    reference: 'port',
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Port'),
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    xtype: 'checkbox',
-		    name: 'usb3',
-		    submitValue: false,
-		    reference: 'usb3',
-		    fieldLabel: gettext('Use USB3')
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.USBEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('USB Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var data = response.result.data[me.confid].split(',');
-		    var port, hostdevice, usb3 = false;
-		    var type = 'spice';
-		    var i;
-		    for (i = 0; i < data.length; i++) {
-			if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
-			    hostdevice = data[i];
-			    hostdevice = hostdevice.replace('host=', '').replace('0x','');
-			    type = 'hostdevice';
-			} else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
-			    port = data[i];
-			    port = port.replace('host=','');
-			    type = 'port';
-			}
-
-			if (/^usb3=(1|on|true)$/.test(data[i])) {
-			    usb3 = true;
-			}
-		    }
-		    var values = {
-			usb : type,
-			hostdevice: hostdevice,
-			port: port,
-			usb3: usb3
-		    };
-
-		    ipanel.setValues(values);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.PCIInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    onlineHelp: 'qm_pci_passthrough',
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-
-	var hostpci = me.vmconfig[me.confid] || '';
-
-	var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-	if (values.host && values.host.length < 6) { // 00:00 format not 00:00.0
-	    values.host += ".0";
-	    values.multifunction = true;
-	}
-	values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
-	values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
-	values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
-
-	me.setValues(values);
-	if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
-	    // machine is not set to some variant of q35, so we disable pcie
-	    var pcie = me.down('field[name=pcie]');
-	    pcie.setDisabled(true);
-	    pcie.setBoxLabel(gettext('Q35 only'));
-	}
-
-	if (values.romfile) {
-	    me.down('field[name=romfile]').setVisible(true);
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var ret = {};
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 5; i++) {
-		if (!me.vmconfig['hostpci' +  i.toString()]) {
-		    me.confid = 'hostpci' + i.toString();
-		    break;
-		}
-	    }
-	}
-	if (values.multifunction) {
-	    // modify host to skip the '.X'
-	    values.host = values.host.substring(0,5);
-	    delete values.multifunction;
-	}
-
-	if (values.rombar) {
-	    delete values.rombar;
-	} else {
-	    values.rombar = 0;
-	}
-
-	if (!values.romfile) {
-	    delete values.romfile;
-	}
-
-	ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-	return ret;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.column1 = [
-	    {
-		xtype: 'pvePCISelector',
-		fieldLabel: gettext('Device'),
-		name: 'host',
-		nodename: me.nodename,
-		allowBlank: false,
-		onLoadCallBack: function(store, records, success) {
-		    if (!success || !records.length) {
-			return;
-		    }
-
-		    var first = records[0];
-		    if (first.data.iommugroup === -1) {
-			// no iommu groups
-			var warning = Ext.create('Ext.form.field.Display', {
-			    columnWidth: 1,
-			    padding: '0 0 10 0',
-			    value: 'No IOMMU detected, please activate it.' +
-				   'See Documentation for further information.',
-			    userCls: 'pve-hint'
-			});
-			me.items.insert(0, warning);
-			me.updateLayout(); // insert does not trigger that
-		    }
-		},
-		listeners: {
-		    change: function(pcisel, value) {
-			if (!value) {
-			    return;
-			}
-			var pcidev = pcisel.getStore().getById(value);
-			var mdevfield = me.down('field[name=mdev]');
-			mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
-			if (!pcidev) {
-			    return;
-			}
-			var id = pcidev.data.id.substring(0,5); // 00:00
-			var iommu = pcidev.data.iommugroup;
-			// try to find out if there are more devices
-			// in that iommu group
-			if (iommu !== -1) {
-			    var count = 0;
-			    pcisel.getStore().each(function(record) {
-				if (record.data.iommugroup === iommu &&
-				    record.data.id.substring(0,5) !== id)
-				{
-				    count++;
-				    return false;
-				}
-			    });
-			    var warning = me.down('#iommuwarning');
-			    if (count && !warning) {
-				warning = Ext.create('Ext.form.field.Display', {
-				    columnWidth: 1,
-				    padding: '0 0 10 0',
-				    itemId: 'iommuwarning',
-				    value: 'The selected Device is not in a seperate' +
-					   'IOMMU group, make sure this is intended.',
-				    userCls: 'pve-hint'
-				});
-				me.items.insert(0, warning);
-				me.updateLayout(); // insert does not trigger that
-			    } else if (!count && warning) {
-				me.remove(warning);
-			    }
-			}
-			if (pcidev.data.mdev) {
-			    mdevfield.setPciID(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('All Functions'),
-		name: 'multifunction'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'pveMDevSelector',
-		name: 'mdev',
-		disabled: true,
-		fieldLabel: gettext('MDev Type'),
-		nodename: me.nodename,
-		listeners: {
-		    change: function(field, value) {
-			var mf = me.down('field[name=multifunction]');
-			if (!!value) {
-			    mf.setValue(false);
-			}
-			mf.setDisabled(!!value);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Primary GPU'),
-		name: 'x-vga'
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'ROM-Bar',
-		name: 'rombar'
-	    },
-	    {
-		xtype: 'displayfield',
-		submitValue: true,
-		hidden: true,
-		fieldLabel: 'ROM-File',
-		name: 'romfile'
-	    }
-	];
-
-	me.advancedColumn2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'PCI-Express',
-		name: 'pcie'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.PCIEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('PCI Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.SerialnputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    autoComplete: false,
-
-    setVMConfig: function(vmconfig) {
-	var me = this, i;
-	me.vmconfig = vmconfig;
-
-	for (i = 0; i < 4; i++) {
-	    var port = 'serial' +  i.toString();
-	    if (!me.vmconfig[port]) {
-		me.down('field[name=serialid]').setValue(i);
-		break;
-	    }
-	}
-
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id = 'serial' + values.serialid;
-	delete values.serialid;
-	values[id] = 'socket';
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'serialid',
-	    fieldLabel: gettext('Serial Port'),
-	    minValue: 0,
-	    maxValue: 3,
-	    allowBlank: false,
-	    validator: function(id) {
-		if (!this.rendered) {
-		    return true;
-		}
-		var me = this.up('panel');
-		if (me.vmconfig !== undefined && Ext.isDefined(me.vmconfig['serial' + id])) {
-			return "This device is already in use.";
-		}
-		return true;
-	    }
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.SerialEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('Serial Port'),
-
-    initComponent : function() {
-	var me = this;
-
-	// for now create of (socket) serial port only
-	me.isCreate = true;
-
-	var ipanel = Ext.create('PVE.qemu.SerialnputPanel', {});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.IPInfo', {
-    extend: 'Ext.window.Window',
-    width: 600,
-    title: gettext('Guest Agent Network Information'),
-    height: 300,
-    layout: {
-	type: 'fit'
-    },
-    modal: true,
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: gettext('No network information'),
-	    columns: [
-		{
-		    dataIndex: 'name',
-		    text: gettext('Name'),
-		    flex: 3
-		},
-		{
-		    dataIndex: 'hardware-address',
-		    text: gettext('MAC address'),
-		    width: 140
-		},
-		{
-		    dataIndex: 'ip-addresses',
-		    text: gettext('IP address'),
-		    align: 'right',
-		    flex: 4,
-		    renderer: function(val) {
-			if (!Ext.isArray(val)) {
-			    return '';
-			}
-			var ips = [];
-			val.forEach(function(ip) {
-			    var addr = ip['ip-address'];
-			    var pref = ip.prefix;
-			    if  (addr && pref) {
-				ips.push(addr + '/' + pref);
-			    }
-			});
-			return ips.join('<br>');
-		    }
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.AgentIPView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveAgentIPView',
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    nics: [],
-
-    items: [
-	{
-	    xtype: 'box',
-	    html: '<i class="fa fa-exchange"></i> IPs'
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'right',
-		pack: 'end'
-	    },
-	    items: [
-		{
-		    xtype: 'label',
-		    flex: 1,
-		    itemId: 'ipBox',
-		    style: {
-			'text-align': 'right'
-		    }
-		},
-		{
-		    xtype: 'button',
-		    itemId: 'moreBtn',
-		    hidden: true,
-		    ui: 'default-toolbar',
-		    handler: function(btn) {
-			var me = this.up('pveAgentIPView');
-
-			var win = Ext.create('PVE.window.IPInfo');
-			win.down('grid').getStore().setData(me.nics);
-			win.show();
-		    },
-		    text: gettext('More')
-		}
-	    ]
-	}
-    ],
-
-    getDefaultIps: function(nics) {
-	var me = this;
-	var ips = [];
-	nics.forEach(function(nic) {
-	    if (nic['hardware-address'] &&
-		nic['hardware-address'] != '00:00:00:00:00:00') {
-
-		var nic_ips = nic['ip-addresses'] || [];
-		nic_ips.forEach(function(ip) {
-		    var p = ip['ip-address'];
-		    // show 2 ips at maximum
-		    if (ips.length < 2) {
-			ips.push(p);
-		    }
-		});
-	    }
-	});
-
-	return ips;
-    },
-
-    startIPStore: function(store, records, success) {
-	var me = this;
-	var agentRec = store.getById('agent');
-	/*jslint confusion: true*/
-	/* value is number and string */
-	me.agent = (agentRec && agentRec.data.value === 1);
-	me.running = (store.getById('status').data.value === 'running');
-	/*jslint confusion: false*/
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!caps.vms['VM.Monitor']) {
-	    var errorText = gettext("Requires '{0}' Privileges");
-	    me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
-	    return;
-	}
-
-	if (me.agent && me.running && me.ipStore.isStopped) {
-	    me.ipStore.startUpdate();
-	} else if (me.ipStore.isStopped) {
-	    me.updateStatus();
-	}
-    },
-
-    updateStatus: function(unsuccessful, defaulttext) {
-	var me = this;
-	var text = defaulttext || gettext('No network information');
-	var more = false;
-	if (unsuccessful) {
-	    text = gettext('Guest Agent not running');
-	} else if (me.agent && me.running) {
-	    if (Ext.isArray(me.nics) && me.nics.length) {
-		more = true;
-		var ips = me.getDefaultIps(me.nics);
-		if (ips.length !== 0) {
-		    text = ips.join('<br>');
-		}
-	    } else if (me.nics && me.nics.error) {
-		var msg = gettext('Cannot get info from Guest Agent<br>Error: {0}');
-		text = Ext.String.format(text, me.nics.error.desc);
-	    }
-	} else if (me.agent) {
-	    text = gettext('Guest Agent not running');
-	} else {
-	    text = gettext('No Guest Agent configured');
-	}
-
-	var ipBox = me.down('#ipBox');
-	ipBox.update(text);
-
-	var moreBtn = me.down('#moreBtn');
-	moreBtn.setVisible(more);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw 'rstore not given';
-	}
-
-	if (!me.pveSelNode) {
-	    throw 'pveSelNode not given';
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	var vmid = me.pveSelNode.data.vmid;
-
-	me.ipStore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 10000,
-	    storeid: 'pve-qemu-agent-' + vmid,
-	    method: 'POST',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces'
-	    }
-	});
-
-	me.callParent();
-
-	me.mon(me.ipStore, 'load', function(store, records, success) {
-	    if (records && records.length) {
-		me.nics = records[0].data.result;
-	    } else {
-		me.nics = undefined;
-	    }
-	    me.updateStatus(!success);
-	});
-
-	me.on('destroy', me.ipStore.stopUpdate);
-
-	// if we already have info about the vm, use it immediately
-	if (me.rstore.getCount()) {
-	    me.startIPStore(me.rstore, me.rstore.getData(), false);
-	}
-
-	// check if the guest agent is there on every statusstore load
-	me.mon(me.rstore, 'load', me.startIPStore, me);
-    }
-});
-Ext.define('PVE.qemu.CloudInit', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    xtype: 'pveCiPanel',
-
-    onlineHelp: 'qm_cloud_init',
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var me = this.up('grid');
-		var warn = gettext('Are you sure you want to remove entry {0}');
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		return msg;
-	    },
-	    enableFn: function(record) {
-		var me = this.up('grid');
-		var caps = Ext.state.Manager.get('GuiCap');
-		if (me.rows[record.data.key].never_delete ||
-		    !caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-
-		if (record.data.key === 'cipassword' && !record.data.value) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		var records = me.getSelection();
-		if (!records ||  !records.length) {
-		    return;
-		}
-
-		var id = records[0].data.key;
-		var match = id.match(/^net(\d+)$/);
-		if (match) {
-		    id = 'ipconfig' + match[1];
-		}
-
-		var params = {};
-		params['delete'] = id;
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: params,
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    callback: function() {
-			me.reload();
-		    }
-		});
-	    },
-	    text: gettext('Remove')
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('grid');
-		me.run_editor();
-	    },
-	    text: gettext('Edit')
-	},
-	'-',
-	{
-	    xtype: 'button',
-	    itemId: 'savebtn',
-	    text: gettext('Regenerate Image'),
-	    handler: function() {
-		var me = this.up('grid');
-		var eject_params = {};
-		var insert_params = {};
-		var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
-		var storage = '';
-		var stormatch = disk.file.match(/^([^\:]+)\:/);
-		if (stormatch) {
-		    storage = stormatch[1];
-		}
-		eject_params[me.ciDriveId] = 'none,media=cdrom';
-		insert_params[me.ciDriveId] = storage + ':cloudinit';
-
-		var failure = function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		};
-
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: eject_params,
-		    failure: failure,
-		    callback: function() {
-			Proxmox.Utils.API2Request({
-			    url: me.baseurl + '/config',
-			    waitMsgTarget: me,
-			    method: 'PUT',
-			    params: insert_params,
-			    failure: failure,
-			    callback: function() {
-				me.reload();
-			    }
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    border: false,
-
-    set_button_status: function(rstore, records, success) {
-	if (!success || records.length < 1) {
-	    return;
-	}
-	var me = this;
-	var found;
-	records.forEach(function(record) {
-	    if (found) {
-		return;
-	    }
-	    var id = record.data.key;
-	    var value = record.data.value;
-	    var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
-		if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
-		    found = id;
-		    me.ciDriveId = found;
-		    me.ciDrive = value;
-		}
-	});
-
-	me.down('#savebtn').setDisabled(!found);
-	me.setDisabled(!found);
-	if (!found) {
-	    me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
-	} else {
-	    me.getView().unmask();
-	}
-    },
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-
-	var icon = "";
-	if (rowdef.iconCls) {
-	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
-	}
-	return icon + (rowdef.header || key);
-    },
-
-    listeners: {
-	activate: function () {
-	    var me = this;
-	    me.rstore.startUpdate();
-	},
-	itemdblclick: function() {
-	    var me = this;
-	    me.run_editor();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-	var caps = Ext.state.Manager.get('GuiCap');
-	me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
-	me.url =  me.baseurl + '/pending';
-	me.editorConfig.url = me.baseurl + '/config';
-	me.editorConfig.pveSelNode = me.pveSelNode;
-
-	/*jslint confusion: true*/
-	/* editor is string and object */
-	me.rows = {
-	    ciuser: {
-		header: gettext('User'),
-		iconCls: 'fa fa-user',
-		never_delete: true,
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('User'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('User'),
-			    name: 'ciuser'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.defaultText;
-		}
-	    },
-	    cipassword: {
-		header: gettext('Password'),
-		iconCls: 'fa fa-unlock',
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Password'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    inputType: 'password',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.noneText,
-			    fieldLabel: gettext('Password'),
-			    name: 'cipassword'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.noneText;
-		}
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    nameserver: {
-		header: gettext('DNS servers'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    sshkeys: {
-		header: gettext('SSH public key'),
-		iconCls: 'fa fa-key',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.SSHKeyEdit' : undefined,
-		never_delete: true,
-		renderer: function(value) {
-		    value = decodeURIComponent(value);
-		    var keys = value.split('\n');
-		    var text = [];
-		    keys.forEach(function(key) {
-			if (key.length) {
-			    // First erase all quoted strings (eg. command="foo"
-			    var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
-			    // Now try to detect the comment:
-			    var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
-			    if (res) {
-				key = Ext.String.htmlEncode(res[2]);
-				if (res[1]) {
-				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
-				}
-				text.push(key);
-				return;
-			    }
-			    // Most likely invalid at this point, so just stick to
-			    // the old value.
-			    text.push(Ext.String.htmlEncode(key));
-			}
-		    });
-		    if (text.length) {
-			return text.join('<br>');
-		    } else {
-			return Proxmox.Utils.noneText;
-		    }
-		},
-		defaultValue: ''
-	    }
-	};
-	var i;
-	var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
-	    var id = record.data.key;
-	    var match = id.match(/^net(\d+)$/);
-	    var val = '';
-	    if (match) {
-		val = me.getObjectValue('ipconfig'+match[1], '', pending);
-	    }
-	    return val;
-	};
-	for (i = 0; i < 32; i++) {
-	    // we want to show an entry for every network device
-	    // even if it is empty
-	    me.rows['net' + i.toString()] = {
-		multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
-		header: gettext('IP Config') + ' (net' + i.toString() +')',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
-		iconCls: 'fa fa-exchange',
-		renderer: ipconfig_renderer
-	    };
-	    me.rows['ipconfig' + i.toString()] = {
-		visible: false
-	    };
-	}
-	/*jslint confusion: false*/
-
-	PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
-	    me.rows[type+id] = {
-		visible: false
-	    };
-	});
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-    }
-});
-Ext.define('PVE.qemu.CIDriveInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveCIDriveInputPanel',
-
-    insideWizard: false,
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var drive = {};
-	var params = {};
-	drive.file = values.hdstorage + ":cloudinit";
-	drive.format = values.diskformat;
-	params[values.controller + values.deviceid] = PVE.Parser.printQemuDrive(drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.down('#drive').setVMConfig(config, 'cdrom');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items = [
-	    {
-		xtype: 'pveControllerSelector',
-		noVirtIO: true,
-		itemId: 'drive',
-		fieldLabel: gettext('CloudInit Drive'),
-		name: 'drive'
-	    },
-	    {
-		xtype: 'pveDiskStorageSelector',
-		itemId: 'storselector',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    }
-	];
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CIDriveEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCIDriveEdit',
-
-    isCreate: true,
-    subject: gettext('CloudInit Drive'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveCIDriveInputPanel',
-	    itemId: 'cipanel',
-	    nodename: nodename
-	}];
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		me.down('#cipanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SSHKeyInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSSHKeyInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-	if (values.sshkeys) {
-	    values.sshkeys.trim();
-	}
-	if (!values.sshkeys.length) {
-	    values = {};
-	    values['delete'] = 'sshkeys';
-	    return values;
-	} else {
-	    values.sshkeys = encodeURIComponent(values.sshkeys);
-	}
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'sshkeys',
-	    name: 'sshkeys',
-	    height: 250
-	},
-	{
-	    xtype: 'filebutton',
-	    itemId: 'filebutton',
-	    name: 'file',
-	    text: gettext('Load SSH Key File'),
-	    fieldLabel: 'test',
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('inputpanel');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    var keysField = me.down('#sshkeys');
-			    var old = keysField.getValue();
-			    keysField.setValue(old + res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-	if (!window.FileReader) {
-	    me.down('#filebutton').setVisible(false);
-	}
-
-    }
-});
-
-Ext.define('PVE.qemu.SSHKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 800,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.SSHKeyInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('SSH Keys'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.create) {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.sshkeys) {
-			data.sshkeys = decodeURIComponent(data.sshkeys);
-			ipanel.setValues(data);
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.qemu.IPConfigPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveIPConfigPanel',
-
-    insideWizard: false,
-
-    vmconfig: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-
-	var params = {};
-
-	var cfg = PVE.Parser.printIPConfig(values);
-	if (cfg === '') {
-	    params['delete'] = [me.confid];
-	} else {
-	    params[me.confid] = cfg;
-	}
-	return params;
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.vmconfig = config;
-    },
-
-    setIPConfig: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data.ip === 'dhcp') {
-	    data.ipv4mode = data.ip;
-	    data.ip = '';
-	} else {
-	    data.ipv4mode = 'static';
-	}
-	if (data.ip6 === 'dhcp' || data.ip6 === 'auto') {
-	    data.ipv6mode = data.ip6;
-	    data.ip6 = '';
-	} else {
-	    data.ipv6mode = 'static';
-	}
-
-	me.ipconfig = data;
-	me.setValues(me.ipconfig);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.ipconfig = {};
-
-	me.column1 = [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Network Device'),
-		value: me.netid
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv4') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('IPv4/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: '',
-		vtype: 'IPAddress',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv4') +')'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'displayfield'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv6') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: '',
-		vtype: 'IP6CIDRAddress',
-		disabled: true,
-		fieldLabel: gettext('IPv6/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv6') +')'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.IPConfigEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	// convert confid from netX to ipconfigX
-	var match = me.confid.match(/^net(\d+)$/);
-	if (match) {
-	    me.netid = me.confid;
-	    me.confid = 'ipconfig' + match[1];
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.IPConfigPanel', {
-	    confid: me.confid,
-	    netid: me.netid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Config'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		me.vmconfig = response.result.data;
-		var ipconfig = {};
-		var value = me.vmconfig[me.confid];
-		if (value) {
-		    ipconfig = PVE.Parser.parseIPConfig(me.confid, value);
-		    if (!ipconfig) {
-			Ext.Msg.alert(gettext('Error'), gettext('Unable to parse network configuration'));
-			me.close();
-			return;
-		    }
-		}
-		ipanel.setIPConfig(me.confid, ipconfig);
-		ipanel.setVMConfig(me.vmconfig);
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.SystemInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSystemPanel',
-
-    onlineHelp: 'qm_system_settings',
-
-    viewModel: {
-	data: {
-	    efi: false,
-	    addefi: true
-	},
-
-	formulas: {
-	    efidisk: function(get) {
-		return get('efi') && get('addefi');
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	if (values.vga && values.vga.substr(0,6) === 'serial') {
-	    values['serial' + values.vga.substr(6,1)] = 'socket';
-	}
-
-	var efidrive = {};
-	if (values.hdimage) {
-	    efidrive.file = values.hdimage;
-	} else if (values.hdstorage) {
-	    efidrive.file = values.hdstorage + ":1";
-	}
-
-	if (values.diskformat) {
-	    efidrive.format = values.diskformat;
-	}
-
-	delete values.hdimage;
-	delete values.hdstorage;
-	delete values.diskformat;
-
-	if (efidrive.file) {
-	    values.efidisk0 = PVE.Parser.printQemuDrive(efidrive);
-	}
-
-	return values;
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	scsihwChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('current.scsihw', value);
-	    }
-	},
-
-	biosChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('efi', value === 'ovmf');
-	    }
-	},
-
-	control: {
-	    'pveScsiHwSelector': {
-		change: 'scsihwChange'
-	    },
-	    'pveQemuBiosSelector': {
-		change: 'biosChange'
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: gettext('Graphic card'),
-	    name: 'vga',
-	    comboItems: PVE.Utils.kvm_vga_driver_array()
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'agent',
-	    uncheckedValue: 0,
-	    defaultValue: 0,
-	    deleteDefaultValue: true,
-	    fieldLabel: gettext('Qemu Agent')
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'pveScsiHwSelector',
-	    name: 'scsihw',
-	    value: '__default__',
-	    bind: {
-		value: '{current.scsihw}'
-	    },
-	    fieldLabel: gettext('SCSI Controller')
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    name: 'bios',
-	    value: '__default__',
-	    fieldLabel: 'BIOS'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    bind: {
-		value: '{addefi}',
-		hidden: '{!efi}',
-		disabled: '{!efi}'
-	    },
-	    hidden: true,
-	    submitValue: false,
-	    disabled: true,
-	    fieldLabel: gettext('Add EFI Disk')
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    bind: {
-		nodename: '{nodename}',
-		hidden: '{!efi}',
-		disabled: '{!efidisk}'
-	    },
-	    autoSelect: false,
-	    disabled: true,
-	    hidden: true,
-	    hideSize: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'machine',
-	    value: '__default__',
-	    fieldLabel: gettext('Machine'),
-	    comboItems: [
-		['__default__', PVE.Utils.render_qemu_machine('')],
-		['q35', 'q35']
-	    ]
-	}
-    ]
-
-});
-Ext.define('PVE.lxc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveLxcSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 320,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.lxc.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcNetworkInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_network',
-
-    setNodename: function(nodename) {
-	var me = this;
-	
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	var bridgesel = me.query("[isFormField][name=bridge]")[0];
-	bridgesel.setNodename(nodename);
-    },
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	var id;
-	if (me.isCreate) {
-	    id = values.id;
-	    delete values.id;
-	} else {
-	    id = me.ifname;
-	}
-
-	if (!id) {
-	    return {};
-	}
-
-	var newdata = {};
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-	newdata[id] = PVE.Parser.printLxcNetwork(values);
-	return newdata;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var cdata = {};
-
-	if (me.insideWizard) {
-	    me.ifname = 'net0';
-	    cdata.name = 'eth0';
-	    me.dataCache = {};
-	}
-	cdata.firewall =  (me.insideWizard || me.isCreate);
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.isCreate) {
-	    if (!me.ifname) {
-		throw "no interface name specified";
-	    }
-	    if (!me.dataCache[me.ifname]) {
-		throw "no such interface '" + me.ifname + "'";
-	    }
-
-	    cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
-	}
-
-	var i;
-	for (i = 0; i < 10; i++) {
-	    if (me.isCreate && !me.dataCache['net'+i.toString()]) {
-		me.ifname = 'net' + i.toString();
-		break;
-	    }
-	}
-
-	var idselector = {
-	    xtype: 'hidden',
-	    name: 'id',
-	    value: me.ifname
-	};
-
-	me.column1 = [
-	    idselector,
-	    {
-		xtype: 'textfield',
-		name: 'name',
-		fieldLabel: gettext('Name'),
-		emptyText: '(e.g., eth0)',
-		allowBlank: false,
-		value: cdata.name,
-		validator: function(value) {
-		    var result = '';
-		    Ext.Object.each(me.dataCache, function(key, netstr) {
-			if (!key.match(/^net\d+/) || key === me.ifname) {
-			    return; // continue
-			}
-			var net = PVE.Parser.parseLxcNetwork(netstr);
-			if (net.name === value) {
-			    result = "interface name already in use";
-			    return false;
-			}
-		    });
-		    if (result !== '') {
-			return result;
-		    }
-		    // validator can return bool/string
-		    /*jslint confusion:true*/
-		    return true;
-		}
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'hwaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		value: cdata.hwaddr,
-		allowBlank: true,
-		emptyText: 'auto'
-	    },
-	    {
-		xtype: 'PVE.form.BridgeSelector',
-		name: 'bridge',
-		nodename: me.nodename,
-		fieldLabel: gettext('Bridge'),
-		value: cdata.bridge,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: cdata.tag
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: cdata.rate,
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		value: cdata.firewall
-	    }
-	];
-
-	var dhcp4 = (cdata.ip === 'dhcp');
-	if (dhcp4) {
-	    cdata.ip = '';
-	    cdata.gw = '';
-	}
-
-	var auto6 = (cdata.ip6 === 'auto');
-	var dhcp6 = (cdata.ip6 === 'dhcp');
-	if (auto6 || dhcp6) {
-	    cdata.ip6 = '';
-	    cdata.gw6 = '';
-	}
-	
-	me.column2 = [
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv4:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: !dhcp4,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: dhcp4,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: cdata.ip,
-		disabled: dhcp4,
-		fieldLabel: 'IPv4/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: cdata.gw,
-		vtype: 'IPAddress',
-		disabled: dhcp4,
-		fieldLabel: gettext('Gateway') + ' (IPv4)',
-		margin: '0 0 3 0' // override bottom margin to account for the menuseparator
-	    },
-	    {
-		xtype: 'menuseparator',
-		height: '3',
-		margin: '0'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv6:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: !(auto6 || dhcp6),
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: dhcp6,
-			margin: '0 0 0 10'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'SLAAC', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'auto',
-			checked: auto6,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: cdata.ip6,
-		vtype: 'IP6CIDRAddress',
-		disabled: (dhcp6 || auto6),
-		fieldLabel: 'IPv6/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: cdata.gw6,
-		disabled: (dhcp6 || auto6),
-		fieldLabel: gettext('Gateway') + ' (IPv6)'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-	
-
-Ext.define('PVE.lxc.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
-	    ifname: me.ifname,
-	    nodename: me.nodename,
-	    dataCache: me.dataCache,
-	    isCreate: me.isCreate
-	});
-	   
-	Ext.apply(me, {
-	    subject: gettext('Network Device') + ' (veth)',
-	    digest: me.dataCache.digest,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveLxcNetworkView',
-
-    onlineHelp: 'pct_container_network',
-
-    dataCache: {}, // used to store result of last load
-
-    stateful: true,
-    stateId: 'grid-lxc-network',
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.setErrorMask(me, true);
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		me.dataCache = data;
-		var records = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (!key.match(/^net\d+/)) {
-			return; // continue
-		    }
-		    var net = PVE.Parser.parseLxcNetwork(value);
-		    net.id = key;
-		    records.push(net);
-		});
-		me.store.loadData(records);
-		me.down('button[name=addButton]').setDisabled((records.length >= 10));
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var store = new Ext.data.Store({
-	    model: 'pve-lxc-network',
-	    sorters: [
-		{
-		    property : 'id',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!caps.vms['VM.Config.Network'];
-	    },
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: me.url,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: { 'delete': rec.data.id,  digest: me.dataCache.digest },
-		    callback: function() {
-			me.load();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!caps.vms['VM.Config.Network']) {
-		return false;
-	    }
-
-	    var win = Ext.create('PVE.lxc.NetworkEdit', {
-		url: me.url,
-		nodename: nodename,
-		dataCache: me.dataCache,
-		ifname: rec.data.id
-	    });
-	    win.on('destroy', me.load, me);
-	    win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    name: 'addButton',
-		    disabled: !caps.vms['VM.Config.Network'],
-		    handler: function() {
-			var win = Ext.create('PVE.lxc.NetworkEdit', {
-			    url: me.url,
-			    nodename: nodename,
-			    isCreate: true,
-			    dataCache: me.dataCache
-			});
-			win.on('destroy', me.load, me);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 50,
-		    dataIndex: 'id'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 80,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Bridge'),
-		    width: 80,
-		    dataIndex: 'bridge'
-		},
-		{
-		    header: gettext('Firewall'),
-		    width: 80,
-		    dataIndex: 'firewall',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('VLAN Tag'),
-		    width: 80,
-		    dataIndex: 'tag'
-		},
-		{
-		    header: gettext('MAC address'),
-		    width: 110,
-		    dataIndex: 'hwaddr'
-		},
-		{
-		    header: gettext('IP address'),
-		    width: 150,
-		    dataIndex: 'ip',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.ip && rec.data.ip6) {
-			    return rec.data.ip + "<br>" + rec.data.ip6;
-			} else if (rec.data.ip6) {
-			    return rec.data.ip6;
-			} else {
-			    return rec.data.ip;
-			}
-		    }
-		},
-		{
-		    header: gettext('Gateway'),
-		    width: 150,
-		    dataIndex: 'gw',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.gw && rec.data.gw6) {
-			    return rec.data.gw + "<br>" + rec.data.gw6;
-			} else if (rec.data.gw6) {
-			    return rec.data.gw6;
-			} else {
-			    return rec.data.gw;
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: me.load,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-   }
-}, function() {
-
-    Ext.define('pve-lxc-network', {
-	extend: "Ext.data.Model",
-	proxy: { type: 'memory' },
-	fields: [ 'id', 'name', 'hwaddr', 'bridge',
-		  'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
-    });
-
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.RessourceView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcRessourceView'],
-
-    onlineHelp: 'pct_configuration',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rowdef = me.rows[key] || {};
-
-	metaData.tdAttr = "valign=middle";
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	}
-	return rowdef.header || key;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	var mpeditor = caps.vms['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
-
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-memory',
-		group: 1,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    swap: {
-		header: gettext('Swap'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-swap',
-		group: 2,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    cores: {
-		header: gettext('Cores'),
-		editor: caps.vms['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
-		defaultValue: '',
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		renderer: function(value) {
-		    var cpulimit = me.getObjectValue('cpulimit');
-		    var cpuunits = me.getObjectValue('cpuunits');
-		    var res;
-		    if (value) {
-			res = value;
-		    } else {
-			res = gettext('unlimited');
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit + ']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits + ']';
-		    }
-		    return res;
-		}
-	    },
-	    rootfs: {
-		header: gettext('Root Disk'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: mpeditor,
-		tdCls: 'pve-itype-icon-storage',
-		group: 4
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    unprivileged: {
-		visible: false
-	    }
-	};
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    confid = bus + i;
-	    var group = 5;
-	    var header;
-	    if (bus === 'mp') {
-		header = gettext('Mount Point') + ' (' + confid + ')';
-	    } else {
-		header = gettext('Unused Disk') + ' ' + i;
-		group += 1;
-	    }
-	    rows[confid] = {
-		group: group,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: mpeditor,
-		header: header
-	    };
-	}, true);
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	var run_resize = function() {
-	    var rec = me.selModel.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.MPResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-	};
-
-	var run_remove = function(b, e, rec) {
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/' + baseurl,
-		waitMsgTarget: me,
-		method: 'PUT',
-		params: {
-		    'delete': rec.data.key
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var run_move = function(b, e, rec) {
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid,
-		type: 'lxc'
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec) {
-		    return false;
-		}
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + me.renderKey(rec.data.key, {}, rec) + "'");
-		if (rec.data.key.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: run_remove
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move Volume'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    handler: run_move
-	});
-
-	var set_button_status = function() {
-	    var rec = me.selModel.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		remove_btn.disable();
-		resize_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var isDisk = (rowdef.tdCls == 'pve-itype-icon-storage');
-
-	    var noedit = rec.data['delete'] || !rowdef.editor;
-	    if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) {
-		var mp = PVE.Parser.parseLxcMountPoint(value);
-		if (mp.type !== 'volume') {
-		    noedit = true;
-		}
-	    }
-	    edit_btn.setDisabled(noedit);
-
-	    remove_btn.setDisabled(!isDisk || rec.data.key === 'rootfs' || !diskCap);
-	    resize_btn.setDisabled(!isDisk || !diskCap);
-	    move_btn.setDisabled(!isDisk || !diskCap);
-
-	};
-	
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + baseurl,
-	    selModel: me.selModel,
-	    interval: 2000,
-	    cwidth1: 170,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Mount Point'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.lxc.MountPointEdit', {
-					url: '/api2/extjs/' + baseurl,
-					unprivileged: me.getObjectValue('unprivileged'),
-					pveSelNode: me.pveSelNode
-				    });
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		edit_btn,
-		remove_btn,
-		resize_btn,
-		move_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    editorConfig: {
-		pveSelNode: me.pveSelNode,
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	Ext.apply(me.editorConfig, { unprivileged: me.getObjectValue('unprivileged') });
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.FeaturesInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcFeaturesInputPanel',
-
-    // used to save the mounts fstypes until sending
-    mounts: [],
-
-    fstypes: ['nfs', 'cifs'],
-
-    viewModel: {
-	parent: null,
-	data: {
-	    unprivileged: false
-	},
-	formulas: {
-	    privilegedOnly: function(get) {
-		return (get('unprivileged') ? gettext('privileged only') : '');
-	    },
-	    unprivilegedOnly: function(get) {
-		return (!get('unprivileged') ? gettext('unprivileged only') : '');
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('keyctl'),
-	    name: 'keyctl',
-	    bind: {
-		disabled: '{!unprivileged}',
-		boxLabel: '{unprivilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Nesting'),
-	    name: 'nesting'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'nfs',
-	    fieldLabel: 'NFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cifs',
-	    fieldLabel: 'CIFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'fuse',
-	    fieldLabel: 'FUSE'
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-	var mounts = me.mounts;
-	me.fstypes.forEach(function(fs) {
-	    if (values[fs]) {
-		mounts.push(fs);
-	    }
-	    delete values[fs];
-	});
-
-	if (mounts.length) {
-	    values.mount = mounts.join(';');
-	}
-
-	var featuresstring = PVE.Parser.printPropertyString(values, undefined);
-	if (featuresstring == '') {
-	    return { 'delete': 'features' };
-	}
-	return { features: featuresstring };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	me.viewModel.set({ unprivileged: values.unprivileged });
-
-	if (values.features) {
-	    var res = PVE.Parser.parsePropertyString(values.features);
-	    me.mounts = [];
-	    if (res.mount) {
-		res.mount.split(/[; ]/).forEach(function(item) {
-		    if (me.fstypes.indexOf(item) === -1) {
-			me.mounts.push(item);
-		    } else {
-			res[item] = 1;
-		    }
-		});
-	    }
-	    this.callParent([res]);
-	}
-    }
-});
-
-Ext.define('PVE.lxc.FeaturesEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveLxcFeaturesEdit',
-
-    subject: gettext('Features'),
-
-    items: [{
-	xtype: 'pveLxcFeaturesInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.lxc.Options', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcOptions'],
-
-    onlineHelp: 'pct_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ? 
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'pct_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    arch: {
-		header: gettext('Architecture'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    console: {
-		header: '/dev/console',
-		defaultValue: 1,
-		renderer: Proxmox.Utils.format_enabled_toggle,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: '/dev/console',
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'console',
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			checked: true,
-			fieldLabel: '/dev/console'
-		    }
-		} : undefined
-	    },
-	    tty: {
-		header: gettext('TTY count'),
-		defaultValue: 2,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('TTY count'),
-		    items: {
-			xtype: 'proxmoxintegerfield',
-			name: 'tty',
-			minValue: 0,
-			maxValue: 6,
-			value: 2,
-			fieldLabel: gettext('TTY count'),
-			emptyText: gettext('Default'),
-			deleteEmpty: true
-		    }
-		} : undefined
-	    },
-	    cmode: {
-		header: gettext('Console mode'),
-		defaultValue: 'tty',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Console mode'),
-		    items: {
-			xtype: 'proxmoxKVComboBox',
-			name: 'cmode',
-			deleteEmpty: true,
-			value: '__default__',
-			comboItems: [
-			    ['__default__', Proxmox.Utils.defaultText + " (tty)"],
-			    ['tty', "/dev/tty[X]"],
-			    ['console', "/dev/console"],
-			    ['shell', "shell"]
-			],
-			fieldLabel: gettext('Console mode')
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    unprivileged: {
-		header: gettext('Unprivileged container'),
-		renderer: Proxmox.Utils.format_boolean,
-		defaultValue: 0
-	    },
-	    features: {
-		header: gettext('Features'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: Proxmox.UserName === 'root@pam' ?
-		    'PVE.lxc.FeaturesEdit' : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	Ext.apply(me, {
-	    url: "/api2/json/" + baseurl,
-	    selModel: sm,
-	    interval: 5000,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-    }
-});
-
-Ext.define('PVE.lxc.DNSInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcDNSInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var deletes = [];
-	if (!values.searchdomain && !me.insideWizard) {
-	    deletes.push('searchdomain');
-	}
-
-	if (values.nameserver) {
-	    var list = values.nameserver.split(/[\ \,\;]+/);
-	    values.nameserver = list.join(' ');
-	} else if(!me.insideWizard) {
-	    deletes.push('nameserver');
-	}
-
-	if (deletes.length) {
-	    values['delete'] = deletes.join(',');
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxtextfield',
-		name: 'searchdomain',
-		skipEmptyText: true,
-		fieldLabel: gettext('DNS domain'),
-		emptyText: gettext('use host settings'),
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS servers'),
-		vtype: 'IP64AddressList',
-		allowBlank: true,
-		emptyText: gettext('use host settings'),
-		name: 'nameserver',
-		itemId: 'nameserver'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.lxc.DNSInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Resources'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-
-		    if (values.nameserver) {
-			values.nameserver.replace(/[,;]/, ' ');
-			values.nameserver.replace(/^\s+/, '');
-		    }
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.DNS', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcDNS'],
-
-    onlineHelp: 'pct_container_network',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    hostname: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Hostname'),
-		editor: caps.vms['VM.Config.Network'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hostname'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    fieldLabel: gettext('Hostname'),
-			    xtype: 'textfield',
-			    name: 'hostname',
-			    vtype: 'DnsName',
-			    allowBlank: true,
-			    emptyText: 'CT' + vmid.toString()
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.hostname === undefined ||
-				values.hostname === null ||
-				values.hostname === '') {
-				params = { hostname: 'CT'+vmid.toString()};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    },
-	    nameserver: {
-		header: gettext('DNS server'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var win;
-	    if (Ext.isString(rowdef.editor)) {
-		win = Ext.create(rowdef.editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-	    //win.load();
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: run_editor
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/config",
-	    selModel: sm,
-	    cwidth1: 150,
-	    run_editor: run_editor,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status,
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.lxc.Config',
-
-    onlineHelp: 'chapter_pct',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + "/status/" + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var stopBtn = Ext.create('Ext.menu.Item',{
-	    text: gettext('Stop'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
-	    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-	    dangerous: true,
-	    handler: function() {
-		vm_command("stop");
-	    },
-	    iconCls: 'fa fa-stop'
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items:[stopBtn]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'lxc',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    guestType: 'ct',
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    disabled: !caps.vms['VM.Allocate'],
-		    itemId: 'removeBtn',
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'CT', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    consoleType: 'lxc',
-	    consoleName: vm.name,
-	    hidden: template,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'lxctab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveLxcSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push(
-		{
-		    title: gettext('Console'),
-		    itemId: 'consolejs',
-		    iconCls: 'fa fa-terminal',
-		    xtype: 'pveNoVncConsole',
-		    vmid: vmid,
-		    consoleType: 'lxc',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Resources'),
-		itemId: 'resources',
-		expandedOnInit: true,
-		iconCls: 'fa fa-cube',
-		xtype: 'pveLxcRessourceView'
-	    },
-	    {
-		title: gettext('Network'),
-		iconCls: 'fa fa-exchange',
-		itemId: 'network',
-		xtype: 'pveLxcNetworkView'
-	    },
-	    {
-		title: gettext('DNS'),
-		iconCls: 'fa fa-globe',
-		itemId: 'dns',
-		xtype: 'pveLxcDNS'
-	    },
-	    {
-		title: gettext('Options'),
-		itemId: 'options',
-		iconCls: 'fa fa-gear',
-		xtype: 'pveLxcOptions'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		iconCls: 'fa fa-list',
-		xtype: 'proxmoxNodeTasks',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveLxcSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		itemId: 'permissions',
-		iconCls: 'fa fa-unlock',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var lock;
-	    if (!success) {
-		status = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-	    }
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    stopBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'stopped');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    storage: '',
-	    unprivileged: true
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('LXC Container'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'pct_general',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid', // backend only knows vmid
-		    guestType: 'lxc',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'hostname',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Hostname'),
-		    skipEmptyText: true,
-		    allowBlank: true
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unprivileged',
-		    value: true,
-		    bind: {
-			value: '{unprivileged}'
-		    },
-		    fieldLabel: gettext('Unprivileged container')
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'password',
-		    value: '',
-		    fieldLabel: gettext('Password'),
-		    allowBlank: false,
-		    minLength: 5,
-		    change: function(f, value) {
-			if (f.rendered) {
-			    f.up().down('field[name=confirmpw]').validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'confirmpw',
-		    value: '',
-		    fieldLabel: gettext('Confirm password'),
-		    allowBlank: true,
-		    submitValue: false,
-		    validator: function(value) {
-			var pw = this.up().down('field[name=password]').getValue();
-			if (pw !== value) {
-			    return "Passwords do not match!";
-			}
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'ssh-public-keys',
-		    value: '',
-		    fieldLabel: gettext('SSH public key'),
-		    allowBlank: true,
-		    validator: function(value) {
-			var pwfield = this.up().down('field[name=password]');
-			if (value.length) {
-			    var key = PVE.Parser.parseSSHKey(value);
-			    if (!key) {
-				return "Failed to recognize ssh key";
-			    }
-			    pwfield.allowBlank = true;
-			} else {
-			    pwfield.allowBlank = false;
-			}
-			pwfield.validate();
-			return true;
-		    },
-		    afterRender: function() {
-			if (!window.FileReader) {
-			    // No FileReader support in this browser
-			    return;
-			}
-			var cancel = function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			};
-			var field = this;
-			field.inputEl.on('dragover', cancel);
-			field.inputEl.on('dragenter', cancel);
-			field.inputEl.on('drop', function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			    var files = ev.dataTransfer.files;
-			    PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
-				field.setValue(v);
-			    });
-			});
-		    }
-		},
-		{
-		    xtype: 'filebutton',
-		    name: 'file',
-		    hidden: !window.FileReader,
-		    text: gettext('Load SSH Key File'),
-		    listeners: {
-			change: function(btn, e, value) {
-			    e = e.event;
-			    var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
-			    PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
-				field.setValue(v);
-			    });
-			    btn.reset();
-			}
-		    }
-		}
-	    ]
-	},
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('Template'),
-	    onlineHelp: 'pct_container_images',
-	    column1: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'tmplstorage',
-		    fieldLabel: gettext('Storage'),
-		    storageContent: 'vztmpl',
-		    autoSelect: true,
-		    allowBlank: false,
-		    bind: {
-			value: '{storage}',
-			nodename: '{nodename}'
-		    }
-		},
-		{
-		    xtype: 'pveFileSelector',
-		    name: 'ostemplate',
-		    storageContent: 'vztmpl',
-		    fieldLabel: gettext('Template'),
-		    bind: {
-			storage: '{storage}',
-			nodename: '{nodename}'
-		    },
-		    allowBlank: false
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveLxcMountPointInputPanel',
-	    title: gettext('Root Disk'),
-	    insideWizard: true,
-	    isCreate: true,
-	    unused: false,
-	    bind: {
-		nodename: '{nodename}',
-		unprivileged: '{unprivileged}'
-	    },
-	    confid: 'rootfs'
-	},
-	{
-	    xtype: 'pveLxcCPUInputPanel',
-	    title: gettext('CPU'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcMemoryInputPanel',
-	    title: gettext('Memory'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcNetworkInputPanel',
-	    title: gettext('Network'),
-	    insideWizard: true,
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    isCreate: true
-	},
-	{
-	    xtype: 'pveLxcDNSInputPanel',
-	    title: gettext('DNS'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-				property : 'key',
-				direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var wizard = this.up('window');
-		    var kv = wizard.getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete' || key === 'tmplstorage') { // ignore
-			    return;
-			}
-			if (key === 'password') { // don't show pw
-			    return;
-			}
-			var html = Ext.htmlEncode(Ext.JSON.encode(value));
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-		delete kv.tmplstorage;
-
-		if (!kv.pool.length) {
-		    delete kv.pool;
-		}
-
-		if (!kv.password.length && kv['ssh-public-keys']) {
-		    delete kv.password;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/lxc',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response, opts){
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid
-			});
-			win.show();
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-Ext.define('PVE.lxc.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveLxcSnapshotTree'],
-
-    onlineHelp: 'pct_snapshots',
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-lxc-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-	    method: 'GET',
-	    success: function(response, options) {
-		var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-	    }
-	});
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    dangerous: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		var taskdescription = Proxmox.Utils.format_task_description('vzrollback', me.vmid);
-		var snaptime = Ext.Date.format(rec.data.snaptime,'Y-m-d H:i:s');
-		var snapname = rec.data.name;
-
-		var msg = Ext.String.format(gettext('{0} to {1} ({2})'),
-		                            taskdescription, snapname, snaptime);
-		msg += '<p>' + gettext('Note: Rollback stops CT') + '</p>';
-
-		return msg;
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', {
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-//		{
-//		    text: gettext('RAM'),
-//		    align: 'center',
-//		    resizable: false,
-//		    dataIndex: 'vmstate',
-//		    width: 50,
-//		    renderer: function(value, metaData, record) {
-//			if (record.data.name !== 'current') {
-//			    return Proxmox.Utils.format_boolean(value);
-//			}
-//		    }
-//		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    resizable: false,
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true,
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-Ext.define('PVE.window.LxcSnapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-var labelWidth = 120;
-
-Ext.define('PVE.lxc.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: Ext.create('PVE.lxc.MemoryInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-
-Ext.define('PVE.lxc.CPUEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('CPU'),
-	    items: Ext.create('PVE.lxc.CPUInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.lxc.CPUInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcCPUInputPanel',
-
-    onlineHelp: 'pct_cpu',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	PVE.Utils.delete_if_default(values, 'cores', '', me.insideWizard);
-	// cpu{limit,unit} aren't in the wizard so create is always false
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	return values;
-    },
-
-    advancedColumn1: [
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    value: 1024,
-	    minValue: 8,
-	    maxValue: 500000,
-	    labelWidth: labelWidth,
-	    allowBlank: false
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'cores',
-		minValue: 1,
-		maxValue: 128,
-		value: me.insideWizard ? 1 : '',
-		fieldLabel: gettext('Cores'),
-		allowBlank: true,
-		deleteEmpty: true,
-		emptyText: gettext('unlimited')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcMemoryInputPanel',
-
-    onlineHelp: 'pct_memory',
-
-    insideWizard: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'memory',
-		minValue: 16,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'swap',
-		minValue: 0,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Swap') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
- 
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.MPResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 120,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-/*jslint confusion: true*/
-/* hidden: boolean and string
- * bind: function and object
- * disabled: boolean and string
- */
-Ext.define('PVE.lxc.MountPointInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcMountPointInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_storage',
-
-    unused: false, // add unused disk imaged
-
-    unprivileged: false,
-
-    vmconfig: {}, // used to select unused disks
-
-    setUnprivileged: function(unprivileged) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.unprivileged = unprivileged;
-	vm.set('unpriv', unprivileged);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || "mp"+values.mpid;
-	values.file = me.down('field[name=file]').getValue();
-	if (values.mountoptions) {
-	    values.mountoptions = values.mountoptions.join(';');
-	}
-
-	if (me.unused) {
-	    confid = "mp"+values.mpid;
-	} else if (me.isCreate) {
-	    values.file = values.hdstorage + ':' + values.disksize;
-	}
-
-	// delete unnecessary fields
-	delete values.mpid;
-	delete values.hdstorage;
-	delete values.disksize;
-	delete values.diskformat;
-
-	var res = {};
-	res[confid] = PVE.Parser.printLxcMountPoint(values);
-	return res;
-    },
-
-
-    setMountPoint: function(mp) {
-	var me = this;
-	var vm = this.getViewModel();
-	vm.set('mptype', mp.type);
-	if (mp.mountoptions) {
-	    mp.mountoptions = mp.mountoptions.split(';');
-	}
-
-	if (this.confid === 'rootfs') {
-	    var field = me.down('field[name=mountoptions]');
-	    var forbidden = ['nodev', 'noexec'];
-	    var filtered = field.comboItems.filter(e => !forbidden.includes(e[0]));
-	    field.setComboItems(filtered);
-	}
-
-	me.setValues(mp);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.vmconfig = vmconfig;
-	vm.set('unpriv', vmconfig.unprivileged);
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    var name = "mp" + i.toString();
-	    if (!Ext.isDefined(vmconfig[name])) {
-		me.down('field[name=mpid]').setValue(i);
-		return false;
-	    }
-	});
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var vm = me.getViewModel();
-	vm.set('node', nodename);
-	me.down('#diskstorage').setNodename(nodename);
-    },
-
-    controller:  {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=mpid]': {
-		change: function(field, value) {
-		    field.validate();
-		}
-	    },
-	    '#hdstorage': {
-		change: function(field, newValue) {
-		    var me = this;
-		    if (!newValue) {
-			return;
-		    }
-
-		    var rec = field.store.getById(newValue);
-		    if (!rec) {
-			return;
-		    }
-
-		    var vm = me.getViewModel();
-		    vm.set('type', rec.data.type);
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    vm.set('confid', view.confid);
-	    vm.set('unused', view.unused);
-	    vm.set('node', view.nodename);
-	    vm.set('unpriv', view.unprivileged);
-	    vm.set('hideStorSelector', view.unused || !view.isCreate);
-	}
-    },
-
-    viewModel: {
-	data: {
-	    unpriv: false,
-	    unused: false,
-	    showStorageSelector: false,
-	    mptype: '',
-	    type: '',
-	    confid: '',
-	    node: ''
-	},
-
-	formulas: {
-	    quota: function(get) {
-		return !(get('type') === 'zfs' ||
-			 get('type') === 'zfspool' ||
-			 get('unpriv') ||
-			 get('isBind'));
-	    },
-	    hasMP: function(get) {
-		return !!get('confid') && !get('unused');
-	    },
-	    isRoot: function(get) {
-		return get('confid') === 'rootfs';
-	    },
-	    isBind: function(get) {
-		return get('mptype') === 'bind';
-	    },
-	    isBindOrRoot: function(get) {
-		return get('isBind') || get('isRoot');
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'mpid',
-	    fieldLabel: gettext('Mount Point ID'),
-	    minValue: 0,
-	    maxValue: PVE.Utils.mp_counts.mps - 1,
-	    hidden: true,
-	    allowBlank: false,
-	    disabled: true,
-	    bind: {
-		hidden: '{hasMP}',
-		disabled: '{hasMP}'
-	    },
-	    validator: function(value) {
-		var me = this.up('inputpanel');
-		if (!me.rendered) {
-		    return;
-		}
-		if (Ext.isDefined(me.vmconfig["mp"+value])) {
-		    return "Mount point is already in use.";
-		}
-		/*jslint confusion: true*/
-		/* returns a string above */
-		return true;
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    itemId: 'diskstorage',
-	    storageContent: 'rootdir',
-	    hidden: true,
-	    autoSelect: true,
-	    selectformat: false,
-	    defaultSize: 8,
-	    bind: {
-		hidden: '{hideStorSelector}',
-		disabled: '{hideStorSelector}',
-		nodename: '{node}'
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    disabled: true,
-	    submitValue: false,
-	    fieldLabel: gettext('Disk image'),
-	    name: 'file',
-	    bind: {
-		hidden: '{!hideStorSelector}'
-	    }
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'textfield',
-	    name: 'mp',
-	    value: '',
-	    emptyText:  gettext('/some/path'),
-	    allowBlank: false,
-	    disabled: true,
-	    fieldLabel: gettext('Path'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'backup',
-	    fieldLabel: gettext('Backup'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isBindOrRoot}'
-	    }
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'quota',
-	    defaultValue: 0,
-	    bind: {
-		disabled: '{!quota}'
-	    },
-	    fieldLabel: gettext('Enable quota'),
-	    listeners: {
-		disable: function() {
-		    this.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'ro',
-	    defaultValue: 0,
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    },
-	    fieldLabel: gettext('Read-only')
-	},
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'mountoptions',
-	    fieldLabel: gettext('Mount options'),
-	    deleteEmpty: false,
-	    comboItems: [
-		['noatime', 'noatime'],
-		['nodev', 'nodev'],
-		['noexec', 'noexec'],
-		['nosuid', 'nosuid']
-	    ],
-	    multiSelect: true,
-	    value: [],
-	    allowBlank: true
-	},
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'acl',
-	    fieldLabel: 'ACLs',
-	    deleteEmpty: false,
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText],
-		['1', Proxmox.Utils.enabledText],
-		['0', Proxmox.Utils.disabledText]
-	    ],
-	    value: '__default__',
-	    bind: {
-		disabled: '{isBind}'
-	    },
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    inputValue: '0', // reverses the logic
-	    name: 'replicate',
-	    fieldLabel: gettext('Skip replication')
-	}
-    ]
-});
-
-Ext.define('PVE.lxc.MountPointEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    unprivileged: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    unprivileged: me.unprivileged,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-	    subject = gettext('Mount Point');
-	} else {
-	    subject = gettext('Mount Point') + ' (' + me.confid + ')';
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    /*jslint confusion: true*/
-		    /*data is defined as array above*/
-		    var value = response.result.data[me.confid];
-		    /*jslint confusion: false*/
-		    var mp = PVE.Parser.parseLxcMountPoint(value);
-
-		    if (!mp) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
-			me.close();
-			return;
-		    }
-
-		    ipanel.setMountPoint(mp);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.pool.StatusView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-    disabled: true,
-
-    title: gettext('Status'),
-    cwidth1: 150,
-    interval: 30000,
-    //height: 195,
-    initComponent : function() {
-	var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var rows = {
-	    comment: {
-		header: gettext('Comment'), 
-		renderer: Ext.String.htmlEncode,
-		required: true
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/pools/" + pool,
-	    rows: rows
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var statusview = Ext.create('PVE.pool.StatusView', {
-	    pveSelNode: me.pveSelNode,
-	    style: 'padding-top:0px'
-	});
-
-	var rstore = statusview.rstore;
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    defaults: {
-		style: 'padding-top:10px',
-		width: 800
-	    },
-	    items: [ statusview ]
-	});
-
-	me.on('activate', rstore.startUpdate);
-	me.on('destroy', rstore.stopUpdate);	
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    onlineHelp: 'pveum_pools',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-	    hstateid: 'pooltab',
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    xtype: 'pvePoolSummary',
-		    itemId: 'summary'
-		},
-		{
-		    title: gettext('Members'),
-		    xtype: 'pvePoolMembers',
-		    iconCls: 'fa fa-th',
-		    pool: pool,
-		    itemId: 'members'
-		},
-		{
-		    xtype: 'pveACLView',
-		    title: gettext('Permissions'),
-		    iconCls: 'fa fa-unlock',
-		    itemId: 'permissions',
-		    path: '/pool/' + pool
-		}
-	    ]
-	});
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.panel.StorageBase', {
-    extend: 'Proxmox.panel.InputPanel',
-    controller: 'storageEdit',
-
-    type: '',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = me.type;
-	} else {
-	    delete values.storage;
-	}
-
-	values.disable = values.enable ? 0 : 1;
-	delete values.enable;
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1.unshift({
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    name: 'storage',
-	    value: me.storageId || '',
-	    fieldLabel: 'ID',
-	    vtype: 'StorageId',
-	    allowBlank: false
-	});
-
-	me.column2.unshift(
-	    {
-		xtype: 'pveNodeSelector',
-		name: 'nodes',
-		disabled: me.storageId === 'local',
-		fieldLabel: gettext('Nodes'),
-		emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
-		multiSelect: true,
-		autoSelect: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.storageId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/storage';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/storage/' + me.storageId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create(me.paneltype, {
-	    type: me.type,
-	    isCreate: me.isCreate,
-	    storageId: me.storageId
-	});
-
-	Ext.apply(me, {
-            subject: PVE.Utils.format_storage_type(me.type),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    var ctypes = values.content || '';
-
-		    values.content = ctypes.split(',');
-
-		    if (values.nodes) {
-			values.nodes = values.nodes.split(',');
-		    }
-		    values.enable = values.disable ? 0 : 1;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.Upload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveStorageUpload',
-
-    resizable: false,
-
-    modal: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var xhr;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
-
-	var pbar = Ext.create('Ext.ProgressBar', {
-            text: 'Ready',
-	    hidden: true
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    method: 'POST',
-	    waitMsgTarget: true,
-	    bodyPadding: 10,
-	    border: false,
-	    width: 300,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-            },
-	    items: [
-		{
-		    xtype: 'pveContentTypeSelector',
-		    cts: me.contents,
-		    fieldLabel: gettext('Content'),
-		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
-		    allowBlank: false
-		},
-		pbar
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doStandardSubmit = function() {
-	    form.submit({
-		url: "/api2/htmljs" + baseurl,
-		waitMsg: gettext('Uploading file...'),
-		success: function(f, action) {
-		    me.close();
-		},
-		failure: function(f, action) {
-		    var msg = PVE.Utils.extractFormActionError(action);
-                    Ext.Msg.alert(gettext('Error'), msg);
-		}
-	    });
-	};
-
-	var updateProgress = function(per, bytes) {
-	    var text = (per * 100).toFixed(2) + '%';
-	    if (bytes) {
-		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
-	    }
-	    pbar.updateProgress(per, text);
-	};
-
-	var abortBtn = Ext.create('Ext.Button', {
-	    text: gettext('Abort'),
-	    disabled: true,
-	    handler: function() {
-		me.close();
-	    }
-	});
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Upload'),
-	    disabled: true,
-	    handler: function(button) {
-		var fd;
-		try {
-		    fd = new FormData();
-		} catch (err) {
-		    doStandardSubmit();
-		    return;
-		}
-
-		button.setDisabled(true);
-		abortBtn.setDisabled(false);
-
-		var field = form.findField('content');
-		fd.append("content", field.getValue());
-		field.setDisabled(true);
-
-		field = form.findField('filename');
-		var file = field.fileInputEl.dom;
-		fd.append("filename", file.files[0]);
-		field.setDisabled(true);
-
-		pbar.setVisible(true);
-		updateProgress(0);
-
-		xhr = new XMLHttpRequest();
-
-		xhr.addEventListener("load", function(e) {
-		    if (xhr.status == 200) {
-			me.close();
-		    } else {
-			var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
-			if (xhr.responseText !== "") {
-			    var result = Ext.decode(xhr.responseText);
-			    result.message = msg;
-			    msg = Proxmox.Utils.extractRequestError(result, true);
-			}
-			Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			    me.close();
-			});
-		    }
-		}, false);
-
-		xhr.addEventListener("error", function(e) {
-		    var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
-		    Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			me.close();
-		    });
-		});
-
-		xhr.upload.addEventListener("progress", function(evt) {
-		    if (evt.lengthComputable) {
-			var percentComplete = evt.loaded / evt.total;
-			updateProgress(percentComplete, evt.loaded);
-		    }
-		}, false);
-
-		xhr.open("POST", "/api2/json" + baseurl, true);
-		xhr.send(fd);
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-        Ext.apply(me, {
-            title: gettext('Upload'),
-	    items: me.formPanel,
-	    buttons: [ abortBtn, submitBtn ],
-	    listeners: {
-		close: function() {
-		    if (xhr) {
-			xhr.abort();
-		    }
-		}
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ContentView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveStorageContentView',
-
-    stateful: true,
-    stateId: 'grid-storage-content',
-    viewConfig: {
-	trackOver: false,
-	loadMask: false
-    },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-storage-content',
-	    groupField: 'content',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    },
-	    sorters: {
-		property: 'volid',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	    me.statusStore.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-
-	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
-	    text: gettext('Upload'),
-	    handler: function() {
-		var me = this;
-		var win = Ext.create('PVE.storage.Upload', {
-		    nodename: nodename,
-		    storage: storage,
-		    contents: me.contents
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var imageRemoveButton;
-	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: baseurl + '/'
-	});
-
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && rec.data.content === 'images') {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		me = this;
-
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
-		    reload();
-
-		});
-	    }
-	});
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (rec.data.volid.match(/vzdump-qemu-/)) {
-			    vmtype = 'qemu';
-			} else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
-		    }
-		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
-    }
-}, function() {
-
-    Ext.define('pve-storage-content', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'volid', 'content', 'format', 'size', 'used', 'vmid',
-	    'channel', 'id', 'lun',
-	    {
-		name: 'text',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    return PVE.Utils.render_storage_content(value, {}, record);
-		}
-	    }
-	],
-	idProperty: 'volid'
-    });
-
-});
-Ext.define('PVE.storage.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveStorageStatusView',
-
-    height: 230,
-    title: gettext('Status'),
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 30 5 30'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 30
-	},
-	{
-	    itemId: 'enabled',
-	    title: gettext('Enabled'),
-	    printBar: false,
-	    textField: 'disabled',
-	    renderer: Proxmox.Utils.format_neg_boolean
-	},
-	{
-	    itemId: 'active',
-	    title: gettext('Active'),
-	    printBar: false,
-	    textField: 'active',
-	    renderer: Proxmox.Utils.format_boolean
-	},
-	{
-	    itemId: 'content',
-	    title: gettext('Content'),
-	    printBar: false,
-	    textField: 'content',
-	    renderer: PVE.Utils.format_content_types
-	},
-	{
-	    itemId: 'type',
-	    title: gettext('Type'),
-	    printBar: false,
-	    textField: 'type',
-	    renderer: PVE.Utils.format_storage_type
-	},
-	{
-	    xtype: 'box',
-	    height: 10
-	},
-	{
-	    itemId: 'usage',
-	    title: gettext('Usage'),
-	    valueField: 'used',
-	    maxField: 'total'
-	}
-    ],
-
-    updateTitle: function() {
-	return;
-    }
-});
-Ext.define('PVE.storage.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStorageSummary',
-    scrollable: true,
-    bodyPadding: 5,
-    tbar: [
-	'->',
-	{
-	    xtype: 'proxmoxRRDTypeSelector'
-	}
-    ],
-    layout: {
-	type: 'column'
-    },
-    defaults: {
-	padding: 5,
-	columnWidth: 1
-    },
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var rstore  = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/storage/" + storage + "/status",
-	    interval: 1000
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl:  "/api2/json/nodes/" + nodename + "/storage/" + storage + "/rrddata",
-	    model: 'pve-rrd-storage'
-	});
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'pveStorageStatusView',
-		    pveSelNode: me.pveSelNode,
-		    rstore: rstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Usage'),
-		    fields: ['total','used'],
-		    fieldTitles: ['Total Size', 'Used Size'],
-		    store: rrdstore
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.Browser', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.storage.Browser',
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storeid = me.pveSelNode.data.storage;
-	if (!storeid) {
-	    throw "no storage ID specified";
-	}
-
-
-	me.items = [
-	    {
-		title: gettext('Summary'),
-		xtype: 'pveStorageSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    }
-	];
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Storage {0} on node {1}"),
-				     "'" + storeid + "'", "'" + nodename + "'"),
-	    hstateid: 'storagetab'
-	});
-
-	if (caps.storage['Datastore.Allocate'] ||
-	    caps.storage['Datastore.AllocateSpace'] ||
-	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
-	}
-
-	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.storage.DirInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_directory',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'path',
-		value: '',
-		fieldLabel: gettext('Directory'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.NFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveNFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'path',
-    displayField: 'path',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.nfsServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.nfsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.nfsServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'path', 'options' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/nfs'
-	    }
-	});
-
-	store.sort('path', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.NFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_nfs',
-
-    options : [],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var i;
-	var res = [];
-	for (i = 0; i < me.options.length; i++) {
-	    var item = me.options[i];
-	    if (!item.match(/^vers=(.*)$/)) {
-		res.push(item);
-	    }
-	}
-	if (values.nfsversion && values.nfsversion !== '__default__') {
-	    res.push('vers=' + values.nfsversion);
-	}
-	delete values.nfsversion;
-	values.options = res.join(',');
-	if (values.options === '') {
-	    delete values.options;
-	    if (!me.isCreate) {
-		values["delete"] = "options";
-	    }
-	}
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	var me = this;
-	if (values.options) {
-	    var res = values.options;
-	    me.options = values.options.split(',');
-	    me.options.forEach(function(item) {
-		var match = item.match(/^vers=(.*)$/);
-		if (match) {
-		    values.nfsversion = match[1];
-		}
-	    });
-	}
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=export]');
-			    exportField.setServer(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'pveNFSScan' : 'displayfield',
-		name: 'export',
-		value: '',
-		fieldLabel: 'Export',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxKVComboBox',
-		fieldLabel: gettext('NFS Version'),
-		name: 'nfsversion',
-		value: '__default__',
-		deleteEmpty: false,
-		comboItems: [
-			['__default__', Proxmox.Utils.defaultText],
-			['3', '3'],
-			['4', '4'],
-			['4.1', '4.1'],
-			['4.2', '4.2']
-		]
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.CIFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCIFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'share',
-    displayField: 'share',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.cifsServer) {
-	    me.store.removeAll();
-	}
-
-	var params = {};
-	if (me.cifsUsername && me.cifsPassword) {
-	    params.username =  me.cifsUsername;
-	    params.password = me.cifsPassword;
-	}
-
-	if (me.cifsDomain) {
-	    params.domain = me.cifsDomain;
-	}
-
-	me.store.getProxy().setExtraParams(params);
-	me.allQuery = me.cifsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	this.cifsServer = server;
-    },
-
-    setUsername: function(username) {
-	this.cifsUsername = username;
-    },
-
-    setPassword: function(password) {
-	this.cifsPassword = password;
-    },
-
-    setDomain: function(domain) {
-	this.cifsDomain = domain;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['description', 'share'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/cifs'
-	    }
-	});
-	store.sort('share', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.CIFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_cifs',
-
-    initComponent : function() {
-	var me = this;
-
-	var passwordfield = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    inputType: 'password',
-	    name: 'password',
-	    value: me.isCreate ? '' : '********',
-	    fieldLabel: gettext('Password'),
-	    allowBlank: false,
-	    disabled: me.isCreate,
-	    minLength: 1,
-	    listeners: {
-		change: function(f, value) {
-
-		    if (me.isCreate) {
-			var exportField = me.down('field[name=share]');
-			exportField.setPassword(value);
-		    }
-		}
-	    }
-	});
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=share]');
-			    exportField.setServer(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: '',
-		fieldLabel: gettext('Username'),
-		emptyText: gettext('Guest user'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (!me.isCreate) {
-			    return;
-			}
-			var exportField = me.down('field[name=share]');
-			exportField.setUsername(value);
-
-			if (value == "") {
-			    passwordfield.disable();
-			} else {
-			    passwordfield.enable();
-			}
-			passwordfield.validate();
-		    }
-		}
-	    },
-	    passwordfield,
-	    {
-		xtype: me.isCreate ? 'pveCIFSScan' : 'displayfield',
-		name: 'share',
-		value: '',
-		fieldLabel: 'Share',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'domain',
-		value: me.isCreate ? '' : undefined,
-		fieldLabel: gettext('Domain'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-
-			    var exportField = me.down('field[name=share]');
-			    exportField.setDomain(value);
-			}
-		    }
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.GlusterFsScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveGlusterFsScan',
-
-    queryParam: 'server',
-
-    valueField: 'volname',
-    displayField: 'volname',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: 'Scanning...',
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.glusterServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.glusterServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.glusterServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'volname' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/glusterfs'
-	    }
-	});
-
-	store.sort('volname', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.GlusterFsInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_glusterfs',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var volumeField = me.down('field[name=volume]');
-			    volumeField.setServer(value);
-			    volumeField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		name: 'server2',
-		value: '',
-		fieldLabel: gettext('Second Server'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'pveGlusterFsScan' : 'displayfield',
-		name: 'volume',
-		value: '',
-		fieldLabel: 'Volume name',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'iso', 'backup', 'vztmpl', 'snippets'],
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.IScsiScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveIScsiScan',
-
-    queryParam: 'portal',
-    valueField: 'target',
-    displayField: 'target',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.portal) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.portal;
-
-	me.callParent();
-    },
-
-    setPortal: function(portal) {
-	var me = this;
-
-	me.portal = portal;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'target', 'portal' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/iscsi'
-	    }
-	});
-
-	store.sort('target', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.IScsiInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_open_iscsi',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	values.content = values.luns ? 'images' : 'none';
-	delete values.luns;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	values.luns = (values.content.indexOf('images') !== -1) ? true : false;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: 'Portal',
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=target]');
-			    exportField.setPortal(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		readOnly: !me.isCreate,
-		xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: 'Target',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'checkbox',
-		name: 'luns',
-		checked: true,
-		fieldLabel: gettext('Use LUNs directly')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.VgSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveVgSelector',
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'vg', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	store.sort('vg', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseStorageSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseStorageSelector',
-
-    existingGroupsText: gettext("Existing volume groups"),
-    queryMode: 'local',
-    editable: false,
-    value: '',
-    valueField: 'storage',
-    displayField: 'text',
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {
-		addRecords: true,
-		params: {
-		    type: 'iscsi'
-		}
-	    },
-	    fields: [ 'storage', 'type', 'content',
-		      {
-			  name: 'text',
-			  convert: function(value, record) {
-			      if (record.data.storage) {
-				  return record.data.storage + " (iSCSI)";
-			      } else {
-				  return me.existingGroupsText;
-			      }
-			  }
-		      }],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/storage/'
-	    }
-	});
-
-	store.loadData([{ storage: '' }], true);
-
-	store.sort('storage', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LVMInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvm',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.VgSelector', {
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		allowBlank: false
-	    });
-
-	    var baseField = Ext.createWidget('pveFileSelector', {
-		name: 'base',
-		hidden: true,
-		disabled: true,
-		nodename: 'localhost',
-		storageContent: 'images',
-		fieldLabel: gettext('Base volume'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseStorageSelector',
-		name: 'basesel',
-		fieldLabel: gettext('Base storage'),
-		submitValue: false,
-		listeners: {
-		    change: function(f, value) {
-			if (value) {
-			    vgnameField.setVisible(true);
-			    vgnameField.setDisabled(false);
-			    vgField.setVisible(false);
-			    vgField.setDisabled(true);
-			    baseField.setVisible(true);
-			    baseField.setDisabled(false);
-			} else {
-			    vgnameField.setVisible(false);
-			    vgnameField.setDisabled(true);
-			    vgField.setVisible(true);
-			    vgField.setDisabled(false);
-			    baseField.setVisible(false);
-			    baseField.setDisabled(true);
-			}
-			baseField.setStorage(value);
-		    }
-		}
-	    });
-
-	    me.column1.push(baseField);
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	// here value is an array, 
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.TPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveTPSelector',
-
-    queryParam: 'vg',
-    valueField: 'lv',
-    displayField: 'lv',
-    editable: false,
-
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.vg) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.vg;
-
-	me.callParent();
-    },
-
-    setVG: function(myvg) {
-	var me = this;
-
-	me.vg = myvg;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'lv' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin'
-	    }
-	});
-
-	store.sort('lv', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseVGSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseVGSelector',
-
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {},
-	    fields: [ 'vg', 'size', 'free'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LvmThinInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvmthin',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	var thinpoolField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'thinpool',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Thin Pool'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.TPoolSelector', {
-		name: 'thinpool',
-		fieldLabel: gettext('Thin Pool'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseVGSelector',
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    vgField.setVG(value);
-			    vgField.setValue('');
-			}
-		    }
-		}
-	    });
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	me.column1.push(thinpoolField);
-
-	// here value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.CephFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'storage_cephfs',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'cephfs';
-
-	me.column1 = [];
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		value: '',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: 'admin',
-		bind:  {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['backup', 'iso', 'vztmpl', 'snippets'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: 'backup',
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged cephFS')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.Ceph.Model', {
-    extend: 'Ext.app.ViewModel',
-    alias: 'viewmodel.cephstorage',
-
-    data: {
-	pveceph: true,
-	pvecephPossible: true
-    }
-});
-
-Ext.define('PVE.storage.Ceph.Controller', {
-    extend: 'PVE.controller.StorageEdit',
-    alias: 'controller.cephstorage',
-
-    control: {
-	'#': {
-	    afterrender: 'queryMonitors'
-	},
-	'textfield[name=username]': {
-	    disable: 'resetField'
-	},
-	'displayfield[name=monhost]': {
-	    enable: 'queryMonitors'
-	},
-	'textfield[name=monhost]': {
-	    disable: 'resetField',
-	    enable: 'resetField'
-	}
-    },
-    resetField: function(field) {
-	field.reset();
-    },
-    queryMonitors: function(field, newVal, oldVal) {
-	// we get called with two signatures, the above one for a field
-	// change event and the afterrender from the view, this check only
-	// can be true for the field change one and omit the API request if
-	// pveceph got unchecked - as it's not needed there.
-	if (field && !newVal && oldVal) {
-	    return;
-	}
-	var view = this.getView();
-	var vm = this.getViewModel();
-	if (!(view.isCreate || vm.get('pveceph'))) {
-	    return; // only query on create or if editing a pveceph store
-	}
-
-	var monhostField = this.lookupReference('monhost');
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/json/nodes/localhost/ceph/mon',
-	    method: 'GET',
-	    scope: this,
-	    callback: function(options, success, response) {
-		var data = response.result.data;
-		if (response.status === 200) {
-		    if (data.length > 0) {
-			var monhost = Ext.Array.pluck(data, 'name').sort().join(',');
-			monhostField.setValue(monhost);
-			monhostField.resetOriginalValue();
-			if (view.isCreate) {
-			    vm.set('pvecephPossible', true);
-			}
-		    } else {
-			vm.set('pveceph', false);
-		    }
-		} else {
-		    vm.set('pveceph', false);
-		    vm.set('pvecephPossible', false);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.storage.RBDInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'ceph_rados_block_devices',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'rbd';
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveCephPoolSelector',
-		nodename: me.nodename,
-		name: 'pool',
-		bind: {
-		    disabled: '{!pveceph}',
-		    submitValue: '{pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },{
-		xtype: 'textfield',
-		name: 'pool',
-		value: 'rbd',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		nodename: me.nodename,
-		name: 'pool',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		value: 'admin',
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'rootdir'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: ['images'],
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'krbd',
-		uncheckedValue: 0,
-		fieldLabel: 'KRBD'
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.ZFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    isLIO: false,
-	    isComstar: true,
-	    hasWriteCacheOption: true
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[name=iscsiprovider]': {
-		change: 'changeISCSIProvider'
-	    }
-	},
-	changeISCSIProvider: function(f, newVal, oldVal) {
-	    var vm = this.getViewModel();
-	    vm.set('isLIO', newVal === 'LIO');
-	    vm.set('isComstar', newVal === 'comstar');
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.content = 'images';
-	}
-
-	values.nowritecache = values.writecache ? 0 : 1;
-	delete values.writecache;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function diff(values) {
-	values.writecache = values.nowritecache ? 0 : 1;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: gettext('Portal'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'blocksize',
-		value: '4k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: gettext('Target'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_tg',
-		value: '',
-		fieldLabel: gettext('Target group'),
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		allowBlank: true
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: me.isCreate ? 'pveiScsiProviderSelector' : 'displayfield',
-		name: 'iscsiprovider',
-		value: 'comstar',
-		fieldLabel: gettext('iSCSI Provider'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'writecache',
-		checked: true,
-		bind: me.isCreate ? { disabled: '{!hasWriteCacheOption}' } : { hidden: '{!hasWriteCacheOption}' },
-		uncheckedValue: 0,
-		fieldLabel: gettext('Write cache')
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_hg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		fieldLabel: gettext('Host group'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'lio_tpg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
-		allowBlank: false,
-		fieldLabel: gettext('Target portal group')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.ZFSPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveZFSPoolSelector',
-    valueField: 'pool',
-    displayField: 'pool',
-    queryMode: 'local',
-    editable: false,
-    listConfig: {
-	loadingText: gettext('Scanning...')
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'pool', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/zfs'
-	    }
-	});
-
-	store.sort('pool', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ZFSPoolInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_zfspool',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
-		name: 'pool',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	} else {
-	    me.column1.push(Ext.createWidget('displayfield', {
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	}
-
-	// value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push(
-	    {xtype: 'pveContentTypeSelector',
-	     cts: ['images', 'rootdir'],
-	     fieldLabel: gettext('Content'),
-	     name: 'content',
-	     value: ['images', 'rootdir'],
-	     multiSelect: true,
-	     allowBlank: false
-	});
-	/*jslint confusion: false*/
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'blocksize',
-		emptyText: '8k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.StatusView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAStatusView'],
-
-    onlineHelp: 'chapter_ha_manager',
-
-    sortPriority: {
-	quorum: 1,
-	master: 2,
-	lrm: 3,
-	service: 4
-    },
-    
-    initComponent : function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sortAfterUpdate: true,
-	    sorters: [{
-		sorterFn: function(rec1, rec2) {
-		    var p1 = me.sortPriority[rec1.data.type];
-		    var p2 = me.sortPriority[rec2.data.type];
-		    return (p1 !== p2) ? ((p1 > p2) ? 1 : -1) : 0;
-		}
-	    }],
-	    filters: {
-		property: 'type',
-		value: 'service',
-		operator: '!='
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 80,
-		    flex: 1,
-		    dataIndex: 'status'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-    }
-}, function() {
-
-    Ext.define('pve-ha-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'type', 'node', 'status', 'sid',
-	    'state', 'group', 'comment',
-	    'max_restart', 'max_relocate', 'type',
-	    'crm_state', 'request_state'
-	],
-	idProperty: 'id'
-    });
-
-});
-Ext.define('PVE.ha.Status', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveHAStatus',
-
-    onlineHelp: 'chapter_ha_manager',
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-	    interval: me.interval,
-	    model: 'pve-ha-status',
-	    storeid: 'pve-store-' + (++Ext.idSeed),
-	    groupField: 'type',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/ha/status/current'
-	    }
-	});
-
-	me.items = [{
-	    xtype: 'pveHAStatusView',
-	    title: gettext('Status'),
-	    rstore: me.rstore,
-	    border: 0,
-	    collapsible: true,
-	    padding: '0 0 20 0'
-	},{
-	    xtype: 'pveHAResourcesView',
-	    flex: 1,
-	    collapsible: true,
-	    title: gettext('Resources'),
-	    border: 0,
-	    rstore: me.rstore
-	}];
-
-	me.callParent();
-	me.on('activate', me.rstore.startUpdate);
-    }
-});
-Ext.define('PVE.ha.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveHAGroupSelector'],
-
-    value: [],
-    autoSelect: false,
-    valueField: 'group',
-    displayField: 'group',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		width: 100,
-		sortable: true,
-		dataIndex: 'group'
-	    },
-	    {
-		header: gettext('Nodes'),
-		width: 100,
-		sortable: false,
-		dataIndex: 'nodes'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 1,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode
-	    }
-	]
-    },
-    store: {
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getStore().load();
-    }
-
-}, function() {
-
-    Ext.define('pve-ha-groups', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'group', 'type', 'digest', 'nodes', 'comment',
-	    {
-		name : 'restricted',
-		type: 'boolean'
-	    },
-	    {
-		name : 'nofailback',
-		type: 'boolean'
-	    }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/cluster/ha/groups"
-	},
-	idProperty: 'group'
-    });
-});
-Ext.define('PVE.ha.VMResourceInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_resource_config',
-    vmid: undefined,
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.vmid) {
-	    values.sid = values.vmid;
-	}
-	delete values.vmid;
-
-	PVE.Utils.delete_if_default(values, 'group', '', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_restart', '1', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_relocate', '1', me.isCreate);
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var MIN_QUORUM_VOTES = 3;
-
-	var disabledHint = Ext.createWidget({
-	    xtype: 'displayfield', // won't get submitted by default
-	    userCls: 'pve-hint',
-	    value: 'Disabling the resource will stop the guest system. ' +
-	    'See the online help for details.',
-	    hidden: true
-	});
-
-	var fewVotesHint = Ext.createWidget({
-	    itemId: 'fewVotesHint',
-	    xtype: 'displayfield',
-	    userCls: 'pve-hint',
-	    value: 'At least three quorum votes are recommended for reliable HA.',
-	    hidden: true
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/config/nodes',
-	    method: 'GET',
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var nodes = response.result.data;
-		var votes = 0;
-		Ext.Array.forEach(nodes, function(node) {
-		    var vote = parseInt(node.quorum_votes, 10); // parse as base 10
-		    votes += vote || 0; // parseInt might return NaN, which is false
-		});
-
-		if (votes < MIN_QUORUM_VOTES) {
-		    fewVotesHint.setVisible(true);
-		}
-	    }
-	});
-
-	/*jslint confusion: true */
-	var vmidStore = (me.vmid) ? {} : {
-	    model: 'PVEResources',
-	    autoLoad: true,
-	    sorters: 'vmid',
-	    filters: [
-		{
-		    property: 'type',
-		    value: /lxc|qemu/
-		},
-		{
-		    property: 'hastate',
-		    value: /unmanaged/
-		}
-	    ]
-	};
-
-	// value is a string above, but a number below
-	me.column1 = [
-	    {
-		xtype: me.vmid ? 'displayfield' : 'vmComboSelector',
-		submitValue: me.isCreate,
-		name: 'vmid',
-		fieldLabel: (me.vmid && me.guestType === 'ct') ? 'CT' : 'VM',
-		value: me.vmid,
-		store: vmidStore,
-		validateExists: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_restart',
-		fieldLabel: gettext('Max. Restart'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_relocate',
-		fieldLabel: gettext('Max. Relocate'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.column2 = [
-	    {
-		xtype: 'pveHAGroupSelector',
-		name: 'group',
-		fieldLabel: gettext('Group')
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'state',
-		value: 'started',
-		fieldLabel: gettext('Request State'),
-		comboItems: [
-		    ['started', 'started'],
-		    ['stopped', 'stopped'],
-		    ['ignored', 'ignored'],
-		    ['disabled', 'disabled']
-		],
-		listeners: {
-		    'change': function(field, newValue) {
-			if (newValue === 'disabled') {
-			    disabledHint.setVisible(true);
-			}
-			else {
-			    if (disabledHint.isVisible()) {
-				disabledHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    disabledHint
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    fewVotesHint
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.VMResourceEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmid: undefined,
-    guestType: undefined,
-    isCreate: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	if (me.isCreate === undefined) {
-	    me.isCreate = !me.vmid;
-	}
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/resources';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/resources/' + me.vmid;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.VMResourceInputPanel', {
-	    isCreate: me.isCreate,
-	    vmid: me.vmid,
-	    guestType: me.guestType
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Resource') + ': ' + gettext('Container') +
-	    '/' + gettext('Virtual Machine'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    var regex =  /^(\S+):(\S+)$/;
-		    var res = regex.exec(values.sid);
-
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			throw "got unexpected resource type";
-		    }
-
-		    values.vmid = res[2];
-		    
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.ResourcesView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAResourcesView'],
-
-    onlineHelp: 'ha_manager_resources',
-
-    stateful: true,
-    stateId: 'grid-ha-resources',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!me.rstore) {
-	    throw "no store given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    filters: {
-		property: 'type',
-		value: 'service'
-	    }
-	});
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var render_error = function(dataIndex, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors[dataIndex];
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    var sid = rec.data.sid;
-	    
-	    var regex =  /^(\S+):(\S+)$/;
-	    var res = regex.exec(sid);
-
-	    if (res[1] !== 'vm' && res[1] !== 'ct') {
-		return;
-	    }
-	    var guestType = res[1];
-	    var vmid = res[2];
-	    
-            var win = Ext.create('PVE.ha.VMResourceEdit',{
-                guestType: guestType,
-                vmid: vmid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/resources/',
-	    getUrl: function(rec) {
-		var me = this;
-		return me.baseurl + '/' + rec.get('sid');
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.VMResourceEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'sid'
-		},
-		{
-		    header: gettext('State'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Request State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'started';
-		    },
-		    dataIndex: 'request_state'
-		},
-		{
-		    header: gettext('CRM State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    dataIndex: 'crm_state'
-		},
-		{
-		    header: gettext('Max. Restart'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_restart'
-		},
-		{
-		    header: gettext('Max. Relocate'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_relocate'
-		},
-		{
-		    header: gettext('Group'),
-		    width: 200,
-		    sortable: true,
-		    renderer: function(value, metaData, record) {
-			return render_error('group', value, metaData, record);
-		    },
-		    dataIndex: 'group'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-resources', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	  'sid', 'state', 'digest', 'errors', 'group', 'comment',
-	  'max_restart', 'max_relocate', 'type', 'status', 'node',
-	  'crm_state', 'request_state'
-	],
-	idProperty: 'sid'
-    });
-
-});
-Ext.define('PVE.ha.GroupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_groups',
-
-    groupId: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = 'group';
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var update_nodefield, update_node_selection;
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    update_nodefield(selected);
-		}
-	    }
-	});
-
-	// use already cached data to avoid an API call
-	var data = PVE.data.ResourceStore.getNodes();
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'node', 'mem', 'cpu', 'priority' ],
-	    data: data,
-	    proxy: {
-		type: 'memory',
-		reader: {type: 'json'}
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var nodegrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Node'),
-		    flex: 1,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Memory usage') + " %",
-		    renderer: PVE.Utils.render_mem_usage_percent,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'mem'
-		},
-		{
-		    header: gettext('CPU usage'),
-		    renderer: PVE.Utils.render_cpu,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'cpu'
-		},
-		{
-		    header: 'Priority',
-		    xtype: 'widgetcolumn',
-		    dataIndex: 'priority',
-		    sortable: true,
-		    stopSelection: true,
-		    widget: {
-			xtype: 'proxmoxintegerfield',
-			minValue: 0,
-			maxValue: 1000,
-			isFormField: false,
-			listeners: {
-			    change: function(numberfield, value, old_value) {
-				var record = numberfield.getWidgetRecord();
-				record.set('priority', value);
-				update_nodefield(sm.getSelection());
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	var nodefield = Ext.create('Ext.form.field.Hidden', {
-	    name: 'nodes',
-	    value: '',
-	    listeners: {
-		change: function (nodefield, value) {
-		    update_node_selection(value);
-		}
-	    },
-	    isValid: function () {
-		var value = nodefield.getValue();
-		return (value && 0 !== value.length);
-	    }
-	});
-
-	update_node_selection = function(string) {
-	    sm.deselectAll(true);
-
-	    string.split(',').forEach(function (e, idx, array) {
-		var res = e.split(':');
-
-		store.each(function(record) {
-		    var node = record.get('node');
-
-		    if (node == res[0]) {
-			sm.select(record, true);
-			record.set('priority', res[1]);
-			record.commit();
-		    }
-		});
-	    });
-	    nodegrid.reconfigure(store);
-
-	};
-
-	update_nodefield = function(selected) {
-	    var nodes = '';
-	    var first_iteration = true;
-	    Ext.Array.each(selected, function(record) {
-		if (!first_iteration) {
-		    nodes += ',';
-		}
-		first_iteration = false;
-
-		nodes += record.data.node;
-		if (record.data.priority) {
-		    nodes += ':' + record.data.priority;
-		}
-	    });
-
-	    // nodefield change listener calls us again, which results in a
-	    // endless recursion, suspend the event temporary to avoid this
-	    nodefield.suspendEvent('change');
-	    nodefield.setValue(nodes);
-	    nodefield.resumeEvent('change');
-	};
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'group',
-		value: me.groupId || '',
-		fieldLabel: 'ID',
-		vtype: 'StorageId',
-		allowBlank: false
-	    },
-	    nodefield
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'restricted',
-		uncheckedValue: 0,
-		fieldLabel: 'restricted'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'nofailback',
-		uncheckedValue: 0,
-		fieldLabel: 'nofailback'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    nodegrid
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    groupId: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	me.isCreate = !me.groupId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/groups';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
-	    isCreate: me.isCreate,
-	    groupId: me.groupId
-	});
-
-	Ext.apply(me, {
-            subject: gettext('HA Group'),
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.GroupsView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAGroupsView'],
-
-    onlineHelp: 'ha_manager_groups',
-
-    stateful: true,
-    stateId: 'grid-ha-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-	});
-	
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-            var win = Ext.create('PVE.ha.GroupEdit',{
-                groupId: rec.data.group
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/groups/',
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.GroupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Group'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'group'
-		},
-		{
-		    header: 'restricted',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'restricted'
-		},
-		{
-		    header: 'nofailback',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'nofailback'
-		},
-		{
-		    header: gettext('Nodes'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'nodes'
-		},
-		{
-		    header: gettext('Comment'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.FencingView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveFencingView'],
-
-    onlineHelp: 'ha_manager_fencing',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-fencing',
-	    data: []
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false,
-		deferEmptyText: false,
-		emptyText: 'Use watchdog based fencing.'
-	    },
-	    columns: [
-		{
-		    header: 'Node',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Command'),
-		    flex: 1,
-		    dataIndex: 'command'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-fencing', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'node', 'command', 'digest'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSummary',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: 'column',
-
-    defaults: {
-	padding: 5,
-	plugins: 'responsive',
-	responsiveConfig: {
-	    'width < 1900': {
-		columnWidth: 1
-	    },
-	    'width >= 1900': {
-		columnWidth: 0.5
-	    }
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'dcHealth',
-	    xtype: 'pveDcHealth'
-	},
-	{
-	    itemId: 'dcGuests',
-	    xtype: 'pveDcGuests'
-	},
-	{
-	    title: gettext('Resources'),
-	    xtype: 'panel',
-	    minHeight: 250,
-	    bodyPadding: 5,
-	    layout: 'hbox',
-	    defaults: {
-		xtype: 'proxmoxGauge',
-		flex: 1
-	    },
-	    items:[
-		{
-		    title: gettext('CPU'),
-		    itemId: 'cpu'
-		},
-		{
-		    title: gettext('Memory'),
-		    itemId: 'memory'
-		},
-		{
-		    title: gettext('Storage'),
-		    itemId: 'storage'
-		}
-	    ]
-	},
-	{
-	    itemId: 'nodeview',
-	    xtype: 'pveDcNodeView',
-	    height: 250
-	},
-	{
-	    title: gettext('Subscriptions'),
-	    height: 220,
-	    items: [
-		{
-		    itemId: 'subscriptions',
-		    xtype: 'pveHealthWidget',
-		    userCls: 'pointer',
-		    listeners: {
-			element: 'el',
-			click: function() {
-			    if (this.component.userCls === 'pointer') {
-				window.open('https://www.proxmox.com/en/proxmox-ve/pricing', '_blank');
-			    }
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-status',
-	    model: 'pve-dc-nodes',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/cluster/status"
-	    }
-	});
-
-	var gridstore = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    filters: {
-		property: 'type',
-		value: 'node'
-	    },
-	    sorters: {
-		property: 'id',
-		direction: 'ASC'
-	    }
-	});
-
-	me.callParent();
-
-	me.getComponent('nodeview').setStore(gridstore);
-
-	var gueststatus = me.getComponent('dcGuests');
-
-	var cpustat = me.down('#cpu');
-	var memorystat = me.down('#memory');
-	var storagestat = me.down('#storage');
-	var sp = Ext.state.Manager.getProvider();
-
-	me.mon(PVE.data.ResourceStore, 'load', function(curstore, results) {
-	    me.suspendLayout = true;
-
-	    var cpu = 0;
-	    var maxcpu = 0;
-
-	    var nodes = 0;
-
-	    var memory = 0;
-	    var maxmem = 0;
-
-	    var countedStorages = {};
-	    var used = 0;
-	    var total = 0;
-	    var usableStorages = {};
-	    var storages = sp.get('dash-storages') || '';
-	    storages.split(',').forEach(function(storage){
-		if (storage !== '') {
-		    usableStorages[storage] = true;
-		}
-	    });
-
-	    var qemu = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var lxc = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var error = 0;
-
-	    var i;
-
-	    for (i = 0; i < results.length; i++) {
-		var item = results[i];
-		switch(item.data.type) {
-		    case 'node':
-			cpu += (item.data.cpu * item.data.maxcpu);
-			maxcpu += item.data.maxcpu || 0;
-			memory += item.data.mem || 0;
-			maxmem += item.data.maxmem || 0;
-			nodes++;
-
-			// update grid also
-			var griditem = gridstore.getById(item.data.id);
-			if (griditem) {
-			    griditem.set('cpuusage', item.data.cpu);
-			    var max = item.data.maxmem || 1;
-			    var val = item.data.mem || 0;
-			    griditem.set('memoryusage', val/max);
-			    griditem.set('uptime', item.data.uptime);
-			    griditem.commit(); //else it marks the fields as dirty
-			}
-			break;
-		    case 'storage':
-			if (!Ext.Object.isEmpty(usableStorages)) {
-			    if (usableStorages[item.data.id] === true) {
-				used += item.data.disk;
-				total += item.data.maxdisk;
-			    }
-			    break;
-			}
-			if (!countedStorages[item.data.storage] ||
-			    (item.data.storage === 'local' &&
-			    !countedStorages[item.data.id])) {
-			    used += item.data.disk;
-			    total += item.data.maxdisk;
-
-			    countedStorages[item.data.storage === 'local'?item.data.id:item.data.storage] = true;
-			}
-			break;
-		    case 'qemu':
-			qemu[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    case 'lxc':
-			lxc[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    default: break;
-		}
-	    }
-
-	    var text = Ext.String.format(gettext('of {0} CPU(s)'), maxcpu);
-	    cpustat.updateValue((cpu/maxcpu), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(memory), PVE.Utils.render_size(maxmem));
-	    memorystat.updateValue((memory/maxmem), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(used), PVE.Utils.render_size(total));
-	    storagestat.updateValue((used/total), text);
-
-	    gueststatus.updateValues(qemu,lxc,error);
-
-	    me.suspendLayout = false;
-	    me.updateLayout(true);
-	});
-
-	var dcHealth = me.getComponent('dcHealth');
-	me.mon(rstore, 'load', dcHealth.updateStatus, dcHealth);
-
-	var subs = me.down('#subscriptions');
-	me.mon(rstore, 'load', function(store, records, success) {
-	    var i;
-	    var level;
-	    var mixed = false;
-	    for (i = 0; i < records.length; i++) {
-		if (records[i].get('type') !== 'node') {
-		    continue;
-		}
-		var node = records[i];
-		if (node.get('status') === 'offline') {
-		    continue;
-		}
-
-		var curlevel = node.get('level');
-
-		if (curlevel === '') { // no subscription trumps all, set and break
-		    level = '';
-		    break;
-		}
-
-		if (level === undefined) { // save level
-		    level = curlevel;
-		} else if (level !== curlevel) { // detect different levels
-		    mixed = true;
-		}
-	    }
-
-	    var data = {
-		title: Proxmox.Utils.unknownText,
-		text: Proxmox.Utils.unknownText,
-		iconCls: PVE.Utils.get_health_icon(undefined, true)
-	    };
-	    if (level === '') {
-		data = {
-		    title: gettext('No Subscription'),
-		    iconCls: PVE.Utils.get_health_icon('critical', true),
-		    text: gettext('You have at least one node without subscription.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (mixed) {
-		data = {
-		    title: gettext('Mixed Subscriptions'),
-		    iconCls: PVE.Utils.get_health_icon('warning', true),
-		    text: gettext('Warning: Your subscription levels are not the same.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (level) {
-		data = {
-		    title: PVE.Utils.render_support_level(level),
-		    iconCls: PVE.Utils.get_health_icon('good', true),
-		    text: gettext('Your subscription status is valid.')
-		};
-		subs.setUserCls('');
-	    }
-
-	    subs.setData(data);
-	});
-
-	me.on('destroy', function(){
-	    rstore.stopUpdate();
-	});
-
-	rstore.startUpdate();
-    }
-
-});
-Ext.define('PVE.window.ReplicaEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveReplicaEdit',
-
-    subject: gettext('Replication Job'),
-
-
-    url: '/cluster/replication',
-    method: 'POST',
-
-    initComponent: function() {
-	var me = this;
-
-	var vmid = me.pveSelNode.data.vmid;
-	var nodename = me.pveSelNode.data.node;
-
-	var items = [];
-
-	items.push({
-	    xtype: (me.isCreate && !vmid)?'pveGuestIDSelector':'displayfield',
-	    name: 'guest',
-	    fieldLabel: 'CT/VM ID',
-	    value: vmid || ''
-	});
-
-	items.push(
-	    {
-		xtype: me.isCreate ? 'pveNodeSelector':'displayfield',
-		name: 'target',
-		disallowedNodes: [nodename],
-		allowBlank: false,
-		onlineValidator: true,
-		fieldLabel: gettext("Target")
-	    },
-	    {
-		xtype: 'pveCalendarEvent',
-		fieldLabel: gettext('Schedule'),
-		emptyText: '*/15 - ' + Ext.String.format(gettext('Every {0} minutes'), 15),
-		name: 'schedule'
-	    },
-	    {
-		xtype: 'numberfield',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		step: 1,
-		minValue: 1,
-		emptyText: gettext('unlimited'),
-		name: 'rate'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Comment'),
-		name: 'comment'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enabled',
-		defaultValue: 'on',
-		checked: true,
-		fieldLabel: gettext('Enabled')
-	    }
-	);
-
-	me.items = [
-	    {
-		xtype: 'inputpanel',
-		itemId: 'ipanel',
-		onlineHelp: 'pvesr_schedule_time_format',
-
-		onGetValues: function(values) {
-		    var me = this.up('window');
-
-		    values.disable = values.enabled ? 0 : 1;
-		    delete values.enabled;
-
-		    PVE.Utils.delete_if_default(values, 'rate', '', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'disable', 0, me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'schedule', '*/15', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'comment', '', me.isCreate);
-
-		    if (me.isCreate) {
-			values.type = 'local';
-			var vm = vmid || values.guest;
-			var id = -1;
-			if (me.highestids[vm] !== undefined) {
-			    id = me.highestids[vm];
-			}
-			id++;
-			values.id = vm + '-' + id.toString();
-			delete values.guest;
-		    }
-		    return values;
-		},
-		items: items
-	    }
-	];
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var jobs = response.result.data;
-		    var highestids = {};
-		    Ext.Array.forEach(jobs, function(job) {
-			var match = /^([0-9]+)\-([0-9]+)$/.exec(job.id);
-			if (match) {
-			    var vmid = parseInt(match[1],10);
-			    var id = parseInt(match[2],10);
-			    if (highestids[vmid] < id ||
-				highestids[vmid] === undefined) {
-				highestids[vmid] = id;
-			    }
-			}
-		    });
-
-		    me.highestids = highestids;
-		}
-	    });
-
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    response.result.data.enabled = !response.result.data.disable;
-		    me.setValues(response.result.data);
-		    me.digest = response.result.data.digest;
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-/* callback is a function and string */
-Ext.define('PVE.grid.ReplicaView', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveReplicaView',
-
-    onlineHelp: 'chapter_pvesr',
-
-    stateful: true,
-    stateId: 'grid-pve-replication-status',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	addJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		isCreate: true,
-		method: 'POST',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	editJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var data = rec.data;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		url: '/cluster/replication/' + data.id,
-		method: 'PUT',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	scheduleJobNow: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-
-	    Proxmox.Utils.API2Request({
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/schedule_now",
-		method: 'POST',
-		waitMsgTarget: me,
-		callback: function() { controller.reload(); },
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	showLog: function(button, event, rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var logView = Ext.create('Proxmox.panel.LogView', {
-		border: false,
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/log"
-	    });
-	    var win = Ext.create('Ext.window.Window', {
-		items: [ logView ],
-		layout: 'fit',
-		width: 800,
-		height: 400,
-		modal: true,
-		title: gettext("Replication Log")
-	    });
-	    var task = {
-		run: function() {
-		    logView.requestUpdate();
-		},
-		interval: 1000
-	    };
-	    Ext.TaskManager.start(task);
-	    win.on('destroy', function() {
-		Ext.TaskManager.stop(task);
-		controller.reload();
-	    });
-	    win.show();
-	},
-
-	reload: function() {
-	    var me = this.getView();
-	    me.rstore.load();
-	},
-
-	dblClick: function(grid, record, item) {
-	    var me = this;
-	    me.editJob(undefined, undefined, record);
-	},
-
-	// check for cluster
-	// currently replication is for cluster only, so we disable the whole
-	// component
-	checkPrerequisites: function() {
-	    var me = this.getView();
-	    if (PVE.data.ResourceStore.getNodes().length < 2) {
-		me.mask(gettext("Replication needs at least two nodes"), ['pve-static-mask']);
-	    }
-	},
-
-	control: {
-	    '#': {
-		itemdblclick: 'dblClick',
-		afterlayout: 'checkPrerequisites'
-	    }
-	}
-    },
-
-    tbar: [
-	{
-	    text: gettext('Add'),
-	    itemId: 'addButton',
-	    handler: 'addJob'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    itemId: 'editButton',
-	    handler: 'editJob',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxStdRemoveButton',
-	    itemId: 'removeButton',
-	    baseurl: '/api2/extjs/cluster/replication/',
-	    dangerous: true,
-	    callback: 'reload'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Log'),
-	    itemId: 'logButton',
-	    handler: 'showLog',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Schedule now'),
-	    itemId: 'scheduleNowButton',
-	    handler: 'scheduleJobNow',
-	    disabled: true
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	var mode = '';
-	var url = '/cluster/replication';
-
-	me.nodename = me.pveSelNode.data.node;
-	me.vmid = me.pveSelNode.data.vmid;
-
-	me.columns = [
-	    {
-		text: gettext('Enabled'),
-		dataIndex: 'enabled',
-		xtype: 'checkcolumn',
-		sortable: true,
-		disabled: true
-	    },
-	    {
-		text: 'ID',
-		dataIndex: 'id',
-		width: 60,
-		hidden: true
-	    },
-	    {
-		text: gettext('Guest'),
-		dataIndex: 'guest',
-		width: 75
-	    },
-	    {
-		text: gettext('Job'),
-		dataIndex: 'jobnum',
-		width: 60
-	    },
-	    {
-		text: gettext('Target'),
-		dataIndex: 'target'
-	    }
-	];
-
-	if (!me.nodename) {
-	    mode = 'dc';
-	    me.stateId = 'grid-pve-replication-dc';
-	} else if (!me.vmid) {
-	    mode = 'node';
-	    url = '/nodes/' + me.nodename + '/replication';
-	} else {
-	    mode = 'vm';
-	    url = '/nodes/' + me.nodename + '/replication' + '?guest=' + me.vmid;
-	}
-
-	if (mode !== 'dc') {
-	    me.columns.push(
-		{
-		    text: gettext('Status'),
-		    dataIndex: 'state',
-		    minWidth: 160,
-		    flex: 1,
-		    renderer: function(value, metadata, record) {
-
-			if (record.data.pid) {
-			    metadata.tdCls = 'x-grid-row-loading';
-			    return '';
-			}
-
-			var icons = [];
-			var states = [];
-
-			if (record.data.remove_job) {
-			    icons.push('<i class="fa fa-ban warning" title="'
-					+ gettext("Removal Scheduled") + '"></i>');
-			    states.push(gettext("Removal Scheduled"));
-			}
-
-			if (record.data.error) {
-			    icons.push('<i class="fa fa-times critical" title="'
-					+ gettext("Error") + '"></i>');
-			    states.push(record.data.error);
-			}
-
-			if (icons.length == 0) {
-			    icons.push('<i class="fa fa-check good"></i>');
-			    states.push(gettext('OK'));
-			}
-
-			return icons.join(',') + ' ' + states.join(',');
-		    }
-		},
-		{
-		    text: gettext('Last Sync'),
-		    dataIndex: 'last_sync',
-		    width: 150,
-		    renderer: function(value, metadata, record) {
-			if (!value) {
-			    return '-';
-			}
-
-			if (record.data.pid) {
-			    return gettext('syncing');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		},
-		{
-		    text: gettext('Duration'),
-		    dataIndex: 'duration',
-		    width: 60,
-		    renderer: PVE.Utils.render_duration
-		},
-		{
-		    text: gettext('Next Sync'),
-		    dataIndex: 'next_sync',
-		    width: 150,
-		    renderer: function(value) {
-			if (!value) {
-			    return '-';
-			}
-
-			var now = new Date();
-			var next = new Date(value*1000);
-
-			if (next < now) {
-			    return gettext('pending');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		}
-	    );
-	}
-
-	me.columns.push(
-	    {
-		text: gettext('Schedule'),
-		width: 75,
-		dataIndex: 'schedule'
-	    },
-	    {
-		text: gettext('Rate limit'),
-		dataIndex: 'rate',
-		renderer: function(value) {
-		    if (!value) {
-			return gettext('unlimited');
-		    }
-
-		    return value.toString() + ' MB/s';
-		},
-		hidden: true
-	    },
-	    {
-		text: gettext('Comment'),
-		dataIndex: 'comment',
-		renderer: Ext.htmlEncode
-	    }
-	);
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-replica-' + me.nodename + me.vmid,
-	    model: (mode === 'dc')? 'pve-replication' : 'pve-replication-state',
-	    interval: 3000,
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + url
-	    }
-	});
-
-	me.store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sorters: [
-		{
-		    property: 'guest'
-		},
-		{
-		    property: 'jobnum'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	// we cannot access the log and scheduleNow button
-	// in the datacenter, because
-	// we do not know where/if the jobs runs
-	if (mode === 'dc') {
-	    me.down('#logButton').setHidden(true);
-	    me.down('#scheduleNowButton').setHidden(true);
-	}
-
-	// if we set the warning mask, we do not want to load
-	// or set the mask on store errors
-	if (PVE.data.ResourceStore.getNodes().length < 2) {
-	    return;
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.on('destroy', me.rstore.stopUpdate);
-	me.rstore.startUpdate();
-    }
-}, function() {
-
-    Ext.define('pve-replication', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'target', 'comment', 'rate', 'type',
-	    { name: 'guest', type: 'integer' },
-	    { name: 'jobnum', type: 'integer' },
-	    { name: 'schedule', defaultValue: '*/15' },
-	    { name: 'disable', defaultValue: '' },
-	    { name: 'enabled', calculate: function(data) { return !data.disable; } }
-	]
-    });
-
-    Ext.define('pve-replication-state', {
-	extend: 'pve-replication',
-	fields: [
-	    'last_sync', 'next_sync', 'error', 'duration', 'state',
-	    'fail_count', 'remove_job', 'pid'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Health', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcHealth',
-
-    title: gettext('Health'),
-
-    bodyPadding: 10,
-    height: 220,
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	flex: 1,
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    nodeList: [],
-    nodeIndex: 0,
-
-    updateStatus: function(store, records, success) {
-	var me = this;
-	if (!success) {
-	    return;
-	}
-
-	var cluster = {
-	    iconCls: PVE.Utils.get_health_icon('good', true),
-	    text: gettext("Standalone node - no cluster defined")
-	};
-
-	var nodes = {
-	    online: 0,
-	    offline: 0
-	};
-
-	// by default we have one node
-	var numNodes = 1;
-	var i;
-
-	for (i = 0; i < records.length; i++) {
-	    var item = records[i];
-	    if (item.data.type === 'node') {
-		nodes[item.data.online === 1 ? 'online':'offline']++;
-	    } else if(item.data.type === 'cluster') {
-		cluster.text = gettext("Cluster") + ": ";
-		cluster.text += item.data.name + ", ";
-		cluster.text += gettext("Quorate") + ": ";
-		cluster.text += Proxmox.Utils.format_boolean(item.data.quorate);
-		if (item.data.quorate != 1) {
-		    cluster.iconCls = PVE.Utils.get_health_icon('critical', true);
-		}
-
-		numNodes = item.data.nodes;
-	    }
-	}
-
-	if (numNodes !== (nodes.online + nodes.offline)) {
-	    nodes.offline = numNodes - nodes.online;
-	}
-
-	me.getComponent('clusterstatus').updateHealth(cluster);
-	me.getComponent('nodestatus').update(nodes);
-    },
-
-    updateCeph: function(store, records, success) {
-	var me = this;
-	var cephstatus = me.getComponent('ceph');
-	if (!success || records.length < 1) {
-
-	    // if ceph status is already visible
-	    // don't stop to update
-	    if (cephstatus.isVisible()) {
-		return;
-	    }
-
-	    // try all nodes until we either get a successful api call,
-	    // or we tried all nodes
-	    if (++me.nodeIndex >= me.nodeList.length) {
-		me.cephstore.stopUpdate();
-	    } else {
-		store.getProxy().setUrl('/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status');
-	    }
-
-	    return;
-	}
-
-	var state = PVE.Utils.render_ceph_health(records[0].data.health || {});
-	cephstatus.updateHealth(state);
-	cephstatus.setVisible(true);
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    me.cephstore.stopUpdate();
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'clusterstatus',
-	    xtype: 'pveHealthWidget',
-	    title: gettext('Status')
-	},
-	{
-	    itemId: 'nodestatus',
-	    data: {
-		online: 0,
-		offline: 0
-	    },
-	    tpl: [
-		'<h3>' + gettext('Nodes') + '</h3><br />',
-		'<div style="width: 150px;margin: auto;font-size: 12pt">',
-		'<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-check">&nbsp;</i>',
-		gettext('Online'),
-		'</div>',
-		'<div class="right-aligned">{online}</div>',
-		'<br /><br />',
-		'<div class="left-aligned">',
-		'<i class="critical fa fa-fw fa-times">&nbsp;</i>',
-		gettext('Offline'),
-		'</div>',
-		'<div class="right-aligned">{offline}</div>',
-		'</div>'
-	    ]
-	},
-	{
-	    itemId: 'ceph',
-	    width: 250,
-	    columnWidth: undefined,
-	    userCls: 'pointer',
-	    title: 'Ceph',
-	    xtype: 'pveHealthWidget',
-	    hidden: true,
-	    listeners: {
-		element: 'el',
-		click: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    sp.set('dctab', {value:'ceph'}, true);
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodeList = PVE.data.ResourceStore.getNodes();
-	me.nodeIndex = 0;
-	me.cephstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-ceph',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status'
-	    }
-	});
-	me.callParent();
-	me.mon(me.cephstore, 'load', me.updateCeph, me);
-	me.cephstore.startUpdate();
-    }
-});
-Ext.define('PVE.dc.Guests', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcGuests',
-
-
-    title: gettext('Guests'),
-    height: 220,
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-    bodyPadding: '0 20 20 20',
-
-    defaults: {
-	xtype: 'box',
-	padding: '0 50 0 50',
-	style: {
-	    'text-align':'center',
-	    'line-height':'1.2'
-	}
-    },
-    items: [{
-	itemId: 'qemu',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("Virtual Machines") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'lxc',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("LXC Container") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'error',
-	colspan: 2,
-	data: {
-	    num: 0
-	},
-	columnWidth: 1,
-	padding: '10 250 0 250',
-	tpl: [
-	    '<tpl if="num &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="critical fa fa-fw fa-times-circle">&nbsp;</i>',
-		    gettext('Error'),
-		'</div>',
-		'<div class="right-aligned">{num}</div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateValues: function(qemu, lxc, error) {
-	var me = this;
-	me.getComponent('qemu').update(qemu);
-	me.getComponent('lxc').update(lxc);
-	me.getComponent('error').update({num: error});
-    }
-});
- /*jslint confusion: true*/
-Ext.define('PVE.dc.OptionView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    onlineHelp: 'datacenter_configuration_file',
-
-    monStoreErrors: true,
-
-    add_inputpanel_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	var canEdit = (opts.caps === undefined || opts.caps);
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: canEdit ? {
-		xtype: 'proxmoxWindowEdit',
-		width: 350,
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		setValues: function(values) {
-		    // FIXME: run through parsePropertyString if not an object?
-		    var edit_value = values[name];
-		    Ext.Array.each(this.query('inputpanel'), function(panel) {
-			panel.setValues(edit_value);
-		    });
-		},
-		url: opts.url,
-		items: [{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			if (values === undefined || Object.keys(values).length === 0) {
-			    return { 'delete': name };
-			}
-			var ret_val = {};
-			ret_val[name] = PVE.Parser.printPropertyString(values);
-			return ret_val;
-		    },
-		    items: opts.items
-		}]
-	    } : undefined
-	};
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.add_combobox_row('keyboard', gettext('Keyboard Layout'), {
-	    renderer: PVE.Utils.render_kvm_language,
-	    comboItems: PVE.Utils.kvm_keymap_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('http_proxy', gettext('HTTP proxy'), {
-	    defaultValue: Proxmox.Utils.noneText,
-	    vtype: 'HttpProxy',
-	    deleteEmpty: true
-	});
-	me.add_combobox_row('console', gettext('Console Viewer'), {
-	    renderer: PVE.Utils.render_console_viewer,
-	    comboItems: PVE.Utils.console_viewer_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('email_from', gettext('Email from address'), {
-	    deleteEmpty: true,
-	    vtype: 'proxmoxMail',
-	    defaultValue: 'root@$hostname'
-	});
-	me.add_text_row('mac_prefix', gettext('MAC address prefix'), {
-	    deleteEmpty: true,
-	    vtype: 'MacPrefix',
-	    defaultValue: Proxmox.Utils.noneText
-	});
-	me.add_inputpanel_row('migration', gettext('Migration Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    defaultKey: 'type',
-	    items: [{
-		xtype: 'displayfield',
-		name: 'type',
-		fieldLabel: gettext('Type'),
-		value: 'secure',
-		submitValue: true,
-	    }, {
-		xtype: 'proxmoxNetworkSelector',
-		name: 'network',
-		fieldLabel: gettext('Network'),
-		value: null,
-		emptyText: Proxmox.Utils.defaultText,
-		autoSelect: false,
-		skipEmptyText: true
-	    }]
-	});
-	me.add_inputpanel_row('ha', gettext('HA Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    items: [{
-		xtype: 'proxmoxKVComboBox',
-		name: 'shutdown_policy',
-		fieldLabel: gettext('Shutdown Policy'),
-		deleteEmpty: false,
-		value: '__default__',
-		comboItems: [
-		    ['__default__', Proxmox.Utils.defaultText + ' (conditional)' ],
-		    ['freeze', 'freeze'],
-		    ['failover', 'failover'],
-		    ['conditional', 'conditional']
-		],
-		defaultValue: '__default__'
-	    }]
-	});
-
-	// TODO: bwlimits, u2f?
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    tbar: [{
-		text: gettext('Edit'),
-		xtype: 'proxmoxButton',
-		disabled: true,
-		handler: function() { me.run_editor(); },
-		selModel: me.selModel
-	    }],
-	    url: "/api2/json/cluster/options",
-	    editorConfig: {
-		url: "/api2/extjs/cluster/options"
-	    },
-	    interval: 5000,
-	    cwidth1: 200,
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	// set the new value for the default console
-	me.mon(me.rstore, 'load', function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-
-	    var rec = store.getById('console');
-	    PVE.VersionInfo.console = rec.data.value;
-	    if (rec.data.value === '__default__') {
-		delete PVE.VersionInfo.console;
-	    }
-	});
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    onlineHelp: 'chapter_storage',
-
-    stateful: true,
-    stateId: 'grid-dc-storage',
-
-    createStorageEditWindow: function(type, sid) {
-	var schema = PVE.Utils.storageSchema[type];
-	if (!schema || !schema.ipanel) {
-	    throw "no editor registered for storage type: " + type;
-	}
-
-	Ext.create('PVE.storage.BaseEdit', {
-	    paneltype: 'PVE.storage.' + schema.ipanel,
-	    type: type,
-	    storageId: sid,
-	    autoShow: true,
-	    listeners: {
-		destroy: this.reloadStore
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-storage',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/storage"
-	    },
-	    sorters: {
-		property: 'storage',
-		order: 'DESC'
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type,
-	        sid = rec.data.storage;
-
-	    me.createStorageEditWindow(type, sid);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/storage/',
-	    callback: reload
-	});
-
-	// else we cannot dynamically generate the add menu handlers
-	var addHandleGenerator = function(type) {
-	    return function() { me.createStorageEditWindow(type); };
-	};
-	var addMenuItems = [], type;
-	/*jslint forin: true */
-	for (type in PVE.Utils.storageSchema) {
-	    var storage = PVE.Utils.storageSchema[type];
-	    if (storage.hideAdd) {
-		continue;
-	    }
-	    addMenuItems.push({
-		text:  PVE.Utils.format_storage_type(type),
-		iconCls: 'fa fa-fw fa-' + storage.faIcon,
-		handler: addHandleGenerator(type)
-	    });
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    reloadStore: reload,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: addMenuItems
-		    })
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Type'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'type',
-		    renderer: PVE.Utils.format_storage_type
-		},
-		{
-		    header: gettext('Content'),
-		    flex: 3,
-		    sortable: true,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Path') + '/' + gettext('Target'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'path',
-		    renderer: function(value, metaData, record) {
-			if (record.data.target) {
-			    return record.data.target;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Shared'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'shared',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Enabled'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'disable',
-		    renderer: Proxmox.Utils.format_neg_boolean
-		},
-		{
-		    header: gettext('Bandwidth Limit'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'bwlimit'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-	    { name: 'shared', type: 'boolean'},
-	    { name: 'disable', type: 'boolean'}
-	],
-	idProperty: 'storage'
-    });
-
-});
-/*global u2f,QRCode,Uint8Array*/
-/*jslint confusion: true*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' + encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer)
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    PVE.Utils.render_u2f_error(error)
-	);
-    },
-
-    doU2FChallenge: function(response) {
-	var me = this;
-
-	var data = response.result.data;
-	me.lookup('password').setDisabled(true);
-	var msg = Ext.Msg.show({
-	    title: 'U2F: '+gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: []
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(data.appId, [data], [], function(data) {
-		msg.close();
-		if (data.errorCode) {
-		    me.showError(data.errorCode);
-		} else {
-		    me.respondToU2FChallenge(data);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data)
-	};
-	if (Proxmox.UserName !== 'root@pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    tfa_type: null, // dependencies of formulas should not be undefined
-	    valid: false,
-	    u2f_available: true
-	},
-	formulas: {
-	    canDeleteTFA: function(get) {
-		return (get('tfa_type') !== null && !get('tfa_required'));
-	    },
-	    canSetupTOTP: function(get) {
-		var tfa = get('tfa_type');
-		return (tfa === null || tfa === 'totp' || tfa === 1);
-	    },
-	    canSetupU2F: function(get) {
-		var tfa = get('tfa_type');
-		return (get('u2f_available') && (tfa === null || tfa === 'u2f' || tfa === 1));
-	    }
-	}
-    },
-
-    afterLoading: function(realm_tfa_type, user_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (user_tfa_type === 'oath') {
-	    user_tfa_type = 'totp';
-	}
-	viewmodel.set('tfa_type', user_tfa_type || null);
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    if (user_tfa_type !== 'totp' && user_tfa_type !== null) {
-		// user had a different tfa method, so
-		// we have to change back to the totp tab and
-		// generate a secret
-		viewmodel.set('tfa_type', null);
-		me.lookup('tfatabs').setActiveTab(me.lookup('totp_panel'));
-		me.getController().randomizeSecret();
-	    }
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type
-		)
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    var me = this.getView();
-		    me.updateQrCode();
-		}
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		}
-	    },
-	    '#': {
-		show: function() {
-		    var me = this.getView();
-		    var viewmodel = this.getViewModel();
-
-		    var loadMaskContainer = me.down('#tfatabs');
-		    Proxmox.Utils.API2Request({
-			url: '/access/users/' + encodeURIComponent(me.userid) + '/tfa',
-			waitMsgTarget: loadMaskContainer,
-			method: 'GET',
-			success: function(response, opts) {
-			    var data = response.result.data;
-			    me.afterLoading(data.realm, data.user);
-			},
-			failure: function(response, opts) {
-			    Proxmox.Utils.setErrorMask(loadMaskContainer, response.htmlStatus);
-			}
-		    });
-
-		    me.qrdiv = document.createElement('center');
-		    me.qrcode = new QRCode(me.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M
-		    });
-		    me.down('#qrbox').getEl().appendChild(me.qrdiv);
-
-		    viewmodel.set('tfa_type', me.tfa_type || null);
-		    if (!me.tfa_type) {
-			this.randomizeSecret();
-		    } else {
-			me.down('#qrbox').setVisible(false);
-			me.lookup('challenge').setVisible(false);
-			if (me.tfa_type === 'u2f') {
-			    var u2f_panel = me.lookup('u2f_panel');
-			    me.lookup('tfatabs').setActiveTab(u2f_panel);
-			}
-		    }
-
-		    if (Proxmox.UserName === 'root@pam') {
-			me.lookup('password').setVisible(false);
-			me.lookup('password').setDisabled(true);
-		    }
-		}
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    var viewmodel = this.getViewModel();
-		    viewmodel.set('in_totp_tab', newcard.itemId === 'totp-panel');
-		}
-	    }
-	},
-
-	applySettings: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	deleteTFA: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'delete'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	randomizeSecret: function() {
-	    var me = this;
-	    var rnd = new Uint8Array(16);
-	    window.crypto.getRandomValues(rnd);
-	    var data = '';
-	    rnd.forEach(function(b) {
-		// secret must be base32, so just use the first 5 bits
-		b = b & 0x1f;
-		if (b < 26) {
-		    // A..Z
-		    data += String.fromCharCode(b + 0x41);
-		} else {
-		    // 2..7
-		    data += String.fromCharCode(b-26 + 0x32);
-		}
-	    });
-	    me.lookup('tfa_secret').setValue(data);
-	},
-
-	startU2FRegistration: function() {
-	    var me = this;
-
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    reference: 'tfatabs',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    reference: 'totp_panel',
-		    tfa_type: 'totp',
-		    border: false,
-		    bind: {
-			disabled: '{!canSetupTOTP}'
-		    },
-		    layout: {
-			type: 'vbox',
-			align: 'stretch'
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5'
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    cbind: {
-					value: '{userid}'
-				    }
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					flex: 4
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1
-				    }]
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true
-				}
-			    ]
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    style: {
-				'background-color': '#23272a',
-				padding: '5px',
-				width: '266px',
-				height: '266px'
-			    }
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify')
-			}
-		    ]
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    tfa_type: 'u2f',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle'
-		    },
-		    bind: {
-			disabled: '{!canSetupU2F}'
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.')
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password')
-	}
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton'
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}'
-	    }
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}',
-		disabled: '{tfa_type}'
-	    }
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    disabled: true,
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}'
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid given";
-	}
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    }
-});
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + encodeURIComponent(me.userid);
-            method = 'PUT';
-	}
-
-	var verifypw;
-	var pwfield;
-
-	var validate_pw = function() {
-	    if (verifypw.getValue() !== pwfield.getValue()) {
-		return gettext("Passwords do not match");
-	    }
-	    return true;
-	};
-
-	verifypw = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'), 
-	    name: 'verifypassword',
-	    submitValue: false,
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	pwfield = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'), 
-	    minLength: 5,
-	    name: 'password',
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	var update_passwd_field = function(realm) {
-	    if (realm === 'pve') {
-		pwfield.setVisible(true);
-		pwfield.setDisabled(false);
-		verifypw.setVisible(true);
-		verifypw.setDisabled(false);
-	    } else {
-		pwfield.setVisible(false);
-		pwfield.setDisabled(true);
-		verifypw.setVisible(false);
-		verifypw.setDisabled(true);
-	    }
-
-	};
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.isCreate ? true : false
-            },
-	    pwfield, verifypw,
-	    {
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		multiSelect: true,
-		allowBlank: true,
-		fieldLabel: gettext('Group')
-	    },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-		emptyText: 'never',
-		format: 'Y-m-d',
-		submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enabled'),
-		name: 'enable',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    }
-        ];
-
-        var column2 = [
-	    {
-		xtype: 'textfield',
-		name: 'firstname',
-		fieldLabel: gettext('First Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'lastname',
-		fieldLabel: gettext('Last Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'email',
-		fieldLabel: gettext('E-Mail'),
-		vtype: 'proxmoxMail'
-	    }
-	];
-
-        if (me.isCreate) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-		matchFieldWidth: false,
-		listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-			update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    fieldLabel: gettext('Comment')
-		}
-	    ],
-	    advancedItems: [
-		{
-		    xtype: 'textfield',
-		    name: 'keys',
-		    fieldLabel: gettext('Key IDs')
-		}
-	    ],
-	    onGetValues: function(values) {
-		// hack: ExtJS datefield does not submit 0, so we need to set that
-		if (!values.expire) {
-		    values.expire = 0;
-		}
-
-		if (realm) {
-		    values.userid = values.userid + '@' + realm;
-		}
-
-		if (!values.password) {
-		    delete values.password;
-		}
-
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 110 // for spanish translation 
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (Ext.isDefined(data.expire)) {
-			if (data.expire) {
-			    data.expire = new Date(data.expire * 1000);
-			} else {
-			    // display 'never' instead of '1970-01-01'
-			    data.expire = null;
-			}
-		    }
-		    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    onlineHelp: 'pveum_users',
-
-    stateful: true,
-    stateId: 'grid-users',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-            id: "users",
-	    model: 'pve-users',
-	    sorters: { 
-		property: 'userid', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/access/users/',
-	    enableFn: function(rec) {
-		if (!caps.access['User.Modify']) {
-		    return false;
-		}
-		return rec.data.userid !== 'root@pam';
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
- 
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec || !caps.access['User.Modify']) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    enableFn: function(rec) {
-		return !!caps.access['User.Modify'];
-	    },
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var pwchange_btn = new Proxmox.button.Button({
-	    text: gettext('Password'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('Proxmox.window.PasswordEdit', {
-                    userid: rec.data.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var tfa_type = PVE.Parser.parseTfaType(d.keys);
-		var win = Ext.create('PVE.window.TFAEdit',{
-		    tfa_type: tfa_type,
-		    userid: d.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-        var tbar = [
-            {
-		text: gettext('Add'),
-		disabled: !caps.access['User.Modify'],
-		handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-		}
-            },
-	    edit_btn, remove_btn, pwchange_btn, tfachange_btn
-        ];
-
-	var render_username = function(userid) {
-	    return userid.match(/^(.+)(@[^@]+)$/)[1];
-	};
-
-	var render_realm = function(userid) {
-	    return userid.match(/@([^@]+)$/)[1];
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('User name'),
-		    width: 200,
-		    sortable: true,
-		    renderer: render_username,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    renderer: render_realm,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'enable'
-		},
-		{
-		    header: gettext('Expire'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_expire, 
-		    dataIndex: 'expire'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    renderer: PVE.Utils.render_full_name,
-		    dataIndex: 'firstname'
-		},
-		{
-		    header: 'TFA',
-		    width: 50,
-		    sortable: true,
-		    renderer: function(v) {
-			var tfa_type = PVE.Parser.parseTfaType(v);
-			if (tfa_type === undefined) {
-			    return Proxmox.Utils.noText;
-			} else if (tfa_type === 1) {
-			    return Proxmox.Utils.yesText;
-			} else {
-			    return tfa_type;
-			}
-		    },
-		    dataIndex: 'keys'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    onlineHelp: 'pveum_pools',
-
-    stateful: true,
-    stateId: 'grid-pools',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: { 
-		property: 'poolid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/pools/',
-	    callback: function () {
-		reload();
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.PoolEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'poolid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'poolid',
-		    value: me.poolid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    onlineHelp: 'pveum_groups',
-
-    stateful: true,
-    stateId: 'grid-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: { 
-		property: 'groupid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: '/access/groups/'
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.GroupEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'groupid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'groupid',
-		    value: me.groupid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    onlineHelp: 'pveum_roles',
-
-    stateful: true,
-    stateId: 'grid-roles',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: {
-		property: 'roleid',
-		order: 'DESC'
-	    }
-	});
-
-	var render_privs = function(value, metaData) {
-
-	    if (!value) {
-		return '-';
-	    }
-
-	    // allow word wrap
-	    metaData.style = 'white-space:normal;';
-
-	    return value.replace(/\,/g, ' ');
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-		store.load();
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (rec.data.special === "1") {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.RoleEdit',{
-		roleid: rec.data.roleid,
-		privs: rec.data.privs
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Built-In'),
-		    width: 65,
-		    sortable: true,
-		    dataIndex: 'special',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'roleid'
-		},
-		{
-		    itemid: 'privs',
-		    header: gettext('Privileges'),
-		    sortable: false,
-		    renderer: render_privs,
-		    dataIndex: 'privs',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: function() {
-		    store.load();
-		},
-		itemdblclick: run_editor
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.RoleEdit', {});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Edit'),
-		    disabled: true,
-		    selModel: sm,
-		    handler: run_editor,
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		},
-		{
-		    xtype: 'proxmoxStdRemoveButton',
-		    selModel: sm,
-		    callback: function() {
-			reload();
-		    },
-		    baseurl: '/access/roles/',
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.RoleEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveDcRoleEdit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.roleid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = '/api2/extjs/access/roles';
-	    method = 'POST';
-	} else {
-	    url = '/api2/extjs/access/roles/' + me.roleid;
-	    method = 'PUT';
-	}
-
-	Ext.applyIf(me, {
-	    subject: gettext('Role'),
-	    url: url,
-	    method: method,
-	    items: [
-		{
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    name: 'roleid',
-		    value: me.roleid,
-		    allowBlank: false,
-		    fieldLabel: gettext('Name')
-		},
-		{
-		    xtype: 'pvePrivilegesSelector',
-		    name: 'privs',
-		    value: me.privs,
-		    allowBlank: false,
-		    fieldLabel: gettext('Privileges')
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var data = response.result.data;
-		    var keys = Ext.Object.getKeys(data);
-
-		    me.setValues({
-			privs: keys,
-			roleid: me.roleid
-		    });
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveACLAdd'],
-    url: '/access/acl',
-    method: 'PUT',
-    isAdd: true,
-    initComponent : function() {
-
-        var me = this;
-
-	me.isCreate = true;
-
-	var items = [
-	    {
-		xtype: me.path ? 'hiddenfield' : 'pvePermPathSelector',
-		name: 'path',
-		value: me.path,
-		allowBlank: false,
-		fieldLabel: gettext('Path')
-	    }
-	];
-
-	if (me.aclType === 'group') {
-	    me.subject = gettext("Group Permission");
-	    items.push({
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		fieldLabel: gettext('Group')
-	    });
-	} else if (me.aclType === 'user') {
-	    me.subject = gettext("User Permission");
-	    items.push({
-		xtype: 'pveUserSelector',
-		name: 'users',
-		fieldLabel: gettext('User')
-	    });
-	} else {
-	    throw "unknown ACL type";
-	}
-
-	items.push({
-	    xtype: 'pveRoleSelector',
-	    name: 'roles',
-	    value: 'NoAccess',
-	    fieldLabel: gettext('Role')
-	});
-
-	if (!me.path) {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'propagate',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Propagate')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    items: items,
-	    onlineHelp: 'pveum_permission_management'
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    onlineHelp: 'chapter_user_management',
-
-    stateful: true,
-    stateId: 'grid-acls',
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-acl',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/access/acl"
-	    },
-	    sorters: {
-		property: 'path',
-		order: 'DESC'
-	    }
-	});
-
-	if (me.path) {
-	    store.addFilter(Ext.create('Ext.util.Filter',{
-		filterFn: function(item) {
-		    if (item.data.path === me.path) {
-			return true;
-		    }
-		}
-	    }));
-	}
-
-	var render_ugid = function(ugid, metaData, record) {
-	    if (record.data.type == 'group') {
-		return '@' + ugid;
-	    }
-
-	    return ugid;
-	};
-
-	var columns = [
-	    {
-		header: gettext('User') + '/' + gettext('Group'),
-		flex: 1,
-		sortable: true,
-		renderer: render_ugid,
-		dataIndex: 'ugid'
-	    },
-	    {
-		header: gettext('Role'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'roleid'
-	    }
-	];
-
-	if (!me.path) {
-	    columns.unshift({
-		header: gettext('Path'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'path'
-	    });
-	    columns.push({
-		header: gettext('Propagate'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'propagate'
-	    });
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: gettext('Are you sure you want to remove this entry'),
-	    handler: function(btn, event, rec) {
-		var params = {
-		    'delete': 1,
-		    path: rec.data.path,
-		    roles: rec.data.roleid
-		};
-		if (rec.data.type === 'group') {
-		    params.groups = rec.data.ugid;
-		} else if (rec.data.type === 'user') {
-		    params.users = rec.data.ugid;
-		} else {
-		    throw 'unknown data type';
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/access/acl',
-		    params: params,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: {
-			xtype: 'menu',
-			items: [
-			    {
-				text: gettext('Group Permission'),
-				iconCls: 'fa fa-fw fa-group',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'group',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('User Permission'),
-				iconCls: 'fa fa-fw fa-user',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'user',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    }
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'ugid', 'roleid',
-	    {
-		name: 'propagate',
-		type: 'boolean'
-	    }
-	]
-    });
-
-});
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    onlineHelp: 'pveum_authentication_realms',
-
-    stateful: true,
-    stateId: 'grid-authrealms',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    sorters: { 
-		property: 'realm', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-		authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    baseurl: '/access/domains/',
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
-
-        var tbar = [
-	    {
-		text: gettext('Add'),
-		menu: new Ext.menu.Menu({
-		    items: [
-			{
-			    text: gettext('Active Directory Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit', {
-				    authType: 'ad'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			},
-			{
-			    text: gettext('LDAP Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit',{
-				    authType: 'ldap'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			}
-		    ]
-		})
-	    },
-	    edit_btn, remove_btn
-        ];
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-            tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'realm'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('TFA'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'tfa'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-	];
-
-	if (me.authType === 'ad') {
-
-	    me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-	} else if (me.authType === 'ldap') {
-
-	    me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-		emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-	} else if (me.authType === 'pve') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'Proxmox VE authentication server';
-
-	} else if (me.authType === 'pam') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'linux PAM';
-
-	} else {
-	    throw 'unknown auth type ';
-	}
-
-        column1.push({
-            xtype: 'proxmoxcheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-	if (me.authType === 'ldap' || me.authType === 'ad') {
-	    column2.push(
-		{
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-		},
-		{
-                    xtype: 'proxmoxtextfield',
-                    fieldLabel: gettext('Fallback Server'),
-		    deleteEmpty: !me.isCreate,
-		    name: 'server2'
-		},
-		{
-                    xtype: 'proxmoxintegerfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-		    emptyText: gettext('Default'),
-		    submitEmptyText: false
-		},
-		{
-                    xtype: 'proxmoxcheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-		}
-            );
-	}
-
-	// Two Factor Auth settings
-
-        column2.push({
-            xtype: 'proxmoxKVComboBox',
-            name: 'tfa',
-	    deleteEmpty: !me.isCreate,
-	    value: '',
-            fieldLabel: gettext('TFA'),
-	    comboItems: [ ['__default__', Proxmox.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=oath_step]').setVisible(value === 'oath');
-		    me.down('field[name=oath_digits]').setVisible(value === 'oath');
-		    me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-		}
-	    }
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_step',
-	    value: '',
-	    minValue: 10,
-	    emptyText: Proxmox.Utils.defaultText + ' (30)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_digits',
-	    value: '',
-	    minValue: 6,
-	    maxValue: 8,
-	    emptyText: Proxmox.Utils.defaultText + ' (6)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-	    hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-	    hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-	    hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [{
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-            }],
-	    onGetValues: function(values) {
-		if (!values.port) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'port' });
-		    }
-		    delete values.port;
-		}
-
-		if (me.isCreate) {
-		    values.type = me.authType;
-		}
-
-		if (values.tfa === 'oath') {
-		    values.tfa = "type=oath";
-		    if (values.oath_step) {
-			values.tfa += ",step=" + values.oath_step;
-		    }
-		    if (values.oath_digits) {
-			values.tfa += ",digits=" + values.oath_digits;
-		    }
-		} else if (values.tfa === 'yubico') {
-		    values.tfa = "type=yubico";
-		    values.tfa += ",id=" + values.yubico_api_id;
-		    values.tfa += ",key=" + values.yubico_api_key;
-		    if (values.yubico_url) {
-			values.tfa += ",url=" + values.yubico_url;
-		    }
-		} else {
-		    delete values.tfa;
-		}
-
-		delete values.oath_step;
-		delete values.oath_digits;
-		delete values.yubico_api_id;
-		delete values.yubico_api_key;
-		delete values.yubico_url;
-		
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-                success: function(response, options) {
-		    var data = response.result.data || {};
-		    // just to be sure (should not happen)
-		    if (data.type !== me.authType) {
-			me.close();
-			throw "got wrong auth type";
-		    }
-
-		    if (data.tfa) {
-			var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-			data.tfa = tfacfg.type;
-			if (tfacfg.type === 'yubico') {
-			    data.yubico_api_key = tfacfg.key;
-			    data.yubico_api_id = tfacfg.id;
-			    data.yubico_url = tfacfg.url;
-			} else if (tfacfg.type === 'oath') {
-			    // step is a number before
-			    /*jslint confusion: true*/
-			    data.oath_step = tfacfg.step;
-			    data.oath_digits = tfacfg.digits;
-			    /*jslint confusion: false*/
-			}
-		    }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    defaultFocus: undefined,
-
-    initComponent : function() {
-         var me = this;
-
-        me.isCreate = !me.jobid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-	var vmidField = Ext.create('Ext.form.field.Hidden', {
-	    name: 'vmid'
-	});
-
-	/*jslint confusion: true*/
-	// 'value' can be assigned a string or an array
-	var selModeField =  Ext.create('Proxmox.form.KVComboBox', {
-	    xtype: 'proxmoxKVComboBox',
-	    comboItems: [
-		['include', gettext('Include selected VMs')],
-		['all', gettext('All')],
-		['exclude', gettext('Exclude selected VMs')],
-		['pool', gettext('Pool based')]
-	    ],
-	    fieldLabel: gettext('Selection mode'),
-	    name: 'selMode',
-	    value: ''
-	});
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    var sel = [];
-		    Ext.Array.each(selected, function(record) {
-			sel.push(record.data.vmid);
-		    });
-
-		    // to avoid endless recursion suspend the vmidField change
-		    // event temporary as it calls us again
-		    vmidField.suspendEvent('change');
-		    vmidField.setValue(sel);
-		    vmidField.resumeEvent('change');
-		}
-	    }
-	});
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    fieldLabel: gettext('Storage'),
-	    nodename: 'localhost',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    name: 'storage'
-	});
-
-	var store = new Ext.data.Store({
-	    model: 'PVEResources',
-	    sorters: {
-		property: 'vmid',
-		order: 'ASC'
-	    }
-	});
-
-	var vmgrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    disabled: true,
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-
-	var selectPoolMembers = function(poolid) {
-	    if (!poolid) {
-		return;
-	    }
-	    sm.deselectAll(true);
-	    store.filter([
-		{
-		    id: 'poolFilter',
-		    property: 'pool',
-		    value: poolid
-		}
-	    ]);
-	    sm.selectAll(true);
-	};
-
-	var selPool = Ext.create('PVE.form.PoolSelector', {
-	    fieldLabel: gettext('Pool to backup'),
-	    hidden: true,
-	    allowBlank: true,
-	    name: 'pool',
-	    listeners: {
-		change: function( selpool, newValue, oldValue) {
-		    selectPoolMembers(newValue);
-		}
-	    }
-	});
-
-	var nodesel = Ext.create('PVE.form.NodeSelector', {
-	    name: 'node',
-	    fieldLabel: gettext('Node'),
-	    allowBlank: true,
-	    editable: true,
-	    autoSelect: false,
-	    emptyText: '-- ' + gettext('All') + ' --',
-	    listeners: {
-		change: function(f, value) {
-		    storagesel.setNodename(value || 'localhost');
-		    var mode = selModeField.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!value || rec.get('node') === value);
-		    });
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    }
-
-		    if (mode === 'pool') {
-			selectPoolMembers(selPool.value);
-		    }
-		}
-	    }
-	});
-
-	var column1 = [
-	    nodesel,
-	    storagesel,
-	    {
-		xtype: 'pveDayOfWeekSelector',
-		name: 'dow',
-		fieldLabel: gettext('Day of week'),
-		multiSelect: true,
-		value: ['sat'],
-		allowBlank: false
-	    },
-	    {
-		xtype: 'timefield',
-		fieldLabel: gettext('Start Time'),
-		name: 'starttime',
-		format: 'H:i',
-		formatText: 'HH:MM',
-		value: '00:00',
-		allowBlank: false
-	    },
-	    selModeField,
-	    selPool
-	];
-
-	var column2 = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Send email to'),
-		name: 'mailto'
-	    },
-	    {
-		xtype: 'pveEmailNotificationSelector',
-		fieldLabel: gettext('Email notification'),
-		name: 'mailnotification',
-		deleteEmpty: me.isCreate ? false : true,
-		value: me.isCreate ? 'always' : ''
-	    },
-	    {
-		xtype: 'pveCompressionSelector',
-		fieldLabel: gettext('Compression'),
-		name: 'compress',
-		deleteEmpty: me.isCreate ? false : true,
-		value: 'lzo'
-	    },
-	    {
-		xtype: 'pveBackupModeSelector',
-		fieldLabel: gettext('Mode'),
-		value: 'snapshot',
-		name: 'mode'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enable'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    },
-	    vmidField
-	];
-	/*jslint confusion: false*/
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    onlineHelp: 'chapter_vzdump',
-	    column1: column1,
-	    column2:  column2,
-	    onGetValues: function(values) {
-		if (!values.node) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'node' });
-		    }
-		    delete values.node;
-		}
-
-		var selMode = values.selMode;
-		delete values.selMode;
-
-		if (selMode === 'all') {
-		    values.all = 1;
-		    values.exclude = '';
-		    delete values.vmid;
-		} else if (selMode === 'exclude') {
-		    values.all = 1;
-		    values.exclude = values.vmid;
-		    delete values.vmid;
-		} else if (selMode === 'pool') {
-		    delete values.vmid;
-		}
-
-		if (selMode !== 'pool') {
-		    delete values.pool;
-		}
-		return values;
-	    }
-	});
-
-	var update_vmid_selection = function(list, mode) {
-	    if (mode !== 'all' && mode !== 'pool') {
-		sm.deselectAll(true);
-		if (list) {
-		    Ext.Array.each(list.split(','), function(vmid) {
-			var rec = store.findRecord('vmid', vmid);
-			if (rec) {
-			    sm.select(rec, true);
-			}
-		    });
-		}
-	    }
-	};
-
-	vmidField.on('change', function(f, value) {
-	    var mode = selModeField.getValue();
-	    update_vmid_selection(value, mode);
-	});
-
-	selModeField.on('change', function(f, value, oldValue) {
-	    if (oldValue === 'pool') {
-		store.removeFilter('poolFilter');
-	    }
-
-	    if (oldValue === 'all') {
-		sm.deselectAll(true);
-		vmidField.setValue('');
-	    }
-
-	    if (value === 'all') {
-		sm.selectAll(true);
-		vmgrid.setDisabled(true);
-	    } else {
-		vmgrid.setDisabled(false);
-	    }
-
-	    if (value === 'pool') {
-		vmgrid.setDisabled(true);
-		vmidField.setValue('');
-		selPool.setVisible(true);
-		selPool.allowBlank = false;
-		selectPoolMembers(selPool.value);
-
-	    } else {
-		selPool.setVisible(false);
-		selPool.allowBlank = true;
-	    }
-	    var list = vmidField.getValue();
-	    update_vmid_selection(list, value);
-	});
-
-	var reload = function() {
-	    store.load({
-		params: { type: 'vm' },
-		callback: function() {
-		    var node = nodesel.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!node || node.length === 0 || rec.get('node') === node);
-		    });
-		    var list = vmidField.getValue();
-		    var mode = selModeField.getValue();
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    } else if (mode === 'pool'){
-			selectPoolMembers(selPool.value);
-		    } else {
-			update_vmid_selection(list, mode);
-		    }
-		}
-	    });
-	};
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-	    items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.isCreate) {
-	    selModeField.setValue('include');
-	} else {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-
-		    data.dow = data.dow.split(',');
-
-		    if (data.all || data.exclude) {
-			if (data.exclude) {
-			    data.vmid = data.exclude;
-			    data.selMode = 'exclude';
-			} else {
-			    data.vmid = '';
-			    data.selMode = 'all';
-			}
-		    } else if (data.pool) {
-			data.selMode = 'pool';
-			data.selPool = data.pool;
-		    } else {
-			data.selMode = 'include';
-		    }
-
-		    me.setValues(data);
-               }
-            });
-        }
-
-	reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-cluster-backup',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/cluster/backup"
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.BackupEdit',{
-                jobid: rec.data.id
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/backup',
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    stateful: true,
-	    stateId: 'grid-dc-backup',
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.BackupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    dataIndex: 'enabled',
-		    xtype: 'checkcolumn',
-		    sortable: true,
-		    disabled: true,
-		    disabledCls: 'x-item-enabled',
-		    stopSelection: false
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node',
-		    renderer: function(value) {
-			if (value) {
-			    return value;
-			}
-			return me.allText;
-		    }
-		},
-		{
-		    header: gettext('Day of week'),
-		    width: 200,
-		    sortable: false,
-		    dataIndex: 'dow',
-		    renderer: function(val) {
-			var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-			var selected = [];
-			var cur = -1;
-			val.split(',').forEach(function(day){
-			    cur++;
-			    var dow = (dows.indexOf(day)+6)%7;
-			    if (cur === dow) {
-				if (selected.length === 0 || selected[selected.length-1] === 0) {
-				    selected.push(1);
-				} else {
-				    selected[selected.length-1]++;
-				}
-			    } else {
-				while (cur < dow) {
-				    cur++;
-				    selected.push(0);
-				}
-				selected.push(1);
-			    }
-			});
-
-			cur = -1;
-			var days = [];
-			selected.forEach(function(item) {
-			    cur++;
-			    if (item > 2) {
-				days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
-				cur += item-1;
-			    } else if (item == 2) {
-				days.push(Ext.Date.dayNames[cur+1]);
-				days.push(Ext.Date.dayNames[(cur+2)%7]);
-				cur++;
-			    } else if (item == 1) {
-				days.push(Ext.Date.dayNames[(cur+1)%7]);
-			    }
-			});
-			return days.join(', ');
-		    }
-		},
-		{
-		    header: gettext('Start Time'),
-		    width: 60,
-		    sortable: true,
-		    dataIndex: 'starttime'
-		},
-		{
-		    header: gettext('Storage'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Selection'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'vmid',
-		    renderer: function(value, metaData, record) {
-			/*jslint confusion: true */
-			if (record.data.all) {
-			    if (record.data.exclude) {
-				return Ext.String.format(me.allExceptText, record.data.exclude);
-			    }
-			    return me.allText;
-			}
-			if (record.data.vmid) {
-			    return record.data.vmid;
-			}
-
-			if (record.data.pool) {
-			    return "Pool '"+ record.data.pool + "'";
-			}
-
-			return "-";
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'starttime', 'dow',
-	    'storage', 'node', 'vmid', 'exclude',
-	    'mailto', 'pool',
-	    { name: 'enabled', type: 'boolean' },
-	    { name: 'all', type: 'boolean' },
-	    { name: 'snapshot', type: 'boolean' },
-	    { name: 'stop', type: 'boolean' },
-	    { name: 'suspend', type: 'boolean' },
-	    { name: 'compress', type: 'boolean' }
-	]
-    });
-});
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-    pveGuidePath: '/pve-docs/index.html',
-    onlineHelp: 'getting_help',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: function() {
-	var me = this;
-	var guideUrl = window.location.origin + me.pveGuidePath;
-	var text = Ext.String.format('<h1>Documentation</h1>'
-	+ 'The official Proxmox VE Administration Guide'
-	+ ' is included with this installation and can be browsed at '
-	+ '<a target="_blank" href="{0}">{0}</a>', guideUrl);
-	return text;
-    },
-
-    updateActive: function(data) {
-	var me = this;
-	
-	var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-
-    updateCommunity: function(data) {
-	var me = this;
-
-	var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-	 
-    updateInactive: function(data) {
-	var me = this;
-	me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/localhost/subscription',
-		method: 'GET',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.update('Unable to load subscription status' + ": " + response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-
-		    if (data.status === 'Active') {
-			if (data.level === 'c') {
-			    me.updateCommunity(data);
-			} else {
-			    me.updateActive(data);
-			}
-		    } else {
-			me.updateInactive(data);
-		    }
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('pve-security-groups', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'group', 'comment', 'digest' ],
-    idProperty: 'group'
-});
-
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = (me.group_name === undefined);
-
-	var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-	
-	var items = [	    
-	    {
-		xtype: 'textfield',
-		name: 'group',
-		value: me.group_name || '',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: me.group_comment || '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	if (me.isCreate) {
-	    subject = gettext('Security Group');
-        } else {
-	    subject = gettext('Security Group') + " '" + me.group_name + "'";
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'rename',
-		value: me.group_name
-	    });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	// InputPanel does not have a 'create' property, does it need a 'isCreate'
-	    isCreate: me.isCreate,
-	    items: items 
-	});
-
-
-	Ext.apply(me, {
-            subject: subject,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    stateful: true,
-    stateId: 'grid-securitygroups',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (me.rule_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-security-groups',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json' + me.base_url
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('group', oldrec.data.group);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.SecurityGroupEdit', {
-		digest: rec.data.digest,
-		group_name: rec.data.group,
-		group_comment: rec.data.comment
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('PVE.SecurityGroupEdit', {});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    enableFn: function(rec) {
-		return (rec && me.base_url);
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Group'), dataIndex: 'group', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = '/cluster/firewall/groups/' + rec.data.group;
-		    me.rule_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.rule_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-	var me = this;
-
-	var rule_panel = Ext.createWidget('pveFirewallRules', {
-	    region: 'center',
-	    allow_groups: false,
-	    list_refs_url: '/cluster/firewall/refs',
-	    tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-	    border: false
-	});
-
-	var sglist = Ext.createWidget('pveSecurityGroupList', {
-	    region: 'west',
-	    rule_panel: rule_panel,
-	    width: '25%',
-	    border: false,
-	    split: true
-	});
-
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-	    listeners: {
-		show: function() {
-		    sglist.fireEvent('show', sglist);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    onlineHelp: 'pve_admin_guide',
-
-    initComponent: function() {
-        var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext("Datacenter"),
-	    hstateid: 'dctab'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		title: gettext('Summary'),
-		xtype: 'pveDcSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    },
-	    {
-		title: gettext('Cluster'),
-		xtype: 'pveClusterAdministration',
-		iconCls: 'fa fa-server',
-		itemId: 'cluster'
-	    },
-	    {
-		title: 'Ceph',
-		itemId: 'ceph',
-		iconCls: 'fa fa-ceph',
-		xtype: 'pveNodeCephStatus'
-	    },
-	    {
-		xtype: 'pveDcOptionView',
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options'
-	    });
-	}
-
-	if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageView',
-		title: gettext('Storage'),
-		iconCls: 'fa fa-database',
-		itemId: 'storage'
-	    });
-	}
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveDcBackupView',
-		iconCls: 'fa fa-floppy-o',
-		title: gettext('Backup'),
-		itemId: 'backup'
-	    },
-	    {
-		xtype: 'pveReplicaView',
-		iconCls: 'fa fa-retweet',
-		title: gettext('Replication'),
-		itemId: 'replication'
-	    },
-	    {
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		expandedOnInit: true
-	    });
-	}
-
-	me.items.push({
-	    xtype: 'pveUserView',
-	    groups: ['permissions'],
-	    iconCls: 'fa fa-user',
-	    title: gettext('Users'),
-	    itemId: 'users'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveGroupView',
-		title: gettext('Groups'),
-		iconCls: 'fa fa-users',
-		groups: ['permissions'],
-		itemId: 'groups'
-	    },
-	    {
-		xtype: 'pvePoolView',
-		title: gettext('Pools'),
-		iconCls: 'fa fa-tags',
-		groups: ['permissions'],
-		itemId: 'pools'
-	    },
-	    {
-		xtype: 'pveRoleView',
-		title: gettext('Roles'),
-		iconCls: 'fa fa-male',
-		groups: ['permissions'],
-		itemId: 'roles'
-	    },
-	    {
-		xtype: 'pveAuthView',
-		title: gettext('Authentication'),
-		groups: ['permissions'],
-		iconCls: 'fa fa-key',
-		itemId: 'domains'
-	    },
-	    {
-		xtype: 'pveHAStatus',
-		title: 'HA',
-		iconCls: 'fa fa-heartbeat',
-		itemId: 'ha'
-	    },
-	    {
-		title: gettext('Groups'),
-		groups: ['ha'],
-		xtype: 'pveHAGroupsView',
-		iconCls: 'fa fa-object-group',
-		itemId: 'ha-groups'
-	    },
-	    {
-		title: gettext('Fencing'),
-		groups: ['ha'],
-		iconCls: 'fa fa-bolt',
-		xtype: 'pveFencingView',
-		itemId: 'ha-fencing'
-	    },
-	    {
-		xtype: 'pveFirewallRules',
-		title: gettext('Firewall'),
-		allow_iface: true,
-		base_url: '/cluster/firewall/rules',
-		list_refs_url: '/cluster/firewall/refs',
-		iconCls: 'fa fa-shield',
-		itemId: 'firewall'
-	    },
-	    {
-		xtype: 'pveFirewallOptions',
-		title: gettext('Options'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-gear',
-		base_url: '/cluster/firewall/options',
-		onlineHelp: 'pve_firewall_cluster_wide_setup',
-		fwtype: 'dc',
-		itemId: 'firewall-options'
-	    },
-	    {
-		xtype: 'pveSecurityGroups',
-		title: gettext('Security Group'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-group',
-		itemId: 'firewall-sg'
-	    },
-	    {
-		xtype: 'pveFirewallAliases',
-		title: gettext('Alias'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-external-link',
-		base_url: '/cluster/firewall/aliases',
-		itemId: 'firewall-aliases'
-	    },
-	    {
-		xtype: 'pveIPSet',
-		title: 'IPSet',
-		groups: ['firewall'],
-		iconCls: 'fa fa-list-ol',
-		base_url: '/cluster/firewall/ipset',
-		list_refs_url: '/cluster/firewall/refs',
-		itemId: 'firewall-ipset'
-	    },
-	    {
-		xtype: 'pveDcSupport',
-		title: gettext('Support'),
-		itemId: 'support',
-		iconCls: 'fa fa-comments-o'
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveDcNodeView',
-
-    title: gettext('Nodes'),
-    disableSelection: true,
-    scrollable: true,
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    dataIndex: 'name'
-	},
-	{
-	    header: 'ID',
-	    width: 40,
-	    sortable: true,
-	    dataIndex: 'nodeid'
-	},
-	{
-	    header: gettext('Online'),
-	    width: 60,
-	    sortable: true,
-	    dataIndex: 'online',
-	    renderer: function(value) {
-		var cls = (value)?'good':'critical';
-		return  '<i class="fa ' + PVE.Utils.get_health_icon(cls) + '"><i/>';
-	    }
-	},
-	{
-	    header: gettext('Support'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'level',
-	    renderer: PVE.Utils.render_support_level
-	},
-	{
-	    header: gettext('Server Address'),
-	    width: 115,
-	    sortable: true,
-	    dataIndex: 'ip'
-	},
-	{
-	    header: gettext('CPU usage'),
-	    sortable: true,
-	    width: 110,
-	    dataIndex: 'cpuusage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Memory usage'),
-	    width: 110,
-	    sortable: true,
-	    tdCls: 'x-progressbar-default-cell',
-	    dataIndex: 'memoryusage',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Uptime'),
-	    sortable: true,
-	    dataIndex: 'uptime',
-	    align: 'right',
-	    renderer: Proxmox.Utils.render_uptime
-	}
-    ],
-
-    stateful: true,
-    stateId: 'grid-cluster-nodes',
-    tools: [
-	{
-	    type: 'up',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = Math.max(me.getHeight()-50, 250);
-		me.setHeight(height);
-	    }
-	},
-	{
-	    type: 'down',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = me.getHeight()+50;
-		me.setHeight(height);
-	    }
-	}
-    ]
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-	extend: 'Ext.data.Model',
-	fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-	idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.widget.ProgressBar',{
-    extend: 'Ext.Progress',
-    alias: 'widget.pveProgressBar',
-
-    animate: true,
-    textTpl: [
-	'{percent}%'
-    ],
-
-    setValue: function(value){
-	var me = this;
-	me.callParent([value]);
-
-	me.removeCls(['warning', 'critical']);
-
-	if (value > 0.89) {
-	    me.addCls('critical');
-	} else if (value > 0.59) {
-	    me.addCls('warning');
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('pve-cluster-nodes', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
-	{ type: 'integer', name: 'quorum_votes' }
-    ],
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/nodes"
-    },
-    idProperty: 'nodeid'
-});
-
-Ext.define('pve-cluster-info', {
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/join"
-    }
-});
-
-Ext.define('PVE.ClusterAdministration', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveClusterAdministration',
-
-    title: gettext('Cluster Administration'),
-    onlineHelp: 'chapter_pvecm',
-
-    border: false,
-    defaults: { border: false },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    totem: {},
-	    nodelist: [],
-	    preferred_node: {
-		name: '',
-		fp: '',
-		addr: ''
-	    },
-	    isInCluster: false,
-	    nodecount: 0
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Cluster Information'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.store = Ext.create('Proxmox.data.UpdateStore', {
-			autoStart: true,
-			interval: 15 * 1000,
-			storeid: 'pve-cluster-info',
-			model: 'pve-cluster-info'
-		    });
-		    view.store.on('load', this.onLoad, this);
-		    view.on('destroy', view.store.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records || !records[0].data) {
-			vm.set('totem', {});
-			vm.set('isInCluster', false);
-			vm.set('nodelist', []);
-			vm.set('preferred_node', {
-			    name: '',
-			    addr: '',
-			    fp: ''
-			});
-			return;
-		    }
-		    var data = records[0].data;
-		    vm.set('totem', data.totem);
-		    vm.set('isInCluster', !!data.totem.cluster_name);
-		    vm.set('nodelist', data.nodelist);
-
-		    var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
-			return el.name === data.preferred_node;
-		    });
-
-		    vm.set('preferred_node', {
-			name: data.preferred_node,
-			addr: nodeinfo.pve_addr,
-			ring_addr: [ nodeinfo.ring0_addr, nodeinfo.ring1_addr ],
-			fp: nodeinfo.pve_fp
-		    });
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterCreateWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onClusterInfo: function() {
-		    var vm = this.getViewModel();
-		    var win = Ext.create('PVE.ClusterInfoWindow', {
-			joinInfo: {
-			    ipAddress: vm.get('preferred_node.addr'),
-			    fingerprint: vm.get('preferred_node.fp'),
-			    ring_addr: vm.get('preferred_node.ring_addr'),
-			    totem: vm.get('totem')
-			}
-		    });
-		    win.show();
-		},
-
-		onJoin: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create Cluster'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Information'),
-		    reference: 'addButton',
-		    handler: 'onClusterInfo',
-		    bind: {
-			disabled: '{!isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Cluster'),
-		    reference: 'joinButton',
-		    handler: 'onJoin',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		}
-	    ],
-	    layout: 'hbox',
-	    bodyPadding: 5,
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Cluster Name'),
-		    bind: {
-			value: '{totem.cluster_name}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Config Version'),
-		    bind: {
-			value: '{totem.config_version}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Number of Nodes'),
-		    labelWidth: 120,
-		    bind: {
-			value: '{nodecount}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    value: gettext('Standalone node - no cluster defined'),
-		    bind: {
-			hidden: '{isInCluster}'
-		    },
-		    flex: 1
-		}
-	    ]
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Cluster Nodes'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-cluster-nodes',
-			model: 'pve-cluster-nodes'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'nodeid',
-			    order: 'DESC'
-			}
-		    }));
-		    Proxmox.Utils.monStoreErrors(view, view.rstore);
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('nodecount', 0);
-			return;
-		    }
-		    vm.set('nodecount', records.length);
-		}
-	    },
-	    columns: [
-		{
-		    header: gettext('Nodename'),
-		    flex: 2,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('ID'),
-		    flex: 1,
-		    dataIndex: 'nodeid'
-		},
-		{
-		    header: gettext('Votes'),
-		    flex: 1,
-		    dataIndex: 'quorum_votes'
-		},
-		{
-		    header: Ext.String.format(gettext('Link {0}'), 0),
-		    flex: 2,
-		    dataIndex: 'ring0_addr'
-		},
-		{
-		    header: Ext.String.format(gettext('Link {0}'), 1),
-		    flex: 2,
-		    dataIndex: 'ring1_addr'
-		}
-	    ]
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ClusterCreateWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterCreateWindow',
-
-    title: gettext('Create Cluster'),
-    width: 600,
-
-    method: 'POST',
-    url: '/cluster/config',
-
-    isCreate: true,
-    subject: gettext('Cluster'),
-    showTaskViewer: true,
-
-    onlineHelp: 'pvecm_create_cluster',
-
-    items: {
-	xtype: 'inputpanel',
-	items: [{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Cluster Name'),
-	    allowBlank: false,
-	    name: 'clustername'
-	},
-	{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-	    emptyText: gettext("Optional, defaults to IP resolved by node's hostname"),
-	    name: 'link0',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}],
-	advancedItems: [{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-	    emptyText: gettext("Optional second link for redundancy"),
-	    name: 'link1',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}]
-    }
-});
-
-Ext.define('PVE.ClusterInfoWindow', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveClusterInfoWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 800,
-    modal: true,
-    resizable: false,
-    title: gettext('Cluster Join Information'),
-
-    joinInfo: {
-	ipAddress: undefined,
-	fingerprint: undefined,
-	totem: {}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    border: false,
-	    padding: '10 10 10 10',
-	    html: gettext("Copy the Join Information here and use it on the node you want to add.")
-	},
-	{
-	    xtype: 'container',
-	    layout: 'form',
-	    border: false,
-	    padding: '0 10 10 10',
-	    items: [
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('IP Address'),
-		    cbind: { value: '{joinInfo.ipAddress}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Fingerprint'),
-		    cbind: { value: '{joinInfo.fingerprint}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textarea',
-		    inputId: 'pveSerializedClusterInfo',
-		    fieldLabel: gettext('Join Information'),
-		    grow: true,
-		    cbind: { joinInfo: '{joinInfo}' },
-		    editable: false,
-		    listeners: {
-			afterrender: function(field) {
-			    if (!field.joinInfo) {
-				return;
-			    }
-			    var jsons = Ext.JSON.encode(field.joinInfo);
-			    var base64s = Ext.util.Base64.encode(jsons);
-			    field.setValue(base64s);
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-    dockedItems: [{
-	dock: 'bottom',
-	xtype: 'toolbar',
-	items: [{
-	    xtype: 'button',
-	    handler: function(b) {
-		var el = document.getElementById('pveSerializedClusterInfo');
-		el.select();
-		document.execCommand("copy");
-	    },
-	    text: gettext('Copy Information')
-	}]
-    }]
-});
-
-Ext.define('PVE.ClusterJoinNodeWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterJoinNodeWindow',
-
-    title: gettext('Cluster Join'),
-    width: 800,
-
-    method: 'POST',
-    url: '/cluster/config/join',
-
-    defaultFocus: 'textarea[name=serializedinfo]',
-    isCreate: true,
-    submitText: gettext('Join'),
-    showTaskViewer: true,
-
-    onlineHelp: 'chapter_pvecm',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    info: {
-		fp: '',
-		ip: '',
-		ring0Needed: false,
-		ring1Possible: false,
-		ring1Needed: false
-	    }
-	},
-	formulas: {
-	    ring0EmptyText: function(get) {
-		if (get('info.ring0Needed')) {
-		    return gettext("Cannot use default address safely");
-		} else {
-		    return gettext("Default: IP resolved by node's hostname");
-		}
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#': {
-		close: function() {
-		    delete PVE.Utils.silenceAuthFailures;
-		}
-	    },
-	    'proxmoxcheckbox[name=assistedEntry]': {
-		change: 'onInputTypeChange'
-	    },
-	    'textarea[name=serializedinfo]': {
-		change: 'recomputeSerializedInfo',
-		enable: 'resetField'
-	    },
-	    'proxmoxtextfield[name=ring1_addr]': {
-		enable: 'ring1Needed'
-	    },
-	    'textfield': {
-		disable: 'resetField'
-	    }
-	},
-	resetField: function(field) {
-	    field.reset();
-	},
-	ring1Needed: function(f) {
-	    var vm = this.getViewModel();
-	    f.allowBlank = !vm.get('info.ring1Needed');
-	},
-	onInputTypeChange: function(field, assistedInput) {
-	    var vm = this.getViewModel();
-	    if (!assistedInput) {
-		vm.set('info.ring1Possible', true);
-	    }
-	},
-	recomputeSerializedInfo: function(field, value) {
-	    var vm = this.getViewModel();
-	    var jsons = Ext.util.Base64.decode(value);
-	    var joinInfo = Ext.JSON.decode(jsons, true);
-
-	    var info = {
-		fp: '',
-		ring1Needed: false,
-		ring1Possible: false,
-		ip: ''
-	    };
-
-	    var totem = {};
-	    if (!(joinInfo && joinInfo.totem)) {
-		field.valid = false;
-	    } else {
-		var ring0Needed = false;
-		if (joinInfo.ring_addr !== undefined) {
-		    ring0Needed = joinInfo.ring_addr[0] !== joinInfo.ipAddress;
-		}
-
-		info = {
-		    ip: joinInfo.ipAddress,
-		    fp: joinInfo.fingerprint,
-		    ring0Needed: ring0Needed,
-		    ring1Possible: !!joinInfo.totem['interface']['1'],
-		    ring1Needed: !!joinInfo.totem['interface']['1']
-		};
-		totem = joinInfo.totem;
-		field.valid = true;
-	    }
-
-	    vm.set('info', info);
-	}
-    },
-
-    submit: function() {
-	// joining may produce temporarily auth failures, ignore as long the task runs
-	PVE.Utils.silenceAuthFailures = true;
-	this.callParent();
-    },
-
-    taskDone: function(success) {
-	delete PVE.Utils.silenceAuthFailures;
-	if (success) {
-	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
-	    // ensure user cannot do harm
-	    Ext.getBody().mask(txt, ['pve-static-mask']);
-	    // TaskView may hide above mask, so tell him directly
-	    Ext.Msg.show({
-		title: gettext('Join Task Finished'),
-		icon: Ext.Msg.INFO,
-		msg: txt
-	    });
-	    // reload always (if user wasn't faster), but wait a bit for pveproxy
-	    Ext.defer(function() {
-		window.location.reload(true);
-	    }, 5000);
-	}
-    },
-
-    items: [{
-	xtype: 'proxmoxcheckbox',
-	reference: 'assistedEntry',
-	name: 'assistedEntry',
-	submitValue: false,
-	value: true,
-	autoEl: {
-	    tag: 'div',
-	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
-	},
-	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
-    },
-    {
-	xtype: 'textarea',
-	name: 'serializedinfo',
-	submitValue: false,
-	allowBlank: false,
-	fieldLabel: gettext('Information'),
-	emptyText: gettext('Paste encoded Cluster Information here'),
-	validator: function(val) {
-	    return val === '' || this.valid ||
-	       gettext('Does not seem like a valid encoded Cluster Information!');
-	},
-	bind: {
-	    disabled: '{!assistedEntry.checked}',
-	    hidden: '{!assistedEntry.checked}'
-	},
-	value: ''
-    },
-    {
-	xtype: 'inputpanel',
-	column1: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Peer Address'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.ip}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'hostname'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		emptyText: gettext("Peer's root password"),
-		fieldLabel: gettext('Password'),
-		allowBlank: false,
-		name: 'password'
-	    }
-	],
-	column2: [
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-		bind: {
-		    emptyText: '{ring0EmptyText}',
-		    allowBlank: '{!info.ring0Needed}'
-		},
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		name: 'link0'
-	    },
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		bind: {
-		    disabled: '{!info.ring1Possible}',
-		    allowBlank: '{!info.ring1Needed}',
-		},
-		name: 'link1'
-	    }
-	],
-	columnB: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Fingerprint'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.fp}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'fingerprint'
-	    }
-	]
-    }]
-});
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-	var me = this;
-	me.loginData = loginData;
-	Proxmox.Utils.setAuthData(loginData);
-
-	var rt = me.down('pveResourceTree');
-	rt.setDatacenterText(loginData.clustername);
-
-	if (loginData.cap) {
-	    Ext.state.Manager.set('GuiCap', loginData.cap);
-	}
-	me.response401count = 0;
-
-	me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-	var me = this;
-
-	Proxmox.Utils.authClear();
-	Proxmox.UserName = null;
-	me.loginData = null;
-
-	if (!me.login) {
-	    me.login = Ext.create('PVE.window.LoginWindow', {
-		handler: function(data) {
-		    me.login = null;
-		    me.updateLoginData(data);
-		    Proxmox.Utils.checked_command(function() {}); // display subscription status
-		}
-	    });
-	}
-	me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.tip.QuickTipManager.init();
-
-	// fixme: what about other errors
-	Ext.Ajax.on('requestexception', function(conn, response, options) {
-	    if (response.status == 401 && !PVE.Utils.silenceAuthFailures) { // auth failure
-		// don't immediately show as logged out to cope better with some big
-		// upgrades, which may temporarily produce a false positive 401 err
-		me.response401count++;
-		if (me.response401count > 5) {
-		    me.showLogin();
-		}
-	    }
-	});
-
-	me.callParent();
-
-        if (!Proxmox.Utils.authOK()) {
-	    me.showLogin();
-	} else { 
-	    if (me.loginData) {
-		me.onLogin(me.loginData);
-	    }
-	}
-
-	Ext.TaskManager.start({
-	    run: function() {
-		var ticket = Proxmox.Utils.authOK();
-		if (!ticket || !Proxmox.UserName) {
-		    return;
-		}
-
-		Ext.Ajax.request({
-		    params: { 
-			username: Proxmox.UserName,
-			password: ticket
-		    },
-		    url: '/api2/json/access/ticket',
-		    method: 'POST',
-		    success: function(response, opts) {
-			var obj = Ext.decode(response.responseText);
-			me.updateLoginData(obj.data);
-		    }
-		});
-	    },
-	    interval: 15*60*1000
-	});
-
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-	var me = this;
-	
-	var cont = me.child('#content');
-
-	var lay = cont.getLayout();
-
-	var cur = lay.getActiveItem();
-
-	if (comp) {
-	    Proxmox.Utils.setErrorMask(cont, false);
-	    comp.border = false;
-	    cont.add(comp);
-	    if (cur !== null && lay.getNext()) {
-		lay.next();
-		var task = Ext.create('Ext.util.DelayedTask', function(){
-		    cont.remove(cur);
-		});
-		task.delay(10);
-	    }
-	}
-	else {
-	    // helper for cleaning the content when logging out
-	    cont.removeAll();
-	}
-    },
-
-    selectById: function(nodeid) {
-	var me = this;
-	var tree = me.down('pveResourceTree');
-	tree.selectById(nodeid);
-    },
-
-    onLogin: function(loginData) {
-	var me = this;
-
-	me.updateUserInfo();
-
-	if (loginData) {
-	    PVE.data.ResourceStore.startUpdate();
-
-	    Proxmox.Utils.API2Request({
-		url: '/version',
-		method: 'GET',
-		success: function(response) {
-		    PVE.VersionInfo = response.result.data;
-		    me.updateVersionInfo();
-		}
-	    });
-	}
-    },
-
-    updateUserInfo: function() {
-	var me = this;
-	var ui = me.query('#userinfo')[0];
-	ui.setText(Proxmox.UserName || '');
-	ui.updateLayout();
-    },
-
-    updateVersionInfo: function() {
-	var me = this;
-
-	var ui = me.query('#versioninfo')[0];
-
-	if (PVE.VersionInfo) {
-	    var version = PVE.VersionInfo.version;
-	    ui.update('Virtual Environment ' + version);
-	} else {
-	    ui.update('Virtual Environment');
-	}
-	ui.updateLayout();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.History.init();
-
-	var sprovider = Ext.create('PVE.StateProvider');
-	Ext.state.Manager.setProvider(sprovider);
-
-	var selview = Ext.create('PVE.form.ViewSelector');
-
-	var rtree = Ext.createWidget('pveResourceTree', {
-	    viewFilter: selview.getViewFilter(),
-	    flex: 1,
-	    selModel: {
-		selType: 'treemodel',
-		listeners: {
-		    selectionchange: function(sm, selected) {
-			if (selected.length > 0) {
-			    var n = selected[0];
-			    var tlckup = {
-				root: 'PVE.dc.Config',
-				node: 'PVE.node.Config',
-				qemu: 'PVE.qemu.Config',
-				lxc: 'PVE.lxc.Config',
-				storage: 'PVE.storage.Browser',
-				pool: 'pvePoolConfig'
-			    };
-			    var comp = {
-				xtype: tlckup[n.data.type || 'root'] || 
-				    'pvePanelConfig',
-				showSearch: (n.data.id === 'root') ||
-				    Ext.isDefined(n.data.groupbyid),
-				pveSelNode: n,
-				workspace: me,
-				viewFilter: selview.getViewFilter()
-			    };
-			    PVE.curSelectedNode = n;
-			    me.setContent(comp);
-			}
-		    }
-		}
-	    }
-	});
-
-	selview.on('select', function(combo, records) { 
-	    if (records) {
-		var view = combo.getViewFilter();
-		rtree.setViewFilter(view);
-	    }
-	});
-
-	var caps = sprovider.get('GuiCap');
-
-	var createVM = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-desktop',
-	    text: gettext("Create VM"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	var createCT = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-cube',
-	    text: gettext("Create CT"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	sprovider.on('statechange', function(sp, key, value) {
-	    if (key === 'GuiCap' && value) {
-		caps = value;
-		createVM.setDisabled(!caps.vms['VM.Allocate']);
-		createCT.setDisabled(!caps.vms['VM.Allocate']);
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		{
-		    region: 'north',
-		    layout: { 
-			type: 'hbox',
-			align: 'middle'
-		    },
-		    baseCls: 'x-plain',		
-		    defaults: {
-			baseCls: 'x-plain'			
-		    },
-		    border: false,
-		    margin: '2 0 2 5',
-		    items: [
-			{
-			    html: '<a class="x-unselectable" target=_blank href="https://www.proxmox.com">' +
-				'<img style="padding-top:4px;padding-right:5px" src="/pve2/images/proxmox_logo.png"/></a>'
-			},
-			{
-			    minWidth: 150,
-			    id: 'versioninfo',
-			    html: 'Virtual Environment'
-			},
-			{
-			    xtype: 'pveGlobalSearchField',
-			    tree: rtree
-			},
-			{
-			    flex: 1
-			},
-			{
-			    xtype: 'proxmoxHelpButton',
-			    hidden: false,
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
-			    listenToGlobalEvent: false,
-			    onlineHelp: 'pve_documentation_index',
-			    text: gettext('Documentation'),
-			    margin: '0 5 0 0'
-			},
-			createVM, 
-			createCT,
-			{
-			    pack: 'end',
-			    margin: '0 5 0 0',
-			    id: 'userinfo',
-			    xtype: 'button',
-			    baseCls: 'x-btn',
-			    style: {
-				// proxmox dark grey p light grey as border
-				backgroundColor: '#464d4d',
-				borderColor: '#ABBABA'
-			    },
-			    iconCls: 'fa fa-user',
-			    menu: [
-				{
-				    iconCls: 'fa fa-gear',
-				    text: gettext('My Settings'),
-				    handler: function() {
-					var win = Ext.create('PVE.window.Settings');
-					win.show();
-				    }
-				},
-				{
-				    text: gettext('Password'),
-				    iconCls: 'fa fa-fw fa-key',
-				    handler: function() {
-					var win = Ext.create('Proxmox.window.PasswordEdit', {
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				{
-				    text: 'TFA',
-				    iconCls: 'fa fa-fw fa-lock',
-				    handler: function(btn, event, rec) {
-					var win = Ext.create('PVE.window.TFAEdit',{
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				'-',
-				{
-				    iconCls: 'fa fa-fw fa-sign-out',
-				    text: gettext("Logout"),
-				    handler: function() {
-					PVE.data.ResourceStore.loadData([], false);
-					me.showLogin();
-					me.setContent(null);
-					var rt = me.down('pveResourceTree');
-					rt.setDatacenterText(undefined);
-					rt.clearTree();
-
-					// empty the stores of the StatusPanel child items
-					var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
-					Ext.Array.forEach(statusPanels, function(comp) {
-					    if (comp.getStore()) {
-						comp.getStore().loadData([], false);
-					    }
-					});
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    region: 'center',
-		    stateful: true,
-		    stateId: 'pvecenter',
-		    minWidth: 100,
-		    minHeight: 100,
-		    id: 'content',
-		    xtype: 'container',
-		    layout: { type: 'card' },
-		    border: false,
-		    margin: '0 5 0 0',
-		    items: []
-		},
-		{
-		    region: 'west',
-		    stateful: true,
-		    stateId: 'pvewest',
-		    itemId: 'west',
-		    xtype: 'container',
-		    border: false,
-		    layout: { type: 'vbox', align: 'stretch' },
-		    margin: '0 0 0 5',
-		    split: true,
-		    width: 200,
-		    items: [ selview, rtree ],
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewWidth = me.getSize().width;
-			    if (width > viewWidth - 100) {
-				panel.setWidth(viewWidth - 100);
-			    }
-			}
-		    }
-		},
-		{
-		    xtype: 'pveStatusPanel',
-		    stateful: true,
-		    stateId: 'pvesouth',
-		    itemId: 'south',
-		    region: 'south',
-		    margin:'0 5 5 5',
-		    title: gettext('Logs'),
-		    collapsible: true,
-		    header: false,
-		    height: 200,
-		    split:true,
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewHeight = me.getSize().height;
-			    if (height > (viewHeight - 150)) {
-				panel.setHeight(viewHeight - 150);
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.updateUserInfo();
-
-	// on resize, center all modal windows
-	Ext.on('resize', function(){
-	    var wins = Ext.ComponentQuery.query('window[modal]');
-	    if (wins.length > 0) {
-		wins.forEach(function(win){
-		    win.alignTo(me, 'c-c');
-		});
-	    }
-	});
-    }
-});
-
diff --git a/serverside/jsmod/6.0-4/pvemanagerlib.js.original b/serverside/jsmod/6.0-4/pvemanagerlib.js.original
deleted file mode 100644
index 0ba8b5cf198448bffd8cec99a3e473b6cfd14108..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.0-4/pvemanagerlib.js.original
+++ /dev/null
@@ -1,39779 +0,0 @@
-var pveOnlineHelpInfo = {
-   "ceph_rados_block_devices" : {
-      "link" : "/pve-docs/chapter-pvesm.html#ceph_rados_block_devices",
-      "title" : "Ceph RADOS Block Devices (RBD)"
-   },
-   "chapter_ha_manager" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#chapter_ha_manager",
-      "title" : "High Availability"
-   },
-   "chapter_lvm" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_lvm",
-      "title" : "Logical Volume Manager (LVM)"
-   },
-   "chapter_pct" : {
-      "link" : "/pve-docs/chapter-pct.html#chapter_pct",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "chapter_pve_firewall" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#chapter_pve_firewall",
-      "title" : "Proxmox VE Firewall"
-   },
-   "chapter_pveceph" : {
-      "link" : "/pve-docs/chapter-pveceph.html#chapter_pveceph",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "chapter_pvecm" : {
-      "link" : "/pve-docs/chapter-pvecm.html#chapter_pvecm",
-      "title" : "Cluster Manager"
-   },
-   "chapter_pvesr" : {
-      "link" : "/pve-docs/chapter-pvesr.html#chapter_pvesr",
-      "title" : "Storage Replication"
-   },
-   "chapter_storage" : {
-      "link" : "/pve-docs/chapter-pvesm.html#chapter_storage",
-      "title" : "Proxmox VE Storage"
-   },
-   "chapter_system_administration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_system_administration",
-      "title" : "Host System Administration"
-   },
-   "chapter_user_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#chapter_user_management",
-      "title" : "User Management"
-   },
-   "chapter_virtual_machines" : {
-      "link" : "/pve-docs/chapter-qm.html#chapter_virtual_machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "chapter_vzdump" : {
-      "link" : "/pve-docs/chapter-vzdump.html#chapter_vzdump",
-      "title" : "Backup and Restore"
-   },
-   "chapter_zfs" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_zfs",
-      "title" : "ZFS on Linux"
-   },
-   "datacenter_configuration_file" : {
-      "link" : "/pve-docs/pve-admin-guide.html#datacenter_configuration_file",
-      "title" : "Datacenter Configuration"
-   },
-   "getting_help" : {
-      "link" : "/pve-docs/pve-admin-guide.html#getting_help",
-      "title" : "Getting Help"
-   },
-   "gui_my_settings" : {
-      "link" : "/pve-docs/chapter-pve-gui.html#gui_my_settings",
-      "subtitle" : "My Settings",
-      "title" : "Graphical User Interface"
-   },
-   "ha_manager_fencing" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_fencing",
-      "subtitle" : "Fencing",
-      "title" : "High Availability"
-   },
-   "ha_manager_groups" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_groups",
-      "subtitle" : "Groups",
-      "title" : "High Availability"
-   },
-   "ha_manager_resource_config" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resource_config",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_resources" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resources",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "pct_configuration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_configuration",
-      "subtitle" : "Configuration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_images" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_images",
-      "subtitle" : "Container Images",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_network" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_network",
-      "subtitle" : "Network",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_storage" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_storage",
-      "subtitle" : "Container Storage",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_cpu" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_cpu",
-      "subtitle" : "CPU",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_general" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_general",
-      "subtitle" : "General Settings",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_memory" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_memory",
-      "subtitle" : "Memory",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_migration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_migration",
-      "subtitle" : "Migration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_options" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_options",
-      "subtitle" : "Options",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_snapshots" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_snapshots",
-      "subtitle" : "Snapshots",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Containers",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pve_admin_guide" : {
-      "link" : "/pve-docs/pve-admin-guide.html",
-      "title" : "Proxmox VE Administration Guide"
-   },
-   "pve_ceph_install" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_install",
-      "subtitle" : "Installation of Ceph Packages",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_osds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_osds",
-      "subtitle" : "Creating Ceph OSDs",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_ceph_pools" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_pools",
-      "subtitle" : "Creating Ceph Pools",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pve_documentation_index" : {
-      "link" : "/pve-docs/index.html",
-      "title" : "Proxmox VE Documentation Index"
-   },
-   "pve_firewall_cluster_wide_setup" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_cluster_wide_setup",
-      "subtitle" : "Cluster Wide Setup",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_host_specific_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_host_specific_configuration",
-      "subtitle" : "Host Specific Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_aliases" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_aliases",
-      "subtitle" : "IP Aliases",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_sets" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_sets",
-      "subtitle" : "IP Sets",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_vm_container_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_vm_container_configuration",
-      "subtitle" : "VM/Container Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_service_daemons" : {
-      "link" : "/pve-docs/index.html#_service_daemons",
-      "title" : "Service Daemons"
-   },
-   "pveceph_fs" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs",
-      "subtitle" : "CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pveceph_fs_create" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_create",
-      "subtitle" : "Create a CephFS",
-      "title" : "Manage Ceph Services on Proxmox VE Nodes"
-   },
-   "pvecm_create_cluster" : {
-      "link" : "/pve-docs/chapter-pvecm.html#pvecm_create_cluster",
-      "subtitle" : "Create the Cluster",
-      "title" : "Cluster Manager"
-   },
-   "pvesr_schedule_time_format" : {
-      "link" : "/pve-docs/chapter-pvesr.html#pvesr_schedule_time_format",
-      "subtitle" : "Schedule Format",
-      "title" : "Storage Replication"
-   },
-   "pveum_authentication_realms" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_authentication_realms",
-      "subtitle" : "Authentication Realms",
-      "title" : "User Management"
-   },
-   "pveum_groups" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_groups",
-      "subtitle" : "Groups",
-      "title" : "User Management"
-   },
-   "pveum_permission_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_permission_management",
-      "subtitle" : "Permission Management",
-      "title" : "User Management"
-   },
-   "pveum_pools" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_pools",
-      "subtitle" : "Pools",
-      "title" : "User Management"
-   },
-   "pveum_roles" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_roles",
-      "subtitle" : "Roles",
-      "title" : "User Management"
-   },
-   "pveum_tfa_auth" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_tfa_auth",
-      "subtitle" : "Two factor authentication",
-      "title" : "User Management"
-   },
-   "pveum_users" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_users",
-      "subtitle" : "Users",
-      "title" : "User Management"
-   },
-   "qm_bios_and_uefi" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_bios_and_uefi",
-      "subtitle" : "BIOS and UEFI",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cloud_init" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cloud_init",
-      "title" : "Cloud-Init Support"
-   },
-   "qm_copy_and_clone" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_copy_and_clone",
-      "subtitle" : "Copies and Clones",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cpu" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cpu",
-      "subtitle" : "CPU",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_general_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_general_settings",
-      "subtitle" : "General Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_hard_disk" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_hard_disk",
-      "subtitle" : "Hard Disk",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_memory" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_memory",
-      "subtitle" : "Memory",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_migration" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_migration",
-      "subtitle" : "Migration",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_network_device" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_network_device",
-      "subtitle" : "Network Device",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_options" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_options",
-      "subtitle" : "Options",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_os_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_os_settings",
-      "subtitle" : "OS Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_pci_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_pci_passthrough",
-      "title" : "PCI(e) Passthrough"
-   },
-   "qm_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Virtual Machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_system_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_system_settings",
-      "subtitle" : "System Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_usb_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_usb_passthrough",
-      "subtitle" : "USB Passthrough",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_virtual_machines_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_virtual_machines_settings",
-      "subtitle" : "Virtual Machines Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "storage_cephfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cephfs",
-      "title" : "Ceph Filesystem (CephFS)"
-   },
-   "storage_cifs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cifs",
-      "title" : "CIFS Backend"
-   },
-   "storage_directory" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_directory",
-      "title" : "Directory Backend"
-   },
-   "storage_glusterfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_glusterfs",
-      "title" : "GlusterFS Backend"
-   },
-   "storage_lvm" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvm",
-      "title" : "LVM Backend"
-   },
-   "storage_lvmthin" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvmthin",
-      "title" : "LVM thin Backend"
-   },
-   "storage_nfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_nfs",
-      "title" : "NFS Backend"
-   },
-   "storage_open_iscsi" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_open_iscsi",
-      "title" : "Open-iSCSI initiator"
-   },
-   "storage_zfspool" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_zfspool",
-      "title" : "Local ZFS Pool Backend"
-   },
-   "sysadmin_certificate_management" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_certificate_management",
-      "title" : "Certificate Management"
-   },
-   "sysadmin_network_configuration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_network_configuration",
-      "title" : "Network Configuration"
-   }
-};
-Ext.ns('PVE');
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	log: function() {}
-    };
-}
-console.log("Starting PVE Manager");
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-/*jslint confusion: true */
-Ext.define('PVE.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js
-
-    bus_match: /^(ide|sata|virtio|scsi)\d+$/,
-
-    log_severity_hash: {
-	0: "panic",
-	1: "alert",
-	2: "critical",
-	3: "error",
-	4: "warning",
-	5: "notice",
-	6: "info",
-	7: "debug"
-    },
-
-    support_level_hash: {
-	'c': gettext('Community'),
-	'b': gettext('Basic'),
-	's': gettext('Standard'),
-	'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="https://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-	'Linux': [
-	    { desc: '5.x - 2.6 Kernel', val: 'l26' },
-	    { desc: '2.4 Kernel', val: 'l24' }
-	],
-	'Microsoft Windows': [
-	    { desc: '10/2016', val: 'win10' },
-	    { desc: '8.x/2012/2012r2', val: 'win8' },
-	    { desc: '7/2008r2', val: 'win7' },
-	    { desc: 'Vista/2008', val: 'w2k8' },
-	    { desc: 'XP/2003', val: 'wxp' },
-	    { desc: '2000', val: 'w2k' }
-	],
-	'Solaris Kernel': [
-	    { desc: '-', val: 'solaris'}
-	],
-	'Other': [
-	    { desc: '-', val: 'other'}
-	]
-    },
-
-    get_health_icon: function(state, circle) {
-	if (circle === undefined) {
-	    circle = false;
-	}
-
-	if (state === undefined) {
-	    state = 'uknown';
-	}
-
-	var icon = 'faded fa-question';
-	switch(state) {
-	    case 'good':
-		icon = 'good fa-check';
-		break;
-	    case 'old':
-		icon = 'warning fa-refresh';
-		break;
-	    case 'warning':
-		icon = 'warning fa-exclamation';
-		break;
-	    case 'critical':
-		icon = 'critical fa-times';
-		break;
-	    default: break;
-	}
-
-	if (circle) {
-	    icon += '-circle';
-	}
-
-	return icon;
-    },
-
-    parse_ceph_version: function(service) {
-	if (service.ceph_version_short) {
-	    return service.ceph_version_short;
-	}
-
-	if (service.ceph_version) {
-	    var match = service.ceph_version.match(/version (\d+(\.\d+)*)/);
-	    if (match) {
-		return match[1];
-	    }
-	}
-
-	return undefined;
-    },
-
-    compare_ceph_versions: function(a, b) {
-	if (a === b) {
-	    return 0;
-	}
-	let avers = a.toString().split('.');
-	let bvers = b.toString().split('.');
-
-	while (true) {
-	    let av = avers.shift();
-	    let bv = bvers.shift();
-
-	    if (av === undefined && bv === undefined) {
-		return 0;
-	    } else if (av === undefined)  {
-		return -1;
-	    } else if (bv === undefined) {
-		return 1;
-	    } else {
-		let diff = parseInt(av, 10) - parseInt(bv, 10);
-		if (diff != 0) return diff;
-		// else we need to look at the next parts
-	    }
-	}
-
-    },
-
-    get_ceph_icon_html: function(health, fw) {
-	var state = PVE.Utils.map_ceph_health[health];
-	var cls = PVE.Utils.get_health_icon(state);
-	if (fw) {
-	    cls += ' fa-fw';
-	}
-	return "<i class='fa " + cls + "'></i> ";
-    },
-
-    map_ceph_health: {
-	'HEALTH_OK':'good',
-	'HEALTH_OLD':'old',
-	'HEALTH_WARN':'warning',
-	'HEALTH_ERR':'critical'
-    },
-
-    render_ceph_health: function(healthObj) {
-	var state = {
-	    iconCls: PVE.Utils.get_health_icon(),
-	    text: ''
-	};
-
-	if (!healthObj || !healthObj.status) {
-	    return state;
-	}
-
-	var health = PVE.Utils.map_ceph_health[healthObj.status];
-
-	state.iconCls = PVE.Utils.get_health_icon(health, true);
-	state.text = healthObj.status;
-
-	return state;
-    },
-
-    render_zfs_health: function(value) {
-	if (typeof value == 'undefined'){
-	    return "";
-	}
-	var iconCls = 'question-circle';
-	switch (value) {
-	    case 'AVAIL':
-	    case 'ONLINE':
-		iconCls = 'check-circle good';
-		break;
-	    case 'REMOVED':
-	    case 'DEGRADED':
-		iconCls = 'exclamation-circle warning';
-		break;
-	    case 'UNAVAIL':
-	    case 'FAULTED':
-	    case 'OFFLINE':
-		iconCls = 'times-circle critical';
-		break;
-	    default: //unknown
-	}
-
-	return '<i class="fa fa-' + iconCls + '"></i> ' + value;
-
-    },
-
-    get_kvm_osinfo: function(value) {
-	var info = { base: 'Other' }; // default
-	if (value) {
-	    Ext.each(Object.keys(PVE.Utils.kvm_ostypes), function(k) {
-		Ext.each(PVE.Utils.kvm_ostypes[k], function(e) {
-		    if (e.val === value) {
-			info = { desc: e.desc, base: k };
-		    }
-		});
-	    });
-	}
-	return info;
-    },
-
-    render_kvm_ostype: function (value) {
-	var osinfo = PVE.Utils.get_kvm_osinfo(value);
-	if (osinfo.desc && osinfo.desc !== '-') {
-	    return osinfo.base + ' ' + osinfo.desc;
-	} else {
-	    return osinfo.base;
-	}
-    },
-
-    render_hotplug_features: function (value) {
-	var fa = [];
-
-	if (!value || (value === '0')) {
-	    return gettext('Disabled');
-	}
-
-	if (value === '1') {
-	    value = 'disk,network,usb';
-	}
-
-	Ext.each(value.split(','), function(el) {
-	    if (el === 'disk') {
-		fa.push(gettext('Disk'));
-	    } else if (el === 'network') {
-		fa.push(gettext('Network'));
-	    } else if (el === 'usb') {
-		fa.push('USB');
-	    } else if (el === 'memory') {
-		fa.push(gettext('Memory'));
-	    } else if (el === 'cpu') {
-		fa.push(gettext('CPU'));
-	    } else {
-		fa.push(el);
-	    }
-	});
-
-	return fa.join(', ');
-    },
-
-    render_qga_features: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText  + ')';
-	}
-	var props = PVE.Parser.parsePropertyString(value, 'enabled');
-	if (!PVE.Parser.parseBoolean(props.enabled)) {
-	    return Proxmox.Utils.disabledText;
-	}
-
-	delete props.enabled;
-	var agentstring = Proxmox.Utils.enabledText;
-
-	Ext.Object.each(props, function(key, value) {
-	    var keystring = '' ;
-	    agentstring += ', ' + key + ': ';
-
-	    if (PVE.Parser.parseBoolean(value)) {
-		agentstring += Proxmox.Utils.enabledText;
-	    } else {
-		agentstring += Proxmox.Utils.disabledText;
-	    }
-	});
-
-	return agentstring;
-    },
-
-    render_qemu_machine: function(value) {
-	return value || (Proxmox.Utils.defaultText + ' (i440fx)');
-    },
-
-    render_qemu_bios: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (SeaBIOS)';
-	} else if (value === 'seabios') {
-	    return "SeaBIOS";
-	} else if (value === 'ovmf') {
-	    return "OVMF (UEFI)";
-	} else {
-	    return value;
-	}
-    },
-
-    render_dc_ha_opts: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	} else {
-	    return PVE.Parser.printPropertyString(value);
-	}
-    },
-    render_as_property_string: function(value) {
-	return (!value) ? Proxmox.Utils.defaultText
-	    : PVE.Parser.printPropertyString(value);
-    },
-
-    render_scsihw: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (LSI 53C895A)';
-	} else if (value === 'lsi') {
-	    return 'LSI 53C895A';
-	} else if (value === 'lsi53c810') {
-	    return 'LSI 53C810';
-	} else if (value === 'megasas') {
-	    return 'MegaRAID SAS 8708EM2';
-	} else if (value === 'virtio-scsi-pci') {
-	    return 'VirtIO SCSI';
-	} else if (value === 'virtio-scsi-single') {
-	    return 'VirtIO SCSI single';
-	} else if (value === 'pvscsi') {
-	    return 'VMware PVSCSI';
-	} else {
-	    return value;
-	}
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-	//ar: 'Arabic',
-	da: 'Danish',
-	de: 'German',
-	'de-ch': 'German (Swiss)',
-	'en-gb': 'English (UK)',
-	'en-us': 'English (USA)',
-	es: 'Spanish',
-	//et: 'Estonia',
-	fi: 'Finnish',
-	//fo: 'Faroe Islands',
-	fr: 'French',
-	'fr-be': 'French (Belgium)',
-	'fr-ca': 'French (Canada)',
-	'fr-ch': 'French (Swiss)',
-	//hr: 'Croatia',
-	hu: 'Hungarian',
-	is: 'Icelandic',
-	it: 'Italian',
-	ja: 'Japanese',
-	lt: 'Lithuanian',
-	//lv: 'Latvian',
-	mk: 'Macedonian',
-	nl: 'Dutch',
-	//'nl-be': 'Dutch (Belgium)',
-	no: 'Norwegian',
-	pl: 'Polish',
-	pt: 'Portuguese',
-	'pt-br': 'Portuguese (Brazil)',
-	//ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	//th: 'Thai',
-	tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-	std: gettext('Standard VGA'),
-	vmware: gettext('VMware compatible'),
-	qxl: 'SPICE',
-	qxl2: 'SPICE dual monitor',
-	qxl3: 'SPICE three monitors',
-	qxl4: 'SPICE four monitors',
-	serial0: gettext('Serial terminal') + ' 0',
-	serial1: gettext('Serial terminal') + ' 1',
-	serial2: gettext('Serial terminal') + ' 2',
-	serial3: gettext('Serial terminal') + ' 3',
-	virtio: 'VirtIO-GPU',
-	none: Proxmox.Utils.noneText
-    },
-
-    render_kvm_language: function (value) {
-	if (!value || value === '__default__') {
-	    return Proxmox.Utils.defaultText;
-	}
-	var text = PVE.Utils.kvm_keymaps[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_keymap_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_language('')]];
-	Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_language(value)]);
-	});
-
-	return data;
-    },
-
-    console_map: {
-	'__default__': Proxmox.Utils.defaultText + ' (xterm.js)',
-	'vv': 'SPICE (remote-viewer)',
-	'html5': 'HTML5 (noVNC)',
-	'xtermjs': 'xterm.js'
-    },
-
-    render_console_viewer: function(value) {
-	value = value || '__default__';
-	if (PVE.Utils.console_map[value]) {
-	    return PVE.Utils.console_map[value];
-	}
-	return value;
-    },
-
-    console_viewer_array: function() {
-	return Ext.Array.map(Object.keys(PVE.Utils.console_map), function(v) {
-	    return [v, PVE.Utils.render_console_viewer(v)];
-	});
-    },
-
-    render_kvm_vga_driver: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	}
-	var vga = PVE.Parser.parsePropertyString(value, 'type');
-	var text = PVE.Utils.kvm_vga_drivers[vga.type];
-	if (!vga.type) {
-	    text = Proxmox.Utils.defaultText;
-	}
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_vga_driver_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_vga_driver('')]];
-	Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-	});
-
-	return data;
-    },
-
-    render_kvm_startup: function(value) {
-	var startup = PVE.Parser.parseStartup(value);
-
-	var res = 'order=';
-	if (startup.order === undefined) {
-	    res += 'any';
-	} else {
-	    res += startup.order;
-	}
-	if (startup.up !== undefined) {
-	    res += ',up=' + startup.up;
-	}
-	if (startup.down !== undefined) {
-	    res += ',down=' + startup.down;
-	}
-
-	return res;
-    },
-
-    extractFormActionError: function(action) {
-	var msg;
-	switch (action.failureType) {
-	case Ext.form.action.Action.CLIENT_INVALID:
-	    msg = gettext('Form fields may not be submitted with invalid values');
-	    break;
-	case Ext.form.action.Action.CONNECT_FAILURE:
-	    msg = gettext('Connection error');
-	    var resp = action.response;
-	    if (resp.status && resp.statusText) {
-		msg += " " + resp.status + ": " + resp.statusText;
-	    }
-	    break;
-	case Ext.form.action.Action.LOAD_FAILURE:
-	case Ext.form.action.Action.SERVER_INVALID:
-	    msg = Proxmox.Utils.extractRequestError(action.result, true);
-	    break;
-	}
-	return msg;
-    },
-
-    format_duration_short: function(ut) {
-
-	if (ut < 60) {
-	    return ut.toFixed(1) + 's';
-	}
-
-	if (ut < 3600) {
-	    var mins = ut / 60;
-	    return mins.toFixed(1) + 'm';
-	}
-
-	if (ut < 86400) {
-	    var hours = ut / 3600;
-	    return hours.toFixed(1) + 'h';
-	}
-
-	var days = ut / 86400;
-	return days.toFixed(1) + 'd';
-    },
-
-    contentTypes: {
-	'images': gettext('Disk image'),
-	'backup': gettext('VZDump backup file'),
-	'vztmpl': gettext('Container template'),
-	'iso': gettext('ISO image'),
-	'rootdir': gettext('Container'),
-	'snippets': gettext('Snippets')
-    },
-
-    storageSchema: {
-	dir: {
-	    name: Proxmox.Utils.directoryText,
-	    ipanel: 'DirInputPanel',
-	    faIcon: 'folder'
-	},
-	lvm: {
-	    name: 'LVM',
-	    ipanel: 'LVMInputPanel',
-	    faIcon: 'folder'
-	},
-	lvmthin: {
-	    name: 'LVM-Thin',
-	    ipanel: 'LvmThinInputPanel',
-	    faIcon: 'folder'
-	},
-	nfs: {
-	    name: 'NFS',
-	    ipanel: 'NFSInputPanel',
-	    faIcon: 'building'
-	},
-	cifs: {
-	    name: 'CIFS',
-	    ipanel: 'CIFSInputPanel',
-	    faIcon: 'building'
-	},
-	glusterfs: {
-	    name: 'GlusterFS',
-	    ipanel: 'GlusterFsInputPanel',
-	    faIcon: 'building'
-	},
-	iscsi: {
-	    name: 'iSCSI',
-	    ipanel: 'IScsiInputPanel',
-	    faIcon: 'building'
-	},
-	cephfs: {
-	    name: 'CephFS',
-	    ipanel: 'CephFSInputPanel',
-	    faIcon: 'building'
-	},
-	pvecephfs: {
-	    name: 'CephFS (PVE)',
-	    ipanel: 'CephFSInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	rbd: {
-	    name: 'RBD',
-	    ipanel: 'RBDInputPanel',
-	    faIcon: 'building'
-	},
-	pveceph: {
-	    name: 'RBD (PVE)',
-	    ipanel: 'RBDInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	zfs: {
-	    name: 'ZFS over iSCSI',
-	    ipanel: 'ZFSInputPanel',
-	    faIcon: 'building'
-	},
-	zfspool: {
-	    name: 'ZFS',
-	    ipanel: 'ZFSPoolInputPanel',
-	    faIcon: 'folder'
-	},
-	drbd: {
-	    name: 'DRBD',
-	    hideAdd: true
-	}
-    },
-
-    format_storage_type: function(value, md, record) {
-	if (value === 'rbd') {
-	    value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
-	} else if (value === 'cephfs') {
-	    value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
-	}
-
-	var schema = PVE.Utils.storageSchema[value];
-	if (schema) {
-	    return schema.name;
-	}
-	return Proxmox.Utils.unknownText;
-    },
-
-    format_ha: function(value) {
-	var text = Proxmox.Utils.noneText;
-
-	if (value.managed) {
-	    text = value.state || Proxmox.Utils.noneText;
-
-	    text += ', ' +  Proxmox.Utils.groupText + ': ';
-	    text += value.group || Proxmox.Utils.noneText;
-	}
-
-	return text;
-    },
-
-    format_content_types: function(value) {
-	return value.split(',').sort().map(function(ct) {
-	    return PVE.Utils.contentTypes[ct] || ct;
-	}).join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-	var data = record.data;
-	if (Ext.isNumber(data.channel) &&
-	    Ext.isNumber(data.id) &&
-	    Ext.isNumber(data.lun)) {
-	    return "CH " +
-		Ext.String.leftPad(data.channel,2, '0') +
-		" ID " + data.id + " LUN " + data.lun;
-	}
-	return data.volid.replace(/^.*:(.*\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-	return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	if (!(record.data.uptime && Ext.isNumeric(value))) {
-	    return '';
-	}
-
-	var maxcpu = record.data.maxcpu || 1;
-
-	if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-	    return '';
-	}
-
-	var per = value * 100;
-
-	return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-	/*jslint confusion: true */
-
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value);
-    },
-
-    render_bandwidth: function(value) {
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value) + '/s';
-    },
-
-    render_timestamp_human_readable: function(value) {
-	return Ext.Date.format(new Date(value * 1000), 'l d F Y H:i:s');
-    },
-
-    render_duration: function(value) {
-	if (value === undefined) {
-	    return '-';
-	}
-	return PVE.Utils.format_duration_short(value);
-    },
-
-    calculate_mem_usage: function(data) {
-	if (!Ext.isNumeric(data.mem) ||
-	    data.maxmem === 0 ||
-	    data.uptime < 1) {
-	    return -1;
-	}
-
-	return (data.mem / data.maxmem);
-    },
-
-    render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-	if (value > 1 ) {
-	    // we got no percentage but bytes
-	    var mem = value;
-	    var maxmem = record.data.maxmem;
-	    if (!record.data.uptime ||
-		maxmem === 0 ||
-		!Ext.isNumeric(mem)) {
-		return '';
-	    }
-
-	    return ((mem*100)/maxmem).toFixed(1) + " %";
-	}
-	return (value*100).toFixed(1) + " %";
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var mem = value;
-	var maxmem = record.data.maxmem;
-
-	if (!record.data.uptime) {
-	    return '';
-	}
-
-	if (!(Ext.isNumeric(mem) && maxmem)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    calculate_disk_usage: function(data) {
-
-	if (!Ext.isNumeric(data.disk) ||
-	    data.type === 'qemu' ||
-	    (data.type === 'lxc' && data.uptime === 0) ||
-	    data.maxdisk === 0) {
-	    return -1;
-	}
-
-	return (data.disk / data.maxdisk);
-    },
-
-    render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-
-	return (value * 100).toFixed(1) + " %";
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var disk = value;
-	var maxdisk = record.data.maxdisk;
-	var type = record.data.type;
-
-	if (!Ext.isNumeric(disk) ||
-	    type === 'qemu' ||
-	    maxdisk === 0 ||
-	    (type === 'lxc' && record.data.uptime === 0)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    get_object_icon_class: function(type, record) {
-	var status = '';
-	var objType = type;
-
-	if (type === 'type') {
-	    // for folder view
-	    objType = record.groupbyid;
-	} else if (record.template) {
-	    // templates
-	    objType = 'template';
-	    status = type;
-	} else {
-	    // everything else
-	    status = record.status + ' ha-' + record.hastate;
-	}
-
-	if (record.lock) {
-	    status += ' locked lock-' + record.lock;
-	}
-
-	var defaults = PVE.tree.ResourceTree.typeDefaults[objType];
-	if (defaults && defaults.iconCls) {
-	    var retVal = defaults.iconCls + ' ' + status;
-	    return retVal;
-	}
-
-	return '';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
-	var fa = '<i class="fa-fw x-grid-icon-custom ' + cls  + '"></i> ';
-	return fa + value;
-    },
-
-    render_support_level: function(value, metaData, record) {
-	return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    /* render functions for new status panel */
-
-    render_usage: function(val) {
-	return (val*100).toFixed(2) + '%';
-    },
-
-    render_cpu_usage: function(val, max) {
-	return Ext.String.format(gettext('{0}% of {1}') +
-	    ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
-    },
-
-    render_size_usage: function(val, max) {
-	if (max === 0) {
-	    return gettext('N/A');
-	}
-	return (val*100/max).toFixed(2) + '% '+ '(' +
-	    Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
-    },
-
-    /* this is different for nodes */
-    render_node_cpu_usage: function(value, record) {
-	return PVE.Utils.render_cpu_usage(value, record.cpus);
-    },
-
-    /* this is different for nodes */
-    render_node_size_usage: function(record) {
-	return PVE.Utils.render_size_usage(record.used, record.total);
-    },
-
-    render_optional_url: function(value) {
-	var match;
-	if (value && (match = value.match(/^https?:\/\//)) !== null) {
-	    return '<a target="_blank" href="' + value + '">' + value + '</a>';
-	}
-	return value;
-    },
-
-    render_san: function(value) {
-	var names = [];
-	if (Ext.isArray(value)) {
-	    value.forEach(function(val) {
-		if (!Ext.isNumber(val)) {
-		    names.push(val);
-		}
-	    });
-	    return names.join('<br>');
-	}
-	return value;
-    },
-
-    render_full_name: function(firstname, metaData, record) {
-	var first = firstname || '';
-	var last = record.data.lastname || '';
-	return Ext.htmlEncode(first + " " + last);
-    },
-
-    render_u2f_error: function(error) {
-	var ErrorNames = {
-	    '1': gettext('Other Error'),
-	    '2': gettext('Bad Request'),
-	    '3': gettext('Configuration Unsupported'),
-	    '4': gettext('Device Ineligible'),
-	    '5': gettext('Timeout')
-	};
-	return "U2F Error: "  + ErrorNames[error] || Proxmox.Utils.unknownText;
-    },
-
-    windowHostname: function() {
-	return window.location.hostname.replace(Proxmox.Utils.IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-
-    openDefaultConsoleWindow: function(consoles, vmtype, vmid, nodename, vmname, cmd) {
-	var dv = PVE.Utils.defaultViewer(consoles);
-	PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname, cmd);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname, cmd) {
-	// kvm, lxc, shell, upgrade
-
-	if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-	    throw "missing vmid";
-	}
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (viewer === 'html5') {
-	    PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'xtermjs') {
-	    Proxmox.Utils.openXtermJsViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'vv') {
-	    var url;
-	    var params = { proxy: PVE.Utils.windowHostname() };
-	    if (vmtype === 'kvm') {
-		url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'lxc') {
-		url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'shell') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'upgrade') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.upgrade = 1;
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'cmd') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.cmd = cmd;
-		PVE.Utils.openSpiceViewer(url, params);
-	    }
-	} else {
-	    throw "unknown viewer type";
-	}
-    },
-
-    defaultViewer: function(consoles) {
-
-	var allowSpice, allowXtermjs;
-
-	if (consoles === true) {
-	    allowSpice = true;
-	    allowXtermjs = true;
-	} else if (typeof consoles === 'object') {
-	    allowSpice = consoles.spice;
-	    allowXtermjs = !!consoles.xtermjs;
-	}
-	var dv = PVE.VersionInfo.console || 'xtermjs';
-	if (dv === 'vv' && !allowSpice) {
-	    dv = (allowXtermjs) ? 'xtermjs' : 'html5';
-	} else if (dv === 'xtermjs' && !allowXtermjs) {
-	    dv = (allowSpice) ? 'vv' : 'html5';
-	}
-
-	return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    novnc: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    resize: 'off',
-	    cmd: cmd
-	});
-	var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-	if (nw) {
-	    nw.focus();
-	}
-    },
-
-    openSpiceViewer: function(url, params){
-
-	var downloadWithName = function(uri, name) {
-	    var link = Ext.DomHelper.append(document.body, {
-		tag: 'a',
-		href: uri,
-		css : 'display:none;visibility:hidden;height:0px;'
-	    });
-
-	    // Note: we need to tell android the correct file name extension
-	    // but we do not set 'download' tag for other environments, because
-	    // It can have strange side effects (additional user prompt on firefox)
-	    var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-	    if (andriod) {
-		link.download = name;
-	    }
-
-	    if (link.fireEvent) {
-		link.fireEvent('onclick');
-	    } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-		link.dispatchEvent(evt);
-	    }
-	};
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    params: params,
-	    method: 'POST',
-	    failure: function(response, opts){
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, opts){
-		var raw = "[virt-viewer]\n";
-		Ext.Object.each(response.result.data, function(k, v) {
-		    raw += k + "=" + v + "\n";
-		});
-		var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-		    encodeURIComponent(raw);
-
-		downloadWithName(url, "pve-spice.vv");
-	    }
-	});
-    },
-
-    openTreeConsole: function(tree, record, item, index, e) {
-	e.stopEvent();
-	var nodename = record.data.node;
-	var vmid = record.data.vmid;
-	var vmname = record.data.name;
-	if (record.data.type === 'qemu' && !record.data.template) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    let conf = response.result.data;
-		    var consoles = {
-			spice: !!conf.spice,
-			xtermjs: !!conf.serial,
-		    };
-		    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-		}
-	    });
-	} else if (record.data.type === 'lxc' && !record.data.template) {
-	    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-	}
-    },
-
-    // test automation helper
-    call_menu_handler: function(menu, text) {
-
-	var list = menu.query('menuitem');
-
-	Ext.Array.each(list, function(item) {
-	    if (item.text === text) {
-		if (item.handler) {
-		    item.handler();
-		    return 1;
-		} else {
-		    return undefined;
-		}
-	    }
-	});
-    },
-
-    createCmdMenu: function(v, record, item, index, event) {
-	event.stopEvent();
-	if (!(v instanceof Ext.tree.View)) {
-	    v.select(record);
-	}
-	var menu;
-	var template = !!record.data.template;
-	var type = record.data.type;
-
-	if (template) {
-	    if (type === 'qemu' || type == 'lxc') {
-		menu = Ext.create('PVE.menu.TemplateMenu', {
-		    pveSelNode: record
-		});
-	    }
-	} else if (type === 'qemu' ||
-		   type === 'lxc' ||
-		   type === 'node') {
-	    menu = Ext.create('PVE.' + type + '.CmdMenu', {
-		pveSelNode: record,
-		nodename: record.data.node
-	    });
-	} else {
-	    return;
-	}
-
-	menu.showAt(event.getXY());
-	return menu;
-    },
-
-    // helper for deleting field which are set to there default values
-    delete_if_default: function(values, fieldname, default_val, create) {
-	if (values[fieldname] === '' || values[fieldname] === default_val) {
-	    if (!create) {
-		if (values['delete']) {
-		    values['delete'] += ',' + fieldname;
-		} else {
-		    values['delete'] = fieldname;
-		}
-	    }
-
-	    delete values[fieldname];
-	}
-    },
-
-    loadSSHKeyFromFile: function(file, callback) {
-	// ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-	// a user@host comment, 1420 for 8192 bits; current max is 16kbit
-	// assume: 740*8 for max. 32kbit (5920 byte file)
-	// round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
-	if (file.size > 8192) {
-	    Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
-	    return;
-	}
-	/*global
-	  FileReader
-	*/
-	var reader = new FileReader();
-	reader.onload = function(evt) {
-	    callback(evt.target.result);
-	};
-	reader.readAsText(file);
-    },
-
-    bus_counts: { ide: 4, sata: 6, scsi: 16, virtio: 16 },
-
-    // types is either undefined (all busses), an array of busses, or a single bus
-    forEachBus: function(types, func) {
-	var busses = Object.keys(PVE.Utils.bus_counts);
-	var i, j, count, cont;
-
-	if (Ext.isArray(types)) {
-	    busses = types;
-	} else if (Ext.isDefined(types)) {
-	    busses = [ types ];
-	}
-
-	// check if we only have valid busses
-	for (i = 0; i < busses.length; i++) {
-	    if (!PVE.Utils.bus_counts[busses[i]]) {
-		throw "invalid bus: '" + busses[i] + "'";
-	    }
-	}
-
-	for (i = 0; i < busses.length; i++) {
-	    count = PVE.Utils.bus_counts[busses[i]];
-	    for (j = 0; j < count; j++) {
-		cont = func(busses[i], j);
-		if (!cont && cont !== undefined) {
-		    return;
-		}
-	    }
-	}
-    },
-
-    mp_counts: { mps: 256, unused: 256 },
-
-    forEachMP: function(func, includeUnused) {
-	var i, cont;
-	for (i = 0; i < PVE.Utils.mp_counts.mps; i++) {
-	    cont = func('mp', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-
-	if (!includeUnused) {
-	    return;
-	}
-
-	for (i = 0; i < PVE.Utils.mp_counts.unused; i++) {
-	    cont = func('unused', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-    },
-
-    cleanEmptyObjectKeys: function (obj) {
-	var propName;
-	for (propName in obj) {
-	    if (obj.hasOwnProperty(propName)) {
-		if (obj[propName] === null || obj[propName] === undefined) {
-		    delete obj[propName];
-		}
-	    }
-	}
-    },
-
-    handleStoreErrorOrMask: function(me, store, regex, callback) {
-
-	me.mon(store, 'load', function (proxy, response, success, operation) {
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-	    var msg;
-
-	    if (operation.error.statusText) {
-		if (operation.error.statusText.match(regex)) {
-		    callback(me, operation.error);
-		    return;
-		} else {
-		    msg = operation.error.statusText + ' (' + operation.error.status + ')';
-		}
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    showCephInstallOrMask: function(container, msg, nodename, callback){
-	var regex = new RegExp("not (installed|initialized)", "i");
-	if (msg.match(regex)) {
-	    if (Proxmox.UserName === 'root@pam') {
-		container.el.mask();
-		if (!container.down('pveCephInstallWindow')){
-		    var isInstalled = msg.match(/not initialized/i) ? true : false;
-		    var win = Ext.create('PVE.ceph.Install', {
-			nodename: nodename
-		    });
-		    win.getViewModel().set('isInstalled', isInstalled);
-		    container.add(win);
-		    win.show();
-		    callback(win);
-		}
-	    } else {
-		container.mask(Ext.String.format(gettext('{0} not installed.') +
-		    ' ' + gettext('Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
-	    }
-	    return true;
-	} else {
-	    return false;
-	}
-    }
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-    }
-
-});
-
-// ExtJS related things
-
-Proxmox.Utils.toolkit = 'extjs';
-
-// custom PVE specific VTypes
-Ext.apply(Ext.form.field.VTypes, {
-
-    QemuStartDate: function(v) {
-	return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-    IP64AddressList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == '') {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.IP64_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    IP64AddressListText: gettext('Example') + ': 192.168.1.1,192.168.1.2',
-    IP64AddressListMask: /[A-Fa-f0-9\,\:\.\;\ ]/
-});
-
-Ext.define('PVE.form.field.Display', {
-    override: 'Ext.form.field.Display',
-
-    setSubmitValue: function(value) {
-	// do nothing, this is only to allow generalized  bindings for the:
-	// `me.isCreate ? 'textfield' : 'displayfield'` cases we have.
-    }
-});
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseACME: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-	var errors = false;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; //continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
-		res.domains = match_res[1].split(/[;, ]/);
-	    } else {
-		errors = true;
-		return false;
-	    }
-	});
-
-	if (errors || !res) {
-	    return;
-	}
-
-	return res;
-    },
-
-    parseBoolean: function(value, default_value) {
-	if (!Ext.isDefined(value)) {
-	    return default_value;
-	}
-	value = value.toLowerCase();
-	return value === '1' ||
-	       value === 'on' ||
-	       value === 'yes' ||
-	       value === 'true';
-    },
-
-    parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
-		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	});
-
-	if (error !== undefined) {
-	    console.error(error);
-	    return;
-	}
-
-	return res;
-    },
-
-    printPropertyString: function(data, defaultKey) {
-	var stringparts = [],
-	    gotDefaultKeyVal = false,
-	    defaultKeyVal;
-
-	Ext.Object.each(data, function(key, value) {
-	    if (defaultKey !== undefined && key === defaultKey) {
-		gotDefaultKeyVal = true;
-		defaultKeyVal = value;
-	    } else {
-		stringparts.push(key + '=' + value);
-	    }
-	});
-
-	stringparts = stringparts.sort();
-	if (gotDefaultKeyVal) {
-	    stringparts.unshift(defaultKeyVal);
-	}
-
-	return stringparts.join(',');
-    },
-
-    parseQemuNetwork: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-		res.model = match_res[1].toLowerCase();
-		if (match_res[3]) {
-		    res.macaddr = match_res[3];
-		}
-	    } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-		res.bridge = match_res[1];
-	    } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-		res.rate = match_res[1];
-	    } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-		res.tag = match_res[1];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		res.firewall = match_res[1];
-	    } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-		res.disconnect = match_res[1];
-	    } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-		res.queues = match_res[1];
-	    } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
-		res.trunks = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors || !res.model) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-	var netstr = net.model;
-	if (net.macaddr) {
-	    netstr += "=" + net.macaddr;
-	}
-	if (net.bridge) {
-	    netstr += ",bridge=" + net.bridge;
-	    if (net.tag) {
-		netstr += ",tag=" + net.tag;
-	    }
-	    if (net.firewall) {
-		netstr += ",firewall=" + net.firewall;
-	    }
-	}
-	if (net.rate) {
-	    netstr += ",rate=" + net.rate;
-	}
-	if (net.queues) {
-	    netstr += ",queues=" + net.queues;
-	}
-	if (net.disconnect) {
-	    netstr += ",link_down=" + net.disconnect;
-	}
-	if (net.trunks) {
-	    netstr += ",trunks=" + net.trunks;
-	}
-	return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var match_res = key.match(/^([a-z]+)(\d+)$/);
-	if (!match_res) {
-	    return;
-	}
-	res['interface'] = match_res[1];
-	res.index = match_res[2];
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    if (k === 'cache' && v === 'off') {
-		v = 'none';
-	    }
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-	var drivestr = drive.file;
-
-	Ext.Object.each(drive, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'index' || key === 'interface') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseIPConfig: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
-		res.ip = match_res[1];
-	    } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
-		res.gw = match_res[1];
-	    } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
-		res.ip6 = match_res[1];
-	    } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
-		res.gw6 = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printIPConfig: function(cfg) {
-	var c = "";
-	var str = "";
-	if (cfg.ip) {
-	    str += "ip=" + cfg.ip;
-	    c = ",";
-	}
-	if (cfg.gw) {
-	    str += c + "gw=" + cfg.gw;
-	    c = ",";
-	}
-	if (cfg.ip6) {
-	    str += c + "ip6=" + cfg.ip6;
-	    c = ",";
-	}
-	if (cfg.gw6) {
-	    str += c + "gw6=" + cfg.gw6;
-	    c = ",";
-	}
-	return str;
-    },
-
-    parseOpenVZNetIf: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(';'), function(item) {
-	    if (!item || item.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var data = {};
-	    Ext.Array.each(item.split(','), function(p) {
-		if (!p || p.match(/^\s*$/)) {
-		    return; // continue
-		}
-		var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-		if (!match_res) {
-		    errors = true;
-		    return false; // break
-		}
-		if (match_res[1] === 'bridge'){
-		    var bridgevlanf = match_res[2];
-		    var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-		    if (!bridge_res) {
-			errors = true;
-			return false; // break
-		    }
-		    data.bridge = bridge_res[1];
-		    data.tag = bridge_res[4];
-		    /*jslint confusion: true*/
-		    data.firewall = bridge_res[5] ? 1 : 0;
-		    /*jslint confusion: false*/
-		} else {
-		    data[match_res[1]] = match_res[2];
-		}
-	    });
-
-	    if (errors || !data.ifname) {
-		errors = true;
-		return false; // break
-	    }
-
-	    data.raw = item;
-
-	    res[data.ifname] = data;
-	});
-
-	return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-	var netarray = [];
-
-	Ext.Object.each(netif, function(iface, data) {
-	    var tmparray = [];
-	    Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-		var value = data[key];
-		if (key === 'bridge'){
-		    if(data.tag){
-			value = value + 'v' + data.tag;
-		    }
-		    if (data.firewall){
-			value = value + 'f';
-		    }
-		}
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-
-	    });
-	    netarray.push(tmparray.join(','));
-	});
-
-	return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var data = {};
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
-	    if (match_res) {
-		data[match_res[1]] = match_res[2];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		data.firewall = PVE.Parser.parseBoolean(match_res[1]);
-	    } else {
-		// todo: simply ignore errors ?
-		return; // continue
-	    }
-	});
-
-	return data;
-    },
-
-    printLxcNetwork: function(data) {
-	var tmparray = [];
-	Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-			'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-		var value = data[key];
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-	});
-
-	/*jslint confusion: true*/
-	if (data.rate > 0) {
-	    tmparray.push('rate=' + data.rate);
-	}
-	/*jslint confusion: false*/
-	return tmparray.join(',');
-    },
-
-    parseLxcMountPoint: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(.+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
-	if (m) {
-	    res.storage = m[1];
-	    res.type = 'volume';
-	} else if (res.file.match(/^\/dev\//)) {
-	    res.type = 'device';
-	} else {
-	    res.type = 'bind';
-	}
-
-	return res;
-    },
-
-    printLxcMountPoint: function(mp) {
-	var drivestr = mp.file;
-
-	Ext.Object.each(mp, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'type' || key === 'storage') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseStartup: function(value) {
-	if (value === undefined) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-		res.order = match_res[2];
-	    } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-		res.up = match_res[1];
-	    } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printStartup: function(startup) {
-	var arr = [];
-	if (startup.order !== undefined && startup.order !== '') {
-	    arr.push('order=' + startup.order);
-	}
-	if (startup.up !== undefined && startup.up !== '') {
-	    arr.push('up=' + startup.up);
-	}
-	if (startup.down !== undefined && startup.down !== '') {
-	    arr.push('down=' + startup.down);
-	}
-
-	return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-	var res = value.split(',').reduce(function (accumulator, currentValue) {
-	    var splitted = currentValue.split(new RegExp("=(.+)"));
-	    accumulator[splitted[0]] = splitted[1];
-	    return accumulator;
-	}, {});
-
-	if (PVE.Parser.parseBoolean(res.base64, false)) {
-	    Ext.Object.each(res, function(key, value) {
-		if (key === 'uuid') { return; }
-		res[key] = Ext.util.Base64.decode(value);
-	    });
-	}
-
-	return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-	var datastr = '';
-	var base64 = false;
-	Ext.Object.each(data, function(key, value) {
-	    if (value === '') { return; }
-	    if (key === 'uuid') {
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-	    } else {
-		// values should be base64 encoded from now on, mark config strings correspondingly
-		if (!base64) {
-		    base64 = true;
-		    datastr += (datastr !== '' ? ',' : '') + 'base64=1';
-		}
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
-	    }
-	});
-
-	return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    parseTfaType: function(value) {
-	/*jslint confusion: true*/
-	var match;
-	if (!value || !value.length) {
-	    return undefined;
-	} else if (value === 'x!oath') {
-	    return 'totp';
-	} else if (!!(match = value.match(/^x!(.+)$/))) {
-	    return match[1];
-	} else {
-	    return 1;
-	}
-    },
-
-    parseQemuCpu: function(value) {
-	if (!value) {
-	    return {};
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    if (!p.match(/\=/)) {
-		if (Ext.isDefined(res.cpu)) {
-		    errors = true;
-		    return false; // break
-		}
-		res.cputype = p;
-		return; // continue
-	    }
-
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var k = match_res[1];
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    res[k] = match_res[2];
-	});
-
-	if (errors || !res.cputype) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuCpu: function(cpu) {
-	var cpustr = cpu.cputype;
-	var optstr = '';
-
-	Ext.Object.each(cpu, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'cputype') {
-		return; // continue
-	    }
-	    optstr += ',' + key + '=' + value;
-	});
-
-	if (!cpustr) {
-	    if (optstr) {
-		return 'kvm64' + optstr;
-	    }
-	    return;
-	}
-
-	return cpustr + optstr;
-    },
-
-    parseSSHKey: function(key) {
-	//                |--- options can have quotes--|     type    key        comment
-	var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
-	var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
-
-	var m = key.match(keyre);
-	if (!m) {
-	    return null;
-	}
-	if (m.length < 3 || !m[2]) { // [2] is always either type or key
-	    return null;
-	}
-	if (m[1] && m[1].match(typere)) {
-	    return {
-		type: m[1],
-		key: m[2],
-		comment: m[3]
-	    };
-	}
-	if (m[2].match(typere)) {
-	    return {
-		options: m[1],
-		type: m[2],
-		key: m[3],
-		comment: m[4]
-	    };
-	}
-	return null;
-    }
-}});
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-	var me = this;
-
-	var changes = false;
-	var oldtext = Ext.encode(me.UIState[name]);
-	var newtext = Ext.encode(newvalue);
-	if (newtext != oldtext) {
-	    changes = true;
-	    me.UIState[name] = newvalue;
-	    //console.log("changed old " + name + " " + oldtext);
-	    //console.log("changed new " + name + " " + newtext);
-	    if (fireEvents) {
-		me.fireEvent("statechange", me, name, { value: newvalue });
-	    }
-	}
-	return changes;
-    },
-
-    // private
-    hslist: [
-	// order is important for notifications
-	// [ name, default ]
-	['view', 'server'],
-	['rid', 'root'],
-	['ltab', 'tasks'],
-	['nodetab', ''],
-	['storagetab', ''],
-	['pooltab', ''],
-	['kvmtab', ''],
-	['lxctab', ''],
-	['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-	cloudinit: 52,
-	replication: 51,
-	system: 50,
-	monitor: 49,
-	'ha-fencing': 48,
-	'ha-groups': 47,
-	'ha-resources': 46,
-	'ceph-log': 45,
-	'ceph-crushmap':44,
-	'ceph-pools': 43,
-	'ceph-osdtree': 42,
-	'ceph-disklist': 41,
-	'ceph-monlist': 40,
-	'ceph-config': 39,
-	ceph: 38,
-	'firewall-fwlog': 37,
-	'firewall-options': 36,
-	'firewall-ipset': 35,
-	'firewall-aliases': 34,
-	'firewall-sg': 33,
-	firewall: 32,
-	apt: 31,
-	members: 30,
-	snapshot: 29,
-	ha: 28,
-	support: 27,
-	pools: 26,
-	syslog: 25,
-	ubc: 24,
-	initlog: 23,
-	openvz: 22,
-	backup: 21,
-	resources: 20,
-	content: 19,
-	root: 18,
-	domains: 17,
-	roles: 16,
-	groups: 15,
-	users: 14,
-	time: 13,
-	dns: 12,
-	network: 11,
-	services: 10,
-	options: 9,
-	console: 8,
-	hardware: 7,
-	permissions: 6,
-	summary: 5,
-	tasks: 4,
-	clog: 3,
-	storage: 2,
-	folder: 1,
-	server: 0
-    },
-
-    decodeHToken: function(token) {
-	var me = this;
-
-	var state = {};
-	if (!token) {
-	    Ext.Array.each(me.hslist, function(rec) {
-		state[rec[0]] = rec[1];
-	    });
-	    return state;
-	}
-
-	// return Ext.urlDecode(token);
-
-	var items = token.split(':');
-	var prefix = items.shift();
-
-	if (prefix != me.hprefix) {
-	    return me.decodeHToken();
-	}
-
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = items.shift();
-	    if (value) {
-		if (value[0] === '=') {
-		    value = decodeURIComponent(value.slice(1));
-		} else {
-		    Ext.Object.each(me.compDict, function(key, cv) {
-			if (value == cv) {
-			    value = key;
-			    return false;
-			}
-		    });
-		}
-	    }
-	    state[rec[0]] = value;
-	});
-
-	return state;
-    },
-
-    encodeHToken: function(state) {
-	var me = this;
-
-	// return Ext.urlEncode(state);
-
-	var ctoken = me.hprefix;
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = state[rec[0]];
-	    if (!Ext.isDefined(value)) {
-		value = rec[1];
-	    }
-	    value = encodeURIComponent(value);
-	    if (!value) {
-		ctoken += ':';
-	    } else {
-		var comp = me.compDict[value];
-		if (Ext.isDefined(comp)) {
-		    ctoken += ":" + comp;
-		} else {
-		    ctoken += ":=" + value;
-		}
-	    }
-	});
-
-	return ctoken;
-    },
-
-    constructor: function(config){
-	var me = this;
-
-	me.callParent([config]);
-
-	me.UIState = me.decodeHToken(); // set default
-
-	var history_change_cb = function(token) {
-	    //console.log("HC " + token);
-	    if (!token) {
-		var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-		if (res){
-		    // process text value and close...
-		    Ext.History.back();
-		} else {
-		    Ext.History.forward();
-		}
-		return;
-	    }
-
-	    var newstate = me.decodeHToken(token);
-	    Ext.Array.each(me.hslist, function(rec) {
-		if (typeof newstate[rec[0]] == "undefined") {
-		    return;
-		}
-		me.setHV(rec[0], newstate[rec[0]], true);
-	    });
-	};
-
-	var start_token = Ext.History.getToken();
-	if (start_token) {
-	    history_change_cb(start_token);
-	} else {
-	    var htext = me.encodeHToken(me.UIState);
-	    Ext.History.add(htext);
-	}
-
-	Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-	/*jslint confusion: true */
-	var me = this;
-	var data;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    data = { value: me.UIState[name] };
-	} else {
-	    data = me.callParent(arguments);
-	    if (!data && name === 'GuiCap') {
-		data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-	    }
-	}
-
-	//console.log("GET " + name + " " + Ext.encode(data));
-	return data;
-    },
-
-    clear: function(name){
-	var me = this;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    me.UIState[name] = null;
-	}
-
-	me.callParent(arguments);
-    },
-
-    set: function(name, value, fireevent){
-        var me = this;
-
-	//console.log("SET " + name + " " + Ext.encode(value));
-	if (typeof me.UIState[name] != "undefined") {
-	    var newvalue = value ? value.value : null;
-	    if (me.setHV(name, newvalue, fireevent)) {
-		var htext = me.encodeHToken(me.UIState);
-		Ext.History.add(htext);
-	    }
-	} else {
-	    me.callParent(arguments);
-	}
-    }
-});
-Ext.define('PVE.menu.Item', {
-    extend: 'Ext.menu.Item',
-    alias: 'widget.pveMenuItem',
-
-    // set to wrap the handler callback in a confirm dialog  showing this text
-    confirmMsg: false,
-
-    // set to focus 'No' instead of 'Yes' button and show a warning symbol
-    dangerous: false,
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.handler) {
-	    me.setHandler(me.handler, me.scope);
-	}
-
-	me.callParent();
-    },
-
-    setHandler: function(fn, scope) {
-	var me = this;
-	me.scope = scope;
-	me.handler = function(button, e) {
-	    var rec, msg;
-	    if (me.confirmMsg) {
-		msg = me.confirmMsg;
-		Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: msg,
-		    buttons: Ext.Msg.YESNO,
-		    defaultFocus: me.dangerous ? 'no' : 'yes',
-		    callback: function(btn) {
-			if (btn === 'yes') {
-			    Ext.callback(fn, me.scope, [me, e], 0, me);
-			}
-		    }
-		});
-	    } else {
-		Ext.callback(fn, me.scope, [me, e], 0, me);
-	    }
-	};
-    }
-});
-Ext.define('PVE.menu.TemplateMenu', {
-    extend: 'Ext.menu.Menu',
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var guestType = me.pveSelNode.data.type;
-	if (guestType !== 'qemu' && guestType != 'lxc') {
-	    throw "invalid guest type";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var template = me.pveSelNode.data.template;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	me.title = (guestType === 'qemu' ? 'VM ' : 'CT ') + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: guestType,
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: template
-		    });
-		    win.show();
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade', 'cmd'
-
-    cmd: undefined,
-
-    consoleName: undefined,
-
-    iconCls: 'fa fa-terminal',
-
-    enableSpice: true,
-    enableXtermjs: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    text: gettext('Console'),
-
-    setEnableSpice: function(enable){
-	var me = this;
-
-	me.enableSpice = enable;
-	me.down('#spicemenu').setDisabled(!enable);
-    },
-
-    setEnableXtermJS: function(enable){
-	var me = this;
-
-	me.enableXtermjs = enable;
-	me.down('#xtermjs').setDisabled(!enable);
-    },
-
-    handler: function() {
-	var me = this;
-	var consoles = {
-	    spice: me.enableSpice,
-	    xtermjs: me.enableXtermjs
-	};
-	PVE.Utils.openDefaultConsoleWindow(consoles, me.consoleType, me.vmid,
-					   me.nodename, me.consoleName, me.cmd);
-    },
-
-    menu: [
-	{
-	    xtype:'menuitem',
-	    text: 'noVNC',
-	    iconCls: 'pve-itype-icon-novnc',
-	    type: 'html5',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    xterm: 'menuitem',
-	    itemId: 'spicemenu',
-	    text: 'SPICE',
-	    type: 'vv',
-	    iconCls: 'pve-itype-icon-virt-viewer',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    text: 'xterm.js',
-	    itemId: 'xtermjs',
-	    iconCls: 'pve-itype-icon-xtermjs',
-	    type: 'xtermjs',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- *
- *   does this for the button and every menu item
- */
-Ext.define('PVE.button.Split', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveSplitButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    handlerWrapper: function(button, event) {
-	var me = this;
-	var rec, msg;
-	if (me.selModel) {
-	    rec = me.selModel.getSelection()[0];
-	    if (!rec || (me.enableFn(rec) === false)) {
-		return;
-	    }
-	}
-
-	if (me.confirmMsg) {
-	    msg = me.confirmMsg;
-	    // confirMsg can be boolean or function
-	    /*jslint confusion: true*/
-	    if (Ext.isFunction(me.confirmMsg)) {
-		msg = me.confirmMsg(rec);
-	    }
-	    /*jslint confusion: false*/
-	    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-	    Ext.Msg.show({
-		title: gettext('Confirm'),
-		icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		msg: msg,
-		buttons: Ext.Msg.YESNO,
-		callback: function(btn) {
-		    if (btn !== 'yes') {
-			return;
-		    }
-		    me.realHandler(button, event, rec);
-		}
-	    });
-	} else {
-	    me.realHandler(button, event, rec);
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-	    me.realHandler = me.handler;
-	    me.handler = me.handlerWrapper;
-	}
-
-	if (me.menu && me.menu.items) {
-	    me.menu.items.forEach(function(item) {
-		if (item.handler) {
-		    item.realHandler = item.handler;
-		    item.handler = me.handlerWrapper;
-		}
-
-		if (item.selModel) {
-		    me.mon(item.selModel, "selectionchange", function() {
-			var rec = item.selModel.getSelection()[0];
-			if (!rec || (item.enableFn(rec) === false )) {
-			    item.setDisabled(true);
-			} else {
-			    item.setDisabled(false);
-			}
-		    });
-		}
-	    });
-	}
-
-	me.callParent();
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.controller.StorageEdit', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.storageEdit',
-    control: {
-	'field[name=content]': {
-	    change: function(field, value) {
-		var hasBackups = Ext.Array.contains(value, 'backup');
-		var maxfiles = this.lookupReference('maxfiles');
-		if (!maxfiles) {
-		    return;
-		}
-
-		if (!hasBackups) {
-		// clear values which will never be submitted
-		    maxfiles.reset();
-		}
-		maxfiles.setDisabled(!hasBackups);
-	    }
-	}
-    }
-});
-Ext.define('PVE.qemu.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'suspended':
-		stopped = false;
-		suspended = true;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = "VM " + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: running || suspended,
-		disabled: running || suspended,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-	    {
-		text: gettext('Pause'),
-		iconCls: 'fa fa-fw fa-pause',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmpause', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Hibernate'),
-		iconCls: 'fa fa-fw fa-download',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		tooltip: gettext('Suspend to disk'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmsuspend', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend', { todisk: 1 });
-		    });
-		}
-	    },
-	    {
-		text: gettext('Resume'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: !suspended,
-		handler: function() {
-		    vm_command('resume');
-		}
-	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'qemu',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'qemu');
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		hidden: !caps.vms['VM.Allocate'],
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmtemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			     url: '/nodes/' + nodename + '/qemu/' + vmid + '/template',
-			     method: 'POST',
-			     failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			     }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    Proxmox.Utils.API2Request({
-			url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-			failure: function(response, opts) {
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, opts) {
-			    var allowSpice = response.result.data.spice;
-			    var allowXtermjs = response.result.data.serial;
-			    var consoles = {
-				spice: allowSpice,
-				xtermjs: allowXtermjs
-			    };
-			    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-			}
-		    });
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no CT ID specified";
-	}
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/lxc/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = 'CT ' + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		disabled: running,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-//	    {
-//		text: gettext('Suspend'),
-//		iconCls: 'fa fa-fw fa-pause',
-//		hidde: suspended,
-//		disabled: stopped || suspended,
-//		handler: function() {
-//		    var msg = Proxmox.Utils.format_task_description('vzsuspend', vmid);
-//		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-//			if (btn !== 'yes') {
-//			    return;
-//			}
-//
-//			vm_command('suspend');
-//		    });
-//		}
-//	    },
-//	    {
-//		text: gettext('Resume'),
-//		iconCls: 'fa fa-fw fa-play',
-//		hidden: !suspended,
-//		handler: function() {
-//		    vm_command('resume');
-//		}
-//	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: standalone || !caps.vms['VM.Migrate']
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'lxc');
-		}
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'lxc',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vztemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/lxc/' + vmid + '/template',
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-    xtype: 'nodeCmdMenu',
-
-    showSeparator: false,
-
-    items: [
-	{
-	    text: gettext('Create VM'),
-	    itemId: 'createvm',
-	    iconCls: 'fa fa-desktop',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{
-	    text: gettext('Create CT'),
-	    itemId: 'createct',
-	    iconCls: 'fa fa-cube',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Bulk Start'),
-	    itemId: 'bulkstart',
-	    iconCls: 'fa fa-fw fa-play',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Start'),
-		    btnText: gettext('Start'),
-		    action: 'startall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Stop'),
-	    itemId: 'bulkstop',
-	    iconCls: 'fa fa-fw fa-stop',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Stop'),
-		    btnText: gettext('Stop'),
-		    action: 'stopall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Migrate'),
-	    itemId: 'bulkmigrate',
-	    iconCls: 'fa fa-fw fa-send-o',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Migrate'),
-		    btnText: gettext('Migrate'),
-		    action: 'migrateall'
-		});
-		win.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Shell'),
-	    itemId: 'shell',
-	    iconCls: 'fa fa-fw fa-terminal',
-	    handler: function() {
-		var me = this.up('menu');
-		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, me.nodename, undefined);
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Wake-on-LAN'),
-	    itemId: 'wakeonlan',
-	    iconCls: 'fa fa-fw fa-power-off',
-	    handler: function() {
-		var me = this.up('menu');
-		Proxmox.Utils.API2Request({
-		    param: {},
-		    url: '/nodes/' + me.nodename + '/wakeonlan',
-		    method: 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, opts) {
-			Ext.Msg.show({
-			    title: 'Success',
-			    icon: Ext.Msg.INFO,
-			    msg: Ext.String.format(gettext("Wake on LAN packet send for '{0}': '{1}'"), me.nodename, response.result.data)
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no nodename specified';
-	}
-
-	me.title = gettext('Node') + " '" + me.nodename + "'";
-	me.callParent();
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	// disable not allowed options
-	if (!caps.vms['VM.Allocate']) {
-	    me.getComponent('createct').setDisabled(true);
-	    me.getComponent('createvm').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.PowerMgmt']) {
-	    me.getComponent('bulkstart').setDisabled(true);
-	    me.getComponent('bulkstop').setDisabled(true);
-	    me.getComponent('bulkmigrate').setDisabled(true);
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.Console']) {
-	    me.getComponent('shell').setDisabled(true);
-	}
-
-	if (me.pveSelNode.data.running) {
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-    }
-});
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-
-    vmid: undefined,
-
-    cmd: undefined,
-
-    consoleType: undefined, // lxc, kvm, shell, cmd
-
-    layout: 'fit',
-
-    xtermjs: false,
-
-    border: false,
-
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.consoleType) {
-	    throw "no console type specified";
-	}
-
-	if (!me.vmid && me.consoleType !== 'shell' && me.consoleType !== 'cmd') {
-	    throw "no VM ID specified";
-	}
-
-	// always use same iframe, to avoid running several noVnc clients
-	// at same time (to avoid performance problems)
-	var box = Ext.create('Ext.ux.IFrame', { itemid : "vncconsole" });
-
-	var type = me.xtermjs ? 'xtermjs' : 'novnc';
-	Ext.apply(me, {
-	    items: box,
-	    listeners: {
-		activate: function() {
-		    var queryDict = {
-			console: me.consoleType, // kvm, lxc, upgrade or shell
-			vmid: me.vmid,
-			node: me.nodename,
-			cmd: me.cmd,
-			resize: 'scale'
-		    };
-		    queryDict[type] = 1;
-		    PVE.Utils.cleanEmptyObjectKeys(queryDict);
-		    var url = '/?' + Ext.Object.toQueryString(queryDict);
-		    box.load(url);
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.on('afterrender', function() {
-	    me.focus();
-	});
-    }
-});
-
-Ext.define('PVE.data.PermPathStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.pvePermPath',
-    fields: [ 'value' ],
-    autoLoad: false,
-    data: [
-	{'value':  '/'},
-	{'value':  '/access'},
-	{'value': '/nodes'},
-	{'value': '/pool'},
-	{'value': '/storage'},
-	{'value': '/vms'}
-    ],
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	me.callParent([config]);
-
-	me.suspendEvents();
-	PVE.data.ResourceStore.each(function(record) {
-	    switch (record.get('type')) {
-		case 'node':
-		    me.add({value: '/nodes/' + record.get('text')});
-		    break;
-
-		case 'qemu':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'lxc':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'storage':
-		    me.add({value: '/storage/' + record.get('storage')});
-		    break;
-		case 'pool':
-		    me.add({value: '/pool/' + record.get('pool')});
-		    break;
-	    }
-	});
-	me.resumeEvents();
-
-	me.fireEvent('refresh', me);
-	me.fireEvent('datachanged', me);
-
-	me.sort({
-	    property: 'value',
-	    direction: 'ASC'
-	});
-    }
-});
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-	var me = this, i;
-
-	return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-
-    // returns the cached data from all nodes
-    getNodes: function() {
-	var me = this;
-
-	var nodes = [];
-	me.each(function(record) {
-	    if (record.get('type') == "node") {
-		nodes.push( record.getData() );
-	    }
-	});
-
-	return nodes;
-    },
-
-    storageIsShared: function(storage_path) {
-	var me = this;
-
-	var index = me.findExact('id', storage_path);
-
-	return me.getAt(index).data.shared;
-    },
-
-    guestNode: function(vmid) {
-	var me = this;
-
-	var index = me.findExact('vmid', parseInt(vmid, 10));
-
-	return me.getAt(index).data.node;
-    },
-
-    constructor: function(config) {
-	// fixme: how to avoid those warnings
-	/*jslint confusion: true */
-
-	var me = this;
-
-	config = config || {};
-
-	var field_defaults = {
-	    type: {
-		header: gettext('Type'),
-		type: 'string',
-		renderer: PVE.Utils.render_resource_type,
-		sortable: true,
-		hideable: false,
-		width: 100
-	    },
-	    id: {
-		header: 'ID',
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    running: {
-		header: gettext('Online'),
-		type: 'boolean',
-		renderer: Proxmox.Utils.format_boolean,
-		hidden: true,
-		convert: function(value, record) {
-		    var info = record.data;
-		    return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-		}
-	    },
-	    text: {
-		header: gettext('Description'),
-		type: 'string',
-		sortable: true,
-		width: 200,
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-
-		    if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
-			text = String(info.vmid);
-			if (info.name) {
-			    text += " (" + info.name + ')';
-			}
-		    } else { // node, pool, storage
-			text = info[info.type] || info.id;
-			if (info.node && info.type !== 'node') {
-			    text += " (" + info.node + ")";
-			}
-		    }
-
-		    return text;
-		}
-	    },
-	    vmid: {
-		header: 'VMID',
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    name: {
-		header: gettext('Name'),
-		hidden: true,
-		sortable: true,
-		type: 'string'
-	    },
-	    disk: {
-		header: gettext('Disk usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_disk_usage,
-		sortable: true,
-		width: 100,
-		hidden: true
-	    },
-	    diskuse: {
-		header: gettext('Disk usage') + " %",
-		type: 'number',
-		sortable: true,
-		renderer: PVE.Utils.render_disk_usage_percent,
-		width: 100,
-		calculate: PVE.Utils.calculate_disk_usage,
-		sortType: 'asFloat'
-	    },
-	    maxdisk: {
-		header: gettext('Disk size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    mem: {
-		header: gettext('Memory usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_mem_usage,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    memuse: {
-		header: gettext('Memory usage') + " %",
-		type: 'number',
-		renderer: PVE.Utils.render_mem_usage_percent,
-		calculate: PVE.Utils.calculate_mem_usage,
-		sortType: 'asFloat',
-		sortable: true,
-		width: 100
-	    },
-	    maxmem: {
-		header: gettext('Memory size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		hidden: true,
-		sortable: true,
-		width: 100
-	    },
-	    cpu: {
-		header: gettext('CPU usage'),
-		type: 'float',
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100
-	    },
-	    maxcpu: {
-		header: gettext('maxcpu'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    diskread: {
-		header: gettext('Total Disk Read'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    diskwrite: {
-		header: gettext('Total Disk Write'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netin: {
-		header: gettext('Total NetIn'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netout: {
-		header: gettext('Total NetOut'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    template: {
-		header: gettext('Template'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    uptime: {
-		header: gettext('Uptime'),
-		type: 'integer',
-		renderer: Proxmox.Utils.render_uptime,
-		sortable: true,
-		width: 110
-	    },
-	    node: {
-		header: gettext('Node'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    storage: {
-		header: gettext('Storage'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    pool: {
-		header: gettext('Pool'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    hastate: {
-		header: gettext('HA State'),
-		type: 'string',
-		defaultValue: 'unmanaged',
-		hidden: true,
-		sortable: true
-	    },
-	    status: {
-		header: gettext('Status'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    lock: {
-		header: gettext('Lock'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    }
-	};
-
-	var fields = [];
-	var fieldNames = [];
-	Ext.Object.each(field_defaults, function(key, value) {
-	    var field = {name: key, type: value.type};
-	    if (Ext.isDefined(value.convert)) {
-		field.convert = value.convert;
-	    }
-
-	    if (Ext.isDefined(value.calculate)) {
-		field.calculate = value.calculate;
-	    }
-
-	    if (Ext.isDefined(value.defaultValue)) {
-		field.defaultValue = value.defaultValue;
-	    }
-
-	    fields.push(field);
-	    fieldNames.push(key);
-	});
-
-	Ext.define('PVEResources', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/resources'
-	    }
-	});
-
-	Ext.define('PVETree', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: { type: 'memory' }
-	});
-
-	Ext.apply(config, {
-	    storeid: 'PVEResources',
-	    model: 'PVEResources',
-	    defaultColumns: function() {
-		var res = [];
-		Ext.Object.each(field_defaults, function(field, info) {
-		    var fi = Ext.apply({ dataIndex: field }, info);
-		    res.push(fi);
-		});
-		return res;
-	    },
-	    fieldNames: fieldNames
-	});
-
-	me.callParent([config]);
-    }
-});
-Ext.define('pve-domains', {
-    extend: "Ext.data.Model",
-    fields: [
-	'realm', 'type', 'comment', 'default', 'tfa',
-	{
-	    name: 'descr',
-	    // Note: We use this in the RealmComboBox.js (see Bug #125)
-	    convert: function(value, record) {
-		if (value) {
-		    return value;
-		}
-
-		var info = record.data;
-		// return realm if there is no comment
-		var text = info.comment || info.realm;
-
-		if (info.tfa) {
-		    text += " (+ " + info.tfa + ")";
-		}
-
-		return Ext.String.htmlEncode(text);
-	    }
-	}
-    ],
-    idProperty: 'realm',
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/domains"
-    }
-});
-Ext.define('pve-rrd-node', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	{
-	    name:'iowait',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'loadavg',
-	'maxcpu',
-	'memtotal',
-	'memused',
-	'netin',
-	'netout',
-	'roottotal',
-	'rootused',
-	'swaptotal',
-	'swapused',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-guest', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'maxcpu',
-	'netin',
-	'netout',
-	'mem',
-	'maxmem',
-	'disk',
-	'maxdisk',
-	'diskread',
-	'diskwrite',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-storage', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'used',
-	'total',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    minValue: 1,
-	    maxValue: 4094
-	});
-
-	me.callParent();
-    }
-});
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-    comboItems: [
-	['__default__', gettext('Default')],
-	[1, gettext('Yes')],
-	[0, gettext('No')]
-    ]
-});
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['0', Proxmox.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-    valueField: 'poolid',
-    displayField: 'poolid',
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: 'poolid'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    autoSelect: false,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Pool'),
-			sortable: true,
-			dataIndex: 'poolid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-	extend: 'Ext.data.Model',
-	fields: [ 'poolid', 'comment' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/pools"
-	},
-	idProperty: 'poolid'
-    });
-
-});
-Ext.define('PVE.form.PrivilegesSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'pvePrivilegesSelector',
-
-    multiSelect: true,
-
-    initComponent: function() {
-	var me = this;
-
-	// So me.store is available.
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/roles/Administrator',
-	    method: 'GET',
-	    success: function(response, options) {
-		var data = [], key;
-		/*jslint forin: true */
-		for (key in response.result.data) {
-		    data.push([key, key]);
-		}
-		/*jslint forin: false */
-
-		me.store.setData(data);
-
-		me.store.sort({
-		    property: 'key',
-		    direction: 'ASC'
-		});
-	    },
-
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-Ext.define('pve-groups', {
-    extend: 'Ext.data.Model',
-    fields: [ 'groupid', 'comment' ],
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/groups"
-    },
-    idProperty: 'groupid'
-});
-
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveGroupSelector',
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'groupid',
-    displayField: 'groupid',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		sortable: true,
-		dataIndex: 'groupid',
-		flex: 1
-	    },
-	    {
-		header: gettext('Comment'),
-		sortable: false,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: [{
-		property: 'groupid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-Ext.define('PVE.form.UserSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'userid',
-    displayField: 'userid',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-users',
-	    sorters: [{
-		property: 'userid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('User'),
-			sortable: true,
-			dataIndex: 'userid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Name'),
-			sortable: true,
-			renderer: PVE.Utils.render_full_name,
-			dataIndex: 'firstname',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'userid', 'firstname', 'lastname' , 'email', 'comment',
-	    { type: 'boolean', name: 'enable' },
-	    { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/users"
-	},
-	idProperty: 'userid'
-    });
-
-});
-
-
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'roleid',
-    displayField: 'roleid',
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: [{
-		property: 'roleid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Role'),
-			sortable: true,
-			dataIndex: 'roleid',
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-	extend: 'Ext.data.Model',
-	fields: [ 'roleid', 'privs' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/roles"
-	},
-	idProperty: 'roleid'
-    });
-
-});
-Ext.define('PVE.form.GuestIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveGuestIDSelector',
-
-    allowBlank: false,
-
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeID: false,
-
-    guestType: undefined,
-
-    validator: function(value) {
-	var me = this;
-
-	if (!Ext.isNumeric(value) ||
-	    value < me.minValue ||
-	    value > me.maxValue) {
-	    // check is done by ExtJS
-	    return true;
-	}
-
-	if (me.validateExists === true && !me.exists) {
-	    return me.unknownID;
-	}
-
-	if (me.validateExists === false && me.exists) {
-	    return me.inUseID;
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var label = '{0} ID';
-	var unknownID = gettext('This {0} ID does not exists');
-	var inUseID = gettext('This {0} ID is already in use');
-	var type = 'CT/VM';
-
-	if (me.guestType === 'lxc') {
-	    type = 'CT';
-	} else if (me.guestType === 'qemu') {
-	    type = 'VM';
-	}
-
-	me.label = Ext.String.format(label, type);
-	me.unknownID = Ext.String.format(unknownID, type);
-	me.inUseID = Ext.String.format(inUseID, type);
-
-	Ext.apply(me, {
-	    fieldLabel: me.label,
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    if (!Ext.isDefined(me.validateExists)) {
-			return;
-		    }
-		    Proxmox.Utils.API2Request({
-			params: { vmid: newValue },
-			url: '/cluster/nextid',
-			method: 'GET',
-			success: function(response, opts) {
-			    me.exists = false;
-			    me.validate();
-			},
-			failure: function(response, opts) {
-			    me.exists = true;
-			    me.validate();
-			}
-		    });
-		}
-	    }
-	});
-
-        me.callParent();
-
-	if (me.loadNextFreeID) {
-	    Proxmox.Utils.API2Request({
-		url: '/cluster/nextid',
-		method: 'GET',
-		success: function(response, opts) {
-		    me.setRawValue(response.result.data);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    allowDecimals: false,
-
-    allowExponential: false,
-
-    computeUpDown: function(value) {
-	var me = this;
-
-	if (!me.hotplug) {
-	    return { up: value + me.step, down: value - me.step };
-	}
-	
-	var dimm_size = 512;
-	var prev_dimm_size = 0;
-	var min_size = 1024;
-	var current_size = min_size;
-	var value_up = min_size;
-	var value_down = min_size;
-	var value_start = min_size;
-
-	var i, j;
-	for (j = 0; j < 9; j++) {
-	    for (i = 0; i < 32; i++) {
-		if ((value >= current_size) && (value < (current_size + dimm_size))) {
-		    value_start = current_size;
-		    value_up = current_size + dimm_size;
-		    value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-		}
-		current_size += dimm_size;				
-	    }
-	    prev_dimm_size = dimm_size;
-	    dimm_size = dimm_size*2;
-	}
-
-	return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-	}
-    },
-
-    onSpinDown: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.hotplug) {
-	    me.minValue = 1024;
-
-	    me.on('blur', function(field) {
-		var value = me.getValue();
-		var res = me.computeUpDown(value);
-		if (value === res.start || value === res.up || value === res.down) {
-		    return;
-		}
-		field.setValue(res.up);
-	    });
-	}
-
-        me.callParent();
-    }
-});
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveNetworkCardSelector',
-    comboItems: [
-	['e1000', 'Intel E1000'],
-	['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-	['rtl8139', 'Realtek RTL8139'],
-	['vmxnet3', 'VMware vmxnet3']
-    ]
-});
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveDiskFormatSelector',
-    comboItems:  [
-	['raw', gettext('Raw disk image') + ' (raw)'],
-	['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-	['vmdk', gettext('VMware image format') + ' (vmdk)']
-    ]
-});
-Ext.define('PVE.form.DiskSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveDiskSelector',
-
-    // can be
-    // undefined: all
-    // unused: only unused
-    // journal_disk: all disks with gpt
-    diskType: undefined,
-
-    valueField: 'devpath',
-    displayField: 'devpath',
-    emptyText: gettext('No Disks unused'),
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Device'),
-		flex: 3,
-		sortable: true,
-		dataIndex: 'devpath'
-	    },
-	    {
-		header: gettext('Size'),
-		flex: 2,
-		sortable: false,
-		renderer: Proxmox.Utils.format_size,
-		dataIndex: 'size'
-	    },
-	    {
-		header: gettext('Serial'),
-		flex: 5,
-		sortable: true,
-		dataIndex: 'serial'
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    filterOnLoad: true,
-	    model: 'pve-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list",
-		extraParams: { type: me.diskType }
-	    },
-	    sorters: [
-		{
-		    property : 'devpath',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-}, function() {
-
-    Ext.define('pve-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial'],
-	idProperty: 'devpath'
-    });
-});
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveBusSelector',
-  
-    noVirtIO: false,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [['ide', 'IDE'], ['sata', 'SATA']];
-
-	if (!me.noVirtIO) {
-	    me.comboItems.push(['virtio', 'VirtIO Block']);
-	}
-
-	me.comboItems.push(['scsi', 'SCSI']);
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveControllerSelector',
-   
-    statics: {
-	maxIds: {
-	    ide: 3,
-	    sata: 5,
-	    virtio: 15,
-	    scsi: 13
-	}
-    },
-
-    noVirtIO: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    sortByPreviousUsage: function(vmconfig, controllerList) {
-
-	var usedControllers = Ext.clone(PVE.form.ControllerSelector.maxIds);
-
-	var type;
-	for (type in usedControllers) {
-	    if(usedControllers.hasOwnProperty(type)) {
-		usedControllers[type] = 0;
-	    }
-	}
-
-	var property;
-	for (property in vmconfig) {
-	    if (vmconfig.hasOwnProperty(property)) {
-		if (property.match(PVE.Utils.bus_match) && !vmconfig[property].match(/media=cdrom/)) {
-		    var foundController = property.match(PVE.Utils.bus_match)[1];
-		    usedControllers[foundController]++;
-		}
-	    }
-	}
-
-	var vmDefaults = PVE.qemu.OSDefaults[vmconfig.ostype];
-
-	var sortPriority = vmDefaults && vmDefaults.busPriority
-	    ? vmDefaults.busPriority : PVE.qemu.OSDefaults.generic;
-
-	var sortedList = Ext.clone(controllerList);
-	sortedList.sort(function(a,b) {
-	    if (usedControllers[b] == usedControllers[a]) {
-		return sortPriority[b] - sortPriority[a];
-	    }
-	    return usedControllers[b] - usedControllers[a];
-	});
-	
-	return sortedList;
-    },
-
-    setVMConfig: function(vmconfig, autoSelect) {
-	var me = this;
-
-	me.vmconfig = Ext.apply({}, vmconfig);
-
-	var clist = ['ide', 'virtio', 'scsi', 'sata'];
-	var bussel = me.down('field[name=controller]');
-	var deviceid = me.down('field[name=deviceid]');
-
-	if (autoSelect === 'cdrom') {
-	    clist = ['ide', 'scsi', 'sata'];
-	    if (!Ext.isDefined(me.vmconfig.ide2)) {
-		bussel.setValue('ide');
-		deviceid.setValue(2);
-		return;
-	    }
-	} else  {
-	    // in most cases we want to add a disk to the same controller
-	    // we previously used
-	    clist = me.sortByPreviousUsage(me.vmconfig, clist);
-	}
-
-	Ext.Array.each(clist, function(controller) {
-	    var confid, i;
-	    bussel.setValue(controller);
-	    for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) {
-		confid = controller + i.toString();
-		if (!Ext.isDefined(me.vmconfig[confid])) {
-		    deviceid.setValue(i);
-		    return false; // break
-		}
-	    }
-	});
-	deviceid.validate();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    fieldLabel: gettext('Bus/Device'),
-	    layout: 'hbox',
-	    defaults: {
-                hideLabel: true
-	    },
-	    items: [
-		{
-		    xtype: 'pveBusSelector',
-		    name: 'controller',
-		    value: PVE.qemu.OSDefaults.generic.busType,
-		    noVirtIO: me.noVirtIO,
-		    allowBlank: false,
-		    flex: 2,
-		    listeners: {
-			change: function(t, value) {
-			    if (!value) {
-				return;
-			    }
-			    var field = me.down('field[name=deviceid]');
-			    field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]);
-			    field.validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'deviceid',
-		    minValue: 0,
-		    maxValue: PVE.form.ControllerSelector.maxIds.ide,
-		    value: '0',
-		    flex: 1,
-		    allowBlank: false,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.rendered) {
-			    return;
-			}
-			var field = me.down('field[name=controller]');
-			var controller = field.getValue();
-			var confid = controller + value;
-			if (Ext.isDefined(me.vmconfig[confid])) {
-			    return "This device is already in use.";
-			}
-			return true;
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
-/*global Proxmox*/
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    view.store.on('load', this.onLoad, view);
-	},
-
-	onLoad: function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-	    var me = this;
-	    var val = me.getValue();
-	    if (!val || !me.store.findRecord('realm', val)) {
-		var def = 'pam';
-		Ext.each(records, function(rec) {
-		    if (rec.data && rec.data['default']) {
-			def = rec.data.realm;
-		    }
-		});
-		me.setValue(def);
-	    }
-	}
-    },
-
-    fieldLabel: gettext('Realm'),
-    name: 'realm',
-    queryMode: 'local',
-    allowBlank: false,
-    editable: false,
-    forceSelection: true,
-    autoSelect: false,
-    triggerAction: 'all',
-    valueField: 'realm',
-    displayField: 'descr',
-    getState: function() {
-	return { value: this.getValue() };
-    },
-    applyState : function(state) {
-	if (state && state.value) {
-	    this.setValue(state.value);
-	}
-    },
-    stateEvents: [ 'select' ],
-    stateful: true, // last chosen auth realm is saved between page reloads
-    id: 'pveloginrealm', // We need stable ids when using stateful, not autogenerated
-    stateID: 'pveloginrealm',
-
-    needOTP: function(realm) {
-	var me = this;
-	// use exact match
-	var rec = me.store.findRecord('realm', realm, 0, false, false, true);
-	return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    store: {
-	model: 'pve-domains',
-	autoLoad: true
-    }
-});
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    editable: false,
-    allowBlank: false,
-    forceSelection: true,
-    autoSelect: false,
-    valueField: 'key',
-    displayField: 'value',
-    hideLabel: true,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	var default_views = {
-	    server: {
-		text: gettext('Server View'),
-		groups: ['node']
-	    },
-	    folder: {
-		text: gettext('Folder View'),
-		groups: ['type']
-	    },
-	    storage: {
-		text: gettext('Storage View'),
-		groups: ['node'],
-		filterfn: function(node) {
-		    return node.data.type === 'storage' || node.data.type === 'node';
-		}
-	    },
-	    pool: { 
-		text: gettext('Pool View'), 
-		groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-			node.data.type === 'pool';
-                }
-	    }
-	};
-
-	var groupdef = [];
-	Ext.Object.each(default_views, function(viewname, value) {
-	    groupdef.push([viewname, value.text]);
-	});
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-            proxy: {
-		type: 'memory',
-		reader: 'array'
-            },
-	    data: groupdef,
-	    autoload: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    value: groupdef[0][0],
-	    getViewFilter: function() {
-		var view = me.getValue();
-		return Ext.apply({ id: view }, default_views[view] || default_views.server);
-	    },
-
-	    getState: function() {
-		return { value: me.getValue() };
-	    },
-
-	    applyState : function(state, doSelect) {
-		var view = me.getValue();
-		if (state && state.value && (view != state.value)) {
-		    var record = store.findRecord('key', state.value);
-		    if (record) {
-			me.setValue(state.value, true);
-			if (doSelect) {
-			    me.fireEvent('select', me, [record]);
-			}
-		    }
-		}
-	    },
-	    stateEvents: [ 'select' ],
-	    stateful: true,
-	    stateId: 'pveview',
-	    id: 'view'
-	});
-
-	me.callParent();
-
-	var statechange = function(sp, key, value) {
-	    if (key === me.id) {
-		me.applyState(value, true);
-	    }
-	};
-
-	var sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', statechange, me);
-    }
-});
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveNodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // do not allow those nodes (array)
-    disallowedNodes: undefined,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'node',
-    displayField: 'node',
-    store: {
-	    fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes'
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		},
-		{
-		    property : 'mem',
-		    direction: 'DESC'
-		}
-	    ]
-	},
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node',
-		sortable: true,
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Memory usage') + " %",
-		renderer: PVE.Utils.render_mem_usage_percent,
-		sortable: true,
-		width: 100,
-		dataIndex: 'mem'
-	    },
-	    {
-		header: gettext('CPU usage'),
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100,
-		dataIndex: 'cpu'
-	    }
-	]
-    },
-
-    validator: function(value) {
-	/*jslint confusion: true */
-	var me = this;
-	if (!me.onlineValidator || (me.allowBlank && !value)) {
-	    return true;
-	}
-
-	var offline = [];
-	var notAllowed = [];
-
-	Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-	    var rec = me.store.findRecord(me.valueField, node);
-	    if (!(rec && rec.data) || rec.data.status !== 'online') {
-		offline.push(node);
-	    } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-		notAllowed.push(node);
-	    }
-	});
-
-	if (value && notAllowed.length !== 0) {
-	    return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-	}
-
-	if (value && offline.length !== 0) {
-	    return "Node " + offline.join(', ') + " seems to be offline!";
-	}
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-        me.getStore().load();
-
-	// filter out disallowed nodes
-	me.getStore().addFilter(new Ext.util.Filter({
-	    filterFn: function(item) {
-		if (Ext.isArray(me.disallowedNodes)) {
-		    return !Ext.Array.contains(me.disallowedNodes, item.data.node);
-		} else {
-		    return true;
-		}
-	    }
-	}));
-
-	me.mon(me.getStore(), 'load', function(){
-	    me.isValid();
-	});
-    }
-});
-Ext.define('PVE.form.FileSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFileSelector',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    listeners: {
-	afterrender: function() {
-	    var me = this;
-	    if (!me.disabled) {
-		me.setStorage(me.storage, me.nodename);
-	    }
-	}
-    },
-
-    setStorage: function(storage, nodename) {
-	var me = this;
-
-	var change = false;
-	if (storage && (me.storage !== storage)) {
-	    me.storage = storage;
-	    change = true;
-	}
-
-	if (nodename && (me.nodename !== nodename)) {
-	    me.nodename = nodename;
-	    change = true;
-	}
-
-	if (!(me.storage && me.nodename && change)) {
-	    return;
-	}
-
-	var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-	if (me.storageContent) {
-	    url += '?content=' + me.storageContent;
-	}
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url
-	});
-
-	me.store.removeAll();
-	me.store.load();
-    },
-
-    setNodename: function(nodename) {
-	this.setStorage(undefined, nodename);
-    },
-
-    store: {
-	model: 'pve-storage-content'
-    },
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'volid',
-    displayField: 'text',
-
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'text',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Format'),
-		width: 60,
-		dataIndex: 'format'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 100,
-		dataIndex: 'size',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveStorageSelector',
-
-    allowBlank: false,
-    valueField: 'storage',
-    displayField: 'storage',
-    listConfig: {
-	width: 450,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'storage',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Type'),
-		width: 75,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Avail'),
-		width: 90,
-		dataIndex: 'avail',
-		renderer: Proxmox.Utils.format_size
-	    },
-	    {
-		header: gettext('Capacity'),
-		width: 90,
-		dataIndex: 'total',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    },
-
-    reloadStorageList: function() {
-	var me = this;
-	if (!me.nodename) {
-	    return;
-	}
-
-	var params = {
-	    format: 1
-	};
-	var url = '/api2/json/nodes/' + me.nodename + '/storage';
-	if (me.storageContent) {
-	    params.content = me.storageContent;
-	}
-	if (me.targetNode) {
-	    params.target = me.targetNode;
-	    params.enabled = 1; // skip disabled storages
-	}
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url,
-	    extraParams: params
-	});
-
-	me.store.load();
- 
-    },
-
-    setTargetNode: function(targetNode) {
-	var me = this;
-
-	if (!targetNode || (me.targetNode === targetNode)) {
-	    return;
-	}
-
-	me.targetNode = targetNode;
-
-	me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.reloadStorageList();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-status',
-	    sorters: {
-		property: 'storage', 
-		order: 'DESC' 
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	if (nodename) {
-	    me.setNodename(nodename);
-	}
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-	idProperty: 'storage'
-    });
-
-});
-Ext.define('PVE.form.DiskStorageSelector', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveDiskStorageSelector',
-
-    layout: 'fit',
-    defaults: {
-	margin: '0 0 5 0'
-    },
-
-    // the fieldLabel for the storageselector
-    storageLabel: gettext('Storage'),
-
-    // the content to show (e.g., images or rootdir)
-    storageContent: undefined,
-
-    // if true, selects the first available storage
-    autoSelect: false,
-
-    allowBlank: false,
-    emptyText: '',
-
-    // hides the selection field
-    // this is always hidden on creation,
-    // and only shown when the storage needs a selection and
-    // hideSelection is not true
-    hideSelection: undefined,
-
-    // hides the size field (e.g, for the efi disk dialog)
-    hideSize: false,
-
-    // sets the initial size value
-    // string because else we get a type confusion
-    defaultSize: '32',
-
-    changeStorage: function(f, value) {
-	var me = this;
-	var formatsel = me.getComponent('diskformat');
-	var hdfilesel = me.getComponent('hdimage');
-	var hdsizesel = me.getComponent('disksize');
-
-	// initial store load, and reset/deletion of the storage
-	if (!value) {
-	    hdfilesel.setDisabled(true);
-	    hdfilesel.setVisible(false);
-
-	    formatsel.setDisabled(true);
-	    return;
-	}
-
-	var rec = f.store.getById(value);
-	// if the storage is not defined, or valid,
-	// we cannot know what to enable/disable
-	if (!rec) {
-	    return;
-	}
-
-	var selectformat = false;
-	if (rec.data.format) {
-	    var format = rec.data.format[0]; // 0 is the formats, 1 the default in the backend
-	    delete format.subvol; // we never need subvol in the gui
-	    selectformat = (Ext.Object.getSize(format) > 1);
-	}
-
-	var select = !!rec.data.select_existing && !me.hideSelection;
-
-	formatsel.setDisabled(!selectformat);
-	formatsel.setValue(selectformat ? 'qcow2' : 'raw');
-
-	hdfilesel.setDisabled(!select);
-	hdfilesel.setVisible(select);
-	if (select) {
-	    hdfilesel.setStorage(value);
-	}
-
-	hdsizesel.setDisabled(select || me.hideSize);
-	hdsizesel.setVisible(!select && !me.hideSize);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-	var hdfilesel = me.getComponent('hdimage');
-
-	hdstorage.setNodename(nodename);
-	hdfilesel.setNodename(nodename);
-    },
-
-    setDisabled: function(value) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-
-	// reset on disable
-	if (value) {
-	    hdstorage.setValue();
-	}
-	hdstorage.setDisabled(value);
-
-	// disabling does not always fire this event and we do not need
-	// the value of the validity
-	hdstorage.fireEvent('validitychange');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'pveStorageSelector',
-		itemId: 'hdstorage',
-		name: 'hdstorage',
-		reference: 'hdstorage',
-		fieldLabel: me.storageLabel,
-		nodename: me.nodename,
-		storageContent: me.storageContent,
-		disabled: me.disabled,
-		autoSelect: me.autoSelect,
-		allowBlank: me.allowBlank,
-		emptyText: me.emptyText,
-		listeners: {
-		    change: {
-			fn: me.changeStorage,
-			scope: me
-		    }
-		}
-	    },
-	    {
-		xtype: 'pveFileSelector',
-		name: 'hdimage',
-		reference: 'hdimage',
-		itemId: 'hdimage',
-		fieldLabel: gettext('Disk image'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: true
-	    },
-	    {
-		xtype: 'numberfield',
-		itemId: 'disksize',
-		reference: 'disksize',
-		name: 'disksize',
-		fieldLabel: gettext('Disk size') + ' (GiB)',
-		hidden: me.hideSize,
-		disabled: me.hideSize,
-		minValue: 0.001,
-		maxValue: 128*1024,
-		decimalPrecision: 3,
-		value: me.defaultSize,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveDiskFormatSelector',
-		itemId: 'diskformat',
-		reference: 'diskformat',
-		name: 'diskformat',
-		fieldLabel: gettext('Format'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: me.storageContent === 'rootdir',
-		value: 'qcow2',
-		allowBlank: false
-	    }
-	];
-
-	// use it to disable the children but not ourself
-	me.disabled = false;
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    store: {
-	fields: [ 'iface', 'active', 'type' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	]
-    },
-    valueField: 'iface',
-    displayField: 'iface',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Bridge'),
-		dataIndex: 'iface',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Active'),
-		width: 60,
-		dataIndex: 'active',
-		renderer: Proxmox.Utils.format_boolean
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comments',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-		me.bridgeType
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-        me.callParent();
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.PCISelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pvePCISelector',
-
-    store: {
-	fields: [ 'id','vendor_name', 'device_name', 'vendor', 'device', 'iommugroup', 'mdev' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'id',
-		direction: 'ASC'
-	    }
-	]
-    },
-
-    autoSelect: false,
-    valueField: 'id',
-    displayField: 'id',
-
-    // can contain a load callback for the store
-    // useful to determine the state of the IOMMU
-    onLoadCallBack: undefined,
-
-    listConfig: {
-	width: 800,
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'id',
-		width: 80
-	    },
-	    {
-		header: gettext('IOMMU Group'),
-		dataIndex: 'iommugroup',
-		width: 50
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor_name',
-		flex: 2
-	    },
-	    {
-		header: gettext('Device'),
-		dataIndex: 'device_name',
-		flex: 6
-	    },
-	    {
-		header: gettext('Mediated Devices'),
-		dataIndex: 'mdev',
-		flex: 1,
-		renderer: function(val) {
-		    return Proxmox.Utils.format_boolean(!!val);
-		}
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined;
-
-        me.callParent();
-
-	if (me.onLoadCallBack !== undefined) {
-	    me.mon(me.getStore(), 'load', me.onLoadCallBack);
-	}
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.MDevSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveMDevSelector',
-
-    store: {
-	fields: [ 'type','available', 'description' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'type',
-		direction: 'ASC'
-	    }
-	]
-    },
-    autoSelect: false,
-    valueField: 'type',
-    displayField: 'type',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		flex: 1
-	    },
-	    {
-		header: gettext('Available'),
-		dataIndex: 'available',
-		width: 80
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'description',
-		flex: 1,
-		renderer: function(value) {
-		    if (!value) {
-			return '';
-		    }
-
-		    return value.split('\n').join('<br>');
-		}
-	    }
-	]
-    },
-
-    setPciID: function(pciid, force) {
-	var me = this;
-
-	if (!force && (!pciid || (me.pciid === pciid))) {
-	    return;
-	}
-
-	me.pciid = pciid;
-	me.updateProxy();
-    },
-
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-	me.updateProxy();
-    },
-
-    updateProxy: function() {
-	var me = this;
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci/' + me.pciid + '/mdev'
-	});
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no node name specified';
-	}
-
-        me.callParent();
-
-	if (me.pciid) {
-	    me.setPciID(me.pciid, true);
-	}
-    }
-});
-
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    valueField: 'group',
-    displayField: 'group',
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'group', 'comment' ],
-	    idProperty: 'group',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/groups"
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Security Group'),
-			dataIndex: 'group',
-			hideable: false,
-			width: 100
-		    },
-		    {
-			header: gettext('Comment'),  
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    valueField: 'ref',
-    displayField: 'ref',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-
-	var url = "/api2/json" + me.base_url;
-	if (me.ref_type) {
-	    url += "?type=" + me.ref_type;
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'type', 'name', 'ref', 'comment' ],
-	    idProperty: 'ref',
-	    proxy: {
-		type: 'proxmox',
-		url: url
-	    },
-	    sorters: {
-		property: 'ref',
-		order: 'DESC'
-	    }
-	});
-
-	var disable_query_for_ips = function(f, value) {
-	    if (value === null || 
-		value.match(/^\d/)) { // IP address starts with \d
-		f.queryDelay = 9999999999; // hack: disable with long delay
-	    } else {
-		f.queryDelay = 10;
-	    }
-	};
-
-	var columns = [];
-
-	if (!me.ref_type) {
-	    columns.push({
-		header: gettext('Type'),
-		dataIndex: 'type',
-		hideable: false,
-		width: 60
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Name'),
-		dataIndex: 'ref',
-		hideable: false,
-		width: 140
-	    },
-	    {
-		header: gettext('Comment'),  
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: { columns: columns }
-	});
-
-	me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-    valueField: 'p',
-    displayField: 'p',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'p',
-		hideable: false,
-		sortable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Number'),
-		dataIndex: 'n',
-		hideable: false,
-		sortable: false,
-		width: 50
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'd',
-		hideable: false,
-		sortable: false,
-		flex: 1
-	    }
-	]
-    },
-    store: {
-	    fields: [ 'p', 'd', 'n'],
-	    data: [
-		{ p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-		{ p: 'udp', n: 17, d: 'User Datagram Protocol' },
-		{ p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-		{ p: 'igmp', n: 2,  d: 'Internet Group Management' },
-		{ p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-		{ p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-		{ p: 'st', n: 5, d: 'ST datagram mode' },
-		{ p: 'egp', n: 8, d: 'exterior gateway protocol' },
-		{ p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-		{ p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-		{ p: 'hmp', n: 20, d: 'host monitoring protocol' },
-		{ p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-		{ p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-		{ p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-		{ p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-		{ p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-		{ p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-		{ p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-		{ p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-		{ p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-		{ p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-		{ p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-		{ p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-		{ p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-		{ p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-		{ p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-		{ p: 'skip', n: 57, d: 'SKIP' },
-		{ p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-		{ p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-		{ p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-		{ p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-		{ p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-		{ p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-		{ p: 'ax.25', n: 93, d: 'AX.25 frames' },
-		{ p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-		{ p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-		{ p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-		{ p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-		{ p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-		{ p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-		{ p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-		{ p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-		{ p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-		{ p: 'fc', n: 133, d: 'Fibre Channel' },
-		{ p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-		{ p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-		{ p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-		{ p: 'hip', n: 139, d: 'Host Identity Protocol' },
-		{ p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-		{ p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-		{ p: 'rohc', n: 142, d: 'Robust Header Compression' }
-	    ]
-	}
-});
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CPUModelSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + ' (kvm64)'],
-	['486', '486'],
-	['athlon', 'athlon'],
-	['core2duo', 'core2duo'],
-	['coreduo', 'coreduo'],
-	['kvm32', 'kvm32'],
-	['kvm64', 'kvm64'],
-	['pentium', 'pentium'],
-	['pentium2', 'pentium2'],
-	['pentium3', 'pentium3'],
-	['phenom', 'phenom'],
-	['qemu32', 'qemu32'],
-	['qemu64', 'qemu64'],
-	['Conroe', 'Conroe'],
-	['Penryn', 'Penryn'],
-	['Nehalem', 'Nehalem'],
-	['Westmere', 'Westmere'],
-	['SandyBridge', 'SandyBridge'],
-	['IvyBridge', 'IvyBridge'],
-	['Haswell', 'Haswell'],
-	['Haswell-noTSX','Haswell-noTSX'],
-	['Broadwell', 'Broadwell'],
-	['Broadwell-noTSX','Broadwell-noTSX'],
-	['Skylake-Client','Skylake-Client'],
-	['Opteron_G1', 'Opteron_G1'],
-	['Opteron_G2', 'Opteron_G2'],
-	['Opteron_G3', 'Opteron_G3'],
-	['Opteron_G4', 'Opteron_G4'],
-	['Opteron_G5', 'Opteron_G5'],
-	['EPYC', 'EPYC'],
-	['host', 'host']
-
-    ]
-});
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + " (" + gettext('No cache') + ")"],
-	['directsync', 'Direct sync'],
-	['writethrough', 'Write through'],
-	['writeback', 'Write back'],
-	['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-	['none', gettext('No cache')]
-    ]
-});
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    valueField: 'name',
-    displayField: 'name',
-
-    loadStore: function(nodename, vmid) {
-	var me = this;
-
-	if (!nodename) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-        if (!vmid) {
-	    return;
-        }
-
-	me.vmid = vmid;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid +'/snapshot'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-	if (!me.guestType) {
-	    throw "no guest type specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'name'],
-	    filterOnLoad: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Snapshot'),
-			dataIndex: 'name',
-			hideable: false,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	me.loadStore(me.nodename, me.vmid);
-    }
-});
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-
-    cts: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [];
-
-	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'snippets'];
-	}
-
-	Ext.Array.each(me.cts, function(ct) {
-	    me.comboItems.push([ct, PVE.Utils.format_content_types(ct)]);
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'Ext.form.CheckboxGroup',
-    alias: 'widget.pveHotplugFeatureSelector',
-
-    columns: 1,
-    vertical: true,
-
-    defaults: {
-	name: 'hotplug',
-	submitValue: false
-    },
-    items: [
-	{
-	    boxLabel: gettext('Disk'),
-	    inputValue: 'disk',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Network'),
-	    inputValue: 'network',
-	    checked: true
-	},
-	{
-	    boxLabel: 'USB',
-	    inputValue: 'usb',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Memory'),
-	    inputValue: 'memory'
-	},
-	{
-	    boxLabel: gettext('CPU'),
-	    inputValue: 'cpu'
-	}
-    ],
-
-    setValue: function(value) {
-	var me = this;
-	var newVal = [];
-	if (value === '1') {
-	    newVal = ['disk', 'network', 'usb'];
-	} else if (value !== '0') {
-	    newVal = value.split(',');
-	}
-	me.callParent([{ hotplug: newVal }]);
-    },
-
-    // override framework function to
-    // assemble the hotplug value
-    getSubmitData: function() {
-	var me = this,
-	boxes = me.getBoxes(),
-	data = [];
-	Ext.Array.forEach(boxes, function(box){
-	    if (box.getValue()) {
-		data.push(box.inputValue);
-	    }
-	});
-
-	/* because above is hotplug an array */
-	/*jslint confusion: true*/
-	if (data.length === 0) {
-	    return { 'hotplug':'0' };
-	} else {
-	    return { 'hotplug': data.join(',') };
-	}
-    }
-
-});
-Ext.define('PVE.form.AgentFeatureSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: ['widget.pveAgentFeatureSelector'],
-
-    initComponent: function() {
-	var me = this;
-	me.items= [
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Qemu Agent'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		listeners: {
-		    change: function(f, value, old) {
-			var gtcb = me.down('proxmoxcheckbox[name=fstrim_cloned_disks]');
-			if (value) {
-			    gtcb.setDisabled(false);
-			} else {
-			    gtcb.setDisabled(true);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		boxLabel: gettext('Run guest-trim after clone disk'),
-		name: 'fstrim_cloned_disks',
-		disabled: true
-	    }
-	];
-	me.callParent();
-    },
-
-    onGetValues: function(values) {
-	var agentstr = PVE.Parser.printPropertyString(values, 'enabled');
-	return { agent: agentstr };
-    },
-
-    setValues: function(values) {
-	var agent = values.agent || '';
-	var res = PVE.Parser.parsePropertyString(agent, 'enabled');
-	this.callParent([res]);
-    }
-});
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-    comboItems: [
-	['comstar', 'Comstar'],
-	[ 'istgt', 'istgt'],
-	[ 'iet', 'IET'],
-	[ 'LIO', 'LIO']
-    ]
-});
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems:[],
-    initComponent: function(){
-	var me = this;
-	me.comboItems = [
-	    ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-	    ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-	    ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-	    ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-	    ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-	    ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])],
-	    ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])]
-	];
-	this.callParent();
-    }
-});
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-    comboItems: [
-	['__default__', PVE.Utils.render_scsihw('')],
-	['lsi', PVE.Utils.render_scsihw('lsi')],
-	['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-	['megasas', PVE.Utils.render_scsihw('megasas')],
-	['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-	['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-	['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-    ]
-});
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-    comboItems: [
-	    ['ACCEPT', 'ACCEPT'],
-	    ['REJECT', 'REJECT'],
-	    [ 'DROP', 'DROP']
-	]
-});
-/*
- *  This is a global search field
- *  it loads the /cluster/resources on focus
- *  and displays the result in a floating grid
- *
- *  it filters and sorts the objects by the algorithm in
- *  the customFilter function
- *
- *  also it does accept key up/down and enter for input
- *  and it opens to ctrl+shift+f and ctrl+space
- */
-Ext.define('PVE.form.GlobalSearchField', {
-    extend: 'Ext.form.field.Text',
-    alias: 'widget.pveGlobalSearchField',
-
-    emptyText: gettext('Search'),
-    enableKeyEvents: true,
-    selectOnFocus: true,
-    padding: '0 5 0 5',
-
-    grid: {
-	xtype: 'gridpanel',
-	focusOnToFront: false,
-	floating: true,
-	emptyText: Proxmox.Utils.noneText,
-	width: 600,
-	height: 400,
-	scrollable: {
-	    xtype: 'scroller',
-	    y: true,
-	    x:false
-	},
-	store: {
-	    model: 'PVEResources',
-	    proxy:{
-		type: 'proxmox',
-		url: '/api2/extjs/cluster/resources'
-	    }
-	},
-	plugins: {
-	    ptype: 'bufferedrenderer',
-	    trailingBufferZone: 20,
-	    leadingBufferZone: 20
-	},
-
-	hideMe: function() {
-	    var me = this;
-	    if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
-		return;
-	    }
-	    me.hasFocus = false;
-	    if (!me.textfield.hasFocus) {
-		me.hide();
-	    }
-	},
-
-	setFocus: function() {
-	    var me = this;
-	    me.hasFocus = true;
-	},
-
-	listeners: {
-	    rowclick: function(grid, record) {
-		var me = this;
-		me.textfield.selectAndHide(record.id);
-	    },
-	    itemcontextmenu: function(v, record, item, index, event) {
-		var me = this;
-		me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
-	    },
-	    /* because of lint */
-	    focusleave: {
-		fn: 'hideMe'
-	    },
-	    focusenter: 'setFocus'
-	},
-
-	columns: [
-	    {
-		text: gettext('Type'),
-		dataIndex: 'type',
-		width: 100,
-		renderer: PVE.Utils.render_resource_type
-	    },
-	    {
-		text: gettext('Description'),
-		flex: 1,
-		dataIndex: 'text'
-	    },
-	    {
-		text: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		text: gettext('Pool'),
-		dataIndex: 'pool'
-	    }
-	]
-    },
-
-    customFilter: function(item) {
-	var me = this;
-	var match = 0;
-	var fieldArr = [];
-	var i,j, fields;
-
-	// different types of objects have different fields to search
-	// for example, a node will never have a pool and vice versa
-	switch (item.data.type) {
-	    case 'pool': fieldArr = ['type', 'pool', 'text']; break;
-	    case 'node': fieldArr = ['type', 'node', 'text']; break;
-	    case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
-	    default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
-	}
-	if (me.filterVal === '') {
-	    item.data.relevance = 0;
-	    return true;
-	}
-
-	// all text is case insensitive and each word is
-	// searched alone
-	// for every partial match, the row gets
-	// 1 match point, for every exact match
-	// it gets 2 points
-	//
-	// results gets sorted by points (descending)
-	fields = me.filterVal.split(/\s+/);
-	for(i = 0; i < fieldArr.length; i++) {
-	    var v = item.data[fieldArr[i]];
-	    if (v !== undefined) {
-		v = v.toString().toLowerCase();
-		for(j = 0; j < fields.length; j++) {
-		    if (v.indexOf(fields[j]) !== -1) {
-			match++;
-			if(v === fields[j]) {
-			    match++;
-			}
-		    }
-		}
-	    }
-	}
-	// give the row the 'relevance' value
-	item.data.relevance = match;
-	return (match > 0);
-    },
-
-    updateFilter: function(field, newValue, oldValue) {
-	var me = this;
-	// parse input and filter store,
-	// show grid
-	me.grid.store.filterVal = newValue.toLowerCase().trim();
-	me.grid.store.clearFilter(true);
-	me.grid.store.filterBy(me.customFilter);
-	me.grid.getSelectionModel().select(0);
-    },
-
-    selectAndHide: function(id) {
-	var me = this;
-	me.tree.selectById(id);
-	me.grid.hide();
-	me.setValue('');
-	me.blur();
-    },
-
-    onKey: function(field, e) {
-	var me = this;
-	var key = e.getKey();
-
-	switch(key) {
-	    case Ext.event.Event.ENTER:
-		// go to first entry if there is one
-		if (me.grid.store.getCount() > 0) {
-		    me.selectAndHide(me.grid.getSelection()[0].data.id);
-		}
-		break;
-	    case Ext.event.Event.UP:
-		me.grid.getSelectionModel().selectPrevious();
-		break;
-	    case Ext.event.Event.DOWN:
-		me.grid.getSelectionModel().selectNext();
-		break;
-	    case Ext.event.Event.ESC:
-		me.grid.hide();
-		me.blur();
-		break;
-	}
-    },
-
-    loadValues: function(field) {
-	var me = this;
-	var records = [];
-
-	me.hasFocus = true;
-	me.grid.textfield = me;
-	me.grid.store.load();
-	me.grid.showBy(me, 'tl-bl');
-    },
-
-    hideGrid: function() {
-	var me = this;
-
-	me.hasFocus = false;
-	if (!me.grid.hasFocus) {
-	    me.grid.hide();
-	}
-    },
-
-    listeners: {
-	change: {
-	    fn: 'updateFilter',
-	    buffer: 250
-	},
-	specialkey: 'onKey',
-	focusenter: 'loadValues',
-	focusleave: {
-	    fn: 'hideGrid',
-	    delay: 100
-	}
-    },
-
-    toggleFocus: function() {
-	var me = this;
-	if (!me.hasFocus) {
-	    me.focus();
-	} else {
-	    me.blur();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.tree) {
-	    throw "no tree given";
-	}
-
-	me.grid = Ext.create(me.grid);
-
-	me.callParent();
-
-	/*jslint confusion: true*/
-	/*because shift is also a function*/
-	// bind ctrl+shift+f and ctrl+space
-	// to open/close the search
-	me.keymap = new Ext.KeyMap({
-	    target: Ext.get(document),
-	    binding: [{
-		key:'F',
-		ctrl: true,
-		shift: true,
-		fn: me.toggleFocus,
-		scope: me
-	    },{
-		key:' ',
-		ctrl: true,
-		fn: me.toggleFocus,
-		scope: me
-	    }]
-	});
-
-	// always select first item and
-	// sort by relevance after load
-	me.mon(me.grid.store, 'load', function() {
-	    me.grid.getSelectionModel().select(0);
-	    me.grid.store.sort({
-		property: 'relevance',
-		direction: 'DESC'
-	    });
-	});
-    }
-
-});
-Ext.define('PVE.form.QemuBiosSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveQemuBiosSelector'],
-
-    initComponent: function() {
-	var me = this;
-
-        me.comboItems = [
-	    ['__default__', PVE.Utils.render_qemu_bios('')],
-	    ['seabios', PVE.Utils.render_qemu_bios('seabios')],
-	    ['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-/* filter is a javascript builtin, but extjs calls it also filter */
-Ext.define('PVE.form.VMSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    allowBlank: true,
-    selectAll: false,
-    isFormField: true,
-
-    plugins: 'gridfilters',
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-    columns: [
-	{
-	    header: 'ID',
-	    dataIndex: 'vmid',
-	    width: 80,
-	    filter: {
-		type: 'number'
-	    }
-	},
-	{
-	    header: gettext('Node'),
-	    dataIndex: 'node'
-	},
-	{
-	    header: gettext('Status'),
-	    dataIndex: 'status',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1,
-	    filter: {
-		type: 'string'
-	    }
-	},
-	{
-	    header: gettext('Pool'),
-	    dataIndex: 'pool',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Type'),
-	    dataIndex: 'type',
-	    width: 120,
-	    renderer: function(value) {
-		if (value === 'qemu') {
-		    return gettext('Virtual Machine');
-		} else if (value === 'lxc') {
-		    return gettext('LXC Container');
-		}
-
-		return '';
-	    },
-	    filter: {
-		type: 'list',
-		store: {
-		    data: [
-			{id: 'qemu', text: gettext('Virtual Machine')},
-			{id: 'lxc', text: gettext('LXC Container')}
-		    ],
-		    // due to EXTJS-18711
-		    // we have to do a static list via a store
-		    // but to avoid creating an object,
-		    // we have to have a pseudo un function
-		    un: function(){}
-		}
-	    }
-	},
-	{
-	    header: 'HA ' + gettext('Status'),
-	    dataIndex: 'hastate',
-	    flex: 1,
-	    filter: {
-		type: 'list'
-	    }
-	}
-    ],
-
-    selModel: {
-	selType: 'checkboxmodel',
-	mode: 'SIMPLE'
-    },
-
-    checkChangeEvents: [
-	'selectionchange',
-	'change'
-    ],
-
-    listeners: {
-	selectionchange: function() {
-	    // to trigger validity and error checks
-	    this.checkChange();
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	var selection = sm.getSelection();
-	var values = [];
-	var store = me.getStore();
-	selection.forEach(function(item) {
-	    // only add if not filtered
-	    if (store.findExact('vmid', item.data.vmid) !== -1) {
-		values.push(item.data.vmid);
-	    }
-	});
-	return values;
-    },
-
-    setValue: function(value) {
-	console.log(value);
-	var me = this;
-	var sm = me.getSelectionModel();
-	if (!Ext.isArray(value)) {
-	    value = value.split(',');
-	}
-	var selection = [];
-	var store = me.getStore();
-
-	value.forEach(function(item) {
-	    var rec = store.findRecord('vmid',item, 0, false, true, true);
-	    console.log(store);
-
-	    if (rec) {
-		console.log(rec);
-		selection.push(rec);
-	    }
-	});
-
-	sm.select(selection);
-
-	return me.mixins.field.setValue.call(me, value);
-    },
-
-    getErrors: function(value) {
-	var me = this;
-	if (me.allowBlank ===  false &&
-	    me.getSelectionModel().getCount() === 0) {
-	    me.addBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	    return [gettext('No VM selected')];
-	}
-
-	me.removeBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	return [];
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.nodename) {
-	    me.store.filters.add({
-		property: 'node',
-		exactMatch: true,
-		value: me.nodename
-	    });
-	}
-
-	// only show the relevant guests by default
-	if (me.action) {
-	    var statusfilter = '';
-	    switch (me.action) {
-		case 'startall':
-		    statusfilter = 'stopped';
-		    break;
-		case 'stopall':
-		    statusfilter = 'running';
-		    break;
-	    }
-	    if (statusfilter !== '') {
-		me.store.filters.add({
-		    property: 'template',
-		    value: 0
-		},{
-		    id: 'x-gridfilter-status',
-		    operator: 'in',
-		    property: 'status',
-		    value: [statusfilter]
-		});
-	    }
-	}
-
-	var store = me.getStore();
-	var sm = me.getSelectionModel();
-
-	if (me.selectAll) {
-	    me.mon(store,'load', function(){
-		me.getSelectionModel().selectAll(false);
-	    });
-	}
-    }
-});
-
-
-Ext.define('PVE.form.VMComboSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.vmComboSelector',
-
-    valueField: 'vmid',
-    displayField: 'vmid',
-
-    autoSelect: false,
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-
-    listConfig: {
-	width: 600,
-	plugins: 'gridfilters',
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'vmid',
-		width: 80,
-		filter: {
-		    type: 'number'
-		}
-	    },
-	    {
-		header: gettext('Name'),
-		dataIndex: 'name',
-		flex: 1,
-		filter: {
-		    type: 'string'
-		}
-	    },
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		header: gettext('Status'),
-		dataIndex: 'status',
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Pool'),
-		dataIndex: 'pool',
-		hidden: true,
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		width: 120,
-		renderer: function(value) {
-		    if (value === 'qemu') {
-			return gettext('Virtual Machine');
-		    } else if (value === 'lxc') {
-			return gettext('LXC Container');
-		    }
-
-		    return '';
-		},
-		filter: {
-		    type: 'list',
-		    store: {
-			data: [
-			    {id: 'qemu', text: gettext('Virtual Machine')},
-			    {id: 'lxc', text: gettext('LXC Container')}
-			],
-			un: function(){} // due to EXTJS-18711
-		    }
-		}
-	    },
-	    {
-		header: 'HA ' + gettext('Status'),
-		dataIndex: 'hastate',
-		hidden: true,
-		flex: 1,
-		filter: {
-		    type: 'list'
-		}
-	    }
-	]
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.form.VMCPUFlagSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmcpuflagselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    disableSelection: true,
-    columnLines: false,
-    selectable: false,
-    hideHeaders: true,
-
-    scrollable: 'y',
-    height: 200,
-
-    unkownFlags: [],
-
-    store: {
-	type: 'store',
-	fields: ['flag', { name: 'state', defaultValue: '=' }, 'desc'],
-	data: [
-	    // FIXME: let qemu-server host this and autogenerate or get from API call??
-	    { flag: 'md-clear', desc: 'Required to let the guest OS know if MDS is mitigated correctly' },
-	    { flag: 'pcid', desc: 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs' },
-	    { flag: 'spec-ctrl', desc: 'Allows improved Spectre mitigation with Intel CPUs' },
-	    { flag: 'ssbd', desc: 'Protection for "Speculative Store Bypass" for Intel models' },
-	    { flag: 'ibpb', desc: 'Allows improved Spectre mitigation with AMD CPUs' },
-	    { flag: 'virt-ssbd', desc: 'Basis for "Speculative Store Bypass" protection for AMD models' },
-	    { flag: 'amd-ssbd', desc: 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"' },
-	    { flag: 'amd-no-ssb', desc: 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs' },
-	    { flag: 'pdpe1gb', desc: 'Allow guest OS to use 1GB size pages, if host HW supports it' }
-	],
-	listeners: {
-	    update: function() {
-		this.commitChanges();
-	    }
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var store = me.getStore();
-	var flags = '';
-
-	// ExtJS does not has a nice getAllRecords interface for stores :/
-	store.queryBy(Ext.returnTrue).each(function(rec) {
-	    var s = rec.get('state');
-	    if (s && s !== '=') {
-		var f = rec.get('flag');
-		if (flags === '') {
-		    flags = s + f;
-		} else {
-		    flags += ';' + s + f;
-		}
-	    }
-	});
-
-	flags += me.unkownFlags.join(';');
-
-	return flags;
-    },
-
-    setValue: function(value) {
-	var me = this;
-	var store = me.getStore();
-
-	me.value = value || '';
-
-	me.unkownFlags = [];
-
-	me.getStore().queryBy(Ext.returnTrue).each(function(rec) {
-	    rec.set('state', '=');
-	});
-
-	var flags = value ? value.split(';') : [];
-	flags.forEach(function(flag) {
-	    var sign = flag.substr(0, 1);
-	    flag = flag.substr(1);
-
-	    var rec = store.findRecord('flag', flag);
-	    if (rec !== null) {
-		rec.set('state', sign);
-	    } else {
-		me.unkownFlags.push(flag);
-	    }
-	});
-	store.reload();
-
-	var res = me.mixins.field.setValue.call(me, value);
-
-	return res;
-    },
-    columns: [
-	{
-	    dataIndex: 'state',
-	    renderer: function(v) {
-		switch(v) {
-		    case '=': return 'Default';
-		    case '-': return 'Off';
-		    case '+': return 'On';
-		    default: return 'Unknown';
-		}
-	    },
-	    width: 65
-	},
-	{
-	    xtype: 'widgetcolumn',
-	    dataIndex: 'state',
-	    width: 95,
-	    onWidgetAttach: function (column, widget, record) {
-		var val = record.get('state') || '=';
-		widget.down('[inputValue=' + val + ']').setValue(true);
-		// TODO: disable if selected CPU model and flag are incompatible
-	    },
-	    widget: {
-		xtype: 'radiogroup',
-		hideLabel: true,
-		layout: 'hbox',
-		validateOnChange: false,
-		value: '=',
-		listeners: {
-		    change: function(f, value) {
-			var v = Object.values(value)[0];
-			f.getWidgetRecord().set('state', v);
-
-			var view = this.up('grid');
-			view.dirty = view.getValue() !== view.originalValue;
-			view.checkDirty();
-			//view.checkChange();
-		    }
-		},
-		items: [
-		    {
-			boxLabel: '-',
-			boxLabelAlign: 'before',
-			inputValue: '-'
-		    },
-		    {
-			checked: true,
-			inputValue: '='
-		    },
-		    {
-			boxLabel: '+',
-			inputValue: '+'
-		    }
-		]
-	    }
-	},
-	{
-	    dataIndex: 'flag',
-	    width: 100
-	},
-	{
-	    dataIndex: 'desc',
-	    cellWrap: true,
-	    flex: 1
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	// static class store, thus gets not recreated, so ensure defaults are set!
-	me.getStore().data.forEach(function(v) {
-	    v.state = '=';
-	});
-
-	me.value = me.originalValue = '';
-
-	me.callParent(arguments);
-    }
-});
-Ext.define('PVE.form.USBSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUSBSelector'],
-    allowBlank: false,
-    autoSelect: false,
-    displayField: 'usbid',
-    valueField: 'usbid',
-    editable: true,
-
-    getUSBValue: function() {
-	var me = this;
-	var rec = me.store.findRecord('usbid', me.value);
-	var val = 'host='+ me.value;
-	if (rec && rec.data.speed === "5000") {
-	    val = 'host=' + me.value + ",usb3=1";
-	}
-	return val;
-    },
-
-    validator: function(value) {
-	var me = this;
-	if (me.type === 'device') {
-	    return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
-	} else if (me.type === 'port') {
-	    return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
-	}
-	return false;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (me.type !== 'device' && me.type !== 'port') {
-	    throw "no valid type specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-usb-' + me.type,
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/scan/usb"
-	    },
-	    filters: [
-		function (item) {
-		    return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: (me.type === 'device')?gettext('Device'):gettext('Port'),
-			sortable: true,
-			dataIndex: 'usbid',
-			width: 80
-		    },
-		    {
-			header: gettext('Manufacturer'),
-			sortable: true,
-			dataIndex: 'manufacturer',
-			width: 100
-		    },
-		    {
-			header: gettext('Product'),
-			sortable: true,
-			dataIndex: 'product',
-			flex: 1
-		    },
-		    {
-			header: gettext('Speed'),
-			width: 70,
-			sortable: true,
-			dataIndex: 'speed',
-			renderer: function(value) {
-			    if (value === "5000") {
-				return "USB 3.0";
-			    } else if (value === "480") {
-				return "USB 2.0";
-			    } else {
-				return "USB 1.x";
-			    }
-			}
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-usb-device', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val, data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('vendid') + ':' + data.get('prodid');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-
-    Ext.define('pve-usb-port', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val,data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('busnum') + '-' + data.get('usbpath');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' }
-	]
-    });
-});
-Ext.define('PVE.form.CalendarEvent', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pveCalendarEvent',
-
-    editable: true,
-
-    valueField: 'value',
-    displayField: 'text',
-    queryMode: 'local',
-
-    store: {
-	field: [ 'value', 'text'],
-	data: [
-	    { value: '*/30', text: Ext.String.format(gettext("Every {0} minutes"), 30) },
-	    { value: '*/2:00', text: gettext("Every two hours")},
-	    { value: '2,22:30', text: gettext("Every day") + " 02:30, 22:30"},
-	    { value: 'mon..fri', text: gettext("Monday to Friday") + " 00:00"},
-	    { value: 'mon..fri */1:00', text: gettext("Monday to Friday") + ': ' +  gettext("hourly")},
-	    { value: 'sun 01:00', text: gettext("Sunday") + " 01:00"}
-	]
-    },
-
-    tpl: [
-	'<ul class="x-list-plain"><tpl for=".">',
-	    '<li role="option" class="x-boundlist-item">{text}</li>',
-	'</tpl></ul>'
-    ],
-
-    displayTpl: [
-	'<tpl for=".">',
-	'{value}',
-	'</tpl>'
-    ]
-
-});
-Ext.define('PVE.form.CephPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephPoolSelector',
-
-    allowBlank: false,
-    valueField: 'pool_name',
-    displayField: 'pool_name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/pools'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.form.PermPathSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pvePermPathSelector',
-
-    valueField: 'value',
-    displayField: 'value',
-    typeAhead: true,
-    queryMode: 'local',
-    store: {
-	type: 'pvePermPath'
-    }
-});
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-	var me = this;
-
-	var taskstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-tasks',
-	    model: 'proxmox-tasks',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/tasks'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: taskstore,
-	    sortAfterUpdate: true,
-	    appendAtStart: true,
-	    sorters: [
-		{
-		    property : 'pid',
-		    direction: 'DESC'
-		},
-		{
-		    property : 'starttime',
-		    direction: 'DESC'
-		}
-	    ]
-
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 150,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type == "vncproxy" ||
-				record.data.type == "vncshell" ||
-				record.data.type == "spiceproxy") {
-				metaData.tdCls =  "x-grid-row-console";
-			    } else {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type != "vncproxy") {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return Proxmox.Utils.errorText + ': ' + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		show: taskstore.startUpdate,
-		destroy: taskstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-	var me = this;
-
-	var logstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-log',
-	    model: 'proxmox-cluster-log',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/log'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: logstore,
-	    appendAtStart: true 
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true,
- 
-		getRowClass: function(record, index) {
-		    var pri = record.get('pri');
-
-		    if (pri && pri <= 3) {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{ 
-		    header: gettext("Time"), 
-		    dataIndex: 'time',
-		    width: 150,
-		    renderer: function(value) { 
-			return Ext.Date.format(value, "M d H:i:s"); 
-		    }
-		},
-		{ 
-		    header: gettext("Node"), 
-		    dataIndex: 'node',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Service"), 
-		    dataIndex: 'tag',
-		    width: 100
-		},
-		{ 
-		    header: "PID", 
-		    dataIndex: 'pid',
-		    width: 100 
-		},
-		{ 
-		    header: gettext("User name"), 
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Severity"), 
-		    dataIndex: 'pri',
-		    renderer: PVE.Utils.render_serverity,
-		    width: 100 
-		},
-		{ 
-		    header: gettext("Message"), 
-		    dataIndex: 'msg',
-		    flex: 1	  
-		}
-	    ],
-	    listeners: {
-		activate: logstore.startUpdate,
-		deactivate: logstore.stopUpdate,
-		destroy: logstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = 'ltab';
-	var sp = Ext.state.Manager.getProvider();
-
-	var state = sp.get(stateid);
-	if (state && state.value) {
-	    me.activeTab = state.value;
-	}
-
-	Ext.apply(me, {
-	    listeners: {
-		tabchange: function() {
-		    var atab = me.getActiveTab().itemId;
-		    var state = { value: atab };
-		    sp.set(stateid, state);
-		}
-	    },
-	    items: [
-		{
-		    itemId: 'tasks',
-		    title: gettext('Tasks'),
-		    xtype: 'pveClusterTasks'
-		},
-		{
-		    itemId: 'clog',
-		    title: gettext('Cluster log'),
-		    xtype: 'pveClusterLog'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.items.get(0).fireEvent('show', me.items.get(0));
-
-	var statechange = function(sp, key, state) {
-	    if (key === stateid) {
-		var atab = me.getActiveTab().itemId;
-		var ntab = state.value;
-		if (state && ntab && (atab != ntab)) {
-		    me.setActiveTab(ntab);
-		}
-	    }
-	};
-
-	sp.on('statechange', statechange);
-	me.on('destroy', function() {
-	    sp.un('statechange', statechange);		    
-	});
-
-    }
-});
-Ext.define('PVE.panel.StatusView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStatusView',
-
-    layout: {
-	type: 'column'
-    },
-
-    title: gettext('Status'),
-
-    getRecordValue: function(key, store) {
-	if (!key) {
-	    throw "no key given";
-	}
-	var me = this;
-
-	if (store === undefined) {
-	    store = me.getStore();
-	}
-
-	var rec = store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-
-	return '';
-    },
-
-    fieldRenderer: function(val,max) {
-	if (max === undefined) {
-	    return val;
-	}
-
-	if (!Ext.isNumeric(max) || max === 1) {
-	    return PVE.Utils.render_usage(val);
-	}
-	return PVE.Utils.render_size_usage(val,max);
-    },
-
-    fieldCalculator: function(used, max) {
-	if (!Ext.isNumeric(max) && Ext.isNumeric(used)) {
-	    return used;
-	} else if(!Ext.isNumeric(used)) {
-	    /* we come here if the field is from a node
-	     * where the records are not mem and maxmem
-	     * but mem.used and mem.total
-	     */
-	    if (used.used !== undefined &&
-		used.total !== undefined) {
-		return used.used/used.total;
-	    }
-	}
-
-	return used/max;
-    },
-
-    updateField: function(field) {
-	var me = this;
-	var text = '';
-	var renderer = me.fieldRenderer;
-	if (Ext.isFunction(field.renderer)) {
-	    renderer = field.renderer;
-	}
-	if (field.multiField === true) {
-	    field.updateValue(renderer.call(field, me.getStore().getRecord()));
-	} else if (field.textField !== undefined) {
-	    field.updateValue(renderer.call(field, me.getRecordValue(field.textField)));
-	} else if(field.valueField !== undefined) {
-	    var used = me.getRecordValue(field.valueField);
-	    /*jslint confusion: true*/
-	    /* string and int */
-	    var max = field.maxField !== undefined ? me.getRecordValue(field.maxField) : 1;
-
-	    var calculate = me.fieldCalculator;
-
-	    if (Ext.isFunction(field.calculate)) {
-		calculate = field.calculate;
-	    }
-	    field.updateValue(renderer.call(field, used,max), calculate(used,max));
-	}
-    },
-
-    getStore: function() {
-	var me = this;
-	if (!me.rstore) {
-	    throw "there is no rstore";
-	}
-
-	return me.rstore;
-    },
-
-    updateTitle: function() {
-	var me = this;
-	me.setTitle(me.getRecordValue('name'));
-    },
-
-    updateValues: function(store, records, success) {
-	if (!success) {
-	    return; // do not update if store load was not successful
-	}
-	var me = this;
-	var itemsToUpdate = me.query('pveInfoWidget');
-
-	itemsToUpdate.forEach(me.updateField, me);
-
-	me.updateTitle(store);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	if (!me.title) {
-	    throw "no title given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', 'updateValues');
-    }
-
-});
-Ext.define('PVE.panel.GuestStatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveGuestStatusView',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    height: 300,
-
-    cbindData: function (initialConfig) {
-	var me = this;
-	return {
-	    isQemu: me.pveSelNode.data.type === 'qemu',
-	    isLxc: me.pveSelNode.data.type === 'lxc'
-	};
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'status',
-	    title: gettext('Status'),
-	    iconCls: 'fa fa-info fa-fw',
-	    printBar: false,
-	    multiField: true,
-	    renderer: function(record) {
-		var me = this;
-		var text = record.data.status;
-		var qmpstatus = record.data.qmpstatus;
-		if (qmpstatus && qmpstatus !== record.data.status) {
-		    text += ' (' + qmpstatus + ')';
-		}
-		return text;
-	    }
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    xtype: 'pveInfoWidget',
-	    itemId: 'node',
-	    iconCls: 'fa fa-building fa-fw',
-	    title: gettext('Node'),
-	    cbind: {
-		text: '{pveSelNode.data.node}'
-	    },
-	    printBar: false
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpus',
-	    renderer: PVE.Utils.render_cpu_usage,
-	    // in this specific api call
-	    // we already have the correct value for the usage
-	    calculate: Ext.identityFn
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory usage'),
-	    valueField: 'mem',
-	    maxField: 'maxmem'
-	},
-	{
-	    itemId: 'swap',
-	    xtype: 'pveInfoWidget',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'maxswap',
-	    cbind: {
-		hidden: '{isQemu}',
-		disabled: '{isQemu}'
-	    }
-	},
-	{
-	    itemId: 'rootfs',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    valueField: 'disk',
-	    maxField: 'maxdisk',
-	    printBar: false,
-	    renderer: function(used, max) {
-		var me = this;
-		me.setPrintBar(used > 0);
-		if (used === 0) {
-		    return PVE.Utils.render_size(max);
-		} else {
-		    return PVE.Utils.render_size_usage(used,max);
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'ips',
-	    xtype: 'pveAgentIPView',
-	    cbind: {
-		rstore: '{rstore}',
-		pveSelNode: '{pveSelNode}',
-		hidden: '{isLxc}',
-		disabled: '{isLxc}'
-	    }
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = me.getRecordValue('uptime');
-
-	var text = "";
-	if (Number(uptime) > 0) {
-	    text = " (" + gettext('Uptime') + ': ' + Proxmox.Utils.format_duration_long(uptime)
-		+ ')';
-	}
-
-	me.setTitle(me.getRecordValue('name') + text);
-    }
-});
-/*
- * This is a running chart widget
- * you add time datapoints to it,
- * and we only show the last x of it
- * used for ceph performance charts
- */
-Ext.define('PVE.widget.RunningChart', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveRunningChart',
-
-    layout: {
-	type: 'hbox',
-	align: 'center'
-    },
-    items: [
-	{
-	    width: 80,
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}:</h3>'
-	},
-	{
-	    flex: 1,
-	    xtype: 'cartesian',
-	    height: '100%',
-	    itemId: 'chart',
-	    border: false,
-	    axes: [
-		{
-		    type: 'numeric',
-		    position: 'left',
-		    hidden: true,
-		    minimum: 0
-		},
-		{
-		    type: 'numeric',
-		    position: 'bottom',
-		    hidden: true
-		}
-	    ],
-
-	    store: {
-		data: {}
-	    },
-
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '0 B/s',
-		textAlign: 'end',
-		textBaseline: 'middle',
-		fontSize: 14
-	    }],
-
-	    series: [{
-		type: 'line',
-		xField: 'time',
-		yField: 'val',
-		fill: 'true',
-		colors: ['#cfcfcf'],
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function( tooltip, record, ctx) {
-			var me = this.getChart();
-			var date = new Date(record.data.time);
-			var value = me.up().renderer(record.data.val);
-			tooltip.setHtml(
-			    me.up().title + ': ' + value + '<br />' +
-			    Ext.Date.format(date, 'H:i:s')
-			);
-		    }
-		},
-		style: {
-		    lineWidth: 1.5,
-		    opacity: 0.60
-		},
-		marker: {
-		    opacity: 0,
-		    scaling: 0.01,
-		    fx: {
-			duration: 200,
-			easing: 'easeOut'
-		    }
-		},
-		highlightCfg: {
-		    opacity: 1,
-		    scaling: 1.5
-		}
-	    }]
-	}
-    ],
-
-    // the renderer for the tooltip and last value,
-    // default just the value
-    renderer: Ext.identityFn,
-
-    // show the last x seconds
-    // default is 5 minutes
-    timeFrame: 5*60,
-
-    addDataPoint: function(value, time) {
-	var me = this.chart;
-	var panel = me.up();
-	var now = new Date();
-	var begin = new Date(now.getTime() - (1000*panel.timeFrame));
-
-	me.store.add({
-	    time: time || now.getTime(),
-	    val: value || 0
-	});
-
-	// delete all old records when we have 20 times more datapoints
-	// than seconds in our timeframe (so even a subsecond graph does
-	// not trigger this often)
-	//
-	// records in the store do not take much space, but like this,
-	// we prevent a memory leak when someone has the site open for a long time
-	// with minimal graphical glitches
-	if (me.store.count() > panel.timeFrame * 20) {
-	    var oldData = me.store.getData().createFiltered(function(item) {
-		return item.data.time < begin.getTime();
-	    });
-
-	    me.store.remove(oldData.getRange());
-	}
-
-	me.timeaxis.setMinimum(begin.getTime());
-	me.timeaxis.setMaximum(now.getTime());
-	me.valuesprite.setText(panel.renderer(value || 0).toString());
-	me.valuesprite.setAttributes({
-	    x: me.getWidth() - 15,
-	    y: me.getHeight()/2
-	}, true);
-	me.redraw();
-    },
-
-    setTitle: function(title) {
-	this.title = title;
-	var me = this.getComponent('title');
-	me.update({title: title});
-    },
-
-    initComponent: function(){
-	var me = this;
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.chart = me.getComponent('chart');
-	me.chart.timeaxis = me.chart.getAxes()[1];
-	me.chart.valuesprite = me.chart.getSurface('chart').get('valueSprite');
-	if (me.color) {
-	    me.chart.series[0].setStyle({
-		fill: me.color,
-		stroke: me.color
-	    });
-	}
-    }
-});
-Ext.define('PVE.widget.Info',{
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveInfoWidget',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    value: 0,
-    maximum: 1,
-    printBar: true,
-    items: [
-	{
-	    xtype: 'component',
-	    itemId: 'label',
-	    data: {
-		title: '',
-		usage: '',
-		iconCls: undefined
-	    },
-	    tpl: [
-		'<div class="left-aligned">',
-		'<tpl if="iconCls">',
-		'<i class="{iconCls}"></i> ',
-		'</tpl>',
-		'{title}</div>&nbsp;<div class="right-aligned">{usage}</div>'
-	    ]
-	},
-	{
-	    height: 2,
-	    border: 0
-	},
-	{
-	    xtype: 'progressbar',
-	    itemId: 'progress',
-	    height: 5,
-	    value: 0,
-	    animate: true
-	}
-    ],
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-
-    setPrintBar: function(enable) {
-	var me = this;
-	me.printBar = enable;
-	me.getComponent('progress').setVisible(enable);
-    },
-
-    setIconCls: function(iconCls) {
-	var me = this;
-	me.getComponent('label').data.iconCls = iconCls;
-    },
-
-    updateValue: function(text, usage) {
-	var me = this;
-	var label = me.getComponent('label');
-	label.update(Ext.apply(label.data, {title: me.title, usage:text}));
-
-	if (usage !== undefined &&
-	    me.printBar &&
-	    Ext.isNumeric(usage) &&
-	    usage >= 0) {
-	    var progressBar = me.getComponent('progress');
-	    progressBar.updateProgress(usage, '');
-	    if (usage > me.criticalThreshold) {
-		progressBar.removeCls('warning');
-		progressBar.addCls('critical');
-	    } else if (usage > me.warningThreshold) {
-		progressBar.removeCls('critical');
-		progressBar.addCls('warning');
-	    } else {
-		progressBar.removeCls('warning');
-		progressBar.removeCls('critical');
-	    }
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.title) {
-	    throw "no title defined";
-	}
-
-	me.callParent();
-
-	me.getComponent('progress').setVisible(me.printBar);
-
-	me.updateValue(me.text, me.value);
-	me.setIconCls(me.iconCls);
-    }
-
-});
-Ext.define('PVE.panel.TemplateStatusView',{
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveTemplateStatusView',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	printBar: false,
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    itemId: 'node',
-	    iconCls: 'fa fa-fw fa-building',
-	    title: gettext('Node')
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'cpus',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('Processors'),
-	    textField: 'cpus'
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory'),
-	    textField: 'maxmem',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'swap',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('Swap'),
-	    textField: 'maxswap',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'disk',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    textField: 'maxdisk',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var name = me.pveSelNode.data.name;
-	if (!name) {
-	    throw "no name specified";
-	}
-
-	me.title = name;
-
-	me.callParent();
-	if (me.pveSelNode.data.type !== 'lxc') {
-	    me.remove(me.getComponent('swap'));
-	}
-	me.getComponent('node').updateValue(me.pveSelNode.data.node);
-    }
-});
-Ext.define('PVE.widget.HealthWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveHealthWidget',
-
-    data: {
-	iconCls: PVE.Utils.get_health_icon(undefined, true),
-	text: '',
-	title: ''
-    },
-
-    style: {
-	'text-align':'center'
-    },
-
-    tpl: [
-	'<h3>{title}</h3>',
-	'<i class="fa fa-5x {iconCls}"></i>',
-	'<br /><br/>',
-	'{text}'
-    ],
-
-    updateHealth: function(data) {
-	var me = this;
-	me.update(Ext.apply(me.data, data));
-    },
-
-    initComponent: function(){
-	var me = this;
-
-	if (me.title) {
-	    me.config.data.title = me.title;
-	}
-
-	me.callParent();
-    }
-
-});
-/*global u2f*/
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onLogon: function() {
-	    var me = this;
-
-	    var form = this.lookupReference('loginForm');
-	    var unField = this.lookupReference('usernameField');
-	    var saveunField = this.lookupReference('saveunField');
-	    var view = this.getView();
-
-	    if (!form.isValid()) {
-		return;
-	    }
-
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
-	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
-
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
-
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
-
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
-			} else {
-			    me.perform_otp();
-			}
-		    } else {
-			me.success(data);
-		    }
-		}
-	    });
-
-	},
-	failure: function(resp) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.unmask();
-	    var handler = function() {
-		var uf = me.lookupReference('usernameField');
-		uf.focus(true, true);
-	    };
-
-	    Ext.MessageBox.alert(gettext('Error'),
-				 gettext("Login failed. Please try again"),
-				 handler);
-	},
-	success: function(data) {
-	    var me = this;
-	    var view = me.getView();
-	    var handler = view.handler || Ext.emptyFn;
-	    handler.call(me, data);
-	    view.close();
-	},
-
-	perform_otp: function() {
-	    var me = this;
-	    var win = Ext.create('PVE.window.TFALoginWindow', {
-		onLogin: function(value) {
-		    me.finish_tfa(value);
-		},
-		onCancel: function() {
-		    Proxmox.LoggedOut = false;
-		    Proxmox.Utils.authClear();
-		    me.getView().show();
-		}
-	    });
-	    win.show();
-	},
-
-	perform_u2f: function(data) {
-	    var me = this;
-	    // Show the message:
-	    var msg = Ext.Msg.show({
-		title: 'U2F: '+gettext('Verification'),
-		message: gettext('Please press the button on your U2F Device'),
-		buttons: []
-	    });
-	    var chlg = data.U2FChallenge;
-	    var key = {
-		version: chlg.version,
-		keyHandle: chlg.keyHandle
-	    };
-	    u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
-		msg.close();
-		if (res.errorCode) {
-		    Proxmox.Utils.authClear();
-		    Ext.Msg.alert(gettext('Error'), PVE.Utils.render_u2f_error(res.errorCode));
-		    return;
-		}
-		delete res.errorCode;
-		me.finish_tfa(JSON.stringify(res));
-	    });
-	},
-	finish_tfa: function(res) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-	    var params = { response: res };
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'POST',
-		timeout: 5000, // it'll delay both success & failure
-		success: function(resp, opts) {
-		    view.el.unmask();
-		    // Fill in what we copy over from the 1st factor:
-		    var data = resp.result.data;
-		    data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-		    data.username = Proxmox.UserName;
-		    // Finish logging in:
-		    me.success(data);
-		},
-		failure: function(resp, opts) {
-		    Proxmox.Utils.authClear();
-		    me.failure(resp);
-		}
-	    });
-	},
-
-	control: {
-	    'field[name=username]': {
-		specialkey: function(f, e) {
-		    if (e.getKey() === e.ENTER) {
-			var pf = this.lookupReference('passwordField');
-			if (!pf.getValue()) {
-			    pf.focus(false);
-			}
-		    }
-		}
-	    },
-	    'field[name=lang]': {
-		change: function(f, value) {
-		    var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-		    Ext.util.Cookies.set('PVELangCookie', value, dt);
-		    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
-		    window.location.reload();
-		}
-	    },
-            'button[reference=loginButton]': {
-		click: 'onLogon'
-            },
-	    '#': {
-		show: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var checkboxField = this.lookupReference('saveunField');
-		    var unField = this.lookupReference('usernameField');
-
-		    var checked = sp.get(checkboxField.getStateId());
-		    checkboxField.setValue(checked);
-
-		    if(checked === true) {
-			var username = sp.get(unField.getStateId());
-			unField.setValue(username);
-			var pwField = this.lookupReference('passwordField');
-			pwField.focus();
-		    }
-		}
-	    }
-	}
-    },
-
-    width: 400,
-
-    modal: true,
-
-    border: false,
-
-    draggable: true,
-
-    closable: false,
-
-    resizable: false,
-
-    layout: 'auto',
-
-    title: gettext('Proxmox VE Login'),
-
-    defaultFocus: 'usernameField',
-
-    defaultButton: 'loginButton',
-
-    items: [{
-	xtype: 'form',
-	layout: 'form',
-	url: '/api2/extjs/access/ticket',
-	reference: 'loginForm',
-
-	fieldDefaults: {
-	    labelAlign: 'right',
-	    allowBlank: false
-	},
-
-	items: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('User name'),
-		name: 'username',
-		itemId: 'usernameField',
-		reference: 'usernameField',
-		stateId: 'login-username'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		fieldLabel: gettext('Password'),
-		name: 'password',
-		reference: 'passwordField'
-	    },
-	    {
-		xtype: 'pveRealmComboBox',
-		name: 'realm'
-	    },
-	    {
-		xtype: 'proxmoxLanguageSelector',
-		fieldLabel: gettext('Language'),
-		value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
-		name: 'lang',
-		reference: 'langField',
-		submitValue: false
-	    }
-	],
-	buttons: [
-	    {
-		xtype: 'checkbox',
-		fieldLabel: gettext('Save User name'),
-		name: 'saveusername',
-		reference: 'saveunField',
-		stateId: 'login-saveusername',
-		labelWidth: 'auto',
-		labelAlign: 'right',
-		submitValue: false
-	    },
-	    {
-		text: gettext('Login'),
-		reference: 'loginButton'
-	    }
-	]
-    }]
- });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	login: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onLogin(me.lookup('otpField').getValue());
-	    view.close();
-	},
-	cancel: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onCancel();
-	    view.close();
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Please enter your OTP verification code:'),
-	    name: 'otp',
-	    itemId: 'otpField',
-	    reference: 'otpField',
-	    allowBlank: false
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Login'),
-	    reference: 'loginButton',
-	    handler: 'login'
-	},
-	{
-	    text: gettext('Cancel'),
-	    handler: 'cancel'
-	}
-    ]
-});
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-
-    activeTitle: '', // used for automated testing
-
-    width: 700,
-    height: 510,
-
-    modal: true,
-    border: false,
-
-    draggable: true,
-    closable: true,
-    resizable: false,
-
-    layout: 'border',
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var tabs = me.items || [];
-	delete me.items;
-	
-	/* 
-	 * Items may have the following functions:
-	 * validator(): per tab custom validation
-	 * onSubmit(): submit handler
-	 * onGetValues(): overwrite getValues results
-	 */
-
-	Ext.Array.each(tabs, function(tab) {
-	    tab.disabled = true;
-	});
-	tabs[0].disabled = false;
-
-	var maxidx = 0;
-	var curidx = 0;
-
-	var check_card = function(card) {
-	    var valid = true;
-	    var fields = card.query('field, fieldcontainer');
-	    if (card.isXType('fieldcontainer')) {
-		fields.unshift(card);
-	    }
-	    Ext.Array.each(fields, function(field) {
-		// Note: not all fielcontainer have isValid()
-		if (Ext.isFunction(field.isValid) && !field.isValid()) {
-		    valid = false;
-		}
-	    });
-
-	    if (Ext.isFunction(card.validator)) {
-		return card.validator();
-	    }
-
-	    return valid;
-	};
-
-	var disable_at = function(card) {
-	    var tp = me.down('#wizcontent');
-	    var idx = tp.items.indexOf(card);
-	    for(;idx < tp.items.getCount();idx++) {
-		var nc = tp.items.getAt(idx);
-		if (nc) {
-		    nc.disable();
-		}
-	    }
-	};
-
-	var tabchange = function(tp, newcard, oldcard) {
-	    if (newcard.onSubmit) {
-		me.down('#next').setVisible(false);
-		me.down('#submit').setVisible(true); 
-	    } else {
-		me.down('#next').setVisible(true);
-		me.down('#submit').setVisible(false); 
-	    }
-	    var valid = check_card(newcard);
-	    me.down('#next').setDisabled(!valid);    
-	    me.down('#submit').setDisabled(!valid);    
-	    me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-	    var idx = tp.items.indexOf(newcard);
-	    if (idx > maxidx) {
-		maxidx = idx;
-	    }
-	    curidx = idx;
-
-	    var next = idx + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (valid && ntab && !newcard.onSubmit) {
-		ntab.enable();
-	    }
-	};
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, true, false);
-	}
-
-	var sp = Ext.state.Manager.getProvider();
-	var advchecked = sp.get('proxmox-advanced-cb');
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'form',
-		    region: 'center',
-		    layout: 'fit',
-		    border: false,
-		    margins: '5 5 0 5',
-		    fieldDefaults: {
-			labelWidth: 100,
-			anchor: '100%'
-		    },
-		    items: [{
-			itemId: 'wizcontent',
-			xtype: 'tabpanel',
-			activeItem: 0,
-			bodyPadding: 10,
-			listeners: {
-			    afterrender: function(tp) {
-				var atab = this.getActiveTab();
-				tabchange(tp, atab);
-			    },
-			    tabchange: function(tp, newcard, oldcard) {
-				tabchange(tp, newcard, oldcard);
-			    }
-			},
-			items: tabs
-		    }]
-		}
-	    ],
-	    fbar: [
-		{
-		    xtype: 'proxmoxHelpButton',
-		    itemId: 'help'
-		},
-		'->',
-		{
-		    xtype: 'proxmoxcheckbox',
-		    boxLabelAlign: 'before',
-		    boxLabel: gettext('Advanced'),
-		    value: advchecked,
-		    listeners: {
-			change: function(cb, val) {
-			    var tp = me.down('#wizcontent');
-			    tp.query('inputpanel').forEach(function(ip) {
-				ip.setAdvancedVisible(val);
-			    });
-
-			    sp.set('proxmox-advanced-cb', val);
-			}
-		    }
-		},
-		{
-		    text: gettext('Back'),
-		    disabled: true,
-		    itemId: 'back',
-		    minWidth: 60,
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			var prev = tp.items.indexOf(atab) - 1;
-			if (prev < 0) {
-			    return;
-			}
-			var ntab = tp.items.getAt(prev);
-			if (ntab) {
-			    tp.setActiveTab(ntab);
-			}
-		    }
-		},
-		{
-		    text: gettext('Next'),
-		    disabled: true,
-		    itemId: 'next',
-		    minWidth: 60,
-		    handler: function() {
-
-			var form = me.down('form').getForm();
-
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			if (!check_card(atab)) {
-			    return;
-			}
-
-			var next = tp.items.indexOf(atab) + 1;
-			var ntab = tp.items.getAt(next);
-			if (ntab) {
-			    ntab.enable();
-			    tp.setActiveTab(ntab);
-			}
-
-		    }
-		},
-		{
-		    text: gettext('Finish'),
-		    minWidth: 60,
-		    hidden: true,
-		    itemId: 'submit',
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			atab.onSubmit();
-		    }
-		}
-	    ]
-	});
-	me.callParent();
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setAdvancedVisible(advchecked);
-	});
-
-	Ext.Array.each(me.query('field'), function(field) {
-	    var validcheck = function() {
-		var tp = me.down('#wizcontent');
-
-		// check tabs from current to the last enabled for validity
-		// since we might have changed a validity on a later one
-		var i;
-		for (i = curidx; i <= maxidx && i < tp.items.getCount(); i++) {
-		    var tab = tp.items.getAt(i);
-		    var valid = check_card(tab);
-
-		    // only set the buttons on the current panel
-		    if (i === curidx) {
-			me.down('#next').setDisabled(!valid);
-			me.down('#submit').setDisabled(!valid);
-		    }
-
-		    // if a panel is invalid, then disable it and all following,
-		    // else enable it and go to the next
-		    var ntab = tp.items.getAt(i + 1);
-		    if (!valid) {
-			disable_at(ntab);
-			return;
-		    } else if (ntab && !tab.onSubmit) {
-			ntab.enable();
-		    }
-		}
-	    };
-	    field.on('change', validcheck);
-	    field.on('validitychange', validcheck);
-	});
-    }
-});
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    title: gettext('Notes'),
-	    width: 600,
-	    height: '400px',
-	    resizable: true,
-	    layout: 'fit',
-	    defaultButton: undefined,
-	    items: {
-		xtype: 'textarea',
-		name: 'description',
-		height: '100%',
-		value: '',
-		hideLabel: true
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: me.storage,
-	    fieldLabel: gettext('Storage'),
-	    storageContent: 'backup',
-	    allowBlank: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		storagesel,
-		{
-		    xtype: 'pveBackupModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    value: 'snapshot',
-		    name: 'mode'
-		},
-		{
-		    xtype: 'pveCompressionSelector',
-		    name: 'compress',
-		    value: 'lzo',
-		    fieldLabel: gettext('Compression')
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Send email to'),
-		    name: 'mailto',
-		    emptyText: Proxmox.Utils.noneText
-		}
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Backup'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid,
-		    mode: values.mode,
-		    remove: 0
-		};
-
-		if ( values.mailto ) {
-		    params.mailto = values.mailto;
-		}
-
-		if (values.compress) {
-		    params.compress = values.compress;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/vzdump',
-		    params: params,
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			// close later so we reload the grid
-			// after the task has completed
-			me.hide();
-
-			var upid = response.result.data;
-			
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				close: function() {
-				    me.close();
-				}
-			    }
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var helpBtn = Ext.create('Proxmox.button.Help', {
-	    onlineHelp: 'chapter_vzdump',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	});
-
-	var title = gettext('Backup') + " " + 
-	    ((me.vmtype === 'lxc') ? "CT" : "VM") +
-	    " " + me.vmid;
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 350,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ helpBtn, '->', submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: Proxmox.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.volid) {
-	    throw "no volume ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no vmtype specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: '',
-	    fieldLabel: gettext('Storage'),
-	    storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-	    allowBlank: true
-	});
-
-	var IDfield;
-	if (me.vmid) {
-	    IDfield = Ext.create('Ext.form.field.Display', {
-		name: 'vmid',
-		value: me.vmid,
-		fieldLabel: (me.vmtype === 'lxc') ? 'CT' : 'VM'
-	    });
-	} else {
-	    IDfield = Ext.create('PVE.form.GuestIDSelector', {
-		name: 'vmid',
-		guestType: me.vmtype,
-		loadNextFreeID: true,
-		validateExists: false
-	    });
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		value: me.volidText || me.volid,
-		fieldLabel: gettext('Source')
-	    },
-	    storagesel,
-	    IDfield,
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'bwlimit',
-		fieldLabel: gettext('Read Limit (MiB/s)'),
-		minValue: 0,
-		emptyText: gettext('Defaults to target storage restore limit'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext("Use '0' to disable all bandwidth limits.")
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'unique',
-		fieldLabel: gettext('Unique'),
-		hidden: !!me.vmid,
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext('Autogenerate unique properties, e.g., MAC addresses')
-		},
-		checked: false
-	    }
-	];
-
-	/*jslint confusion: true*/
-	if (me.vmtype === 'lxc') {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'unprivileged',
-		value: true,
-		fieldLabel: gettext('Unprivileged container')
-	    });
-	}
-	/*jslint confusion: false*/
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doRestore = function(url, params) {
-	    Proxmox.Utils.API2Request({
-		url: url,
-		params: params,
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.close();
-		}
-	    });
-	};
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Restore'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid || values.vmid,
-		    force: me.vmid ? 1 : 0
-		};
-		if (values.unique) { params.unique = 1; }
-
-		if (values.bwlimit !== undefined) {
-		    params.bwlimit = values.bwlimit * 1024;
-		}
-
-		var url;
-		var msg;
-		if (me.vmtype === 'lxc') {
-		    url = '/nodes/' + me.nodename + '/lxc';
-		    params.ostemplate = me.volid;
-		    params.restore = 1;
-		    if (values.unprivileged) { params.unprivileged = 1; }
-		    msg = Proxmox.Utils.format_task_description('vzrestore', params.vmid);
-		} else if (me.vmtype === 'qemu') {
-		    url = '/nodes/' + me.nodename + '/qemu';
-		    params.archive = me.volid;
-		    msg = Proxmox.Utils.format_task_description('qmrestore', params.vmid);
-		} else {
-		    throw 'unknown VM type';
-		}
-
-		if (me.vmid) {
-		    msg += '. ' + gettext('This will permanently erase current VM data.');
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRestore(url, params);
-		    });
-		} else {
-		    doRestore(url, params);
-		}
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-	var title =  gettext('Restore') + ": " + (
-	    (me.vmtype === 'lxc') ? 'CT' : 'VM');
-
-	if (me.vmid) {
-	    title += " " + me.vmid;
-	}
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 500,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-/* Popup a message window
- * where the user has to manually enter the resource ID
- * to enable the destroy button
- */
-Ext.define('PVE.window.SafeDestroy', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSafeDestroy',
-
-    title: gettext('Confirm'),
-    modal: true,
-    buttonAlign: 'center',
-    bodyPadding: 10,
-    width: 450,
-    layout: { type:'hbox' },
-    defaultFocus: 'confirmField',
-    showProgress: false,
-
-    config: {
-	item: {
-	    id: undefined,
-	    type: undefined
-	},
-	url: undefined,
-	params: {}
-    },
-
-    getParams: function() {
-	var me = this;
-	if (Ext.Object.isEmpty(me.params)) {
-	    return '';
-	}
-	return '?' + Ext.Object.toQueryString(me.params);
-    },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=confirm]': {
-		change: function(f, value) {
-		    var view = this.getView();
-		    var removeButton = this.lookupReference('removeButton');
-		    if (value === view.getItem().id.toString()) {
-			removeButton.enable();
-		    } else {
-			removeButton.disable();
-		    }
-		},
-		specialkey: function (field, event) {
-		    var removeButton = this.lookupReference('removeButton');
-		    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
-			removeButton.fireEvent('click', removeButton, event);
-		    }
-		}
-	    },
-           'button[reference=removeButton]': {
-		click: function() {
-		    var view = this.getView();
-		    Proxmox.Utils.API2Request({
-			url: view.getUrl() + view.getParams(),
-			method: 'DELETE',
-			waitMsgTarget: view,
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var hasProgressBar = view.showProgress &&
-				response.result.data ? true : false;
-
-			    if (hasProgressBar) {
-				// stay around so we can trigger our close events
-				// when background action is completed
-				view.hide();
-
-				var upid = response.result.data;
-				var win = Ext.create('Proxmox.window.TaskProgress', {
-				    upid: upid,
-				    listeners: {
-					destroy: function () {
-					    view.close();
-					}
-				    }
-				});
-				win.show();
-			    } else {
-				view.close();
-			    }
-			}
-		    });
-		}
-            }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    cls: [ Ext.baseCSSPrefix + 'message-box-icon',
-		   Ext.baseCSSPrefix + 'message-box-warning',
-		   Ext.baseCSSPrefix + 'dlg-icon']
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    xtype: 'component',
-		    reference: 'messageCmp'
-		},
-		{
-		    itemId: 'confirmField',
-		    reference: 'confirmField',
-		    xtype: 'textfield',
-		    name: 'confirm',
-		    labelWidth: 300,
-		    hideTrigger: true,
-		    allowBlank: false
-		}
-	    ]
-	}
-    ],
-    buttons: [
-	{
-	    reference: 'removeButton',
-	    text: gettext('Remove'),
-	    disabled: true
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	var item = me.getItem();
-
-	if (!Ext.isDefined(item.id)) {
-	    throw "no ID specified";
-	}
-
-	if (!Ext.isDefined(item.type)) {
-	    throw "no VM type specified";
-	}
-
-	var messageCmp = me.lookupReference('messageCmp');
-	var msg;
-
-	if (item.type === 'VM') {
-	    msg = Proxmox.Utils.format_task_description('qmdestroy', item.id);
-	} else if (item.type === 'CT') {
-	    msg = Proxmox.Utils.format_task_description('vzdestroy', item.id);
-	} else if (item.type === 'CephPool') {
-	    msg = Proxmox.Utils.format_task_description('cephdestroypool', item.id);
-	} else if (item.type === 'Image') {
-	    msg = Proxmox.Utils.format_task_description('unknownimgdel', item.id);
-	} else {
-	    throw "unknown item type specified";
-	}
-
-	messageCmp.setHtml(msg);
-
-	var confirmField = me.lookupReference('confirmField');
-	msg = gettext('Please enter the ID to confirm') +
-	    ' (' + item.id + ')';
-	confirmField.setFieldLabel(msg);
-    }
-});
-Ext.define('PVE.window.BackupConfig', {
-    extend: 'Ext.window.Window',
-    title: gettext('Configuration'),
-    width: 600,
-    height: 400,
-    layout: 'fit',
-    modal: true,
-    items: {
-	xtype: 'component',
-	itemId: 'configtext',
-	autoScroll: true,
-	style: {
-	    'background-color': 'white',
-	    'white-space': 'pre',
-	    'font-family': 'monospace',
-	    padding: '5px'
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.volume) {
-	    throw "no volume specified";
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + nodename + "/vzdump/extractconfig",
-	    method: 'GET',
-	    params: {
-		volume: me.volume
-	    },
-	    failure: function(response, opts) {
-		me.close();
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response,options) {
-		me.show();
-		me.down('#configtext').update(Ext.htmlEncode(response.result.data));
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.Settings', {
-    extend: 'Ext.window.Window',
-
-    width: '800px',
-    title: gettext('My Settings'),
-    iconCls: 'fa fa-gear',
-    modal: true,
-    bodyPadding: 10,
-    resizable: false,
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    onlineHelp: 'gui_my_settings',
-	    hidden: false
-	},
-	'->',
-	{
-	    text: gettext('Close'),
-	    handler: function() {
-		this.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    var me = this;
-	    var sp = Ext.state.Manager.getProvider();
-
-	    var username = sp.get('login-username') || Proxmox.Utils.noneText;
-	    me.lookupReference('savedUserName').setValue(username);
-
-	    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-	    settings.forEach(function(setting) {
-		var val = localStorage.getItem('pve-xterm-' + setting);
-		if (val !== undefined && val !== null) {
-		    var field = me.lookup(setting);
-		    field.setValue(val);
-		    field.resetOriginalValue();
-		}
-	    });
-	},
-
-	set_button_status: function() {
-	    var me = this;
-
-	    var form = me.lookup('xtermform');
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-
-	    var hasvalues = false;
-	    var values = form.getValues();
-	    Ext.Object.eachValue(values, function(value) {
-		if (value) {
-		    hasvalues = true;
-		    return false;
-		}
-	    });
-
-	    me.lookup('xtermsave').setDisabled(!dirty || !valid);
-	    me.lookup('xtermreset').setDisabled(!hasvalues);
-	},
-
-	control: {
-	    '#xtermjs form': {
-		dirtychange: 'set_button_status',
-		validitychange: 'set_button_status'
-	    },
-	    '#xtermjs button': {
-		click: function(button) {
-		    var me = this;
-		    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-		    settings.forEach(function(setting) {
-			var field = me.lookup(setting);
-			if (button.reference === 'xtermsave') {
-			    var value = field.getValue();
-			    if (value) {
-				localStorage.setItem('pve-xterm-' + setting, value);
-			    } else {
-				localStorage.removeItem('pve-xterm-' + setting);
-			    }
-			} else if (button.reference === 'xtermreset') {
-			    field.setValue(undefined);
-			    localStorage.removeItem('pve-xterm-' + setting);
-			}
-			field.resetOriginalValue();
-		    });
-		    me.set_button_status();
-		}
-	    },
-	    'button[name=reset]': {
-		click: function () {
-		    var blacklist = ['GuiCap', 'login-username', 'dash-storages'];
-		    var sp = Ext.state.Manager.getProvider();
-		    var state;
-		    for (state in sp.state) {
-			if (sp.state.hasOwnProperty(state)) {
-			    if (blacklist.indexOf(state) !== -1) {
-				continue;
-			    }
-
-			    sp.clear(state);
-			}
-		    }
-
-		    window.location.reload();
-		}
-	    },
-	    'button[name=clear-username]': {
-		click: function () {
-		    var me = this;
-		    var usernamefield = me.lookupReference('savedUserName');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    usernamefield.setValue(Proxmox.Utils.noneText);
-		    sp.clear('login-username');
-		}
-	    },
-	    'grid[reference=dashboard-storages]': {
-		selectionchange: function(grid, selected) {
-		    var me = this;
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // saves the selected storageids as
-		    // "id1,id2,id3,..."
-		    // or clears the variable
-		    if (selected.length > 0) {
-			sp.set('dash-storages',
-			    Ext.Array.pluck(selected, 'id').join(','));
-		    } else {
-			sp.clear('dash-storages');
-		    }
-		},
-		afterrender: function(grid) {
-		    var me = grid;
-		    var sp = Ext.state.Manager.getProvider();
-		    var store = me.getStore();
-		    var items = [];
-		    me.suspendEvent('selectionchange');
-		    var storages = sp.get('dash-storages') || '';
-		    storages.split(',').forEach(function(storage){
-			// we have to get the records
-			// to be able to select them
-			if (storage !== '') {
-			    var item = store.getById(storage);
-			    if (item) {
-				items.push(item);
-			    }
-			}
-		    });
-		    me.getSelectionModel().select(items);
-		    me.resumeEvent('selectionchange');
-		}
-	    }
-	}
-    },
-
-    items: [{
-	    xtype: 'fieldset',
-	    width: '50%',
-	    title: gettext('Webinterface Settings'),
-	    margin: '5',
-	    layout: {
-		type: 'vbox',
-		align: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Dashboard Storages'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'grid',
-		    maxHeight: 150,
-		    reference: 'dashboard-storages',
-		    selModel: {
-			selType: 'checkboxmodel'
-		    },
-		    columns: [{
-			header: gettext('Name'),
-			dataIndex: 'storage',
-			flex: 1
-		    },{
-			header: gettext('Node'),
-			dataIndex: 'node',
-			flex: 1
-		    }],
-		    store: {
-			type: 'diff',
-			field: ['type', 'storage', 'id', 'node'],
-			rstore: PVE.data.ResourceStore,
-			filters: [{
-			    property: 'type',
-			    value: 'storage'
-			}],
-			sorters: [ 'node','storage']
-		    }
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Saved User name'),
-		    labelAlign: 'left',
-		    labelWidth: '50%',
-		    stateId: 'login-username',
-		    reference: 'savedUserName',
-		    value: ''
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Clear User name'),
-		    width: 'auto',
-		    name: 'clear-username'
-		},
-		{
-		    xtype: 'box',
-		    autoEl: { tag: 'hr'}
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Layout'),
-		    labelAlign: 'left',
-		    labelWidth: '50%'
-		},
-		{
-		    xtype: 'button',
-		    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-		    text: gettext('Reset Layout'),
-		    width: 'auto',
-		    name: 'reset'
-		}
-	    ]
-    },{
-	xtype: 'fieldset',
-	itemId: 'xtermjs',
-	width: '50%',
-	margin: '5',
-	title: gettext('xterm.js Settings'),
-	items: [{
-	    xtype: 'form',
-	    reference: 'xtermform',
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		algin: 'left'
-	    },
-	    defaults: {
-		width: '100%',
-		margin: '0 0 10 0'
-	    },
-	    items: [
-		{
-		    xtype: 'textfield',
-		    name: 'fontFamily',
-		    reference: 'fontFamily',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Font-Family')
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    emptyText: Proxmox.Utils.defaultText,
-		    name: 'fontSize',
-		    reference: 'fontSize',
-		    minValue: 1,
-		    fieldLabel: gettext('Font-Size')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'letterSpacing',
-		    reference: 'letterSpacing',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Letter Spacing')
-		},
-		{
-		    xtype: 'numberfield',
-		    name: 'lineHeight',
-		    minValue: 0.1,
-		    reference: 'lineHeight',
-		    emptyText: Proxmox.Utils.defaultText,
-		    fieldLabel: gettext('Line Height')
-		},
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'hbox',
-			pack: 'end'
-		    },
-		    items: [
-			{
-			    xtype: 'button',
-			    reference: 'xtermreset',
-			    disabled: true,
-			    text: gettext('Reset')
-			},
-			{
-			    xtype: 'button',
-			    reference: 'xtermsave',
-			    disabled: true,
-			    text: gettext('Save')
-			}
-		    ]
-		}
-	    ]
-	}]
-    }],
-
-    onShow: function() {
-	var me = this;
-	me.callParent();
-    }
-});
-Ext.define('PVE.panel.StartupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'qm_startup_and_shutdown',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = PVE.Parser.printStartup(values);
-
-	if (res === undefined || res === '') {
-	    return { 'delete': 'startup' };
-	}
-
-	return { startup: res };
-    },
-
-    setStartup: function(value) {
-	var me = this;
-
-	var startup = PVE.Parser.parseStartup(value);
-	if (startup) {
-	    me.setValues(startup);
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		name: 'order',
-		defaultValue: '',
-		emptyText: 'any',
-		fieldLabel: gettext('Start/Shutdown order')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'up',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Startup delay')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'down',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Shutdown timeout')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.window.StartupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveWindowStartupEdit',
-    onlineHelp: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-	var ipanelConfig = me.onlineHelp ? {onlineHelp: me.onlineHelp} : {};
-	var ipanel = Ext.create('PVE.panel.StartupInputPanel', ipanelConfig);
-
-	Ext.applyIf(me, {
-	    subject: gettext('Start/Shutdown order'),
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		ipanel.setStartup(me.vmconfig.startup);		    
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.Install', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveCephInstallWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 220,
-    header: false,
-    resizable: false,
-    draggable: false,
-    modal: true,
-    nodename: undefined,
-    shadow: false,
-    border: false,
-    bodyBorder: false,
-    closable: false,
-    cls: 'install-mask',
-    bodyCls: 'install-mask',
-    layout: {
-        align: 'stretch',
-        pack: 'center',
-	type: 'vbox'
-    },
-    viewModel: {
-	data: {
-	      cephVersion: 'nautilus',
-	      isInstalled: false
-	},
-	formulas: {
-	    buttonText: function (get){
-		if (get('isInstalled')) {
-		    return gettext('Configure Ceph');
-		} else {
-		    return gettext('Install Ceph-') + get('cephVersion');
-		}
-	    },
-	    windowText: function (get) {
-		if (get('isInstalled')) {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not initialized.'), 'Ceph') + ' '+
-		    gettext('You need to create a initial config once.') + '</p>';
-		} else {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '<br>' +
-		    gettext('Would you like to install it now?') + '</p>';
-		}
-	    }
-	}
-    },
-    items: [
-	{
-	    bind: {
-		html: '{windowText}'
-	    },
-	    border: false,
-	    padding: 5,
-	    bodyCls: 'install-mask'
-
-	},
-	{
-	    xtype: 'button',
-	    bind: {
-		text: '{buttonText}'
-	    },
-	    viewModel: {},
-	    cbind: {
-		nodename: '{nodename}'
-	    },
-	    handler: function() {
-		var me = this.up('pveCephInstallWindow');
-		var win = Ext.create('PVE.ceph.CephInstallWizard',{
-		    nodename: me.nodename
-		});
-		win.getViewModel().set('isInstalled', this.getViewModel().get('isInstalled'));
-		win.show();
-		me.mon(win,'beforeClose', function(){
-		    me.fireEvent("cephInstallWindowClosed");
-		    me.close();
-		});
-
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallEnableEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveFirewallEnableEdit'],
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    subject: gettext('Firewall'),
-    cbindData: {
-	defaultValue: 0
-    },
-    width: 350,
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    uncheckedValue: 0,
-	    cbind: {
-		defaultValue: '{defaultValue}',
-		checked: '{defaultValue}'
-	    },
-	    deleteDefaultValue: false,
-	    fieldLabel: gettext('Firewall')
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'warning',
-	    userCls: 'pve-hint',
-	    value: gettext('Warning: Firewall still disabled at datacenter level!'),
-	    hidden: true
-	}
-    ],
-
-    beforeShow: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/cluster/firewall/options',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		if (!response.result.data.enable) {
-		    me.down('displayfield[name=warning]').setVisible(true);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallLograteInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveFirewallLograteInputPanel',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    reference: 'enable',
-	    fieldLabel: gettext('Enable'),
-	    value: true
-	},
-	{
-	    layout: 'hbox',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'numberfield',
-		    name: 'rate',
-		    fieldLabel: gettext('Log rate limit'),
-		    minValue: 1,
-		    maxValue: 99,
-		    allowBlank: false,
-		    flex: 2,
-		    value: 1
-		},
-		{
-		    xtype: 'box',
-		    html: '<div style="margin: auto; padding: 2.5px;"><b>/</b></div>'
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    name: 'unit',
-		    comboItems: [['second', 'second'], ['minute', 'minute'],
-			['hour', 'hour'], ['day', 'day']],
-		    allowBlank: false,
-		    flex: 1,
-		    value: 'second'
-		}
-	    ]
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'burst',
-	    fieldLabel: gettext('Log burst limit'),
-	    minValue: 1,
-	    maxValue: 99,
-	    value: 5
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var vals = {};
-	vals.enable = values.enable !== undefined ? 1 : 0;
-	vals.rate = values.rate + '/' + values.unit;
-	vals.burst = values.burst;
-	var properties = PVE.Parser.printPropertyString(vals, undefined);
-	if (properties == '') {
-	    return { 'delete': 'log_ratelimit' };
-	}
-	return { log_ratelimit: properties };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var properties = {};
-	if (values.log_ratelimit !== undefined) {
-	    properties = PVE.Parser.parsePropertyString(values.log_ratelimit, 'enable');
-	    if (properties.rate) {
-		var matches = properties.rate.match(/^(\d+)\/(second|minute|hour|day)$/);
-		if (matches) {
-		    properties.rate = matches[1];
-		    properties.unit = matches[2];
-		}
-	    }
-	}
-	me.callParent([properties]);
-    }
-});
-
-Ext.define('PVE.FirewallLograteEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveFirewallLograteEdit',
-
-    subject: gettext('Log rate limit'),
-
-    items: [{
-	xtype: 'pveFirewallLograteInputPanel'
-    }],
-    autoLoad: true
-});
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNotesView',
-
-    title: gettext("Notes"),
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 10,
-    scrollable: true,
-
-    tbar: {
-	itemId: 'tbar',
-	hidden: true,
-	items: [
-	    {
-		text: gettext('Edit'),
-		handler: function() {
-		    var me = this.up('panel');
-		    me.run_editor();
-		}
-	    }
-	]
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create('PVE.window.NotesEdit', {
-	    pveSelNode: me.pveSelNode,
-	    url: me.url
-	});
-	win.show();
-	win.on('destroy', me.load, me);
-    },
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data.description || '';
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    listeners: {
-	render: function(c) {
-	    var me = this;
-	    me.getEl().on('dblclick', me.run_editor, me);
-	}
-    },
-
-    tools: [{
-	type: 'gear',
-	handler: function() {
-	    var me = this.up('panel');
-	    me.run_editor();
-	}
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	if (!Ext.Array.contains(['node', 'qemu', 'lxc'], type)) {
-	    throw 'invalid type specified';
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid && type !== 'node') {
-	    throw "no VM ID specified";
-	}
-
-	me.url = '/api2/extjs/nodes/' + nodename + '/';
-
-	// add the type specific path if qemu/lxc
-	if (type === 'qemu' || type === 'lxc') {
-	    me.url += type + '/' + vmid + '/';
-	}
-
-	me.url += 'config';
-
-	me.callParent();
-	if (type === 'node') {
-	    me.down('#tbar').setVisible(true);
-	}
-	me.load();
-    }
-});
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    border: false,
-    defaultSorter: {
-	property: 'type',
-	direction: 'ASC'
-    },
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	var coldef = rstore.defaultColumns();
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: me.defaultSorter,
-	    proxy: { type: 'memory' }
-	});
-
-	var textfilter = '';
-
-	var textfilter_match = function(item) {
-	    var match = false;
-	    Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-		var v = item.data[field];
-		if (v !== undefined) {
-		    v = v.toLowerCase();
-		    if (v.indexOf(textfilter) >= 0) {
-			match = true;
-			return false;
-		    }
-		}
-	    });
-	    return match;
-	};
-
-	var updateGrid = function() {
-
-	    var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-	    
-	    //console.log("START GRID UPDATE " +  me.viewFilter);
-
-	    store.suspendEvents();
-
-	    var nodeidx = {};
-	    var gather_child_nodes = function(cn) {
-		if (!cn) {
-		    return;
-		}
-                var cs = cn.childNodes;
-		if (!cs) {
-		    return;
-		}
-		var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-		    var child = cs[i];
-		    var orgnode = rstore.data.get(child.data.id);
-		    if (orgnode) {
-			if ((!filterfn || filterfn(child)) &&
-			    (!textfilter || textfilter_match(child))) {
-			    nodeidx[child.data.id] = orgnode;
-			}
-		    }
-		    gather_child_nodes(child);
-		}
-	    };
-	    gather_child_nodes(me.pveSelNode);
-
-	    // remove vanished items
-	    var rmlist = [];
-	    store.each(function(olditem) {
-		var item = nodeidx[olditem.data.id];
-		if (!item) {
-		    //console.log("GRID REM UID: " + olditem.data.id);
-		    rmlist.push(olditem);
-		}
-	    });
-
-	    if (rmlist.length) {
-		store.remove(rmlist);
-	    }
-
-	    // add new items
-	    var addlist = [];
-	    var key;
-	    for (key in nodeidx) {
-		if (nodeidx.hasOwnProperty(key)) {
-		    var item = nodeidx[key];
-		
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var olditem = store.getById(item.data.id);
-		    var olditem = store.data.get(item.data.id);
-
-		    if (!olditem) {
-			//console.log("GRID ADD UID: " + item.data.id);
-			var info = Ext.apply({}, item.data);
-			var child = Ext.create(store.model, info);
-			addlist.push(item);
-			continue;
-		    }
-		    // try to detect changes
-		    var changes = false;
-		    var fieldkeys = PVE.data.ResourceStore.fieldNames;
-		    var fieldcount = fieldkeys.length;
-		    var fieldind;
-		    for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-			var field = fieldkeys[fieldind];
-			if (field != 'id' && item.data[field] != olditem.data[field]) {
-			    changes = true;
-			    //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-			    olditem.beginEdit();
-			    olditem.set(field, item.data[field]);
-			}
-		    }
-		    if (changes) {
-			olditem.endEdit(true);
-			olditem.commit(true); 
-		    }
-		}
-	    }
-
-	    if (addlist.length) {
-		store.add(addlist);
-	    }
-
-	    store.sort();
-
-	    store.resumeEvents();
-
-	    store.fireEvent('refresh', store);
-
-	    //console.log("END GRID UPDATE");
-	};
-
-	var filter_task = new Ext.util.DelayedTask(function(){
-	    updateGrid();
-	});
-
-	var load_cb = function() { 
-	    updateGrid(); 
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-resource',
-	    tbar: [
-		'->', 
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: textfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    var v = field.getValue();
-			    textfilter = v.toLowerCase();
-			    filter_task.delay(500);
-			}
-		    }
-		}
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		destroy: function() {
-		    rstore.un("load", load_cb);
-		}
-	    },
-            columns: coldef
-	});
-	me.callParent();
-	updateGrid();
-	rstore.on("load", load_cb);
-    }
-});
-Ext.define('PVE.pool.AddVM', {
-    extend: 'Proxmox.window.Edit',
-    width: 600,
-    height: 400,
-    isAdd: true,
-    isCreate: true,
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	var vmsField = Ext.create('Ext.form.field.Text', {
-	    name: 'vms',
-	    hidden: true,
-	    allowBlank: false
-	});
-
-	var vmStore = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property: 'vmid',
-		    order: 'ASC'
-		}
-	    ],
-	    filters: [
-		function(item) {
-		    return ((item.data.type === 'lxc' || item.data.type === 'qemu') && item.data.pool === '');
-		}
-	    ]
-	});
-
-	var vmGrid = Ext.create('widget.grid',{
-	    store: vmStore,
-	    border: true,
-	    height: 300,
-	    scrollable: true,
-	    selModel: {
-		selType: 'checkboxmodel',
-		mode: 'SIMPLE',
-		listeners: {
-		    selectionchange: function(model, selected, opts) {
-			var selectedVms = [];
-			selected.forEach(function(vm) {
-			    selectedVms.push(vm.data.vmid);
-			});
-			vmsField.setValue(selectedVms);
-		    }
-		}
-	    },
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-	Ext.apply(me, {
-	    subject: gettext('Virtual Machine'),
-	    items: [ vmsField, vmGrid ]
-	});
-
-	me.callParent();
-	vmStore.load();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.isCreate = true;
-	me.isAdd = true;
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	Ext.apply(me, {
-	    subject: gettext('Storage'),
-	    width: 350,
-	    items: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'storage',
-		    nodename: 'localhost',
-		    autoSelect: false,
-		    value:  '',
-		    fieldLabel: gettext("Storage")
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    stateful: true,
-    stateId: 'grid-pool-members',
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property : 'type',
-		    direction: 'ASC'
-		}
-	    ],
-	    proxy: {
-		type: 'proxmox',
-		root: 'data.members',
-		url: "/api2/json/pools/" + me.pool
-	    }
-	});
-
-	var coldef = PVE.data.ResourceStore.defaultColumns();
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		var params = { 'delete': 1 };
-		if (rec.data.type === 'storage') {
-		    params.storage = rec.data.storage;
-		} else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-		    params.vms = rec.data.vmid;
-		} else {
-		    throw "unknown resource type";
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/pools/' + me.pool,
-		    method: 'PUT',
-		    params: params,
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Virtual Machine'),
-				iconCls: 'pve-itype-icon-qemu',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Storage'),
-				iconCls: 'pve-itype-icon-storage',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-            columns: coldef,
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-    allowBlank: true,
-    autoSelect: false,
-    valueField: 'macro',
-    displayField: 'macro',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Description'),
-		renderer: Ext.String.htmlEncode,
-		flex: 1,
-		dataIndex: 'descr'
-	    }
-	]
-    },
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'macro', 'descr' ],
-	    idProperty: 'macro',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/macros"
-	    },
-	    sorters: {
-		property: 'macro',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	// hack: editable ComboGrid returns nothing when empty, so we need to set ''
-	// Also, disabled text fields return nothing, so we need to set ''
-
-	Ext.Array.each(['source', 'dest', 'macro', 'proto', 'sport', 'dport', 'log'], function(key) {
-	    if (values[key] === undefined) {
-		values[key] = '';
-	    }
-	});
-
-	delete values.modified_marker;
- 
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.column1 = [
-	    {
-		// hack: we use this field to mark the form 'dirty' when the
-		// record has errors- so that the user can safe the unmodified 
-		// form again.
-		xtype: 'hiddenfield',
-		name: 'modified_marker',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'type',
-		value: 'in',
-		comboItems: [['in', 'in'], ['out', 'out']],
-		fieldLabel: gettext('Direction'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'action',
-		value: 'ACCEPT',
-		comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-		fieldLabel: gettext('Action'),
-		allowBlank: false
-	    }
-        ];
-
-	if (me.allow_iface) {
-	    me.column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		fieldLabel: '',
-		value: ''
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'source',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Source')
-
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'dest',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Destination')
-	    }
-	);
-
-	
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    },
-	    {
-		xtype: 'pveFWMacroSelector',
-		name: 'macro',
-		fieldLabel: gettext('Macro'),
-		editable: true,
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-                        if (value === null) {
-			    me.down('field[name=proto]').setDisabled(false);
-			    me.down('field[name=sport]').setDisabled(false);
-			    me.down('field[name=dport]').setDisabled(false);
-                        } else {
-			    me.down('field[name=proto]').setDisabled(true);
-			    me.down('field[name=proto]').setValue('');
-			    me.down('field[name=sport]').setDisabled(true);
-			    me.down('field[name=sport]').setValue('');
-			    me.down('field[name=dport]').setDisabled(true);
-			    me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-	    },
-	    {
-		xtype: 'pveIPProtocolSelector',
-		name: 'proto',
-		autoSelect: false,
-		editable: true,
-		value: '',
-		fieldLabel: gettext('Protocol')
-	    },
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'sport',
-		value: '',
-		fieldLabel: gettext('Source port')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'dport',
-		value: '',
-		fieldLabel: gettext('Dest. port')
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'pveFirewallLogLevels'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.FirewallRulePanel', {
-	    isCreate: me.isCreate,
-	    list_refs_url: me.list_refs_url,
-	    allow_iface: me.allow_iface,
-	    rule_pos: me.rule_pos
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		    if (values.errors) {
-			var field = me.query('[isFormField][name=modified_marker]')[0];
-			field.setValue(1);
-			Ext.Function.defer(function() {
-			    var form = ipanel.up('form').getForm();
-			    form.markInvalid(values.errors);
-			}, 100);
-		    }
-		}
-	    });
-	} else if (me.rec) {
-	    ipanel.setValues(me.rec.data);
-	}
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: 'group'
-	    },
-	    {
-		xtype: 'pveSecurityGroupsSelector',
-		name: 'action',
-		value: '',
-		fieldLabel: gettext('Security Group'),
-		allowBlank: false
-	    }
-	];
-
-	if (me.allow_iface) {
-	    column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'enable',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: gettext('Enable')
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    onlineHelp: 'chapter_pve_firewall',
-
-    stateful: true,
-    stateId: 'grid-firewall-rules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(true);
-	    }
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(false);
-	    }
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + "/" + from,
-	    method: 'PUT',
-	    params: { moveto: to },
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	rule.enable = rule.enable ? 1 : 0;
-
-	var pos = rule.pos;
-	delete rule.pos;
-	delete rule.errors;
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + '/' + pos.toString(),
-	    method: 'PUT',
-	    params: rule,
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-fw-rule'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-	    var editor;
-	    if (type === 'in' || type === 'out') {
-		editor = 'PVE.FirewallRuleEdit';
-	    } else if (type === 'group') {
-		editor = 'PVE.FirewallGroupRuleEdit';
-	    } else {
-		return;
-	    }
-
-	    var win = Ext.create(editor, {
-		digest: rec.data.digest,
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rule_pos: rec.data.pos
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallRuleEdit', {
-		    allow_iface: me.allow_iface,
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var run_copy_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-
-	    if (!(type === 'in' || type === 'out')) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallRuleEdit', {
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rec: rec
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.copyBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Copy'),
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return (rec.data.type === 'in' || rec.data.type === 'out');
-	    },
-	    disabled: true,
-	    handler: run_copy_editor
-	});
-
-	if (me.allow_groups) {
-	    me.groupBtn =  Ext.create('Ext.Button', {
-		text: gettext('Insert') + ': ' + 
-		    gettext('Security Group'),
-		disabled: true,
-		handler: function() {
-		    var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-			allow_iface: me.allow_iface,
-			base_url: me.base_url
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    confirmMsg: false,
-	    getRecordName: function(rec) {
-		var rule = rec.data;
-		return rule.pos.toString() +
-		    '?digest=' + encodeURIComponent(rule.digest);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-
-	var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-	tbar.push(me.addBtn, me.copyBtn);
-	if (me.groupBtn) {
-	    tbar.push(me.groupBtn);
-	}
-	tbar.push(me.removeBtn, me.editBtn);
-
-	var render_errors = function(name, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors && errors[name]) {
-		metaData.tdCls = 'proxmox-invalid-row';
-		var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-		metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-		    html.replace(/\"/g,'&quot;') + '"';
-	    }
-	    return value;
-	};
-
-	var columns = [
-	    {
-		// similar to xtype: 'rownumberer',
-		dataIndex: 'pos',
-		resizable: false,
-		width: 23,
-		sortable: false,
-		align: 'right',
-		hideable: false,
-		menuDisabled: true,
-		renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-		    metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-		    if (value >= 0) {
-			return value;
-		    }
-		    return '';
-		}
-	    },
-	    {
-		xtype: 'checkcolumn',
-		header: gettext('Enable'),
-		dataIndex: 'enable',
-		listeners: {
-		    checkchange: function(column, recordIndex, checked) {
-			var record = me.getStore().getData().items[recordIndex];
-			record.commit();
-			var data = {};
-			Ext.Array.forEach(record.getFields(), function(field) {
-			    data[field.name] = record.get(field.name);
-			});
-			if (!me.allow_iface || !data.iface) {
-			    delete data.iface;
-			}
-			me.updateRule(data);
-		    }
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		renderer: function(value, metaData, record) {
-		    return render_errors('type', value, metaData, record);
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Action'),
-		dataIndex: 'action',
-		renderer: function(value, metaData, record) {
-		    return render_errors('action', value, metaData, record);
-		},
-		width: 80
-	    },
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		renderer: function(value, metaData, record) {
-		    return render_errors('macro', value, metaData, record);
-		},
-		width: 80
-	    }
-	];
-
-	if (me.allow_iface) {
-	    columns.push({
-		header: gettext('Interface'),
-		dataIndex: 'iface',
-		renderer: function(value, metaData, record) {
-		    return render_errors('iface', value, metaData, record);
-		},
-		width: 80
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Source'),
-		dataIndex: 'source',
-		renderer: function(value, metaData, record) {
-		    return render_errors('source', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Destination'),
-		dataIndex: 'dest',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dest', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'proto',
-		renderer: function(value, metaData, record) {
-		    return render_errors('proto', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Dest. port'),
-		dataIndex: 'dport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Source port'),
-		dataIndex: 'sport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('sport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Log level'),
-		dataIndex: 'log',
-		renderer: function(value, metaData, record) {
-		    return render_errors('log', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comment',
-		flex: 1,
-		renderer: function(value, metaData, record) {
-		    return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-		}
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-            viewConfig: {
-		plugins: [
-		    {
-			ptype: 'gridviewdragdrop',
-			dragGroup: 'FWRuleDDGroup',
-			dropGroup: 'FWRuleDDGroup'
-		    }
-		],
-		listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-			if (!dropRec) {
-			    return false; // empty view
-			}
-			var moveto = dropRec.get('pos');
-			if (dropPosition === 'after') {
-			    moveto++;
-			}
-			var pos = data.records[0].get('pos');
-			me.moveRule(pos, moveto);
-			return 0;
-                    },
-		    itemdblclick: run_editor
-		}
-	    },
-	    sortableColumns: false,
-	    columns: columns
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'enable', type: 'boolean' },
-		  'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-		  'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-	idProperty: 'pos'
-    });
-
-});
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    
-    alias_name: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.alias_name === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-            me.method = 'PUT';
-        }
-
-	var items =  [
-	    {
-		xtype: 'textfield',
-		name: me.isCreate ? 'name' : 'rename',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'cidr',
-		fieldLabel: gettext('IP/CIDR'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    items: items
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Alias'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    values.rename = values.name;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('pve-fw-aliases', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'name', 'cidr', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    onlineHelp: 'pve_firewall_ip_aliases',
-
-    stateful: true,
-    stateId: 'grid-firewall-aliases',
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-aliases',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallAliasEdit', {
-		base_url: me.base_url,
-		alias_name: rec.data.name
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallAliasEdit', {
-		    base_url: me.base_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Name'), dataIndex: 'name', width: 100 },
-		{ header:  gettext('IP/CIDR'), dataIndex: 'cidr', width: 100 },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-	me.on('activate', reload);
-    }
-});
-Ext.define('PVE.FirewallOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-	    if (me.fwtype === 'node') {
-		me.cwidth1 = 250;
-	    }
-	} else {
-	    throw "unknown firewall option type";
-	}
-
-	me.rows = {};
-
-	var add_boolean_row = function(name, text, defaultValue) {
-	    me.add_boolean_row(name, text, { defaultValue: defaultValue });
-	};
-	var add_integer_row = function(name, text, minValue, labelWidth) {
-	    me.add_integer_row(name, text, {
-		minValue: minValue,
-		deleteEmpty: true,
-		labelWidth: labelWidth,
-		renderer: function(value) {
-		    if (value === undefined) {
-			return Proxmox.Utils.defaultText;
-		    }
-
-		    return value;
-		}
-	    });
-	};
-
-	var add_log_row = function(name, labelWidth) {
-	    me.rows[name] = {
-		header: name,
-		required: true,
-		defaultValue: 'nolog',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: name,
-		    fieldDefaults: { labelWidth: labelWidth || 100 },
-		    items: {
-			xtype: 'pveFirewallLogLevels',
-			name: name,
-			fieldLabel: name
-		    }
-		}
-	    };
-	};
-
-	if (me.fwtype === 'node') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 1,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 1
-		}
-	    };
-	    add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-	    add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 32768, 120);
-	    add_integer_row('nf_conntrack_tcp_timeout_established',
-			    'nf_conntrack_tcp_timeout_established', 7875, 250);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	    add_log_row('tcp_flags_log_level', 120);
-	    add_log_row('smurf_log_level');
-	} else if (me.fwtype === 'vm') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 0,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 0
-		}
-	    };
-	    add_boolean_row('dhcp', 'DHCP', 1);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_boolean_row('radv', gettext('Router Advertisement'), 0);
-	    add_boolean_row('macfilter', gettext('MAC filter'), 1);
-	    add_boolean_row('ipfilter', gettext('IP filter'), 0);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	} else if (me.fwtype === 'dc') {
-	    add_boolean_row('enable', gettext('Firewall'), 0);
-	    add_boolean_row('ebtables', 'ebtables', 1);
-	    me.rows.log_ratelimit = {
-		header: gettext('Log rate limit'),
-		required: true,
-		defaultValue: gettext('Default') + ' (enable=1,rate1/second,burst=5)',
-		editor: {
-		    xtype: 'pveFirewallLograteEdit',
-		    defaultValue: 'enable=1'
-		}
-	    };
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-	    me.rows.policy_in = {
-		header: gettext('Input Policy'),
-		required: true,
-		defaultValue: 'DROP',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Input Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_in',
-			value: 'DROP',
-			fieldLabel: gettext('Input Policy')
-		    }
-		}
-	    };
-
-	    me.rows.policy_out = {
-		header: gettext('Output Policy'),
-		required: true,
-		defaultValue: 'ACCEPT',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Output Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_out',
-			value: 'ACCEPT',
-			fieldLabel: gettext('Output Policy')
-		    }
-		}
-	    };
-	}
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = me.rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json" + me.base_url,
-	    tbar: [ edit_btn ],
-	    editorConfig: {
-		url: '/api2/extjs/' + me.base_url
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-
-
-Ext.define('PVE.FirewallLogLevels', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallLogLevels'],
-
-    name: 'log',
-    fieldLabel: gettext('Log level'),
-    value: 'nolog',
-    comboItems: [['nolog', 'nolog'], ['emerg', 'emerg'], ['alert', 'alert'],
-	['crit', 'crit'], ['err', 'err'], ['warning', 'warning'],
-	['notice', 'notice'], ['info', 'info'], ['debug', 'debug']]
-});
-/*
- * Left Treepanel, containing all the resources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-	typeDefaults: {
-	    node: { 
-		iconCls: 'fa fa-building',
-		text: gettext('Nodes')
-	    },
-	    pool: { 
-		iconCls: 'fa fa-tags',
-		text: gettext('Resource Pool')
-	    },
-	    storage: {
-		iconCls: 'fa fa-database',
-		text: gettext('Storage')
-	    },
-	    qemu: {
-		iconCls: 'fa fa-desktop',
-		text: gettext('Virtual Machine')
-	    },
-	    lxc: {
-		//iconCls: 'x-tree-node-lxc',
-		iconCls: 'fa fa-cube',
-		text: gettext('LXC Container')
-	    },
-	    template: {
-		iconCls: 'fa fa-file-o'
-	    }
-	}
-    },
-
-    useArrows: true,
-
-    // private
-    nodeSortFn: function(node1, node2) {
-	var n1 = node1.data;
-	var n2 = node2.data;
-
-	if ((n1.groupbyid && n2.groupbyid) ||
-	    !(n1.groupbyid || n2.groupbyid)) {
-
-	    var tcmp;
-
-	    var v1 = n1.type;
-	    var v2 = n2.type;
-
-	    if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		return tcmp;
-	    }
-
-	    // numeric compare for VM IDs
-	    // sort templates after regular VMs
-	    if (v1 === 'qemu' || v1 === 'lxc') {
-		if (n1.template && !n2.template) {
-		    return 1;
-		} else if (n2.template && !n1.template) {
-		    return -1;
-		}
-		v1 = n1.vmid;
-		v2 = n2.vmid;
-		if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		    return tcmp;
-		}
-	    }
-
-	    return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
-	} else if (n1.groupbyid) {
-	    return -1;
-	} else if (n2.groupbyid) {
-	    return 1;
-	}
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-	var me = this;
-
-	var diff = end - start;
-
-	var mid = start + (diff>>1);
-
-	if (diff <= 0) {
-	    return start;
-	}
-
-	var res = me.nodeSortFn(child, node.childNodes[mid]);
-	if (res <= 0) {
-	    return me.findInsertIndex(node, child, start, mid);
-	} else {
-	    return me.findInsertIndex(node, child, mid + 1, end);
-	}
-    },
-
-    setIconCls: function(info) {
-	var me = this;
-
-	var cls = PVE.Utils.get_object_icon_class(info.type, info);
-
-	if (cls !== '') {
-	    info.iconCls = cls;
-	}
-    },
-
-    // add additional elements to text
-    // at the moment only the usage indicator for storages
-    setText: function(info) {
-	var me = this;
-
-	var status = '';
-	if (info.type === 'storage') {
-	    var maxdisk = info.maxdisk;
-	    var disk = info.disk;
-	    var usage = disk/maxdisk;
-	    var cls = '';
-	    if (usage <= 1.0 && usage >= 0.0) {
-		var height = (usage*100).toFixed(0);
-		var neg_height = (100-usage*100).toFixed(0);
-		status = '<div class="usage-wrapper">';
-		status += '<div class="usage-negative" style="height: ';
-		status += neg_height + '%"></div>';
-		status += '<div class="usage" style="height: '+ height +'%"></div>';
-		status += '</div> ';
-	    }
-	}
-
-	info.text = status + info.text;
-    },
-
-    setToolTip: function(info) {
-	if (info.type === 'pool' || info.groupbyid !== undefined) {
-	    return;
-	}
-
-	var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
-	if (info.lock) {
-	    qtips.push('Config locked (' + info.lock + ')');
-	}
-	if (info.hastate != 'unmanaged') {
-	    qtips.push(gettext('HA State') + ": " + info.hastate);
-	}
-
-	info.qtip = qtips.join(', ');
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-	var me = this;
-
-	me.setIconCls(info);
-	me.setText(info);
-	me.setToolTip(info);
-
-	var defaults;
-	if (info.groupbyid) {
-	    info.text = info.groupbyid;
-	    if (info.type === 'type') {
-		defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-		if (defaults && defaults.text) {
-		    info.text = defaults.text;
-		}
-	    }
-	}
-	var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-	var pos;
-	if (cs) {
-	    pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-	}
-
-	node.insertBefore(child, pos);
-
-	return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-	var me = this;
-
-	var groupby = groups[level];
-	var v = info[groupby];
-
-	if (v) {
-            var group = node.findChild('groupbyid', v);
-	    if (!group) {
-		var groupinfo;
-		if (info.type === groupby) {
-		    groupinfo = info;
-		} else {
-		    groupinfo = {
-			type: groupby,
-			id : groupby + "/" + v
-		    };
-		    if (groupby !== 'type') {
-			groupinfo[groupby] = v;
-		    }
-		}
-		groupinfo.leaf = false;
-		groupinfo.groupbyid = v; 
-		group = me.addChildSorted(node, groupinfo);
-	    }
-	    if (info.type === groupby) {
-		return group;
-	    }
-	    if (group) {
-		return me.groupChild(group, info, groups, level + 1);
-	    }
-	}
-
-	return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	if (!me.viewFilter) {
-	    me.viewFilter = {};
-	}
-
-	var pdata = {
-	    dataIndex: {},
-	    updateCount: 0
-	};
-
-	var store = Ext.create('Ext.data.TreeStore', {
-	    model: 'PVETree',
-	    root: {
-		expanded: true,
-		id: 'root',
-		text: gettext('Datacenter'),
-		iconCls: 'fa fa-server'
-	    }
-	});
-
-	var stateid = 'rid';
-
-	var updateTree = function() {
-	    var tmp;
-
-	    store.suspendEvents();
-
-	    var rootnode = me.store.getRootNode();
-	    // remember selected node (and all parents)
-	    var sm = me.getSelectionModel();
-
-	    var lastsel = sm.getSelection()[0];
-	    var reselect = false;
-	    var parents = [];
-	    var p = lastsel;
-	    while (p && !!(p = p.parentNode)) {
-		parents.push(p);
-	    }
-
-	    var index = pdata.dataIndex;
-
-	    var groups = me.viewFilter.groups || [];
-	    var filterfn = me.viewFilter.filterfn;
-
-	    // remove vanished or moved items
-	    // update in place changed items
-	    var key;
-	    for (key in index) {
-		if (index.hasOwnProperty(key)) {
-		    var olditem = index[key];
-
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var item = rstore.getById(olditem.data.id);
-		    var item = rstore.data.get(olditem.data.id);
-
-		    var changed = false;
-		    var moved = false;
-		    if (item) {
-			// test if any grouping attributes changed
-			// this will also catch migrated nodes
-			// in server view
-			var i, len;
-			for (i = 0, len = groups.length; i < len; i++) {
-			    var attr = groups[i];
-			    if (item.data[attr] != olditem.data[attr]) {
-				//console.log("changed " + attr);
-				moved = true;
-				break;
-			    }
-			}
-
-			// explicitly check for node, since
-			// in some views, node is not a grouping
-			// attribute
-			if (!moved && item.data.node !== olditem.data.node) {
-			    moved = true;
-			}
-
-			// tree item has been updated
-			var fields = [
-			    'text', 'running', 'template', 'status',
-			    'qmpstatus', 'hastate', 'lock'
-			];
-
-			var field;
-			for (i = 0; i < fields.length; i++) {
-			    field = fields[i];
-			    if (item.data[field] !== olditem.data[field]) {
-				changed = true;
-				break;
-			    }
-			}
-
-			// fixme: also test filterfn()?
-		    }
-
-		    if (changed) {
-			olditem.beginEdit();
-			//console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-			var info = olditem.data;
-			Ext.apply(info, item.data);
-			me.setIconCls(info);
-			me.setText(info);
-			me.setToolTip(info);
-			olditem.commit();
-		    }
-		    if ((!item || moved) && olditem.isLeaf()) {
-			//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-			delete index[key];
-			var parentNode = olditem.parentNode;
-			// when the selected item disappears,
-			// we have to deselect it here, and reselect it
-			// later
-			if (lastsel && olditem.data.id === lastsel.data.id) {
-			    reselect = true;
-			    sm.deselect(olditem);
-			}
-			// since the store events are suspended, we
-			// manually remove the item from the store also
-			store.remove(olditem);
-			parentNode.removeChild(olditem, true);
-		    }
-		}
-	    }
-
-	    // add new items
-            rstore.each(function(item) {
-		var olditem = index[item.data.id];
-		if (olditem) {
-		    return;
-		}
-
-		if (filterfn && !filterfn(item)) {
-		    return;
-		}
-
-		//console.log("ADD UID: " + item.data.id);
-
-		var info = Ext.apply({ leaf: true }, item.data);
-
-		var child = me.groupChild(rootnode, info, groups, 0);
-		if (child) {
-		    index[item.data.id] = child;
-		}
-	    });
-
-	    store.resumeEvents();
-	    store.fireEvent('refresh', store);
-
-	    // select parent node is selection vanished
-	    if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-		lastsel = rootnode;
-		while (!!(p = parents.shift())) {
-		    if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-			lastsel = tmp;
-			break;
-		    }
-		}
-		me.selectById(lastsel.data.id);
-	    } else if (lastsel && reselect) {
-		me.selectById(lastsel.data.id);
-	    }
-
-	    // on first tree load set the selection from the stateful provider
-	    if (!pdata.updateCount) {
-		rootnode.expand();
-		me.applyState(sp.get(stateid));
-	    }
-
-	    pdata.updateCount++;
-	};
-
-	var statechange = function(sp, key, value) {
-	    if (key === stateid) {
-		me.applyState(value);
-	    }
-	};
-
-	sp.on('statechange', statechange);
-
-	Ext.apply(me, {
-	    allowSelection: true,
-	    store: store,
-	    viewConfig: {
-		// note: animate cause problems with applyState
-		animate: false
-	    },
-	    //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		destroy: function() {
-		    rstore.un("load", updateTree);
-		},
-		beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
-		    var sm = me.getSelectionModel();
-		    // disable selection when right clicking
-		    // except the record is already selected
-		    me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
-		},
-		beforeselect: function (tree, record, index, eopts) {
-		    var allow = me.allowSelection;
-		    me.allowSelection = true;
-		    return allow;
-		},
-		itemdblclick: PVE.Utils.openTreeConsole
-	    },
-	    setViewFilter: function(view) {
-		me.viewFilter = view;
-		me.clearTree();
-		updateTree();
-	    },
-	    setDatacenterText: function(clustername) {
-		var rootnode = me.store.getRootNode();
-
-		var rnodeText = gettext('Datacenter');
-		if (clustername !== undefined) {
-		    rnodeText += ' (' + clustername + ')';
-		}
-
-		rootnode.beginEdit();
-		rootnode.data.text = rnodeText;
-		rootnode.commit();
-	    },
-	    clearTree: function() {
-		pdata.updateCount = 0;
-		var rootnode = me.store.getRootNode();
-		rootnode.collapse();
-		rootnode.removeAll();
-		pdata.dataIndex = {};
-		me.getSelectionModel().deselectAll();
-	    },
-	    selectExpand: function(node) {
-		var sm = me.getSelectionModel();
-		if (!sm.isSelected(node)) {
-		    sm.select(node);
-		    var cn = node;
-		    while (!!(cn = cn.parentNode)) {
-			if (!cn.isExpanded()) {
-			    cn.expand();
-			}
-		    }
-		    me.getView().focusRow(node);
-		}
-	    },
-	    selectById: function(nodeid) {
-		var rootnode = me.store.getRootNode();
-		var sm = me.getSelectionModel();
-		var node;
-		if (nodeid === 'root') {
-		    node = rootnode;
-		} else {
-		    node = rootnode.findChild('id', nodeid, true);
-		}
-		if (node) {
-		    me.selectExpand(node);
-		}
-		return node;
-	    },
-	    applyState : function(state) {
-		var sm = me.getSelectionModel();
-		if (state && state.value) {
-		    me.selectById(state.value);
-		} else {
-		    sm.deselectAll();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	var sm = me.getSelectionModel();
-	sm.on('select', function(sm, n) {		    
-	    sp.set(stateid, { value: n.data.id});
-	});
-
-	rstore.on("load", updateTree);
-	rstore.startUpdate();
-	//rstore.stopUpdate();
-    }
-
-});
-Ext.define('pve-fw-ipsets', {
-    extend: 'Ext.data.Model',
-    fields: [ 'name', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsetlist',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-
-        var me = this;
-
-	if (me.ipset_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-ipsets',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('Proxmox.window.Edit', {
-		subject: "IPSet '" + rec.data.name + "'",
-		url: me.base_url,
-		method: 'POST',
-		digest: rec.data.digest,
-		items: [
-		    {
-			xtype: 'hiddenfield',
-			name: 'rename',
-			value: rec.data.name
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'name',
-			value: rec.data.name,
-			fieldLabel: gettext('Name'),
-			allowBlank: false
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'comment',
-			value: rec.data.comment,
-			fieldLabel: gettext('Comment')
-		    }
-		]
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('Proxmox.window.Edit', {
-		    subject: 'IPSet',
-		    url: me.base_url,
-		    method: 'POST',
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'name',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'textfield',
-			    name: 'comment',
-			    value: '',
-			    fieldLabel: gettext('Comment')
-			}
-		    ]
-		});
-		win.show();
-		win.on('destroy', reload);
-
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: 'IPSet', dataIndex: 'name', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = me.base_url + '/' + rec.data.name;
-		    me.ipset_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.ipset_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.cidr === undefined);
-
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-	var column1 = [];
-
-	if (me.isCreate) {
-	    if (!me.list_refs_url) {
-		throw "no alias_base_url specified";
-	    }
-
-	    column1.push({
-		xtype: 'pveIPRefSelector',
-		name: 'cidr',
-		ref_type: 'alias',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	} else {
-	    column1.push({
-		xtype: 'displayfield',
-		name: 'cidr',
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'nomatch',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: 'nomatch'
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('IP/CIDR'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsets',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no1 list_refs_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ipset'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.IPSetCidrEdit', {
-		base_url: me.base_url,
-		cidr: rec.data.cidr
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		if (!me.base_url) {
-		    return;
-		}
-		var win = Ext.create('PVE.IPSetCidrEdit', {
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	var render_errors = function(value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors.cidr || errors.nomatch;
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	Ext.apply(me, {
-	    tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    store: store,
-	    selModel: sm,
-	    listeners: {
-		itemdblclick: run_editor
-	    },
-	    columns: [
-		{
-		    xtype: 'rownumberer'
-		},
-		{
-		    header: gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			value = render_errors(value, metaData, record);
-			if (record.data.nomatch) {
-			    return '<b>! </b>' + value;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    flex: 1,
-		    renderer: function(value) {
-			return Ext.util.Format.htmlEncode(value);
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'nomatch', type: 'boolean' },
-		  'cidr', 'comment', 'errors' ],
-	idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    onlineHelp: 'pve_firewall_ip_sets',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-	    region: 'center',
-	    list_refs_url: me.list_refs_url,
-	    border: false
-	});
-
-	var ipset_list = Ext.createWidget('pveIPSetList', {
-	    region: 'west',
-	    ipset_panel: ipset_panel,
-	    base_url: me.base_url,
-	    width: '50%',
-	    border: false,
-	    split: true
-	});
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-	    listeners: {
-		show: function() {
-		    ipset_list.fireEvent('show', ipset_list);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Base class for all the multitab config panels
- *
- * How to use this:
- *
- * You create a subclass of this, and then define your wanted tabs
- * as items like this:
- *
- * items: [{
- *  title: "myTitle",
- *  xytpe: "somextype",
- *  iconCls: 'fa fa-icon',
- *  groups: ['somegroup'],
- *  expandedOnInit: true,
- *  itemId: 'someId'
- * }]
- *
- * this has to be in the declarative syntax, else we
- * cannot save them for later
- * (so no Ext.create or Ext.apply of an item in the subclass)
- *
- * the groups array expects the itemids of the items
- * which are the parents, which have to come before they
- * are used
- *
- * if you want following the tree:
- *
- * Option1
- * Option2
- *   -> SubOption1
- *	-> SubSubOption1
- *
- * the suboption1 group array has to look like this:
- * groups: ['itemid-of-option2']
- *
- * and of subsuboption1:
- * groups: ['itemid-of-option2', 'itemid-of-suboption1']
- *
- * setting the expandedOnInit determines if the item/group is expanded
- * initially (false by default)
- */
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    showSearch: true, // add a resource grid with a search button as first tab
-    viewFilter: undefined, // a filter to pass to that resource grid
-
-    tbarSpacing: true, // if true, adds a spacer after the title in tbar
-
-    dockedItems: [{
-	// this is needed for the overflow handler
-	xtype: 'toolbar',
-	overflowHandler: 'scroller',
-	dock: 'left',
-	style: {
-	    backgroundColor: '#f5f5f5',
-	    padding: 0,
-	    margin: 0
-	},
-	items: {
-	    xtype: 'treelist',
-	    itemId: 'menu',
-	    ui: 'nav',
-	    expanderOnly: true,
-	    expanderFirst: false,
-	    animation: false,
-	    singleExpand: false,
-	    listeners: {
-		selectionchange: function(treeList, selection) {
-		    var me = this.up('panel');
-		    me.suspendLayout = true;
-		    me.activateCard(selection.data.id);
-		    me.suspendLayout = false;
-		    me.updateLayout();
-		},
-		itemclick: function(treelist, info) {
-		    var olditem = treelist.getSelection();
-		    var newitem = info.node;
-
-		    // when clicking on the expand arrow,
-		    // we don't select items, but still want
-		    // the original behaviour
-		    if (info.select === false) {
-			return;
-		    }
-
-		    // if you click on a different item which is open,
-		    // leave it open
-		    // else toggle the clicked item
-		    if (olditem.data.id !== newitem.data.id &&
-			newitem.data.expanded === true) {
-			info.toggle = false;
-		    } else {
-			info.toggle = true;
-		    }
-		}
-	    }
-	}
-    },
-    {
-	xtype: 'toolbar',
-	itemId: 'toolbar',
-	dock: 'top',
-	height: 36,
-	overflowHandler: 'scroller'
-    }],
-
-    firstItem: '',
-    layout: 'card',
-    border: 0,
-
-    // used for automated test
-    selectById: function(cardid) {
-	var me = this;
-
-	var root = me.store.getRoot();
-	var selection = root.findChild('id', cardid, true);
-
-	if (selection) {
-	    selection.expand();
-	    var menu = me.down('#menu');
-	    menu.setSelection(selection);
-	    return cardid;
-	}
-    },
-
-    activateCard: function(cardid) {
-	var me = this;
-	if (me.savedItems[cardid]) {
-	    var curcard = me.getLayout().getActiveItem();
-	    var newcard = me.add(me.savedItems[cardid]);
-	    me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp);
-	    if (curcard) {
-		me.setActiveItem(cardid);
-		me.remove(curcard, true);
-
-		// trigger state change
-
-		var ncard = cardid;
-		// Note: '' is alias for first tab.
-		// First tab can be 'search' or something else
-		if (cardid === me.firstItem) {
-		    ncard = '';
-		}
-		if (me.hstateid) {
-		   me.sp.set(me.hstateid, { value: ncard });
-		}
-	    }
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = me.hstateid;
-
-	me.sp = Ext.state.Manager.getProvider();
-
-	var activeTab; // leaving this undefined means items[0] will be the default tab
-
-	if (stateid) {
-	    var state = me.sp.get(stateid);
-	    if (state && state.value) {
-		// if this tab does not exists, it chooses the first
-		activeTab = state.value;
-	    }
-	}
-
-	// get title
-	var title = me.title || me.pveSelNode.data.text;
-	me.title = undefined;
-
-	// create toolbar
-	var tbar = me.tbar || [];
-	me.tbar = undefined;
-
-	if (!me.onlineHelp) {
-	    switch(me.pveSelNode.data.id) {
-		case 'type/storage':me.onlineHelp = 'chapter-pvesm.html'; break;
-		case 'type/qemu':me.onlineHelp = 'chapter-qm.html'; break;
-		case 'type/lxc':me.onlineHelp = 'chapter-pct.html'; break;
-		case 'type/pool':me.onlineHelp = 'chapter-pveum.html#_pools'; break;
-		case 'type/node':me.onlineHelp = 'chapter-sysadmin.html'; break;
-	    }
-	}
-
-	if (me.tbarSpacing) {
-	    tbar.unshift('->');
-	}
-	tbar.unshift({
-	    xtype: 'tbtext',
-	    text: title,
-	    baseCls: 'x-panel-header-text'
-	});
-
-	me.helpButton = Ext.create('Proxmox.button.Help', {
-	    hidden: false,
-	    listenToGlobalEvent: false,
-	    onlineHelp: me.onlineHelp || undefined
-	});
-
-	tbar.push(me.helpButton);
-
-	me.dockedItems[1].items = tbar;
-
-	// include search tab
-	me.items = me.items || [];
-	if (me.showSearch) {
-	    me.items.unshift({
-		itemId: 'search',
-		title: gettext('Search'),
-		iconCls: 'fa fa-search',
-		xtype: 'pveResourceGrid',
-		pveSelNode: me.pveSelNode
-	    });
-	}
-
-	me.savedItems = {};
-	/*jslint confusion:true*/
-	if (me.items[0]) {
-	    me.firstItem = me.items[0].itemId;
-	}
-	/*jslint confusion:false*/
-
-	me.store = Ext.create('Ext.data.TreeStore', {
-	    root: {
-		expanded: true
-	    }
-	});
-	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
-
-	delete me.items;
-	me.defaults = me.defaults || {};
-	Ext.apply(me.defaults, {
-	    pveSelNode: me.pveSelNode,
-	    viewFilter: me.viewFilter,
-	    workspace: me.workspace,
-	    border: 0
-	});
-
-	me.callParent();
-
-	var menu = me.down('#menu');
-	var selection = root.findChild('id', activeTab, true) || root.firstChild;
-	var node = selection;
-	while (node !== root) {
-	    node.expand();
-	    node = node.parentNode;
-	}
-	menu.setStore(me.store);
-	menu.setSelection(selection);
-
-	// on a state change,
-	// select the new item
-	var statechange = function(sp, key, state) {
-	    // it the state change is for this panel
-	    if (stateid && (key === stateid) && state) {
-		// get active item
-		var acard = me.getLayout().getActiveItem().itemId;
-		// get the itemid of the new value
-		var ncard = state.value || me.firstItem;
-		if (ncard && (acard != ncard)) {
-		    // select the chosen item
-		    menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
-		}
-	    }
-	};
-
-	if (stateid) {
-	    me.mon(me.sp, 'statechange', statechange);
-	}
-    }
-});
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    stateful: true,
-    stateId: 'grid-guest-backup',
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmtype = me.pveSelNode.data.type;
-	if (!vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var vmtypeFilter;
-	if (vmtype === 'openvz') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-openvz-');
-	    };
-	} else if (vmtype === 'lxc') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-lxc-');
-	    };
-	} else if (vmtype === 'qemu') {
-	    vmtypeFilter = function(item) {
-		return item.data.volid.match(':backup/vzdump-qemu-');
-	    };
-	} else {
-	    throw "unsupported VM type '" + vmtype + "'";
-	}
-
-	var searchFilter = {
-	    property: 'volid',
-	// on initial store display only our vmid backups
-	// surround with minus sign to prevent the 2016 VMID bug
-	    value: vmtype + '-' + vmid + '-',
-	    anyMatch: true,
-	    caseSensitive: false
-	};
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-content',
-	    sorters: { 
-		property: 'volid', 
-		order: 'DESC' 
-	    },
-	    filters: [
-	        vmtypeFilter,
-		searchFilter
-		]
-	});
-
-	var reload = Ext.Function.createBuffered(function() {
-	    if (me.store) {
-		me.store.load();
-	    }
-	}, 100);
-
-	var setStorage = function(storage) {
-	    var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-	    url += '?content=backup';
-
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: url
-	    });
-
-	    reload();
-	};
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    setStorage(value);
-		}
-	    }
-	});
-
-	var storagefilter = Ext.create('Ext.form.field.Text', {
-	    fieldLabel: gettext('Search'),
-	    labelWidth: 50,
-	    labelAlign: 'right',
-	    enableKeyEvents: true,
-	    value: searchFilter.value,
-	    listeners: {
-		buffer: 500,
-		keyup: function(field) {
-		    me.store.clearFilter(true);
-		    searchFilter.value = field.getValue();
-		    me.store.filter([
-			vmtypeFilter,
-			searchFilter
-		    ]);
-		}
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var backup_btn = Ext.create('Ext.button.Button', {
-	    text: gettext('Backup now'),
-	    handler: function() {
-		var win = Ext.create('PVE.window.Backup', { 
-		    nodename: nodename,
-		    vmid: vmid,
-		    vmtype: vmtype,
-		    storage: storagesel.getValue(),
-		    listeners : {
-			close: function() {
-			    reload();
-			}
-		    }
-		});
-		win.show();
-	    }
-	});
-
-	var restore_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Restore'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var volid = rec.data.volid;
-
-		var win = Ext.create('PVE.window.Restore', {
-		    nodename: nodename,
-		    vmid: vmid,
-		    volid: rec.data.volid,
-		    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-		    vmtype: vmtype
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var delete_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.volid + "'");
-		msg += " " + gettext('This will permanently erase all data.');
-
-		return msg;
-	    },
-	    getUrl: function(rec) {
-		var storage = storagesel.getValue();
-		return '/nodes/' + nodename + '/storage/' + storage + '/content/' + rec.data.volid;
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	var config_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show Configuration'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var storage = storagesel.getValue();
-		if (!storage) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.window.BackupConfig', {
-		    volume: rec.data.volid,
-		    pveSelNode: me.pveSelNode
-		});
-
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    tbar: [ backup_btn, restore_btn, delete_btn,config_btn, '->', storagesel, storagefilter ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'volid'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.CephCreateService', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateService',
-
-    showProgress: true,
-
-    setNode: function(nodename) {
-        var me = this;
-
-	me.nodename = nodename;
-        me.url = "/nodes/" + nodename + "/ceph/" + me.type + "/" + nodename;
-    },
-
-    method: 'POST',
-    isCreate: true,
-
-    items: [
-	{
-	    xtype: 'pveNodeSelector',
-	    submitValue: false,
-	    fieldLabel: gettext('Host'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    var me = this.up('pveCephCreateService');
-		    me.setNode(value);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.type) {
-	    throw "no type specified";
-	}
-
-	me.setNode(me.nodename);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephServiceList', {
-    extend: 'Ext.grid.GridPanel',
-    xtype: 'pveNodeCephServiceList',
-
-    onlineHelp: 'chapter_pveceph',
-    emptyText: gettext('No such service configured.'),
-
-    stateful: true,
-
-    // will be called when the store loads
-    storeLoadCallback: Ext.emptyFn,
-
-    // if set to true, does shows the ceph install mask if needed
-    showCephInstallMask: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    if (view.pveSelNode) {
-		view.nodename = view.pveSelNode.data.node;
-	    }
-	    if (!view.nodename) {
-		throw "no node name specified";
-	    }
-
-	    if (!view.type) {
-		throw "no type specified";
-	    }
-
-	    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-		autoLoad: true,
-		autoStart: true,
-		interval: 3000,
-		storeid: 'ceph-' + view.type + '-list' + view.nodename,
-		model: 'ceph-service-list',
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + view.nodename + "/ceph/" + view.type
-		}
-	    });
-
-	    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-		rstore: view.rstore,
-		sorters: [{ property: 'name' }]
-	    }));
-
-	    if (view.storeLoadCallback) {
-		view.rstore.on('load', view.storeLoadCallback, this);
-	    }
-	    view.on('destroy', view.rstore.stopUpdate);
-
-	    if (view.showCephInstallMask) {
-		var regex = new RegExp("not (installed|initialized)", "i");
-		PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error) {
-		    view.rstore.stopUpdate();
-		    PVE.Utils.showCephInstallOrMask(view.ownerCt, error.statusText, view.nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', function(){
-				view.rstore.startUpdate();
-			    });
-			}
-		    );
-		});
-	    }
-	},
-
-	service_cmd: function(rec, cmd) {
-	    var view = this.getView();
-	    if (!rec.data.host) {
-		Ext.Msg.alert(gettext('Error'), "entry has no host");
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		method: 'POST',
-		params: { service: view.type + '.' + rec.data.name },
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: function() {
-			    view.rstore.load();
-			}
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-	onChangeService: function(btn) {
-	    var me = this;
-	    var view = this.getView();
-	    var cmd = btn.action;
-	    var rec = view.getSelection()[0];
-	    me.service_cmd(rec, cmd);
-	},
-
-	showSyslog: function() {
-	    var view = this.getView();
-	    var rec = view.getSelection()[0];
-	    var servicename = 'ceph-' + view.type + '@' + rec.data.name;
-	    var url = "/api2/extjs/nodes/" + rec.data.host + "/syslog?service=" +  encodeURIComponent(servicename);
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + servicename,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: [{
-		    xtype: 'proxmoxLogView',
-		    url: url,
-		    log_select_timespan: 1
-		}]
-	    });
-	    win.show();
-	},
-
-	onCreate: function() {
-	    var view = this.getView();
-	    var win = Ext.create('PVE.CephCreateService', {
-		autoShow: true,
-		nodename: view.nodename,
-		subject: view.getTitle(),
-		type: view.type,
-		taskDone: function() {
-		    view.rstore.load();
-		}
-	    });
-	}
-    },
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Start'),
-	    iconCls: 'fa fa-play',
-	    action: 'start',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state === 'stopped' ||
-		  rec.data.state === 'unknown';
-	    },
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Stop'),
-	    iconCls: 'fa fa-stop',
-	    action: 'stop',
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    disabled: true,
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Restart'),
-	    iconCls: 'fa fa-refresh',
-	    action: 'restart',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    handler: 'onChangeService'
-	},
-	'-',
-	{
-	    text: gettext('Create'),
-	    reference: 'createButton',
-	    handler: 'onCreate'
-	},
-	{
-	    text: gettext('Destroy'),
-	    xtype: 'proxmoxStdRemoveButton',
-	    getUrl: function(rec) {
-		var view = this.up('grid');
-		if (!rec.data.host) {
-		    Ext.Msg.alert(gettext('Error'), "entry has no host");
-		    return;
-		}
-		return "/nodes/" + rec.data.host + "/ceph/" + view.type + "/" + rec.data.name;
-	    },
-	    callback: function(options, success, response) {
-		var view = this.up('grid');
-		if (!success) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    return;
-		}
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', {
-		    upid: upid,
-		    taskDone: function() {
-			view.rstore.load();
-		    }
-		});
-		win.show();
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: 'showSyslog'
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return this.type + '.' + v;
-	    },
-	    dataIndex: 'name'
-	},
-	{
-	    header: gettext('Host'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'host'
-	},
-	{
-	    header: gettext('Status'),
-	    flex: 1,
-	    sortable: false,
-	    dataIndex: 'state'
-	},
-	{
-	    header: gettext('Address'),
-	    flex: 3,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'addr'
-	},
-	{
-	    header: gettext('Version'),
-	    flex: 3,
-	    sortable: true,
-	    dataIndex: 'version'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.additionalColumns) {
-	    me.columns = me.columns.concat(me.additionalColumns);
-	}
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('ceph-service-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'addr', 'name', 'rank', 'host', 'quorum', 'state',
-	    'ceph_version', 'ceph_version_short',
-	    { type: 'string', name: 'version', calculate: function(data) {
-		return PVE.Utils.parse_ceph_version(data);
-	    } }
-	],
-	idProperty: 'name'
-    });
-});
-/*jslint confusion: true */
-Ext.define('PVE.CephCreateFS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateFS',
-
-    showTaskViewer: true,
-    onlineHelp: 'pveceph_fs_create',
-
-    subject: 'Ceph FS',
-    isCreate: true,
-    method: 'POST',
-
-    setFSName: function(fsName) {
-	var me = this;
-
-	if (fsName === '' || fsName === undefined) {
-	    fsName = 'cephfs';
-	}
-
-	me.url = "/nodes/" + me.nodename + "/ceph/fs/" + fsName;
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    value: 'cephfs',
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateFS').setFSName(value);
-		}
-	    },
-	    submitValue: false, // already encoded in apicall URL
-	    emptyText: 'cephfs'
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'Placement Groups',
-	    name: 'pg_num',
-	    value: 128,
-	    emptyText: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add-storage',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new CephFS to the cluster storage configuration.'),
-	    },
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setFSName();
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.NodeCephFSPanel', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNodeCephFSPanel',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    title: gettext('CephFS'),
-    onlineHelp: 'pveceph_fs',
-
-    border: false,
-    defaults: {
-	border: false,
-	cbind: {
-	    nodename: '{nodename}'
-	}
-    },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    cephfsConfigured: false,
-	    mdsCount: 0
-	},
-	formulas: {
-	    canCreateFS: function(get) {
-		return (!get('cephfsConfigured') && get('mdsCount') > 0);
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'CephFS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-fs',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/' + view.nodename + '/ceph/fs'
-			},
-			model: 'pve-ceph-fs'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'name',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateFS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!(success && records && records.length > 0)) {
-			vm.set('cephfsConfigured', false);
-			return;
-		    }
-		    vm.set('cephfsConfigured', true);
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create CephFS'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			// only one CephFS per Ceph cluster makes sense for now
-			disabled: '{!canCreateFS}'
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: 'Data Pool',
-		    flex: 1,
-		    dataIndex: 'data_pool'
-		},
-		{
-		    header: 'Metadata Pool',
-		    flex: 1,
-		    dataIndex: 'metadata_pool'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    title: gettext('Metadata Servers'),
-	    stateId: 'grid-ceph-mds',
-	    type: 'mds',
-	    storeLoadCallback: function(store, records, success) {
-		var vm = this.getViewModel();
-		if (!success || !records) {
-		    vm.set('mdsCount', 0);
-		    return;
-		}
-		vm.set('mdsCount', records.length);
-	    },
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-}, function() {
-    Ext.define('pve-ceph-fs', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'data_pool', 'metadata_pool' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/fs"
-	},
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.CephCreatePool', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreatePool',
-
-    showProgress: true,
-    onlineHelp: 'pve_ceph_pools',
-
-    subject: 'Ceph Pool',
-    isCreate: true,
-    method: 'POST',
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Size'),
-	    name: 'size',
-	    value: 3,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Min. Size'),
-	    name: 'min_size',
-	    value: 2,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'pveCephRuleSelector',
-	    fieldLabel: 'Crush Rule', // do not localize
-	    name: 'crush_rule',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'pg_num',
-	    name: 'pg_num',
-	    value: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add_storages',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new pool to the cluster storage configuration.'),
-	    },
-	}
-    ],
-    initComponent : function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.apply(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/pools",
-	    defaults: {
-		nodename: me.nodename
-	    }
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephPoolList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeCephPoolList',
-
-    onlineHelp: 'chapter_pveceph',
-
-    stateful: true,
-    stateId: 'grid-ceph-pools',
-    bufferedRenderer: false,
-
-    features: [ { ftype: 'summary'} ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    width: 120,
-	    sortable: true,
-	    dataIndex: 'pool_name'
-	},
-	{
-	    header: gettext('Size') + '/min',
-	    width: 100,
-	    align: 'right',
-	    renderer: function(v, meta, rec) {
-		return v + '/' + rec.data.min_size;
-	    },
-	    dataIndex: 'size'
-	},
-	{
-	    text: '# Placement Groups', // pg_num',
-	    width: 180,
-	    align: 'right',
-	    dataIndex: 'pg_num'
-	},
-	{
-	    text: 'CRUSH Rule',
-	    columns: [
-		{
-		    text: 'ID',
-		    align: 'right',
-		    width: 50,
-		    dataIndex: 'crush_rule'
-		},
-		{
-		    text: gettext('Name'),
-		    width: 150,
-		    dataIndex: 'crush_rule_name',
-		},
-	    ]
-	},
-	{
-	    text: gettext('Used'),
-	    columns: [
-		{
-		    text: '%',
-		    width: 100,
-		    sortable: true,
-		    align: 'right',
-		    renderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		    dataIndex: 'percent_used',
-		    summaryType: 'sum',
-		    summaryRenderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		},
-		{
-		    text: gettext('Total'),
-		    width: 100,
-		    sortable: true,
-		    renderer: PVE.Utils.render_size,
-		    align: 'right',
-		    dataIndex: 'bytes_used',
-		    summaryType: 'sum',
-		    summaryRenderer: PVE.Utils.render_size
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-pool-list' + nodename,
-	    model: 'ceph-pool-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/pools"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		var win = Ext.create('PVE.CephCreatePool', {
-                    nodename: nodename
-		});
-		win.show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	var destroy_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Destroy'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.pool_name) {
-		    return;
-		}
-		var base_url = '/nodes/' + nodename + '/ceph/pools/' +
-		    rec.data.pool_name;
-
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    showProgress: true,
-		    url: base_url,
-		    params: {
-			remove_storages: 1
-		    },
-		    item: { type: 'CephPool', id: rec.data.pool_name }
-		}).show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ create_btn, destroy_btn ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-pool-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'pool_name',
-		  { name: 'pool', type: 'integer'},
-		  { name: 'size', type: 'integer'},
-		  { name: 'min_size', type: 'integer'},
-		  { name: 'pg_num', type: 'integer'},
-		  { name: 'bytes_used', type: 'integer'},
-		  { name: 'percent_used', type: 'number'},
-		  { name: 'crush_rule', type: 'integer'},
-		  { name: 'crush_rule_name', type: 'string'}
-		],
-	idProperty: 'pool_name'
-    });
-});
-
-Ext.define('PVE.form.CephRuleSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephRuleSelector',
-
-    allowBlank: false,
-    valueField: 'name',
-    displayField: 'name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/rules'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.CephCreateOsd', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateOsd',
-
-    subject: 'Ceph OSD',
-
-    showProgress: true,
-
-    onlineHelp: 'pve_ceph_osds',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			Object.keys(values || {}).forEach(function(name) {
-			    if (values[name] === '') {
-				delete values[name];
-			    }
-			});
-
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'dev',
-			    nodename: me.nodename,
-			    diskType: 'unused',
-			    fieldLabel: gettext('Disk'),
-			    allowBlank: false
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'db_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('DB Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=db_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'db_size',
-			    fieldLabel: gettext('DB size') + ' (GiB)',
-			    minValue: 1,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ],
-		    advancedColumn1: [
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'encrypted',
-			    fieldLabel: gettext('Encrypt OSD')
-			},
-		    ],
-		    advancedColumn2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'wal_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('WAL Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD/DB disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=wal_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'wal_size',
-			    fieldLabel: gettext('WAL size') + ' (GiB)',
-			    minValue: 0.5,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pve-hint',
-		    value: 'Note: Ceph is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_pveceph') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.CephRemoveOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephRemoveOsd'],
-
-    isRemove: true,
-
-    showProgress: true,
-    method: 'DELETE',
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cleanup',
-	    checked: true,
-	    labelWidth: 130,
-	    fieldLabel: gettext('Cleanup Disks')
-	}
-    ],
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (me.osdid === undefined || me.osdid < 0) {
-	    throw "no osdid specified";
-	}
-
-	me.isCreate = true;
-
-	me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephOsdTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveNodeCephOsdTree'],
-    onlineHelp: 'chapter_pveceph',
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    flags: [],
-	    maxversion: '0',
-	    versions: {},
-	    isOsd: false,
-	    downOsd: false,
-	    upOsd: false,
-	    inOsd: false,
-	    outOsd: false,
-	    osdid: '',
-	    osdhost: '',
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	reload: function() {
-	    var me = this.getView();
-	    var vm = this.getViewModel();
-	    var nodename = vm.get('nodename');
-	    var sm = me.getSelectionModel();
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + nodename + "/ceph/osd",
-		waitMsgTarget: me,
-		method: 'GET',
-		failure: function(response, opts) {
-		    var msg = response.htmlStatus;
-		    PVE.Utils.showCephInstallOrMask(me, msg, nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', this.reload);
-			}
-		    );
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-		    var selected = me.getSelection();
-		    var name;
-		    if (selected.length) {
-			name = selected[0].data.name;
-		    }
-		    vm.set('versions', data.versions);
-		    // extract max version
-		    var maxversion = vm.get('maxversion');
-		    Object.values(data.versions || {}).forEach(function(version) {
-			if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-			    maxversion = version;
-			}
-		    });
-		    vm.set('maxversion', maxversion);
-		    sm.deselectAll();
-		    me.setRootNode(data.root);
-		    me.expandAll();
-		    if (name) {
-			var node = me.getRootNode().findChild('name', name, true);
-			if (node) {
-			    me.setSelection([node]);
-			}
-		    }
-
-		    var flags = data.flags.split(',');
-		    vm.set('flags', flags);
-		    var noout = flags.includes('noout');
-		    me.down('#nooutBtn').setText(noout ? gettext("Unset noout") : gettext("Set noout"));
-		}
-	    });
-	},
-
-	osd_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd;
-	    var params = comp.params || {};
-	    var osdid = vm.get('osdid');
-
-	    var doRequest = function() {
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + vm.get('osdhost') + "/ceph/osd/" + osdid + '/' + cmd,
-		    waitMsgTarget: me.getView(),
-		    method: 'POST',
-		    params: params,
-		    success: () => { me.reload(); },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    };
-
-	    if (cmd === 'scrub') {
-		Ext.MessageBox.defaultButton = params.deep === 1 ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: params.deep === 1 ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: params.deep !== 1 ?
-		       Ext.String.format(gettext("Scrub OSD.{0}"), osdid) :
-		       Ext.String.format(gettext("Deep Scrub OSD.{0}"), osdid) +
-			   "<br>Caution: This can reduce performance while it is running.",
-		    buttons: Ext.Msg.YESNO,
-		    callback: function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRequest();
-		    }
-		});
-	    } else {
-		doRequest();
-	    }
-	},
-
-	create_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephCreateOsd', {
-		nodename: vm.get('nodename'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	destroy_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephRemoveOsd', {
-		nodename: vm.get('osdhost'),
-		osdid: vm.get('osdid'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	set_flag: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var flags = vm.get('flags');
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + vm.get('nodename') + "/ceph/flags/noout",
-		waitMsgTarget: me.getView(),
-		method: flags.includes('noout') ? 'DELETE' : 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: () => { me.reload(); }
-	    });
-	},
-
-	service_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd || comp;
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + vm.get('osdhost') + "/ceph/" + cmd,
-		params: { service: "osd." + vm.get('osdid') },
-		waitMsgTarget: me.getView(),
-		method: 'POST',
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: () => { me.reload(); }
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	set_selection_status: function(tp, selection) {
-	    if (selection.length < 1) {
-		return;
-	    }
-	    var rec = selection[0];
-	    var vm = this.getViewModel();
-
-	    var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
-
-	    vm.set('isOsd', isOsd);
-	    vm.set('downOsd', isOsd && rec.data.status === 'down');
-	    vm.set('upOsd', isOsd && rec.data.status !== 'down');
-	    vm.set('inOsd', isOsd && rec.data.in);
-	    vm.set('outOsd', isOsd && !rec.data.in);
-	    vm.set('osdid', isOsd ? rec.data.id : undefined);
-	    vm.set('osdhost', isOsd ? rec.data.host : undefined);
-	},
-
-	render_status: function(value, metaData, rec) {
-	    if (!value) {
-		return value;
-	    }
-	    var inout = rec.data['in'] ? 'in' : 'out';
-	    var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
-		'critical fa-arrow-circle-down';
-
-	    var inouticon = rec.data['in'] ? 'good fa-circle' :
-		'warning fa-circle-o';
-
-	    var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
-		inout + ' <i class="fa ' + inouticon + '"></i>';
-
-	    return text;
-	},
-
-	render_wal: function(value, metaData, rec) {
-	    if (!value &&
-		rec.data.osdtype === 'bluestore' &&
-		rec.data.type === 'osd') {
-		return 'N/A';
-	    }
-	    return value;
-	},
-
-	render_version: function(value, metadata, rec) {
-	    var vm = this.getViewModel();
-	    var versions = vm.get('versions');
-	    var icon = "";
-	    var version = value || "";
-	    if (value && value != vm.get('maxversion')) {
-		icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
-	    }
-
-	    if (!value && rec.data.type == 'host') {
-		version = versions[rec.data.name] || Proxmox.Utils.unknownText;
-	    }
-
-	    return icon + version;
-	},
-
-	render_osd_val: function(value, metaData, rec) {
-	    return (rec.data.type === 'osd') ? value : '';
-	},
-	render_osd_weight: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    return Ext.util.Format.number(value, '0.00###');
-	},
-
-	render_osd_latency: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    let commit_ms = rec.data.commit_latency_ms,
-	        apply_ms = rec.data.apply_latency_ms;
-	    return apply_ms + ' / ' + commit_ms;
-	},
-
-	render_osd_size: function(value, metaData, rec) {
-	    return this.render_osd_val(PVE.Utils.render_size(value), metaData, rec);
-	},
-
-	control: {
-	    '#': {
-		selectionchange: 'set_selection_status'
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-
-	    if (!view.pveSelNode.data.node) {
-		throw "no node name specified";
-	    }
-
-	    vm.set('nodename', view.pveSelNode.data.node);
-
-	    me.callParent();
-	    me.reload();
-	}
-    },
-
-    stateful: true,
-    stateId: 'grid-ceph-osd',
-    rootVisible: false,
-    useArrows: true,
-
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: 'Name',
-	    dataIndex: 'name',
-	    width: 150
-	},
-	{
-	    text: 'Type',
-	    dataIndex: 'type',
-	    hidden: true,
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: gettext("Class"),
-	    dataIndex: 'device_class',
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: "OSD Type",
-	    dataIndex: 'osdtype',
-	    align: 'right',
-	    width: 100
-	},
-	{
-	    text: "Bluestore Device",
-	    dataIndex: 'blfsdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "DB Device",
-	    dataIndex: 'dbdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "WAL Device",
-	    dataIndex: 'waldev',
-	    align: 'right',
-	    renderer: 'render_wal',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: 'Status',
-	    dataIndex: 'status',
-	    align: 'right',
-	    renderer: 'render_status',
-	    width: 120
-	},
-	{
-	    text: gettext('Version'),
-	    dataIndex: 'version',
-	    align: 'right',
-	    renderer: 'render_version'
-	},
-	{
-	    text: 'weight',
-	    dataIndex: 'crush_weight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: 'reweight',
-	    dataIndex: 'reweight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: gettext('Used') + ' (%)',
-	    dataIndex: 'percent_used',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return Ext.util.Format.number(value, '0.00');
-	    },
-	    width: 100
-	},
-	{
-	    text: gettext('Total'),
-	    dataIndex: 'total_space',
-	    align: 'right',
-	    renderer: 'render_osd_size',
-	    width: 100
-	},
-	{
-	    text: 'Apply/Commit<br>Latency (ms)',
-	    dataIndex: 'apply_latency_ms',
-	    align: 'right',
-	    renderer: 'render_osd_latency',
-	    width: 120
-	}
-    ],
-
-
-    tbar: {
-	items: [
-	    {
-		text: gettext('Reload'),
-		iconCls: 'fa fa-refresh',
-		handler: 'reload'
-	    },
-	    '-',
-	    {
-		text: gettext('Create') + ': OSD',
-		handler: 'create_osd',
-	    },
-	    {
-		text: gettext('Set noout'),
-		itemId: 'nooutBtn',
-		handler: 'set_flag',
-	    },
-	    '->',
-	    {
-		xtype: 'tbtext',
-		data: {
-		    osd: undefined
-		},
-		bind: {
-		    data: {
-			osd: "{osdid}"
-		    }
-		},
-		tpl: [
-		    '<tpl if="osd">',
-		    'osd.{osd}:',
-		    '<tpl else>',
-		    gettext('No OSD selected'),
-		    '</tpl>'
-		]
-	    },
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-play',
-		disabled: true,
-		bind: {
-		    disabled: '{!downOsd}'
-		},
-		cmd: 'start',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-stop',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'stop',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Restart'),
-		iconCls: 'fa fa-refresh',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'restart',
-		handler: 'service_cmd'
-	    },
-	    '-',
-	    {
-		text: 'Out',
-		iconCls: 'fa fa-circle-o',
-		disabled: true,
-		bind: {
-		    disabled: '{!inOsd}'
-		},
-		cmd: 'out',
-		handler: 'osd_cmd'
-	    },
-	    {
-		text: 'In',
-		iconCls: 'fa fa-circle',
-		disabled: true,
-		bind: {
-		    disabled: '{!outOsd}'
-		},
-		cmd: 'in',
-		handler: 'osd_cmd'
-	    },
-	    '-',
-	    {
-		text: gettext('More'),
-		iconCls: 'fa fa-bars',
-		disabled: true,
-		bind: {
-		    disabled: '{!isOsd}'
-		},
-		menu: [
-		    {
-			text: gettext('Scrub'),
-			iconCls: 'fa fa-shower',
-			cmd: 'scrub',
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Deep Scrub'),
-			iconCls: 'fa fa-bath',
-			cmd: 'scrub',
-			params: {
-			    deep: 1,
-			},
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Destroy'),
-			itemId: 'remove',
-			iconCls: 'fa fa-fw fa-trash-o',
-			bind: {
-			    disabled: '{!downOsd}'
-			},
-			handler: 'destroy_osd'
-		    }
-		],
-	    }
-	]
-    },
-
-    fields: [
-	'name', 'type', 'status', 'host', 'in', 'id' ,
-	{ type: 'number', name: 'reweight' },
-	{ type: 'number', name: 'percent_used' },
-	{ type: 'integer', name: 'bytes_used' },
-	{ type: 'integer', name: 'total_space' },
-	{ type: 'integer', name: 'apply_latency_ms' },
-	{ type: 'integer', name: 'commit_latency_ms' },
-	{ type: 'string', name: 'device_class' },
-	{ type: 'string', name: 'osdtype' },
-	{ type: 'string', name: 'blfsdev' },
-	{ type: 'string', name: 'dbdev' },
-	{ type: 'string', name: 'waldev' },
-	{ type: 'string', name: 'version', calculate: function(data) {
-	    return PVE.Utils.parse_ceph_version(data);
-	} },
-	{ type: 'string', name: 'iconCls', calculate: function(data) {
-	    var iconMap = {
-		host: 'fa-building',
-		osd: 'fa-hdd-o',
-		root: 'fa-server',
-	    };
-	    return 'fa x-fa-tree ' + iconMap[data.type];
-	} },
-	{ type: 'number', name: 'crush_weight' }
-    ],
-});
-Ext.define('PVE.node.CephMonMgrList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveNodeCephMonMgr',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    onlineHelp: 'chapter_pveceph',
-
-    defaults: {
-	border: false,
-	onlineHelp: 'chapter_pveceph',
-	flex: 1
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    items: [
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    type: 'mon',
-	    additionalColumns: [
-		{
-		    header: gettext('Quorum'),
-		    width: 70,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'quorum'
-		}
-	    ],
-	    stateId: 'grid-ceph-monitor',
-	    showCephInstallMask: true,
-	    title: gettext('Monitor')
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    type: 'mgr',
-	    stateId: 'grid-ceph-manager',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    title: gettext('Manager')
-	}
-    ]
-});
-Ext.define('PVE.node.CephCrushMap', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveNodeCephCrushMap'],
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    stateful: true,
-    stateId: 'layout-ceph-crush',
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/crush',
-
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.node.CephStatus', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephStatus',
-
-    onlineHelp: 'chapter_pveceph',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: {
-	type: 'column'
-    },
-
-    defaults: {
-	padding: 5
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Health'),
-	    bodyPadding: 10,
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    minHeight: 230,
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    minHeight: 500,
-		    columnWidth: 0.5
-		}
-	    },
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    itemId: 'overallhealth',
-		    xtype: 'pveHealthWidget',
-		    title: gettext('Status')
-		},
-		{
-		    flex: 2,
-		    itemId: 'warnings',
-		    stateful: true,
-		    stateId: 'ceph-status-warnings',
-		    xtype: 'grid',
-		    // since we load the store manually,
-		    // to show the emptytext, we have to
-		    // specify an empty store
-		    store: { data:[] },
-		    emptyText: gettext('No Warnings/Errors'),
-		    columns: [
-			{
-			    dataIndex: 'severity',
-			    header: gettext('Severity'),
-			    align: 'center',
-			    width: 70,
-			    renderer: function(value) {
-				var health = PVE.Utils.map_ceph_health[value];
-				var classes = PVE.Utils.get_health_icon(health);
-
-				return '<i class="fa fa-fw ' + classes + '"></i>';
-			    },
-			    sorter: {
-				sorterFn: function(a,b) {
-				    var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-				    return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-				}
-			    }
-			},
-			{
-			    dataIndex: 'summary',
-			    header: gettext('Summary'),
-			    flex: 1
-			},
-			{
-			    xtype: 'actioncolumn',
-			    width: 40,
-			    align: 'center',
-			    tooltip: gettext('Detail'),
-			    items: [
-				{
-				    iconCls: 'x-fa fa-info-circle',
-				    handler: function(grid, rowindex, colindex, item, e, record) {
-					var win = Ext.create('Ext.window.Window', {
-					    title: gettext('Detail'),
-					    resizable: true,
-					    modal: true,
-					    width: 650,
-					    height: 400,
-					    layout: {
-						type: 'fit'
-					    },
-					    items: [{
-						scrollable: true,
-						padding: 10,
-						xtype: 'box',
-						html: [
-						    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-						    '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-						]
-					    }]
-					});
-					win.show();
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveCephStatusDetail',
-	    itemId: 'statusdetail',
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 250
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 300
-		}
-	    },
-	    title: gettext('Status')
-	},
-	{
-	    title: gettext('Services'),
-	    xtype: 'pveCephServices',
-	    itemId: 'services',
-	    plugins: 'responsive',
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 200
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 200
-		}
-	    }
-	},
-	{
-	    xtype: 'panel',
-	    title: gettext('Performance'),
-	    columnWidth: 1,
-	    bodyPadding: 5,
-	    layout: {
-		type: 'hbox',
-		align: 'center'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    xtype: 'proxmoxGauge',
-		    itemId: 'space',
-		    title: gettext('Usage')
-		},
-		{
-		    flex: 2,
-		    xtype: 'container',
-		    defaults: {
-			padding: 0,
-			height: 100
-		    },
-		    items: [
-			{
-			    itemId: 'reads',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Reads'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'writes',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Writes'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'iops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS', // do not localize
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'readiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Reads'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'writeiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Writes'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			}
-		    ]
-		}
-	    ]
-	}
-    ],
-
-    generateCheckData: function(health) {
-	var result = [];
-	var checks = health.checks || {};
-	var keys = Ext.Object.getKeys(checks).sort();
-
-	Ext.Array.forEach(keys, function(key) {
-	    var details = checks[key].detail || [];
-	    result.push({
-		id: key,
-		summary: checks[key].summary.message,
-		detail: Ext.Array.reduce(
-			    checks[key].detail,
-			    function(first, second) {
-				return first + '\n' + second.message;
-			    },
-			    ''
-			),
-		severity: checks[key].severity
-	    });
-	});
-
-	return result;
-    },
-
-    updateAll: function(store, records, success) {
-	if (!success || records.length === 0) {
-	    return;
-	}
-
-	var me = this;
-	var rec = records[0];
-	me.status = rec.data;
-
-	// add health panel
-	me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
-	// add errors to gridstore
-	me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
-
-	// update services
-	me.getComponent('services').updateAll(me.metadata || {}, rec.data);
-
-	// update detailstatus panel
-	me.getComponent('statusdetail').updateAll(me.metadata || {}, rec.data);
-
-	// add performance data
-	var used = rec.data.pgmap.bytes_used;
-	var total = rec.data.pgmap.bytes_total;
-
-	var text = Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(used),
-	    PVE.Utils.render_size(total)
-	);
-
-	// update the usage widget
-	me.down('#space').updateValue(used/total, text);
-
-	// TODO: logic for jewel (iops split in read/write)
-
-	var iops = rec.data.pgmap.op_per_sec;
-	var readiops = rec.data.pgmap.read_op_per_sec;
-	var writeiops = rec.data.pgmap.write_op_per_sec;
-	var reads = rec.data.pgmap.read_bytes_sec || 0;
-	var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-	if (iops !== undefined && me.version !== 'hammer') {
-	    me.change_version('hammer');
-	} else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-	    me.change_version('jewel');
-	}
-	// update the graphs
-	me.reads.addDataPoint(reads);
-	me.writes.addDataPoint(writes);
-	me.iops.addDataPoint(iops);
-	me.readiops.addDataPoint(readiops);
-	me.writeiops.addDataPoint(writeiops);
-    },
-
-    change_version: function(version) {
-	var me = this;
-	me.version = version;
-	me.sp.set('ceph-version', version);
-	me.iops.setVisible(version === 'hammer');
-	me.readiops.setVisible(version === 'jewel');
-	me.writeiops.setVisible(version === 'jewel');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	me.callParent();
-	var baseurl = '/api2/json' + (nodename ? '/nodes/' + nodename : '/cluster') + '/ceph';
-	me.store = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-status-' + (nodename || 'cluster'),
-	    interval: 5000,
-	    proxy: {
-		type: 'proxmox',
-		url: baseurl + '/status'
-	    }
-	});
-
-	me.metadatastore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-metadata-' + (nodename || 'cluster'),
-	    interval: 15*1000,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/ceph/metadata'
-	    }
-	});
-
-	// save references for the updatefunction
-	me.iops = me.down('#iops');
-	me.readiops = me.down('#readiops');
-	me.writeiops = me.down('#writeiops');
-	me.reads = me.down('#reads');
-	me.writes = me.down('#writes');
-
-	// get ceph version
-	me.sp = Ext.state.Manager.getProvider();
-	me.version = me.sp.get('ceph-version');
-	me.change_version(me.version);
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-	    me.store.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, (nodename || 'localhost'),
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.mon(me.store, 'load', me.updateAll, me);
-	me.mon(me.metadatastore, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    var rec = records[0];
-	    me.metadata = rec.data;
-
-	    // update services
-	    me.getComponent('services').updateAll(rec.data, me.status || {});
-
-	    // update detailstatus panel
-	    me.getComponent('statusdetail').updateAll(rec.data, me.status || {});
-
-	}, me);
-
-	me.on('destroy', me.store.stopUpdate);
-	me.on('destroy', me.metadatastore.stopUpdate);
-	me.store.startUpdate();
-	me.metadatastore.startUpdate();
-    }
-
-});
-Ext.define('PVE.ceph.StatusDetail', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephStatusDetail',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [{
-	flex: 1,
-	itemId: 'osds',
-	maxHeight: 250,
-	scrollable: true,
-	padding: '0 10 5 10',
-	data: {
-	    total: 0,
-	    upin: 0,
-	    upout: 0,
-	    downin: 0,
-	    downout: 0,
-	    oldosds: []
-	},
-	tpl: [
-	    '<h3>' + 'OSDs' + '</h3>',
-	    '<table class="osds">',
-	    '<tr><td></td>',
-	    '<td><i class="fa fa-fw good fa-circle"></i>',
-	    gettext('In'),
-	    '</td>',
-	    '<td><i class="fa fa-fw warning fa-circle-o"></i>',
-	    gettext('Out'),
-	    '</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
-	    gettext('Up'),
-	    '</td>',
-	    '<td>{upin}</td>',
-	    '<td>{upout}</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
-	    gettext('Down'),
-	    '</td>',
-	    '<td>{downin}</td>',
-	    '<td>{downout}</td>',
-	    '</tr>',
-	    '</table>',
-	    '<br /><div>',
-	    gettext('Total'),
-	    ': {total}',
-	    '</div><br />',
-	    '<tpl if="oldosds.length &gt; 0">',
-	    '<i class="fa fa-refresh warning"></i> ' + gettext('Outdated OSDs') + "<br>",
-	    '<div class="osds">',
-	    '<tpl for="oldosds">',
-	    '<div class="left-aligned">osd.{id}:</div>',
-	    '<div class="right-aligned">{version}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>',
-	    '</div>',
-	    '</tpl>'
-	]
-    },
-    {
-	flex: 1,
-	border: false,
-	itemId: 'pgchart',
-	xtype: 'polar',
-	height: 184,
-	innerPadding: 5,
-	insetPadding: 5,
-	colors: [
-	    '#CFCFCF',
-	    '#21BF4B',
-	    '#FFCC00',
-	    '#FF6C59'
-	],
-	store: { },
-	series: [
-	    {
-		type: 'pie',
-		donut: 60,
-		angleField: 'count',
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function(tooltip, record, ctx) {
-			var html = record.get('text');
-			html += '<br>';
-			record.get('states').forEach(function(state) {
-			    html += '<br>' +
-				state.state_name + ': ' + state.count.toString();
-			});
-			tooltip.setHtml(html);
-		    }
-		},
-		subStyle: {
-		    strokeStyle: false
-		}
-	    }
-	]
-    },
-    {
-	flex: 1.6,
-	itemId: 'pgs',
-	padding: '0 10',
-	maxHeight: 250,
-	scrollable: true,
-	data: {
-	    states: []
-	},
-	tpl: [
-	    '<h3>' + 'PGs' + '</h3>',
-	    '<tpl for="states">',
-	    '<div class="left-aligned"><i class ="fa fa-circle {cls}"></i> {state_name}:</div>',
-	    '<div class="right-aligned">{count}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>'
-	]
-    }],
-
-    // similar to mgr dashboard
-    pgstates: {
-	// clean
-	clean: 1,
-	active: 1,
-
-	// working
-	activating: 2,
-	backfill_wait: 2,
-	backfilling: 2,
-	creating: 2,
-	deep: 2,
-	degraded: 2,
-	forced_backfill: 2,
-	forced_recovery: 2,
-	peered: 2,
-	peering: 2,
-	recovering: 2,
-	recovery_wait: 2,
-	repair: 2,
-	scrubbing: 2,
-	snaptrim: 2,
-	snaptrim_wait: 2,
-
-	// error
-	backfill_toofull: 3,
-	backfill_unfound: 3,
-	down: 3,
-	incomplete: 3,
-	inconsistent: 3,
-	recovery_toofull: 3,
-	recovery_unfound: 3,
-	remapped: 3,
-	snaptrim_error: 3,
-	stale: 3,
-	undersized: 3
-    },
-
-    statecategories: [
-	{
-	    text: gettext('Unknown'),
-	    count: 0,
-	    states: [],
-	    cls: 'faded'
-	},
-	{
-	    text: gettext('Clean'),
-	    cls: 'good'
-	},
-	{
-	    text: gettext('Working'),
-	    cls: 'warning'
-	},
-	{
-	    text: gettext('Error'),
-	    cls: 'critical'
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var maxversion = "0";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-
-	var oldosds = [];
-
-	if (metadata.osd) {
-	    metadata.osd.forEach(function(osd) {
-		var version = PVE.Utils.parse_ceph_version(osd);
-		if (version != maxversion) {
-		    oldosds.push({
-			id: osd.id,
-			version: version
-		    });
-		}
-	    });
-	}
-
-	var pgmap = status.pgmap || {};
-	var health = status.health || {};
-	var osdmap = status.osdmap || { osdmap: {} };
-
-
-	// update pgs sorted
-	var pgs_by_state = pgmap.pgs_by_state || [];
-	pgs_by_state.sort(function(a,b){
-	    return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
-	});
-
-	me.statecategories.forEach(function(cat) {
-	    cat.count = 0;
-	    cat.states = [];
-	});
-
-	pgs_by_state.forEach(function(state) {
-	    var i;
-	    var states = state.state_name.split(/[^a-z]+/);
-	    var result = 0;
-	    for (i = 0; i < states.length; i++) {
-		if (me.pgstates[states[i]] > result) {
-		    result = me.pgstates[states[i]];
-		}
-	    }
-	    // for the list
-	    state.cls = me.statecategories[result].cls;
-
-	    me.statecategories[result].count += state.count;
-	    me.statecategories[result].states.push(state);
-	});
-
-	me.getComponent('pgchart').getStore().setData(me.statecategories);
-	me.getComponent('pgs').update({states: pgs_by_state});
-
-	var downinregex = /(\d+) osds down/;
-	var downin_osds = 0;
-
-	// we collect monitor/osd information from the checks
-	Ext.Object.each(health.checks, function(key, value, obj) {
-	    var found = null;
-	    if (key === 'OSD_DOWN') {
-		found = value.summary.message.match(downinregex);
-		if (found !== null) {
-		    downin_osds = parseInt(found[1],10);
-		}
-	    }
-	});
-
-	// update osds counts
-
-	var total_osds = osdmap.osdmap.num_osds || 0;
-	var in_osds = osdmap.osdmap.num_in_osds || 0;
-	var up_osds = osdmap.osdmap.num_up_osds || 0;
-	var out_osds = total_osds - in_osds;
-	var down_osds = total_osds - up_osds;
-
-	var downout_osds = down_osds - downin_osds;
-	var upin_osds = in_osds - downin_osds;
-	var upout_osds = up_osds - upin_osds;
-	var osds = {
-	    total: total_osds,
-	    upin: upin_osds,
-	    upout: upout_osds,
-	    downin: downin_osds,
-	    downout: downout_osds,
-	    oldosds: oldosds
-	};
-	var osdcomponent = me.getComponent('osds');
-	osdcomponent.update(Ext.apply(osdcomponent.data, osds));
-
-	me.suspendLayout = false;
-	me.updateLayout();
-    }
-});
-
-Ext.define('PVE.ceph.Services', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephServices',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5 20',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mons',
-	    title: gettext('Monitors')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mgrs',
-	    title: gettext('Managers')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mdss',
-	    title: gettext('Meta Data Servers')
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-
-	var healthstates = {
-	    'HEALTH_UNKNOWN': 0,
-	    'HEALTH_ERR': 1,
-	    'HEALTH_WARN': 2,
-	    'HEALTH_OLD': 3,
-	    'HEALTH_OK': 4
-	};
-	var healthmap = [
-	    'HEALTH_UNKNOWN',
-	    'HEALTH_ERR',
-	    'HEALTH_WARN',
-	    'HEALTH_OLD',
-	    'HEALTH_OK'
-	];
-	var reduceFn = function(first, second) {
-	    return first + '\n' + second.message;
-	};
-	var services = ['mon','mgr','mds'];
-	var maxversion = "00.0.00";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-	var i;
-	var quorummap = (status && status.quorum_names) ? status.quorum_names : [];
-	var monmessages = {};
-	var mgrmessages = {};
-	var mdsmessages = {};
-	if (status) {
-	    if (status.health) {
-		Ext.Object.each(status.health.checks, function(key, value, obj) {
-		    if (!Ext.String.startsWith(key, "MON_")) {
-			return;
-		    }
-
-		    var i;
-		    for (i = 0; i < value.detail.length; i++) {
-			var match = value.detail[i].message.match(/mon.([a-zA-Z0-9\-\.]+)/);
-			if (!match) {
-			    continue;
-			}
-			var monid = match[1];
-
-			if (!monmessages[monid]) {
-			    monmessages[monid] = {
-				worstSeverity: healthstates.HEALTH_OK,
-				messages: []
-			    };
-			}
-
-
-			monmessages[monid].messages.push(
-							 PVE.Utils.get_ceph_icon_html(value.severity, true) +
-							 Ext.Array.reduce(value.detail, reduceFn, '')
-			);
-			if (healthstates[value.severity] < monmessages[monid].worstSeverity) {
-			    monmessages[monid].worstSeverity = healthstates[value.severity];
-			}
-		    }
-		});
-	    }
-
-	    if (status.mgrmap) {
-		mgrmessages[status.mgrmap.active_name] = "active";
-		status.mgrmap.standbys.forEach(function(mgr) {
-		    mgrmessages[mgr.name] = "standby";
-		});
-	    }
-
-	    if (status.fsmap) {
-		status.fsmap.by_rank.forEach(function(mds) {
-		    mdsmessages[mds.name] = 'rank: ' + mds.rank + "; " + mds.status;
-		});
-	    }
-	}
-
-	var checks = {
-	    mon: function(mon) {
-		if (quorummap.indexOf(mon.name) !== -1) {
-		    mon.health = healthstates.HEALTH_OK;
-		} else {
-		    mon.health = healthstates.HEALTH_ERR;
-		}
-		if (monmessages[mon.name]) {
-		    if (monmessages[mon.name].worstSeverity < mon.health) {
-			mon.health = monmessages[mon.name].worstSeverity;
-		    }
-		    Array.prototype.push.apply(mon.messages, monmessages[mon.name].messages);
-		}
-		return mon;
-	    },
-	    mgr: function(mgr) {
-		if (mgrmessages[mgr.name] === 'active') {
-		    mgr.title = '<b>' + mgr.title + '</b>';
-		    mgr.statuses.push(gettext('Status') + ': <b>active</b>');
-		} else if (mgrmessages[mgr.name] === 'standby') {
-		    mgr.statuses.push(gettext('Status') + ': standby');
-		} else if (mgr.health > healthstates.HEALTH_WARN) {
-		    mgr.health = healthstates.HEALTH_WARN;
-		}
-
-		return mgr;
-	    },
-	    mds: function(mds) {
-		if (mdsmessages[mds.name]) {
-		    mds.title = '<b>' + mds.title + '</b>';
-		    mds.statuses.push(gettext('Status') + ': <b>' + mdsmessages[mds.name]+"</b>");
-		} else if (mds.addr !== Proxmox.Utils.unknownText) {
-		    mds.statuses.push(gettext('Status') + ': standby');
-		}
-
-		return mds;
-	    }
-	};
-
-	for (i = 0; i < services.length; i++) {
-	    var type = services[i];
-	    var ids = Object.keys(metadata[type] || {});
-	    me[type] = {};
-
-	    var j;
-	    for (j = 0; j < ids.length; j++) {
-		var id = ids[j];
-		var tmp = id.split('@');
-		var name = tmp[0];
-		var host = tmp[1];
-		var result = {
-		    id: id,
-		    health: healthstates.HEALTH_OK,
-		    statuses: [],
-		    messages: [],
-		    name: name,
-		    title: metadata[type][id].name || name,
-		    host: host,
-		    version: PVE.Utils.parse_ceph_version(metadata[type][id]),
-		    service: metadata[type][id].service,
-		    addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText
-		};
-
-		result.statuses = [
-		    gettext('Host') + ": " + result.host,
-		    gettext('Address') + ": " + result.addr
-		];
-
-		if (checks[type]) {
-		    result = checks[type](result);
-		}
-
-		if (result.service && !result.version) {
-		    result.messages.push(
-			PVE.Utils.get_ceph_icon_html('HEALTH_UNKNOWN', true) +
-			gettext('Stopped')
-		    );
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (!result.version && result.addr === Proxmox.Utils.unknownText) {
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (result.version) {
-		    result.statuses.push(gettext('Version') + ": " + result.version);
-
-		    if (result.version != maxversion) {
-			if (result.health > healthstates.HEALTH_OLD) {
-			    result.health = healthstates.HEALTH_OLD;
-			}
-			result.messages.push(
-			    PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) +
-			    gettext('Not Current Version, please upgrade')
-			);
-		    }
-		}
-
-		result.statuses.push(''); // empty line
-		result.text = result.statuses.concat(result.messages).join('<br>');
-
-		result.health = healthmap[result.health];
-
-		me[type][id] = result;
-	    }
-	}
-
-	me.getComponent('mons').updateAll(Object.values(me.mon));
-	me.getComponent('mgrs').updateAll(Object.values(me.mgr));
-	me.getComponent('mdss').updateAll(Object.values(me.mds));
-    }
-});
-
-Ext.define('PVE.ceph.ServiceList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCephServiceList',
-
-    style: {
-	'text-align':'center'
-    },
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	}
-    ],
-
-    updateAll: function(list) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var i;
-	list.sort(function(a,b) {
-	    return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
-	});
-	var ids = {};
-	if (me.ids) {
-	    me.ids.forEach(function(id) {
-		ids[id] = true;
-	    });
-	}
-	for (i = 0; i < list.length; i++) {
-	    var service = me.getComponent(list[i].id);
-	    if (!service) {
-		// since services are already sorted, and
-		// we always have a sorted list
-		// we can add it at the service+1 position (because of the title)
-		service = me.insert(i+1, {
-		    xtype: 'pveCephServiceWidget',
-		    itemId: list[i].id
-		});
-		if (!me.ids) {
-		    me.ids = [];
-		}
-		me.ids.push(list[i].id);
-	    } else {
-		delete ids[list[i].id];
-	    }
-	    service.updateService(list[i].title, list[i].text, list[i].health);
-	}
-
-	Object.keys(ids).forEach(function(id) {
-	    me.remove(id);
-	});
-	me.suspendLayout = false;
-	me.updateLayout();
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getComponent('title').update({
-	    title: me.title
-	});
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.ServiceWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveCephServiceWidget',
-
-    userCls: 'monitor inline-block',
-    data: {
-	title: '0',
-	health: 'HEALTH_ERR',
-	text: '',
-	iconCls: PVE.Utils.get_health_icon()
-    },
-
-    tpl: [
-	'{title}: ',
-	'<i class="fa fa-fw {iconCls}"></i>'
-    ],
-
-    updateService: function(title, text, health) {
-	var me = this;
-
-	me.update(Ext.apply(me.data, {
-	    health: health,
-	    text: text,
-	    title: title,
-	    iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[health])
-	}));
-
-	if (me.tooltip) {
-	    me.tooltip.setHtml(text);
-	}
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    if (me.tooltip) {
-		me.tooltip.destroy();
-		delete me.tooltip;
-	    }
-	},
-	mouseenter: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (!me) {
-		    return;
-		}
-		if (!me.tooltip) {
-		    me.tooltip = Ext.create('Ext.tip.ToolTip', {
-			target: me.el,
-			trackMouse: true,
-			dismissDelay: 0,
-			renderTo: Ext.getBody(),
-			html: me.data.text
-		    });
-		}
-		me.tooltip.show();
-	    }
-	},
-	mouseleave: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (me.tooltip) {
-		    me.tooltip.destroy();
-		    delete me.tooltip;
-		}
-	    }
-	}
-    }
-});
-Ext.define('PVE.node.CephConfigDb', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveNodeCephConfigDb',
-
-    border: false,
-    store: {
-	proxy: {
-	    type: 'proxmox'
-	}
-    },
-
-    columns: [
-	{
-	    dataIndex: 'section',
-	    text: 'WHO',
-	    width: 100,
-	},
-	{
-	    dataIndex: 'mask',
-	    text: 'MASK',
-	    hidden: true,
-	    width: 80,
-	},
-	{
-	    dataIndex: 'level',
-	    hidden: true,
-	    text: 'LEVEL',
-	},
-	{
-	    dataIndex: 'name',
-	    flex: 1,
-	    text: 'OPTION',
-	},
-	{
-	    dataIndex: 'value',
-	    flex: 1,
-	    text: 'VALUE',
-	},
-	{
-	    dataIndex: 'can_update_at_runtime',
-	    text: 'Runtime Updatable',
-	    hidden: true,
-	    width: 80,
-	    renderer: Proxmox.Utils.format_boolean
-	},
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store.proxy.url = '/api2/json/nodes/' + nodename + '/ceph/configdb';
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore());
-	me.getStore().load();
-    }
-});
-Ext.define('PVE.node.CephConfig', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfig',
-
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/config',
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.CephConfigCrush', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfigCrush',
-
-    onlineHelp: 'chapter_pveceph',
-
-    layout: 'border',
-    items: [{
-	    title: gettext('Configuration'),
-	    xtype: 'pveNodeCephConfig',
-	    region: 'center'
-	},
-	{
-	    title: 'Crush Map', // do not localize
-	    xtype: 'pveNodeCephCrushMap',
-	    region: 'east',
-	    split: true,
-	    width: '50%'
-	},
-	{
-	    title: gettext('Configuration Database'),
-	    xtype: 'pveNodeCephConfigDb',
-	    region: 'south',
-	    split: true,
-	    weight: -30,
-	    height: '50%'
-    }],
-
-    initComponent: function() {
-	var me = this;
-	me.defaults = {
-	    pveSelNode: me.pveSelNode
-	};
-	me.callParent();
-    }
-});
-Ext.define('PVE.ceph.Log', {
-    extend: 'Proxmox.panel.LogView',
-    xtype: 'cephLogView',
-    nodename: undefined,
-    failCallback: function(response) {
-	var me = this;
-	var msg = response.htmlStatus;
-	var windowShow = PVE.Utils.showCephInstallOrMask(me, msg, me.nodename,
-	    function(win){
-		me.mon(win, 'cephInstallWindowClosed', function(){
-		    me.loadTask.delay(200);
-		});
-	    }
-	);
-	if (!windowShow) {
-	    Proxmox.Utils.setErrorMask(me, msg);
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.CephInstallWizard', {
-	extend: 'PVE.window.Wizard',
-	alias: 'widget.pveCephInstallWizard',
-	mixins: ['Proxmox.Mixin.CBind'],
-	resizable: false,
-	nodename: undefined,
-	viewModel: {
-	    data: {
-		nodename: '',
-		configuration: true,
-		isInstalled: false
-	    }
-	},
-	cbindData: {
-	    nodename: undefined
-	},
-	title: gettext('Setup'),
-	navigateNext: function() {
-	    var tp = this.down('#wizcontent');
-	    var atab = tp.getActiveTab();
-
-	    var next = tp.items.indexOf(atab) + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (ntab) {
-		ntab.enable();
-		tp.setActiveTab(ntab);
-	    }
-	},
-	setInitialTab: function (index) {
-	    var tp = this.down('#wizcontent');
-	    var initialTab = tp.items.getAt(index);
-	    initialTab.enable();
-	    tp.setActiveTab(initialTab);
-	},
-	onShow: function() {
-		this.callParent(arguments);
-		var isInstalled = this.getViewModel().get('isInstalled');
-		if (isInstalled) {
-		    this.getViewModel().set('configuration', false);
-		    this.setInitialTab(2);
-		}
-	},
-	items: [
-	    {
-		title: gettext('Info'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'chapter_pveceph',
-		html: '<h3>Ceph?</h3>'+
-		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
-		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
-		' This wizard will guide you through the necessary steps, after the initial installation you will be offered to create an initial configuration.'+
-		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
-		'<p>Please take a look at our documentation, by clicking the help button below, before starting the installation, '+
-		'if you want to gain deeper knowledge about Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#back').hide(true);
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Start installation'));
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
-		    }
-		}
-	    },
-	    {
-		title: gettext('Installation'),
-		xtype: 'panel',
-		layout: 'fit',
-		cbind:{
-		    nodename: '{nodename}'
-		},
-		viewModel: {}, // needed to inherit parent viewModel data
-		listeners: {
-		    afterrender: function() {
-			var me = this;
-			if (this.getViewModel().get('isInstalled')) {
-			    this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
-			} else {
-			    me.down('pveNoVncConsole').fireEvent('activate');
-			}
-		    },
-		    activate: function() {
-			var me = this;
-			var nodename = me.nodename;
-			me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
-				storeid: 'ceph-status-' + nodename,
-				interval: 1000,
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + nodename + '/ceph/status'
-				},
-				listeners: {
-				    load: function(rec, response, success, operation) {
-
-					if (success) {
-					    me.updateStore.stopUpdate();
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("not initialized", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("rados_connect failed", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
-					    me.down('textfield').setValue('success');
-					} else if (!operation.error.statusText.match("not installed", "i")) {
-					    Proxmox.Utils.setErrorMask(me, operation.error.statusText);
-					}
-				    }
-				}
-			});
-			me.updateStore.startUpdate();
-		    },
-		    destroy: function() {
-			var me = this;
-			if (me.updateStore) {
-			    me.updateStore.stopUpdate();
-			}
-		    }
-		},
-		items: [
-		    {
-			itemId: 'jsconsole',
-			consoleType: 'cmd',
-			xtermjs: true,
-			xtype: 'pveNoVncConsole',
-			cbind:{
-			    nodename: '{nodename}'
-			},
-			cmd: 'ceph_install'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'installSuccess',
-			value: '',
-			allowBlank: false,
-			submitValue: false,
-			hidden: true
-		    }
-		]
-	    },
-	    {
-		xtype: 'inputpanel',
-		title: gettext('Configuration'),
-		onlineHelp: 'chapter_pveceph',
-		cbind: {
-		    nodename: '{nodename}'
-		},
-		viewModel: {
-		    data: {
-			replicas: undefined,
-			minreplicas: undefined
-		    }
-		},
-		listeners: {
-		    activate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
-		    },
-		    beforeshow: function() {
-			if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			    this.mask("Coniguration already initialized",['pve-static-mask']);
-			} else {
-			    this.unmask();
-			}
-		    },
-		    deactivate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
-		    }
-		},
-		column1: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('Ceph cluster configuration') + ':'
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'network',
-			value: '',
-			fieldLabel: 'Public Network IP/CIDR',
-			bind: {
-			    allowBlank: '{configuration}'
-			}
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'cluster-network',
-			fieldLabel: 'Cluster Network IP/CIDR',
-			allowBlank: true,
-			autoSelect: false,
-			emptyText: gettext('Same as Public Network')
-		    }
-		    // FIXME: add hint about cluster network and/or reference user to docs??
-		],
-		column2: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('First Ceph monitor') + ':'
-		    },
-		    {
-			xtype: 'pveNodeSelector',
-			fieldLabel: gettext('Monitor node'),
-			name: 'mon-node',
-			selectCurNode: true,
-			allowBlank: false
-		    },
-		    {
-			xtype: 'displayfield',
-			value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
-			userCls: 'pve-hint'
-		    }
-		],
-		advancedColumn1: [
-		    {
-			xtype: 'numberfield',
-			name: 'size',
-			fieldLabel: 'Number of replicas',
-			bind: {
-			    value: '{replicas}'
-			},
-			maxValue: 7,
-			minValue: 2,
-			emptyText: '3'
-		    },
-		    {
-			xtype: 'numberfield',
-			name: 'min_size',
-			fieldLabel: 'Minimum replicas',
-			bind: {
-			    maxValue: '{replicas}',
-			    value: '{minreplicas}'
-			},
-			minValue: 2,
-			maxValue: 3,
-			setMaxValue: function(value) {
-			    this.maxValue = Ext.Number.from(value, 2);
-			    // allow enough to avoid split brains with max 'size', but more makes simply no sense
-			    if (this.maxValue > 4) {
-				this.maxValue = 4;
-			    }
-			    this.toggleSpinners();
-			    this.validate();
-			},
-			emptyText: '2'
-		    }
-		],
-		onGetValues: function(values) {
-		    ['cluster-network', 'size', 'min_size'].forEach(function(field) {
-			if (!values[field]) {
-			    delete values[field];
-			}
-		    });
-		    return values;
-		},
-		onSubmit: function() {
-		    var me = this;
-		    if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			var wizard = me.up('window');
-			var kv = wizard.getValues();
-			delete kv['delete'];
-			var monNode = kv['mon-node'];
-			delete kv['mon-node'];
-			var nodename = me.nodename;
-			delete kv.nodename;
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/ceph/init',
-			    waitMsgTarget: wizard,
-			    method: 'POST',
-			    params: kv,
-			    success: function() {
-				Proxmox.Utils.API2Request({
-				    url: '/nodes/' + monNode + '/ceph/mon/' + monNode,
-				    waitMsgTarget: wizard,
-				    method: 'POST',
-				    success: function() {
-					me.up('pveCephInstallWizard').navigateNext();
-				    },
-				    failure: function(response, opts) {
-					Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				    }
-				});
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-
-		    } else {
-			me.up('pveCephInstallWizard').navigateNext();
-		    }
-		}
-	    },
-	    {
-		title: gettext('Success'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'pve_ceph_install',
-		html: '<h3>Installation successful!</h3>'+
-		'<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
-		    '<ol><li>Install Ceph on other nodes</li>'+
-		    '<li>Create additional Ceph Monitors</li>'+
-		    '<li>Create Ceph OSDs</li>'+
-		    '<li>Create Ceph Pools</li></ol>'+
-		'<p>To learn more click on the help button below.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-
-			var tp = this.up('#wizcontent');
-			var idx = tp.items.indexOf(this)-1;
-			for(;idx >= 0;idx--) {
-			    var nc = tp.items.getAt(idx);
-			    if (nc) {
-				nc.disable();
-			    }
-			}
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-		    }
-		},
-		onSubmit: function() {
-		    var wizard = this.up('pveCephInstallWizard');
-		    wizard.close();
-		}
-	    }
-	]
-    });
-Ext.define('PVE.node.DiskList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeDiskList',
-
-    emptyText: gettext('No Disks found'),
-
-    stateful: true,
-    stateId: 'grid-node-disks',
-
-    columns: [
-	{
-	    header: gettext('Device'),
-	    width: 150,
-	    sortable: true,
-	    dataIndex: 'devpath'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 80,
-	    sortable: true,
-	    dataIndex: 'type',
-	    renderer: function(v) {
-		if (v === 'ssd') {
-		    return 'SSD';
-		} else if (v === 'hdd') {
-		    return 'Hard Disk';
-		} else if (v === 'usb'){
-		    return 'USB';
-		} else {
-		    return gettext('Unknown');
-		}
-	    }
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 150,
-	    sortable: false,
-	    renderer: function(v, metaData, rec) {
-		if (rec) {
-		    if (rec.data.osdid >= 0) {
-			var bluestore = '';
-			if (rec.data.bluestore === 1) {
-			    bluestore = ' (Bluestore)';
-			}
-			return "Ceph osd." + rec.data.osdid.toString() + bluestore;
-		    }
-
-		    var types = [];
-		    if (rec.data.journals > 0) {
-			types.push('Journal');
-		    }
-
-		    if (rec.data.db > 0) {
-			types.push('DB');
-		    }
-
-		    if (rec.data.wal > 0) {
-			types.push('WAL');
-		    }
-
-		    if (types.length > 0) {
-			return 'Ceph (' + types.join(', ') + ')';
-		    }
-		}
-
-		return v || Proxmox.Utils.noText;
-	    },
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'GPT',
-	    width: 60,
-	    align: 'right',
-	    renderer: Proxmox.Utils.format_boolean,
-	    dataIndex: 'gpt'
-	},
-	{
-	    header: gettext('Vendor'),
-	    width: 100,
-	    sortable: true,
-	    hidden: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'vendor'
-	},
-	{
-	    header: gettext('Model'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'model'
-	},
-	{
-	    header: gettext('Serial'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'serial'
-	},
-	{
-	    header: 'S.M.A.R.T.',
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'health'
-	},
-	{
-	    header: 'Wearout',
-	    width: 90,
-	    sortable: true,
-	    align: 'right',
-	    dataIndex: 'wearout',
-	    renderer: function(value) {
-		if (Ext.isNumeric(value)) {
-		    return (100 - value).toString() + '%';
-		}
-		return 'N/A';
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var store = Ext.create('Ext.data.Store', {
-	    storeid: 'node-disk-list' + nodename,
-	    model: 'node-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list"
-	    },
-	    sorters: [
-		{
-		    property : 'dev',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reloadButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reload'),
-	    handler: function() {
-		me.store.load();
-	    }
-	});
-
-	var smartButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show S.M.A.R.T. values'),
-	    selModel: sm,
-	    enableFn: function() {
-		return !!sm.getSelection().length;
-	    },
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.DiskSmartWindow', {
-                    nodename: nodename,
-		    dev: rec.data.devpath
-		});
-		win.show();
-	    }
-	});
-
-	var initButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Initialize Disk with GPT'),
-	    selModel: sm,
-	    enableFn: function() {
-		var selection = sm.getSelection();
-
-		if (!selection.length || selection[0].data.used) {
-		    return false;
-		} else {
-		    return true;
-		}
-	    },
-	    disabled: true,
-
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
-		    waitMsgTarget: me,
-		    method: 'POST',
-		    params: { disk: rec.data.devpath},
-		    failure: function(response, options) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    upid: upid
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	me.loadCount = 1; // avoid duplicate loadmask
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ reloadButton, smartButton, initButton ],
-	    listeners: {
-		itemdblclick: function() {
-		    var rec = sm.getSelection()[0];
-
-		    var win = Ext.create('PVE.DiskSmartWindow', {
-			nodename: nodename,
-			dev: rec.data.devpath
-		    });
-		    win.show();
-		}
-	    }
-	});
-
-
-	me.callParent();
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('node-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
-	idProperty: 'devpath'
-    });
-});
-
-Ext.define('PVE.DiskSmartWindow', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSmartWindow',
-
-    modal: true,
-
-    items: [
-	{
-	    xtype: 'gridpanel',
-	    layout: {
-		type: 'fit'
-	    },
-	    emptyText: gettext('No S.M.A.R.T. Values'),
-	    scrollable: true,
-	    flex: 1,
-	    itemId: 'smarts',
-	    reserveScrollbar: true,
-	    columns: [
-	    { text: 'ID', dataIndex: 'id', width: 50 },
-	    { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Normalized'), dataIndex: 'value', width: 60},
-	    { text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
-	    { text: gettext('Worst'), dataIndex: 'worst', width: 60},
-	    { text: gettext('Flags'), dataIndex: 'flags'},
-	    { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
-	    ]
-	},
-	{
-	    xtype: 'component',
-	    itemId: 'text',
-	    layout: {
-		type: 'fit'
-	    },
-	    hidden: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Reload'),
-	    name: 'reload',
-	    handler: function() {
-		var me = this;
-		me.up('window').store.reload();
-	    }
-	},
-	{
-	    text: gettext('Close'),
-	    name: 'close',
-	    handler: function() {
-		var me = this;
-		me.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    width: 800,
-    height: 500,
-    minWidth: 600,
-    minHeight: 400,
-    bodyPadding: 5,
-    title: gettext('S.M.A.R.T. Values'),
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var dev = me.dev;
-	if (!dev) {
-	    throw "no device specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'disk-smart',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
-	    }
-	});
-
-	me.callParent();
-	var grid = me.down('#smarts');
-	var text = me.down('#text');
-
-	Proxmox.Utils.monStoreErrors(grid, me.store);
-	me.mon(me.store, 'load', function(s, records, success) {
-	    if (success && records.length > 0) {
-		var rec = records[0];
-		switch (rec.data.type) {
-		    case 'text':
-			grid.setVisible(false);
-			text.setVisible(true);
-			text.setHtml(Ext.String.htmlEncode(rec.data.text));
-			break;
-		    default:
-			// includes 'ata'
-			// cannot use empty case because
-			// of jslint
-			grid.setVisible(true);
-			text.setVisible(false);
-			grid.setStore(rec.attributes());
-			break;
-		}
-	    }
-	});
-
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('disk-smart', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'health'},
-	    { name:'type'},
-	    { name:'text'}
-	],
-	hasMany: {model: 'smart-attribute', name: 'attributes'}
-    });
-    Ext.define('smart-attribute', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
-	]
-    });
-});
-Ext.define('PVE.node.CreateLVM', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVM',
-
-    subject: 'LVM Volume Group',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMList', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveLVMList',
-    emptyText: gettext('No Volume Groups found'),
-    stateful: true,
-    stateId: 'grid-node-lvm',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Number of LVs'),
-	    dataIndex: 'lvcount',
-	    width: 150,
-	    align: 'right'
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Volume Group',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVM', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'size', 'free',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			txt += (data.leaf) ? 'hdd-o' : 'object-group';
-			return txt;
-		    }
-		},
-		{
-		    type: 'number',
-		    name: 'usage',
-		    calculate: function(data) {
-			return ((data.size-data.free)/data.size);
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateLVMThin', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVMThin',
-
-    subject: 'LVM Thinpool',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvmthin",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMThinList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveLVMThinList',
-
-    emptyText: gettext('No thinpools found'),
-    stateful: true,
-    stateId: 'grid-node-lvmthin',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'lv',
-	    flex: 1
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'lv_size'
-	},
-	{
-	    header: gettext('Used'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Metadata Usage'),
-	    width: 120,
-	    dataIndex: 'metadata_usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Metadata Size'),
-	    width: 120,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_size'
-	},
-	{
-	    header: gettext('Metadata Used'),
-	    width: 125,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_used'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Thinpool',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVMThin', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['lv', 'lv_size', 'used', 'metadata_size', 'metadata_used',
-		    {
-			type: 'number',
-			name: 'usage',
-			calculate: function(data) {
-			    return data.used/data.lv_size;
-			}
-		    },
-		    {
-			type: 'number',
-			name: 'metadata_usage',
-			calculate: function(data) {
-			    return data.metadata_used/data.metadata_size;
-			}
-		    }
-		],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/lvmthin'
-		},
-		sorters: 'lv'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateDirectory', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateDirectory',
-
-    subject: Proxmox.Utils.directoryText,
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/directory",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    comboItems: [
-			['ext4', 'ext4'],
-			['xfs', 'xfs']
-		    ],
-		    fieldLabel: gettext('Filesystem'),
-		    name: 'filesystem',
-		    value: '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.Directorylist', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveDirectoryList',
-
-    stateful: true,
-    stateId: 'grid-node-directory',
-    columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 100,
-	    dataIndex: 'type'
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options'
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateDirectory', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['path', 'device', 'type', 'options', 'unitfile' ],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/directory'
-		},
-		sorters: 'path'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.node.CreateZFS', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateZFS',
-
-    subject: 'ZFS',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_zfs',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-	var update_disklist = function() {
-	    var grid = me.down('#disklist');
-	    var disks = grid.getSelection();
-
-	    var val = [];
-	    disks.sort(function(a,b) {
-		var aorder = a.get('order') || 0;
-		var border = b.get('order') || 0;
-		return (aorder - border);
-	    });
-
-	    disks.forEach(function(disk) {
-		val.push(disk.get('devpath'));
-	    });
-
-	    me.down('field[name=devices]').setValue(val.join(','));
-	};
-
-	Ext.apply(me, {
-	    url: '/nodes/' + me.nodename + '/disks/zfs',
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'textfield',
-			    hidden: true,
-			    name: 'devices',
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxtextfield',
-			    name: 'name',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'add_storage',
-			    fieldLabel: gettext('Add Storage'),
-			    value: '1'
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('RAID Level'),
-			    name: 'raidlevel',
-			    value: 'single',
-			    comboItems: [
-				['single', gettext('Single Disk')],
-				['mirror', 'Mirror'],
-				['raid10', 'RAID10'],
-				['raidz', 'RAIDZ'],
-				['raidz2', 'RAIDZ2'],
-				['raidz3', 'RAIDZ3']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('Compression'),
-			    name: 'compression',
-			    value: 'on',
-			    comboItems: [
-				['on', 'on'],
-				['off', 'off'],
-				['gzip', 'gzip'],
-				['lz4', 'lz4'],
-				['lzjb', 'lzjb'],
-				['zle', 'zle']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    fieldLabel: gettext('ashift'),
-			    minValue: 9,
-			    maxValue: 16,
-			    value: '12',
-			    name: 'ashift'
-			}
-		    ],
-		    columnB: [
-			{
-			    xtype: 'grid',
-			    height: 200,
-			    emptyText: gettext('No Disks unused'),
-			    itemId: 'disklist',
-			    selModel: 'checkboxmodel',
-			    listeners: {
-				selectionchange: update_disklist
-			    },
-			    store: {
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + me.nodename + '/disks/list?type=unused'
-				}
-			    },
-			    columns: [
-				{
-				    text: gettext('Device'),
-				    dataIndex: 'devpath',
-				    flex: 1
-				},
-				{
-				    text: gettext('Serial'),
-				    dataIndex: 'serial'
-				},
-				{
-				    text: gettext('Size'),
-				    dataIndex: 'size',
-				    renderer: PVE.Utils.render_size
-				},
-				{
-				    header: gettext('Order'),
-				    xtype: 'widgetcolumn',
-				    dataIndex: 'order',
-				    sortable: true,
-				    widget: {
-					xtype: 'proxmoxintegerfield',
-					minValue: 1,
-					isFormField: false,
-					listeners: {
-					    change: function(numberfield, value, old_value) {
-						var record = numberfield.getWidgetRecord();
-						record.set('order', value);
-						update_disklist(record);
-					    }
-					}
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pve-hint',
-		    value: 'Note: ZFS is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_zfs') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-        me.callParent();
-	me.down('#disklist').getStore().load();
-    }
-});
-
-Ext.define('PVE.node.ZFSDevices', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveZFSDevices',
-    stateful: true,
-    stateId: 'grid-node-zfsstatus',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'state'
-	},
-	{
-	    text: 'READ',
-	    dataIndex: 'read'
-	},
-	{
-	    text: 'WRITE',
-	    dataIndex: 'write'
-	},
-	{
-	    text: 'CKSUM',
-	    dataIndex: 'cksum'
-	},
-	{
-	    text: gettext('Message'),
-	    dataIndex: 'msg'
-	}
-    ],
-
-    rootVisible: true,
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/zfs/" + me.zpool,
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'status',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			if (data.leaf) {
-			    return txt + 'hdd-o';
-			}
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSStatus', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveZFSStatus',
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/disks/zfs/" + me.zpool;
-
-	me.rows = {
-	    scan: {
-		header: gettext('Scan')
-	    },
-	    status: {
-		header: gettext('Status')
-	    },
-	    action: {
-		header: gettext('Action')
-	    },
-	    errors: {
-		header: gettext('Errors')
-	    }
-	};
-
-	me.callParent();
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveZFSList',
-
-    stateful: true,
-    stateId: 'grid-node-zfs',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    header: gettext('Size'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	},
-	{
-	    header: gettext('Allocated'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'alloc'
-	},
-	{
-	    header: gettext('Fragmentation'),
-	    renderer: function(value) {
-		return value.toString() + '%';
-	    },
-	    dataIndex: 'frag'
-	},
-	{
-	    header: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'health'
-	},
-	{
-	    header: gettext('Deduplication'),
-	    hidden: true,
-	    renderer: function(value) {
-		return value.toFixed(2).toString() + 'x';
-	    },
-	    dataIndex: 'dedup'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': ZFS',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateZFS', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	},
-	{
-	    text: gettext('Detail'),
-	    itemId: 'detailbtn',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('panel');
-		var selection = me.getSelection();
-		if (selection.length < 1) {
-		    return;
-		}
-		me.show_detail(selection[0].get('name'));
-	    }
-	}
-    ],
-
-    show_detail: function(zpool) {
-	var me = this;
-
-	var detailsgrid = Ext.create('PVE.node.ZFSStatus', {
-	    layout: 'fit',
-	    nodename: me.nodename,
-	    flex: 0,
-	    zpool: zpool
-	});
-
-	var devicetree = Ext.create('PVE.node.ZFSDevices', {
-	    title: gettext('Devices'),
-	    nodename: me.nodename,
-	    flex: 1,
-	    zpool: zpool
-	});
-
-
-	var win = Ext.create('Ext.window.Window', {
-	    modal: true,
-	    width: 800,
-	    height: 400,
-	    resizable: true,
-	    layout: 'fit',
-	    title: gettext('Status') + ': ' + zpool,
-	    items:[{
-		xtype: 'panel',
-		region: 'center',
-		layout: {
-		    type: 'vbox',
-		    align: 'stretch'
-		},
-		items: [detailsgrid, devicetree],
-		tbar: [{
-		    text: gettext('Reload'),
-		    iconCls: 'fa fa-refresh',
-		    handler: function() {
-
-			devicetree.reload();
-			detailsgrid.reload();
-		    }
-		}]
-	    }]
-	}).show();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var selection = me.getSelection();
-	me.down('#detailbtn').setDisabled(selection.length === 0);
-    },
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	},
-	selectionchange: function() {
-	    this.set_button_status();
-	},
-	itemdblclick: function(grid, record) {
-	    var me = this;
-	    me.show_detail(record.get('name'));
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/zfs'
-		},
-		sorters: 'name'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveNodeStatus',
-
-    height: 300,
-    bodyPadding: '20 15 20 15',
-
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 15 5 15'
-    },
-
-    items: [
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpuinfo',
-	    renderer: PVE.Utils.render_node_cpu_usage
-	},
-	{
-	    itemId: 'wait',
-	    iconCls: 'fa fa-fw fa-clock-o',
-	    title: gettext('IO delay'),
-	    valueField: 'wait',
-	    rowspan: 2
-	},
-	{
-	    itemId: 'load',
-	    iconCls: 'fa fa-fw fa-tasks',
-	    title: gettext('Load average'),
-	    printBar: false,
-	    textField: 'loadavg'
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    itemId: 'memory',
-	    title: gettext('RAM usage'),
-	    valueField: 'memory',
-	    maxField: 'memory',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    itemId: 'ksm',
-	    printBar: false,
-	    title: gettext('KSM sharing'),
-	    textField: 'ksm',
-	    renderer: function(record) {
-		return PVE.Utils.render_size(record.shared);
-	    },
-	    padding: '0 15 10 15'
-	},
-	{
-	    iconCls: 'fa fa-fw fa-hdd-o',
-	    itemId: 'rootfs',
-	    title: gettext('HD space') + '(root)',
-	    valueField: 'rootfs',
-	    maxField: 'rootfs',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    iconCls: 'fa fa-fw fa-refresh',
-	    itemId: 'swap',
-	    printSize: true,
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'swap',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    itemId: 'cpus',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('CPU(s)'),
-	    textField: 'cpuinfo',
-	    renderer: function(cpuinfo) {
-		return cpuinfo.cpus + " x " + cpuinfo.model + " (" +
-		cpuinfo.sockets.toString() + " " +
-		(cpuinfo.sockets > 1 ?
-		    gettext('Sockets') :
-		    gettext('Socket')
-		) + ")";
-	    },
-	    value: ''
-	},
-	{
-	    itemId: 'kversion',
-	    colspan: 2,
-	    title: gettext('Kernel Version'),
-	    printBar: false,
-	    textField: 'kversion',
-	    value: ''
-	},
-	{
-	    itemId: 'version',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('PVE Manager Version'),
-	    textField: 'pveversion',
-	    value: ''
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
-	me.setTitle(me.pveSelNode.data.node + ' (' + gettext('Uptime') + ': ' + uptime + ')');
-    }
-
-});
-Ext.define('PVE.node.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    showVersions: function() {
-	var me = this;
-
-	// Note: we use simply text/html here, because ExtJS grid has problems
-	// with cut&paste
-
-	var nodename = me.pveSelNode.data.node;
-
-	var view = Ext.createWidget('component', {
-	    autoScroll: true,
-	    padding: 5,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	});
-
-	var win = Ext.create('Ext.window.Window', {
-	    title: gettext('Package versions'),
-	    width: 600,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [ view ]
-	});
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: "/nodes/" + nodename + "/apt/versions",
-	    method: 'GET',
-	    failure: function(response, opts) {
-		win.close();
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		win.show();
-		var text = '';
-
-		Ext.Array.each(response.result.data, function(rec) {
-		    var version = "not correctly installed";
-		    var pkg = rec.Package;
-		    if (rec.OldVersion && rec.CurrentState === 'Installed') {
-			version = rec.OldVersion;
-		    }
-		    if (rec.RunningKernel) {
-			text += pkg + ': ' + version + ' (running kernel: ' +
-			    rec.RunningKernel + ')\n';
-		    } else if (rec.ManagerVersion) {
-			text += pkg + ': ' + version + ' (running version: ' +
-			    rec.ManagerVersion + ')\n';
-		    } else {
-			text += pkg + ': ' + version + '\n';
-		    }
-		});
-
-		view.update(Ext.htmlEncode(text));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var rstore = me.statusStore;
-
-	var version_btn = new Ext.Button({
-	    text: gettext('Package versions'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { me.showVersions(); });
-	    }
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl: "/api2/json/nodes/" + nodename + "/rrddata",
-	    model: 'pve-rrd-node'
-	});
-
-	Ext.apply(me, {
-	    tbar: [version_btn, '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: 'column',
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: [
-			{
-			    xtype: 'pveNodeStatus',
-			    rstore: rstore,
-			    width: 770,
-			    pveSelNode: me.pveSelNode
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('CPU usage'),
-			    fields: ['cpu','iowait'],
-			    fieldTitles: [gettext('CPU usage'), gettext('IO delay')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Server load'),
-			    fields: ['loadavg'],
-			    fieldTitles: [gettext('Load average')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Memory usage'),
-			    fields: ['memtotal','memused'],
-			    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Network traffic'),
-			    fields: ['netin','netout'],
-			    store: rrdstore
-			}
-		    ]
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*global Blob*/
-Ext.define('PVE.node.SubscriptionKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-    title: gettext('Upload Subscription Key'),
-    width: 300,
-    items: {
-	xtype: 'textfield',
-	name: 'key',
-	value: '',
-	fieldLabel: gettext('Subscription Key')
-    },
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.Subscription', {
-    extend: 'Proxmox.grid.ObjectGrid',
-
-    alias: ['widget.pveNodeSubscription'],
-
-    onlineHelp: 'getting_help',
-
-    viewConfig: {
-	enableTextSelection: true
-    },
-
-    showReport: function() {
-	var me = this;
-	var nodename = me.pveSelNode.data.node;
-
-	var getReportFileName = function() {
-	    var now = Ext.Date.format(new Date(), 'D-d-F-Y-G-i');
-	    return me.nodename + '-report-'  + now + '.txt';
-	};
-
-	var view = Ext.createWidget('component', {
-	    itemId: 'system-report-view',
-	    scrollable: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace',
-		padding: '5px'
-	    }
-	});
-
-	var reportWindow = Ext.create('Ext.window.Window', {
-	    title: gettext('System Report'),
-	    width: 1024,
-	    height: 600,
-	    layout: 'fit',
-	    modal: true,
-	    buttons: [
-		        '->',
-			{
-			    text: gettext('Download'),
-			    handler: function() {
-				var fileContent = reportWindow.getComponent('system-report-view').html;
-				var fileName = getReportFileName();
-
-				// Internet Explorer
-				if (window.navigator.msSaveOrOpenBlob) {
-				    navigator.msSaveOrOpenBlob(new Blob([fileContent]), fileName);
-				} else {
-				    var element = document.createElement('a');
-				    element.setAttribute('href', 'data:text/plain;charset=utf-8,'
-				      + encodeURIComponent(fileContent));
-				    element.setAttribute('download', fileName);
-				    element.style.display = 'none';
-				    document.body.appendChild(element);
-				    element.click();
-				    document.body.removeChild(element);
-				}
-			    }
-			}
-		],
-	    items: view
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/nodes/' + me.nodename + '/report',
-	    method: 'GET',
-	    waitMsgTarget: me,
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var report = Ext.htmlEncode(response.result.data);
-		reportWindow.show();
-		view.update(report);
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = '/nodes/' + me.nodename + '/subscription';
-
-	var render_status = function(value) {
-
-	    var message = me.getObjectValue('message');
-
-	    if (message) {
-		return value + ": " + message;
-	    }
-	    return value;
-	};
-
-	var rows = {
-	    productname: {
-		header: gettext('Type')
-	    },
-	    key: {
-		header: gettext('Subscription Key')
-	    },
-	    status: {
-		header: gettext('Status'),
-		renderer: render_status
-	    },
-	    message: {
-		visible: false
-	    },
-	    serverid: {
-		header: gettext('Server ID')
-	    },
-	    sockets: {
-		header: gettext('Sockets')
-	    },
-	    checktime: {
-		header: gettext('Last checked'),
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    nextduedate: {
-		header: gettext('Next due date')
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json' + baseurl,
-	    cwidth1: 170,
-	    tbar: [ 
-		{
-		    text: gettext('Upload Subscription Key'),
-		    handler: function() {
-			var win = Ext.create('PVE.node.SubscriptionKeyEdit', {
-			    url: '/api2/extjs/' + baseurl 
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		{
-		    text: gettext('Check'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    params: { force: 1 },
-			    url: baseurl,
-			    method: 'POST',
-			    waitMsgTarget: me,
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    },
-			    callback: reload
-			});
-		    }
-		},
-		{
-		    text: gettext('System Report'),
-		    handler: function() {
-			Proxmox.Utils.checked_command(function (){ me.showReport(); });
-		    }
-		}
-	    ],
-	    rows: rows,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CertificateView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCertificatesView',
-
-    onlineHelp: 'sysadmin_certificate_management',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    items: [
-	{
-	    xtype: 'pveCertView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveACMEView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.CertificateViewer', {
-    extend: 'Proxmox.window.Edit',
-
-    title: gettext('Certificate'),
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-    width: 800,
-    resizable: true,
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'filename'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Fingerprint'),
-	    name: 'fingerprint'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Issuer'),
-	    name: 'issuer'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject'),
-	    name: 'subject'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Valid Since'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notbefore'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Expires'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notafter'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject Alternative Names'),
-	    name: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    xtype: 'textarea',
-	    editable: false,
-	    grow: true,
-	    growMax: 200,
-	    fieldLabel: gettext('Certificate'),
-	    name: 'pem'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.cert) {
-	    throw "no cert given";
-	}
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/info';
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		if (Ext.isArray(response.result.data)) {
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.filename === me.cert) {
-			    me.setValues(item);
-			    return false;
-			}
-		    });
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CertUpload', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCertUpload',
-
-    title: gettext('Upload Custom Certificate'),
-    resizable: false,
-    isCreate: true,
-    submitText: gettext('Upload'),
-    method: 'POST',
-    width: 600,
-
-    apiCallDone: function(success, response, options) {
-	if (!success) {
-	    return;
-	}
-
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    items: [
-	{
-	    fieldLabel: gettext('Private Key (Optional)'),
-	    labelAlign: 'top',
-	    emptyText: gettext('No change'),
-	    name: 'key',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=key]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    autoEl: 'hr'
-	},
-	{
-	    fieldLabel: gettext('Certificate Chain'),
-	    labelAlign: 'top',
-	    allowBlank: false,
-	    name: 'certificates',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=certificates]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'restart',
-	    value: '1'
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'force',
-	    value: '1'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/custom';
-
-	me.callParent();
-    }
-});
-
-Ext.define('pve-certificate', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san' ],
-    idProperty: 'filename'
-});
-
-Ext.define('PVE.node.Certificates', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveCertView',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    text: gettext('Upload Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.CertUpload', {
-		    nodename: me.nodename
-		});
-		win.show();
-		win.on('destroy', me.reload, me);
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'deletebtn',
-	    text: gettext('Delete Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/certificates/custom?restart=1',
-		    method: 'DELETE',
-		    success: function(response, opt) {
-			var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-			Ext.getBody().mask(txt, ['pve-static-mask']);
-			// reload after 10 seconds automatically
-			Ext.defer(function() {
-			    window.location.reload(true);
-			}, 10000);
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    itemId: 'viewbtn',
-	    disabled: true,
-	    text: gettext('View Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		me.view_certificate();
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('File'),
-	    width: 150,
-	    dataIndex: 'filename'
-	},
-	{
-	    header: gettext('Issuer'),
-	    flex: 1,
-	    dataIndex: 'issuer'
-	},
-	{
-	    header: gettext('Subject'),
-	    flex: 1,
-	    dataIndex: 'subject'
-	},
-	{
-	    header: gettext('Valid Since'),
-	    width: 150,
-	    dataIndex: 'notbefore',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Expires'),
-	    width: 150,
-	    dataIndex: 'notafter',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Subject Alternative Names'),
-	    flex: 1,
-	    dataIndex: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    header: gettext('Fingerprint'),
-	    dataIndex: 'fingerprint',
-	    hidden: true
-	},
-	{
-	    header: gettext('PEM'),
-	    dataIndex: 'pem',
-	    hidden: true
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var rec = me.rstore.getById('pveproxy-ssl.pem');
-
-	me.down('#deletebtn').setDisabled(!rec);
-    },
-
-    view_certificate: function() {
-	var me = this;
-	var selection = me.getSelection();
-	if (!selection || selection.length < 1) {
-	    return;
-	}
-	var win = Ext.create('PVE.node.CertificateViewer', {
-	    cert: selection[0].data.filename,
-	    nodename : me.nodename
-	});
-	win.show();
-    },
-
-    listeners: {
-	itemdblclick: 'view_certificate'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'certs-' + me.nodename,
-	    model: 'pve-certificate',
-	    proxy: {
-		type: 'proxmox',
-		    url: '/api2/json/nodes/' + me.nodename + '/certificates/info'
-	    }
-	});
-
-	me.store = {
-	    type: 'diff',
-	    rstore: me.rstore
-	};
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-    }
-});
-Ext.define('PVE.node.ACMEEditor', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveACMEEditor',
-
-    subject: gettext('Domains'),
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    items: [
-		{
-		    xtype: 'textarea',
-		    fieldLabel: gettext('Domains'),
-		    emptyText: "domain1.example.com\ndomain2.example.com",
-		    name: 'domains'
-		}
-	    ],
-	    onGetValues: function(values) {
-		if (!values.domains) {
-		    return {
-			'delete': 'acme'
-		    };
-		}
-		var domains = values.domains.split(/\n/).join(';');
-		return {
-		    'acme': 'domains=' + domains
-		};
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		var res = PVE.Parser.parseACME(response.result.data.acme);
-		if (res) {
-		    res.domains = res.domains.join(' ');
-		    me.setValues(res);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACMEAccountCreate', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-    title: gettext('Register Account'),
-    isCreate: true,
-    method: 'POST',
-    submitText: gettext('Register'),
-    url: '/cluster/acme/account',
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'proxmoxComboGrid',
-	    name: 'directory',
-	    allowBlank: false,
-	    valueField: 'url',
-	    displayField: 'name',
-	    fieldLabel: gettext('ACME Directory'),
-	    store: {
-		autoLoad: true,
-		fields: ['name', 'url'],
-		idProperty: ['name'],
-		proxy: {
-		    type: 'proxmox',
-		    url: '/api2/json/cluster/acme/directories'
-		},
-		sorters: {
-		    property: 'name',
-		    order: 'ASC'
-		}
-	    },
-	    listConfig: {
-		columns: [
-		    {
-			header: gettext('Name'),
-			dataIndex: 'name',
-			flex: 1
-		    },
-		    {
-			header: gettext('URL'),
-			dataIndex: 'url',
-			flex: 1
-		    }
-		]
-	    },
-	    listeners: {
-		change: function(combogrid, value) {
-		    var me = this;
-		    if (!value) {
-			return;
-		    }
-
-		    var disp = me.up('window').down('#tos_url_display');
-		    var field = me.up('window').down('#tos_url');
-		    var checkbox = me.up('window').down('#tos_checkbox');
-
-		    disp.setValue(gettext('Loading'));
-		    field.setValue(undefined);
-		    checkbox.setValue(undefined);
-
-		    Proxmox.Utils.API2Request({
-			url: '/cluster/acme/tos',
-			method: 'GET',
-			params: {
-			    directory: value
-			},
-			success: function(response, opt) {
-			    me.up('window').down('#tos_url').setValue(response.result.data);
-			    me.up('window').down('#tos_url_display').setValue(response.result.data);
-			},
-			failure: function(response, opt) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-		}
-	    }
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'tos_url_display',
-	    fieldLabel: gettext('Terms of Service'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos_url_display'
-	},
-	{
-	    xtype: 'hidden',
-	    itemId: 'tos_url',
-	    name: 'tos_url'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'tos_checkbox',
-	    fieldLabel: gettext('Accept TOS'),
-	    submitValue: false,
-	    validateValue: function(value) {
-		if (value && this.checked) {
-		    return true;
-		}
-		return false;
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'contact',
-	    vtype: 'email',
-	    allowBlank: false,
-	    fieldLabel: gettext('E-Mail')
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.ACMEAccountView', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 600,
-    fieldDefaults: {
-	labelWidth: 140
-    },
-
-    title: gettext('Account'),
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('E-Mail'),
-	    name: 'email'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Created'),
-	    name: 'createdAt'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Status'),
-	    name: 'status'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Directory'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'directory'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Terms of Services'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.accountname) {
-	    throw "no account name defined";
-	}
-
-	me.url = '/cluster/acme/account/' + me.accountname;
-
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		var data = response.result.data;
-		data.email = data.account.contact[0];
-		data.createdAt = data.account.createdAt;
-		data.status = data.account.status;
-		me.setValues(data);
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACME', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveACMEView',
-
-    margin: '10 0 0 0',
-    title: 'ACME',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    itemId: 'edit',
-	    text: gettext('Edit Domains'),
-	    handler: function() {
-		this.up('grid').run_editor();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'createaccount',
-	    text: gettext('Register Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountCreate', {
-		    taskDone: function() {
-			me.load_account();
-			me.reload();
-		    }
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'viewaccount',
-	    text: gettext('View Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountView', {
-		    accountname: 'default'
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'order',
-	    text: gettext('Order Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-
-		Proxmox.Utils.API2Request({
-		    method: 'POST',
-		    params: {
-			force: 1
-		    },
-		    url: '/nodes/' + me.nodename + '/certificates/acme/certificate',
-		    success: function(response, opt) {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: response.result.data,
-			    taskDone: function(success) {
-				me.certificate_order_finished(success);
-			    }
-			});
-			win.show();
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ],
-
-    certificate_order_finished: function(success) {
-	if (!success) {
-	    return;
-	}
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    set_button_status: function() {
-	var me = this;
-
-	var account = !!me.account;
-	var acmeObj = PVE.Parser.parseACME(me.getObjectValue('acme'));
-	var domains = acmeObj ? acmeObj.domains.length : 0;
-
-	var order = me.down('#order');
-	order.setVisible(account);
-	order.setDisabled(!account || !domains);
-
-	me.down('#createaccount').setVisible(!account);
-	me.down('#viewaccount').setVisible(account);
-    },
-
-    load_account: function() {
-	var me = this;
-
-	// for now we only use the 'default' account
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/acme/account/default',
-	    success: function(response, opt) {
-		me.account = response.result.data;
-		me.set_button_status();
-	    },
-	    failure: function(response, opt) {
-		me.account = undefined;
-		me.set_button_status();
-	    }
-	});
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create(me.rows.acme.editor, me.editorConfig);
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    listeners: {
-	itemdblclick: 'run_editor'
-    },
-
-    // account data gets loaded here
-    account: undefined,
-
-    disableSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/api2/json/nodes/' + me.nodename + '/config';
-
-	me.editorConfig = {
-	    url: '/api2/extjs/nodes/' + me.nodename + '/config'
-	};
-	/*jslint confusion: true*/
-	/*acme is a string above*/
-	me.rows = {
-	    acme: {
-		defaultValue: '',
-		header: gettext('Domains'),
-		editor: 'PVE.node.ACMEEditor',
-		renderer: function(value) {
-		    var acmeObj = PVE.Parser.parseACME(value);
-		    if (acmeObj) {
-			return acmeObj.domains.join('<br>');
-		    }
-		    return Proxmox.Utils.noneText;
-		}
-	    }
-	};
-	/*jslint confusion: false*/
-
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-	me.load_account();
-    }
-});
-Ext.define('PVE.node.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.node.Config',
-
-    onlineHelp: 'chapter_system_administration',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/status",
-	    interval: 1000
-	});
-
-	var node_command = function(cmd) {
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/status',
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var actionBtn = Ext.create('Ext.Button', {
-	    text: gettext('Bulk Actions'),
-	    iconCls: 'fa fa-fw fa-ellipsis-v',
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    menu: new Ext.menu.Menu({
-		items: [
-		    {
-			text: gettext('Bulk Start'),
-			iconCls: 'fa fa-fw fa-play',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Start'),
-				btnText: gettext('Start'),
-				action: 'startall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Stop'),
-			iconCls: 'fa fa-fw fa-stop',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Stop'),
-				btnText: gettext('Stop'),
-				action: 'stopall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Migrate'),
-			iconCls: 'fa fa-fw fa-send-o',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Migrate'),
-				btnText: gettext('Migrate'),
-				action: 'migrateall'
-			    });
-			    win.show();
-			}
-		    }
-		]
-	    })
-	});
-
-	var restartBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reboot'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Reboot node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('reboot');
-	    },
-	    iconCls: 'fa fa-undo'
-	});
-
-	var shutdownBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Shutdown node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('shutdown');
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var shellBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.nodes['Sys.Console'],
-	    text: gettext('Shell'),
-	    consoleType: 'shell',
-	    nodename: nodename
-	});
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext('Node') + " '" + nodename + "'",
-	    hstateid: 'nodetab',
-	    defaults: { statusStore: me.statusStore },
-	    tbar: [ restartBtn, shutdownBtn, shellBtn, actionBtn]
-	});
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary',
-		    xtype: 'pveNodeSummary'
-		},
-		{
-		    title: gettext('Notes'),
-		    iconCls: 'fa fa-sticky-note-o',
-		    itemId: 'notes',
-		    xtype: 'pveNotesView'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Console']) {
-	    me.items.push(
-		{
-		    title: gettext('Shell'),
-		    iconCls: 'fa fa-terminal',
-		    itemId: 'jsconsole',
-		    xtype: 'pveNoVncConsole',
-		    consoleType: 'shell',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('System'),
-		    iconCls: 'fa fa-cogs',
-		    itemId: 'services',
-		    expandedOnInit: true,
-		    startOnlyServices: {
-			'pveproxy': true,
-			'pvedaemon': true,
-			'pve-cluster': true
-		    },
-		    nodename: nodename,
-		    onlineHelp: 'pve_service_daemons',
-		    xtype: 'proxmoxNodeServiceView'
-		},
-		{
-		    title: gettext('Network'),
-		    iconCls: 'fa fa-exchange',
-		    itemId: 'network',
-		    groups: ['services'],
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeNetworkView'
-		},
-		{
-		    title: gettext('Certificates'),
-		    iconCls: 'fa fa-certificate',
-		    itemId: 'certificates',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'pveCertificatesView'
-		},
-		{
-		    title: gettext('DNS'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'dns',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeDNSView'
-		},
-		{
-		    title: gettext('Hosts'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'hosts',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeHostsView'
-		},
-		{
-		    title: gettext('Time'),
-		    itemId: 'time',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'proxmoxNodeTimeView',
-		    iconCls: 'fa fa-clock-o'
-		});
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push({
-		title: 'Syslog',
-		iconCls: 'fa fa-list',
-		groups: ['services'],
-		disabled: !caps.nodes['Sys.Syslog'],
-		itemId: 'syslog',
-		xtype: 'proxmoxJournalView',
-		url: "/api2/extjs/nodes/" + nodename + "/journal"
-	    });
-
-	    if (caps.nodes['Sys.Modify']) {
-		me.items.push({
-		    title: gettext('Updates'),
-		    iconCls: 'fa fa-refresh',
-		    disabled: !caps.nodes['Sys.Console'],
-		    // do we want to link to system updates instead?
-		    itemId: 'apt',
-		    xtype: 'proxmoxNodeAPT',
-		    upgradeBtn: {
-			xtype: 'pveConsoleButton',
-			disabled: Proxmox.UserName !== 'root@pam',
-			text: gettext('Upgrade'),
-			consoleType: 'upgrade',
-			nodename: nodename
-		    },
-		    nodename: nodename
-		});
-	    }
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    iconCls: 'fa fa-shield',
-		    title: gettext('Firewall'),
-		    allow_iface: true,
-		    base_url: '/nodes/' + nodename + '/firewall/rules',
-		    list_refs_url: '/cluster/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    title: gettext('Options'),
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_host_specific_configuration',
-		    groups: ['firewall'],
-		    base_url: '/nodes/' + nodename + '/firewall/options',
-		    fwtype: 'node',
-		    itemId: 'firewall-options'
-		});
-	}
-
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Disks'),
-		    itemId: 'storage',
-		    expandedOnInit: true,
-		    iconCls: 'fa fa-hdd-o',
-		    xtype: 'pveNodeDiskList'
-		},
-		{
-		    title: 'LVM',
-		    itemId: 'lvm',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square',
-		    groups: ['storage'],
-		    xtype: 'pveLVMList'
-		},
-		{
-		    title: 'LVM-Thin',
-		    itemId: 'lvmthin',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square-o',
-		    groups: ['storage'],
-		    xtype: 'pveLVMThinList'
-		},
-		{
-		    title: Proxmox.Utils.directoryText,
-		    itemId: 'directory',
-		    onlineHelp: 'chapter_storage',
-		    iconCls: 'fa fa-folder',
-		    groups: ['storage'],
-		    xtype: 'pveDirectoryList'
-		},
-		{
-		    title: 'ZFS',
-		    itemId: 'zfs',
-		    onlineHelp: 'chapter_zfs',
-		    iconCls: 'fa fa-th-large',
-		    groups: ['storage'],
-		    xtype: 'pveZFSList'
-		},
-		{
-		    title: 'Ceph',
-		    itemId: 'ceph',
-		    iconCls: 'fa fa-ceph',
-		    xtype: 'pveNodeCephStatus'
-		},
-		{
-		    xtype: 'pveReplicaView',
-		    iconCls: 'fa fa-retweet',
-		    title: gettext('Replication'),
-		    itemId: 'replication'
-		},
-		{
-		    xtype: 'pveNodeCephConfigCrush',
-		    title: gettext('Configuration'),
-		    iconCls: 'fa fa-gear',
-		    groups: ['ceph'],
-		    itemId: 'ceph-config'
-		},
-		{
-		    xtype: 'pveNodeCephMonMgr',
-		    title: gettext('Monitor'),
-		    iconCls: 'fa fa-tv',
-		    groups: ['ceph'],
-		    itemId: 'ceph-monlist'
-		},
-		{
-		    xtype: 'pveNodeCephOsdTree',
-		    title: 'OSD',
-		    iconCls: 'fa fa-hdd-o',
-		    groups: ['ceph'],
-		    itemId: 'ceph-osdtree'
-		},
-		{
-		    xtype: 'pveNodeCephFSPanel',
-		    title: 'CephFS',
-		    iconCls: 'fa fa-folder',
-		    groups: ['ceph'],
-		    nodename: nodename,
-		    itemId: 'ceph-cephfspanel'
-		},
-		{
-		    xtype: 'pveNodeCephPoolList',
-		    title: 'Pools',
-		    iconCls: 'fa fa-sitemap',
-		    groups: ['ceph'],
-		    itemId: 'ceph-pools'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push(
-		{
-		    xtype: 'proxmoxLogView',
-		    title: gettext('Log'),
-		    iconCls: 'fa fa-list',
-		    groups: ['firewall'],
-		    onlineHelp: 'chapter_pve_firewall',
-		    url: '/api2/extjs/nodes/' + nodename + '/firewall/log',
-		    itemId: 'firewall-fwlog'
-		},
-		{
-		    title: gettext('Log'),
-		    itemId: 'ceph-log',
-		    iconCls: 'fa fa-list',
-		    groups: ['ceph'],
-		    onlineHelp: 'chapter_pveceph',
-		    xtype: 'cephLogView',
-		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
-		    nodename: nodename
-		});
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Task History'),
-		iconCls: 'fa fa-list',
-		itemId: 'tasks',
-		nodename: nodename,
-		xtype: 'proxmoxNodeTasks'
-	    },
-	    {
-		title: gettext('Subscription'),
-		iconCls: 'fa fa-support',
-		itemId: 'support',
-		xtype: 'pveNodeSubscription',
-		nodename: nodename
-	    }
-	);
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var uptimerec = s.data.get('uptime');
-	    var powermgmt = uptimerec ? uptimerec.data.value : false;
-	    if (!caps.nodes['Sys.PowerMgmt']) {
-		powermgmt = false;
-	    }
-	    restartBtn.setDisabled(!powermgmt);
-	    shutdownBtn.setDisabled(!powermgmt);
-	    shellBtn.setDisabled(!powermgmt);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    vmtype: undefined,
-    nodename: undefined,
-    vmid: undefined,
-
-    viewModel: {
-	data: {
-	    vmid: undefined,
-	    nodename: undefined,
-	    vmtype: undefined,
-	    running: false,
-	    qemu: {
-		onlineHelp: 'qm_migration',
-		commonName: 'VM'
-	    },
-	    lxc: {
-		onlineHelp: 'pct_migration',
-		commonName: 'CT'
-	    },
-	    migration: {
-		possible: true,
-		preconditions: [],
-		'with-local-disks': 0,
-		mode: undefined,
-		allowedNodes: undefined
-	    }
-
-	},
-
-	formulas: {
-	    setMigrationMode: function(get) {
-		if (get('running')){
-		    if (get('vmtype') === 'qemu') {
-			return gettext('Online');
-		    } else {
-			return gettext('Restart Mode');
-		    }
-		} else {
-		    return gettext('Offline');
-		}
-	    },
-	    setStorageselectorHidden: function(get) {
-		    if (get('migration.with-local-disks') && get('running')) {
-			return false;
-		    } else {
-			return true;
-		    }
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=formPanel]': {
-		validityChange: function(panel, isValid) {
-		    this.getViewModel().set('migration.possible', isValid);
-		    this.checkMigratePreconditions();
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this,
-		vm = view.getViewModel();
-
-	    if (!view.nodename) {
-		throw "missing custom view config: nodename";
-	    }
-	    vm.set('nodename', view.nodename);
-
-	    if (!view.vmid) {
-		throw "missing custom view config: vmid";
-	    }
-	    vm.set('vmid', view.vmid);
-
-	    if (!view.vmtype) {
-		throw "missing custom view config: vmtype";
-	    }
-	    vm.set('vmtype', view.vmtype);
-
-
-	    view.setTitle(
-		Ext.String.format('{0} {1}{2}', gettext('Migrate'), vm.get(view.vmtype).commonName, view.vmid)
-	    );
-	    me.lookup('proxmoxHelpButton').setHelpConfig({
-		onlineHelp: vm.get(view.vmtype).onlineHelp
-	    });
-	    me.checkMigratePreconditions();
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	onTargetChange: function (nodeSelector) {
-	    //Always display the storages of the currently seleceted migration target
-	    this.lookup('pveDiskStorageSelector').setNodename(nodeSelector.value);
-	    this.checkMigratePreconditions();
-	},
-
-	startMigration: function() {
-	    var me = this,
-		view = me.getView(),
-		vm = me.getViewModel();
-
-	    var values = me.lookup('formPanel').getValues();
-	    var params = {
-		target: values.target
-	    };
-
-	    if (vm.get('migration.mode')) {
-		params[vm.get('migration.mode')] = 1;
-	    }
-	    if (vm.get('migration.with-local-disks')) {
-		params['with-local-disks'] = 1;
-	    }
-	    //only submit targetstorage if vm is running, storage migration to different storage is only possible online
-	    if (vm.get('migration.with-local-disks') && vm.get('running')) {
-		params.targetstorage = values.targetstorage;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		waitMsgTarget: view,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var extraTitle = Ext.String.format(' ({0} ---> {1})', vm.get('nodename'), params.target);
-
-		    Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid,
-			extraTitle: extraTitle
-		    }).show();
-
-		    view.close();
-		}
-	    });
-
-	},
-
-	checkMigratePreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel();
-
-
-	    var vmrec = PVE.data.ResourceStore.findRecord('vmid', vm.get('vmid'),
-			0, false, false, true);
-	    if (vmrec && vmrec.data && vmrec.data.running) {
-		vm.set('running', true);
-	    }
-
-	    if (vm.get('vmtype') === 'qemu') {
-		me.checkQemuPreconditions();
-	    } else {
-		me.checkLxcPreconditions();
-	    }
-	    me.lookup('pveNodeSelector').disallowedNodes = [vm.get('nodename')];
-
-	    // Only allow nodes where the local storage is available in case of offline migration
-	    // where storage migration is not possible
-	    me.lookup('pveNodeSelector').allowedNodes = vm.get('migration.allowedNodes');
-
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	checkQemuPreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel(),
-		migrateStats;
-
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'online');
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		method: 'GET',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    migrateStats = response.result.data;
-		    if (migrateStats.running) {
-			vm.set('running', true);
-		    }
-		    // Get migration object from viewmodel to prevent
-		    // to many bind callbacks
-		    var migration = vm.get('migration');
-		    migration.preconditions = [];
-
-		    if (migrateStats.allowed_nodes) {
-			migration.allowedNodes = migrateStats.allowed_nodes;
-			var target = me.lookup('pveNodeSelector').value;
-			if (target.length && !migrateStats.allowed_nodes.includes(target)) {
-			    let disallowed = migrateStats.not_allowed_nodes[target];
-			    let missing_storages = disallowed.unavailable_storages.join(', ');
-
-			    migration.possible = false;
-			    migration.preconditions.push({
-				text: 'Storage (' + missing_storages + ') not available on selected target. ' +
-				  'Start VM to use live storage migration or select other target node',
-				severity: 'error'
-			    });
-			}
-		    }
-
-		    if (migrateStats.local_resources.length) {
-			migration.possible = false;
-			migration.preconditions.push({
-			    text: 'Can\'t migrate VM with local resources: '+ migrateStats.local_resources.join(', '),
-			    severity: 'error'
-			});
-		    }
-
-		    if (migrateStats.local_disks.length) {
-
-			migrateStats.local_disks.forEach(function (disk) {
-			    if (disk.cdrom && disk.cdrom === 1) {
-				migration.possible = false;
-				migration.preconditions.push({
-				    text: "Can't migrate VM with local CD/DVD",
-				    severity: 'error'
-				});
-
-			    } else if (!disk.referenced_in_config) {
-				migration.possible = false;
-				migration.preconditions.push({
-				    text: 'Found not referenced/unused disk via storage: '+ disk.volid,
-				    severity: 'error'
-				});
-			    } else {
-				migration['with-local-disks'] = 1;
-				migration.preconditions.push({
-				    text:'Migration with local disk might take long: ' + disk.volid
-					+' (' + PVE.Utils.render_size(disk.size) + ')',
-				    severity: 'warning'
-				});
-			    }
-			});
-
-		    }
-
-		    vm.set('migration', migration);
-
-		}
-	    });
-	},
-	checkLxcPreconditions: function() {
-	    var me = this,
-		vm = me.getViewModel();
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'restart');
-	    }
-	}
-
-
-    },
-
-    width: 600,
-    modal: true,
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    border: false,
-    items: [
-	{
-	    xtype: 'form',
-	    reference: 'formPanel',
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'column'
-	    },
-	    items: [
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'displayfield',
-			name: 'source',
-			fieldLabel: gettext('Source node'),
-			bind: {
-			    value: '{nodename}'
-			}
-		    },
-		    {
-			xtype: 'displayfield',
-			reference: 'migrationMode',
-			fieldLabel: gettext('Mode'),
-			bind: {
-			    value: '{setMigrationMode}'
-			}
-		    }]
-		},
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'pveNodeSelector',
-			reference: 'pveNodeSelector',
-			name: 'target',
-			fieldLabel: gettext('Target node'),
-			allowBlank: false,
-			disallowedNodes: undefined,
-			onlineValidator: true,
-			listeners: {
-			    change: 'onTargetChange'
-			}
-		    },
-		    {
-			    xtype: 'pveStorageSelector',
-			    reference: 'pveDiskStorageSelector',
-			    name: 'targetstorage',
-			    fieldLabel: gettext('Target storage'),
-			    storageContent: 'images',
-			    bind: {
-				hidden: '{setStorageselectorHidden}'
-			    }
-		    }]
-		}
-	    ]
-	},
-	{
-	    xtype: 'gridpanel',
-	    reference: 'preconditionGrid',
-	    selectable: false,
-	    flex: 1,
-	    columns: [{
-		text: '',
-		dataIndex: 'severity',
-		renderer: function(v) {
-		    switch (v) {
-			case 'warning':
-			    return '<i class="fa fa-exclamation-triangle warning"></i> ';
-			case 'error':
-			    return '<i class="fa fa-times critical"></i>';
-			default:
-			    return v;
-		    }
-		},
-		width: 35
-	    },
-	    {
-		text: 'Info',
-		dataIndex: 'text',
-		cellWrap: true,
-		flex: 1
-	    }],
-	    bind: {
-		hidden: '{!migration.preconditions.length}',
-		store: {
-		    fields: ['severity','text'],
-		    data: '{migration.preconditions}'
-		}
-	    }
-	}
-
-    ],
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    reference: 'proxmoxHelpButton',
-	    onlineHelp: 'pct_migration',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	},
-	'->',
-	{
-	    xtype: 'button',
-	    reference: 'submitButton',
-	    text: gettext('Migrate'),
-	    handler: 'startMigration',
-	    bind: {
-		disabled: '{!migration.possible}'
-	    }
-	}
-    ]
-});
-Ext.define('PVE.window.BulkAction', {
-    extend: 'Ext.window.Window',
-
-    resizable: true,
-    width: 800,
-    modal: true,
-    layout: {
-	type: 'fit'
-    },
-    border: false,
-
-    // the action to be set
-    // currently there are
-    // startall
-    // migrateall
-    // stopall
-    action: undefined,
-
-    submit: function(params) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.action,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		me.hide();
-		win.on('destroy', function() {
-		    me.close();
-		});
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.action) {
-	    throw "no action specified";
-	}
-
-	if (!me.btnText) {
-	    throw "no button text specified";
-	}
-
-	if (!me.title) {
-	    throw "no title specified";
-	}
-
-	var items = [];
-
-	if (me.action === 'migrateall') {
-	    /*jslint confusion: true*/
-	    /*value is string and number*/
-	    items.push(
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'target',
-		    disallowedNodes: [me.nodename],
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'maxworkers',
-		    minValue: 1,
-		    maxValue: 100,
-		    value: 1,
-		    fieldLabel: gettext('Parallel jobs'),
-		    allowBlank: false
-		},
-		{
-		    itemId: 'lxcwarning',
-		    xtype: 'displayfield',
-		    userCls: 'pve-hint',
-		    value: 'Warning: Running CTs will be migrated in Restart Mode.',
-		    hidden: true // only visible if running container chosen
-		}
-	    );
-	    /*jslint confusion: false*/
-	} else if (me.action === 'startall') {
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'force',
-		value: 1
-	    });
-	}
-
-	items.push({
-	    xtype: 'vmselector',
-	    itemId: 'vms',
-	    name: 'vms',
-	    flex: 1,
-	    height: 300,
-	    selectAll: true,
-	    allowBlank: false,
-	    nodename: me.nodename,
-	    action: me.action,
-	    listeners: {
-		selectionchange: function(vmselector, records) {
-		    if (me.action == 'migrateall') {
-			var showWarning = records.some(function(item) {
-			    return (item.data.type == 'lxc' &&
-				item.data.status == 'running');
-			});
-			me.down('#lxcwarning').setVisible(showWarning);
-		    }
-		}
-	    }
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    fieldDefaults: {
-		labelWidth: 300,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: me.btnText,
-	    handler: function() {
-		form.isValid();
-		me.submit(form.getValues());
-	    }
-	});
-
-	Ext.apply(me, {
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-
-	form.on('validitychange', function() {
-	    var valid = form.isValid();
-	    submitBtn.setDisabled(!valid);
-	});
-	form.isValid();
-    }
-});
-Ext.define('PVE.window.Clone', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    isTemplate: false,
-
-    onlineHelp: 'qm_copy_and_clone',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=cloneform]': {
-		validitychange: 'disableSubmit'
-	    }
-	},
-	disableSubmit: function(form) {
-	    this.lookupReference('submitBtn').setDisabled(!form.isValid());
-	}
-    },
-
-    statics: {
-	// display a snapshot selector only if needed
-	wrap: function(nodename, vmid, isTemplate, guestType) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var snapshotList = response.result.data;
-		    var hasSnapshots = snapshotList.length === 1 &&
-			snapshotList[0].name === 'current' ? false : true;
-
-		    Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: isTemplate,
-			hasSnapshots: hasSnapshots
-		    }).show();
-		}
-	    });
-	}
-    },
-
-    create_clone: function(values) {
-	var me = this;
-
-	var params = { newid: values.newvmid };
-
-	if (values.snapname && values.snapname !== 'current') {
-	    params.snapname = values.snapname;
-	}
-
-	if (values.pool) {
-	    params.pool = values.pool;
-	}
-
-	if (values.name) {
-	    if (me.guestType === 'lxc') {
-		params.hostname = values.name;
-	    } else {
-		params.name = values.name;
-	    }
-	}
-
-	if (values.target) {
-	    params.target = values.target;
-	}
-
-	if (values.clonemode === 'copy') {
-	    params.full = 1;
-	    if (values.hdstorage) {
-		params.storage = values.hdstorage;
-		if (values.diskformat && me.guestType !== 'lxc') {
-		    params.format = values.diskformat;
-		}
-	    }
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/clone',
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-
-    },
-
-    // disable the Storage selector when clone mode is linked clone
-    updateVisibility: function() {
-	var me = this;
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-	var disksel = me.lookup('diskselector');
-	disksel.setDisabled(clonemode === 'clone');
-    },
-
-    // add to the list of valid nodes each node where
-    // all the VM disks are available
-    verifyFeature: function() {
-	var me = this;
-
-	var snapname = me.lookupReference('snapshotsel').getValue();
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-
-	var params = { feature: clonemode };
-	if (snapname !== 'current') {
-	    params.snapname = snapname;
-	}
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/feature',
-	    params: params,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		me.lookupReference('submitBtn').setDisabled(true);
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var res = response.result.data;
-
-		me.lookupReference('targetsel').allowedNodes = res.nodes;
-		me.lookupReference('targetsel').validate();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.snapname) {
-	    me.snapname = 'current';
-	}
-
-	if (!me.guestType) {
-	    throw "no Guest Type specified";
-	}
-
-	var titletext = me.guestType === 'lxc' ? 'CT' : 'VM';
-	if (me.isTemplate) {
-	    titletext += ' Template';
-	}
-	me.title = "Clone " + titletext + " " + me.vmid;
-
-	var col1 = [];
-	var col2 = [];
-
-	col1.push({
-	    xtype: 'pveNodeSelector',
-	    name: 'target',
-	    reference: 'targetsel',
-	    fieldLabel: gettext('Target node'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    onlineValidator: true,
-	    listeners: {
-		change: function(f, value) {
-		    me.lookupReference('hdstorage').setTargetNode(value);
-		}
-	    }
-	});
-
-	var modelist = [['copy', gettext('Full Clone')]];
-	if (me.isTemplate) {
-	    modelist.push(['clone', gettext('Linked Clone')]);
-	}
-
-	col1.push({
-	    xtype: 'pveGuestIDSelector',
-	    name: 'newvmid',
-	    guestType: me.guestType,
-	    value: '',
-	    loadNextFreeID: true,
-	    validateExists: false
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'name',
-	    allowBlank: true,
-	    fieldLabel: me.guestType === 'lxc' ? gettext('Hostname') : gettext('Name')
-	},
-	{
-	    xtype: 'pvePoolSelector',
-	    fieldLabel: gettext('Resource Pool'),
-	    name: 'pool',
-	    value: '',
-	    allowBlank: true
-	}
-	);
-
-	col2.push({
-	    xtype: 'proxmoxKVComboBox',
-	    fieldLabel: gettext('Mode'),
-	    name: 'clonemode',
-	    reference: 'clonemodesel',
-	    allowBlank: false,
-	    hidden: !me.isTemplate,
-	    value: me.isTemplate ? 'clone' : 'copy',
-		    comboItems: modelist,
-		    listeners: {
-			change: function(t, value) {
-			    me.updateVisibility();
-			    me.verifyFeature();
-			}
-		    }
-	},
-	{
-	    xtype: 'PVE.form.SnapshotSelector',
-	    name: 'snapname',
-	    reference: 'snapshotsel',
-	    fieldLabel: gettext('Snapshot'),
-	    nodename: me.nodename,
-	    guestType: me.guestType,
-	    vmid: me.vmid,
-	    hidden: me.isTemplate || !me.hasSnapshots ? true : false,
-	    disabled: false,
-	    allowBlank: false,
-	    value : me.snapname,
-	    listeners: {
-		change: function(f, value) {
-		    me.verifyFeature();
-		}
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    reference: 'diskselector',
-	    nodename: me.nodename,
-	    autoSelect: false,
-	    hideSize: true,
-	    hideSelection: true,
-	    storageLabel: gettext('Target Storage'),
-	    allowBlank: true,
-	    storageContent: me.guestType === 'qemu' ? 'images' : 'rootdir',
-	    emptyText: gettext('Same as source'),
-	    disabled: me.isTemplate ? true : false // because default mode is clone for templates
-	});
-
-	var formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    reference: 'cloneform',
-	    border: false,
-	    layout: 'column',
-	    defaultType: 'container',
-	    columns: 2,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: col1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: col2
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 600,
-	    height: 250,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ {
-		xtype: 'proxmoxHelpButton',
-		listenToGlobalEvent: false,
-		hidden: false,
-		onlineHelp: me.onlineHelp
-	    },
-	    '->',
-	    {
-		reference: 'submitBtn',
-		text: gettext('Clone'),
-		disabled: true,
-		handler: function() {
-		    var cloneForm = me.lookupReference('cloneform');
-		    if (cloneForm.isValid()) {
-			me.create_clone(cloneForm.getValues());
-		    }
-		}
-	    } ],
-	    items: [ formPanel ]
-	});
-
-	me.callParent();
-
-	me.verifyFeature();
-    }
-});
-Ext.define('PVE.qemu.Monitor', {
-    extend: 'Ext.panel.Panel',
-
-    alias: 'widget.pveQemuMonitor',
-
-    maxLines: 500,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var history = [];
-	var histNum = -1;
-	var lines = [];
-
-	var textbox = Ext.createWidget('panel', {
-	    region: 'center',
-	    xtype: 'panel',
-	    autoScroll: true,
-	    border: true,
-	    margins: '5 5 5 5',
-	    bodyStyle: 'font-family: monospace;'
-	});
-
-	var scrollToEnd = function() {
-	    var el = textbox.getTargetEl();
-	    var dom = Ext.getDom(el);
-
-	    var clientHeight = dom.clientHeight;
-	    // BrowserBug: clientHeight reports 0 in IE9 StrictMode
-            // Instead we are using offsetHeight and hardcoding borders
-            if (Ext.isIE9 && Ext.isStrict) {
-		clientHeight = dom.offsetHeight + 2;
-            }
-	    dom.scrollTop = dom.scrollHeight - clientHeight;
-	};
-
-	var refresh = function() {
-	    textbox.update('<pre>' + lines.join('\n') + '</pre>');
-	    scrollToEnd();
-	};
-
-	var addLine = function(line) {
-	    lines.push(line);
-	    if (lines.length > me.maxLines) {
-		lines.shift();
-	    }
-	};
-
-	var executeCmd = function(cmd) {
-	    addLine("# " + Ext.htmlEncode(cmd));
-	    if (cmd) {
-		history.unshift(cmd);
-		if (history.length > 20) {
-		    history.splice(20);
-		}
-	    }
-	    histNum = -1;
-
-	    refresh();
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor",
-		method: 'POST',
-		waitMsgTarget: me,
-		success: function(response, opts) {
-		    var res = response.result.data; 
-		    Ext.Array.each(res.split('\n'), function(line) {
-			addLine(Ext.htmlEncode(line));
-		    });
-		    refresh();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		textbox,
-		{
-		    region: 'south',
-		    margins:'0 5 5 5',
-		    border: false,
-		    xtype: 'textfield',
-		    name: 'cmd',
-		    value: '',
-		    fieldStyle: 'font-family: monospace;',
-		    allowBlank: true,
-		    listeners: {
-			afterrender: function(f) {
-			    f.focus(false);
-			    addLine("Type 'help' for help.");
-			    refresh();
-			},
-			specialkey: function(f, e) {
-			    var key = e.getKey();
-			    switch (key) {
-				case e.ENTER:
-				    var cmd = f.getValue();
-				    f.setValue('');
-				    executeCmd(cmd);
-				    break;
-				case e.PAGE_UP:
-				    textbox.scrollBy(0, -0.9*textbox.getHeight(), false);
-				    break;
-				case e.PAGE_DOWN:
-				    textbox.scrollBy(0, 0.9*textbox.getHeight(), false);
-				    break;
-				case e.UP:
-				    if (histNum + 1 < history.length) {
-					f.setValue(history[++histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				case e.DOWN:
-				    if (histNum > 0) {
-					f.setValue(history[--histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				default:
-				    break;
-			    }
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		show: function() {
-		    var field = me.query('textfield[name="cmd"]')[0];
-		    field.focus(false, true);
-		}
-	    }
-	});		
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveQemuSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 330,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 330,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.qemu.OSTypeInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuOSTypePanel',
-    onlineHelp: 'qm_os_settings',
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'combobox[name=osbase]': {
-		change: 'onOSBaseChange'
-	    },
-	    'combobox[name=ostype]': {
-		afterrender: 'onOSTypeChange',
-		change: 'onOSTypeChange'
-	    }
-	},
-	onOSBaseChange: function(field, value) {
-	    this.lookup('ostype').getStore().setData(PVE.Utils.kvm_ostypes[value]);
-	},
-	onOSTypeChange: function(field) {
-	    var me = this, ostype = field.getValue();
-	    if (!me.getView().insideWizard) {
-		return;
-	    }
-	    var targetValues = PVE.qemu.OSDefaults.getDefaults(ostype);
-
-	    me.setWidget('pveBusSelector', targetValues.busType);
-	    me.setWidget('pveNetworkCardSelector', targetValues.networkCard);
-	    var scsihw = targetValues.scsihw || '__default__';
-	    this.getViewModel().set('current.scsihw', scsihw);
-	},
-	setWidget: function(widget, newValue) {
-	    // changing a widget is safe only if ComponentQuery.query returns us
-	    // a single value array
-	    var widgets = Ext.ComponentQuery.query('pveQemuCreateWizard ' + widget);
-	    if (widgets.length === 1) {
-		widgets[0].setValue(newValue);
-	    } else {
-		throw 'non unique widget :' + widget + ' in Wizard';
-	    }
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	/*jslint confusion: true */
-	me.items = [
-	    {
-		xtype: 'displayfield',
-		value: gettext('Guest OS') + ':',
-		hidden: !me.insideWizard
-	    },
-	    {
-		xtype: 'combobox',
-		submitValue: false,
-		name: 'osbase',
-		fieldLabel: gettext('Type'),
-		editable: false,
-		queryMode: 'local',
-		value: 'Linux',
-		store: Object.keys(PVE.Utils.kvm_ostypes)
-	    },
-	    {
-		xtype: 'combobox',
-		name: 'ostype',
-		reference: 'ostype',
-		fieldLabel: gettext('Version'),
-		value: 'l26',
-		allowBlank : false,
-		editable: false,
-		queryMode: 'local',
-		valueField: 'val',
-		displayField: 'desc',
-		store: {
-		    fields: ['desc', 'val'],
-		    data: PVE.Utils.kvm_ostypes.Linux,
-		    listeners: {
-			datachanged: function (store) {
-			    var ostype = me.lookup('ostype');
-			    var old_val = ostype.getValue();
-			    if (!me.insideWizard && old_val && store.find('val', old_val) != -1) {
-				ostype.setValue(old_val);
-			    } else {
-				ostype.setValue(store.getAt(0));
-			    }
-			}
-		    }
-		}
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.OSTypeEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: 'OS Type',
-
-    items: [{ xtype: 'pveQemuOSTypePanel' }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var value = response.result.data.ostype || 'other';
-		var osinfo = PVE.Utils.get_kvm_osinfo(value);
-		me.setValues({ ostype: value, osbase: osinfo.base });
-	    }
-	});
-    }
-});
-/*
- * This class holds performance *recommended* settings for the PVE Qemu wizards
- * the *mandatory* settings are set in the PVE::QemuServer
- * config_to_command sub
- * We store this here until we get the data from the API server
-*/
-
-// this is how you would add an hypothetic FreeBSD > 10 entry
-//
-//virtio-blk is stable but virtIO net still
-//   problematic as of 10.3
-// see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059
-//	addOS({
-//	    parent: 'generic', // inherits defaults
-//	    pveOS: 'freebsd10', // must match a radiofield in OSTypeEdit.js
-//	    busType: 'virtio' // must match a pveBusController value
-//			    // networkCard muss match a pveNetworkCardSelector
-
-
-Ext.define('PVE.qemu.OSDefaults', {
-    singleton: true, // will also force creation when loaded
-
-    constructor: function() {
-	var me = this;
-
-	var addOS = function(settings) {
-		if (me.hasOwnProperty(settings.parent)) {
-		    var child = Ext.clone(me[settings.parent]);
-		    me[settings.pveOS] = Ext.apply(child, settings);
-
-		} else {
-		    throw("Could not find your genitor");
-		}
-	    };
-
-	// default values
-	me.generic = {
-	    busType: 'ide',
-	    networkCard: 'e1000',
-	    busPriority: {
-		    ide: 4,
-		    sata: 3,
-		    scsi: 2,
-		    virtio: 1
-	    },
-	    scsihw: 'virtio-scsi-pci'
-	};
-
-       // virtio-net is in kernel since 2.6.25
-       // virtio-scsi since 3.2 but backported in RHEL with 2.6 kernel
-	addOS({
-	    pveOS: 'l26',
-	    parent : 'generic',
-	    busType: 'scsi',
-	    busPriority: {
-		    scsi: 4,
-		    virtio: 3,
-		    sata: 2,
-		    ide: 1
-	    },
-	    networkCard: 'virtio'
-	});
-
-	// recommandation from http://wiki.qemu.org/Windows2000
-	addOS({
-	    pveOS: 'w2k',
-	    parent : 'generic',
-	    networkCard: 'rtl8139',
-	    scsihw: ''
-	});
-	// https://pve.proxmox.com/wiki/Windows_XP_Guest_Notes
-	addOS({
-	    pveOS: 'wxp',
-	    parent : 'w2k'
-	});
-
-	me.getDefaults = function(ostype) {
-	    if (PVE.qemu.OSDefaults[ostype]) {
-		return PVE.qemu.OSDefaults[ostype];
-	    } else {
-		return PVE.qemu.OSDefaults.generic;
-	    }
-	};
-    }
-});
-Ext.define('PVE.qemu.ProcessorInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuProcessorPanel',
-    onlineHelp: 'qm_cpu',
-
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateCores: function() {
-	    var me = this.getView();
-	    var sockets = me.down('field[name=sockets]').getValue();
-	    var cores = me.down('field[name=cores]').getValue();
-	    me.down('field[name=totalcores]').setValue(sockets*cores);
-	    var vcpus = me.down('field[name=vcpus]');
-	    vcpus.setMaxValue(sockets*cores);
-	    vcpus.setEmptyText(sockets*cores);
-	    vcpus.validate();
-	},
-
-	control: {
-	    'field[name=sockets]': {
-		change: 'updateCores'
-	    },
-	    'field[name=cores]': {
-		change: 'updateCores'
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (Array.isArray(values['delete'])) {
-	    values['delete'] = values['delete'].join(',');
-	}
-
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	// build the cpu options:
-	me.cpu.cputype = values.cputype;
-
-	if (values.flags) {
-	    me.cpu.flags = values.flags;
-	} else {
-	    delete me.cpu.flags;
-	}
-
-	delete values.cputype;
-	delete values.flags;
-	var cpustring = PVE.Parser.printQemuCpu(me.cpu);
-
-	// remove cputype delete request:
-	var del = values['delete'];
-	delete values['delete'];
-	if (del) {
-	    del = del.split(',');
-	    Ext.Array.remove(del, 'cputype');
-	} else {
-	    del = [];
-	}
-
-	if (cpustring) {
-	    values.cpu = cpustring;
-	} else {
-	    del.push('cpu');
-	}
-
-	var delarr = del.join(',');
-	if (delarr) {
-	    values['delete'] = delarr;
-	}
-
-	return values;
-    },
-
-    cpu: {},
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'sockets',
-	    minValue: 1,
-	    maxValue: 4,
-	    value: '1',
-	    fieldLabel: gettext('Sockets'),
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cores',
-	    minValue: 1,
-	    maxValue: 128,
-	    value: '1',
-	    fieldLabel: gettext('Cores'),
-	    allowBlank: false
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'CPUModelSelector',
-	    name: 'cputype',
-	    value: '__default__',
-	    fieldLabel: gettext('Type')
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Total cores'),
-	    name: 'totalcores',
-	    value: '1'
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'vcpus',
-	    minValue: 1,
-	    maxValue: 1,
-	    value: '',
-	    fieldLabel: gettext('VCPUs'),
-	    deleteEmpty: true,
-	    allowBlank: true,
-	    emptyText: '1'
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    maxValue: 128, // api maximum
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    minValue: 8,
-	    maxValue: 500000,
-	    value: '1024',
-	    deleteEmpty: true,
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Enable NUMA'),
-	    name: 'numa',
-	    uncheckedValue: 0
-	}
-    ],
-    advancedColumnB: [
-	{
-	    xtype: 'label',
-	    text: 'Extra CPU Flags:'
-	},
-	{
-	    xtype: 'vmcpuflagselector',
-	    name: 'flags'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.ProcessorEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 700,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.ProcessorInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Processors'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		var value = data.cpu;
-		if (value) {
-		    var cpu = PVE.Parser.parseQemuCpu(value);
-		    ipanel.cpu = cpu;
-		    data.cputype = cpu.cputype;
-		    if (cpu.flags) {
-			data.flags = cpu.flags;
-		    }
-		}
-		me.setValues(data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuBootOrderPanel',
-    vmconfig: {}, // store loaded vm config
-
-    bootdisk: undefined,
-    selection: [],
-    list: [],
-    comboboxes: [],
-
-    isBootDisk: function(value) {
-	return PVE.Utils.bus_match.test(value);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-	var order = me.vmconfig.boot || 'cdn';
-	me.bootdisk = me.vmconfig.bootdisk || undefined;
-
-	// get the first 3 characters
-	// ignore the rest (there should never be more than 3)
-	me.selection = order.split('').slice(0,3);
-
-	// build bootdev list
-	me.list = [];
-	Ext.Object.each(me.vmconfig, function(key, value) {
-	    if (me.isBootDisk(key) &&
-		!(/media=cdrom/).test(value)) {
-		me.list.push([key, "Disk '" + key + "'"]);
-	    }
-	});
-
-	me.list.push(['d', 'CD-ROM']);
-	me.list.push(['n', gettext('Network')]);
-	me.list.push(['__none__', Proxmox.Utils.noneText]);
-
-	me.recomputeList();
-
-	me.comboboxes.forEach(function(box) {
-	    box.resetOriginalValue();
-	});
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var order = me.selection.join('');
-	var res = { boot: order };
-
-	if  (me.bootdisk && order.indexOf('c') !== -1) {
-	    res.bootdisk = me.bootdisk;
-	} else {
-	    res['delete'] = 'bootdisk';
-	}
-
-	return res;
-    },
-
-    recomputeSelection: function(combobox, newVal, oldVal) {
-	var me = this.up('#inputpanel');
-	me.selection = [];
-	me.comboboxes.forEach(function(item) {
-	    var val = item.getValue();
-
-	    // when selecting an already selected item,
-	    // switch it around
-	    if ((val === newVal || (me.isBootDisk(val) && me.isBootDisk(newVal))) &&
-		item.name !== combobox.name &&
-		newVal !== '__none__') {
-		// swap items
-		val = oldVal;
-	    }
-
-	    // push 'c','d' or 'n' in the array
-	    if (me.isBootDisk(val)) {
-		me.selection.push('c');
-		me.bootdisk = val;
-	    } else if (val === 'd' ||
-		       val === 'n') {
-		me.selection.push(val);
-	    }
-	});
-
-	me.recomputeList();
-    },
-
-    recomputeList: function(){
-	var me = this;
-	// set the correct values in the kvcomboboxes
-	var cnt = 0;
-	me.comboboxes.forEach(function(item) {
-	    if (cnt === 0) {
-		// never show 'none' on first combobox
-		item.store.loadData(me.list.slice(0, me.list.length-1));
-	    } else {
-		item.store.loadData(me.list);
-	    }
-	    item.suspendEvent('change');
-	    if (cnt < me.selection.length) {
-		item.setValue((me.selection[cnt] !== 'c')?me.selection[cnt]:me.bootdisk);
-	    } else if (cnt === 0){
-		item.setValue('');
-	    } else {
-		item.setValue('__none__');
-	    }
-	    cnt++;
-	    item.resumeEvent('change');
-	    item.validate();
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	// this has to be done here, because of
-	// the way our inputPanel class handles items
-	me.comboboxes = [
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 1",
-		labelWidth: 120,
-		name: 'bd1',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 2",
-		labelWidth: 120,
-		name: 'bd2',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 3",
-		labelWidth: 120,
-		name: 'bd3',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    })
-	];
-	Ext.apply(me, { items: me.comboboxes });
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    items: [{
-	xtype: 'pveQemuBootOrderPanel',
-	itemId: 'inputpanel'
-    }],
-
-    subject: gettext('Boot Order'),
-
-    initComponent : function() {
-	var me = this;
-	me.callParent();
-	me.load({
-	    success: function(response, options) {
-		me.down('#inputpanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuMemoryPanel',
-    onlineHelp: 'qm_memory',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = {};
-
-	res.memory = values.memory;
-	res.balloon = values.balloon;
-
-	if (!values.ballooning) {
-	    res.balloon = 0;
-	    res['delete'] = 'shares';
-	} else if (values.memory === values.balloon) {
-	    delete res.balloon;
-	    res['delete'] = 'balloon,shares';
-	} else if (Ext.isDefined(values.shares) && (values.shares !== "")) {
-	    res.shares = values.shares;
-	} else {
-	    res['delete'] = "shares";
-	}
-
-	return res;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var labelWidth = 160;
-
-	me.items= [
-	    {
-		xtype: 'pveMemoryField',
-		labelWidth: labelWidth,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		name: 'memory',
-		minValue: 1,
-		step: 32,
-		hotplug: me.hotplug,
-		listeners: {
-		    change: function(f, value, old) {
-			var bf = me.down('field[name=balloon]');
-			var balloon = bf.getValue();
-			bf.setMaxValue(value);
-			if (balloon === old) {
-			    bf.setValue(value);
-			}
-			bf.validate();
-		    }
-		}
-	    }
-	];
-
-	me.advancedItems= [
-	    {
-		xtype: 'pveMemoryField',
-		name: 'balloon',
-		minValue: 1,
-		step: 32,
-		fieldLabel: gettext('Minimum memory') + ' (MiB)',
-		hotplug: me.hotplug,
-		labelWidth: labelWidth,
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			var memory = me.down('field[name=memory]').getValue();
-			var shares = me.down('field[name=shares]');
-			shares.setDisabled(value === memory);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'shares',
-		disabled: true,
-		minValue: 0,
-		maxValue: 50000,
-		value: '',
-		step: 10,
-		fieldLabel: gettext('Shares'),
-		labelWidth: labelWidth,
-		allowBlank: true,
-		emptyText: Proxmox.Utils.defaultText + ' (1000)',
-		submitEmptyText: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		labelWidth: labelWidth,
-		value: '1',
-		name: 'ballooning',
-		fieldLabel: gettext('Ballooning Device'),
-		listeners: {
-		    change: function(f, value) {
-			var bf = me.down('field[name=balloon]');
-			var shares = me.down('field[name=shares]');
-			var memory = me.down('field[name=memory]');
-			bf.setDisabled(!value);
-			shares.setDisabled(!value || (bf.getValue() === memory.getValue()));
-		    }
-		}
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = me.items;
-	    me.items = undefined;
-	    me.advancedColumn1 = me.advancedItems;
-	    me.advancedItems = undefined;
-	}
-	me.callParent();
-    }
-
-});
-
-Ext.define('PVE.qemu.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent: function() {
-	var me = this;
-
-	var memoryhotplug;
-	if(me.hotplug) {
-	    Ext.each(me.hotplug.split(','), function(el) {
-		if (el === 'memory') {
-		    memoryhotplug = 1;
-	        }
-	    });
-	}
-
-	var ipanel = Ext.create('PVE.qemu.MemoryInputPanel', {
-	    hotplug: memoryhotplug
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: [ ipanel ],
-	    // uncomment the following to use the async configiguration API
-	    // backgroundDelay: 5, 
-	    width: 400
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-
-		var values = {
-		    ballooning: data.balloon === 0 ? '0' : '1',
-		    shares: data.shares,
-		    memory: data.memory || '512',
-		    balloon: data.balloon > 0 ? data.balloon : (data.memory || '512')
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuNetworkInputPanel',
-    onlineHelp: 'qm_network_device',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	me.network.model = values.model;
-	if (values.nonetwork) {
-	    return {};
-	} else {
-	    me.network.bridge = values.bridge;
-	    me.network.tag = values.tag;
-	    me.network.firewall = values.firewall;
-	}
-	me.network.macaddr = values.macaddr;
-	me.network.disconnect = values.disconnect;
-	me.network.queues = values.queues;
-
-	if (values.rate) {
-	    me.network.rate = values.rate;
-	} else {
-	    delete me.network.rate;
-	}
-
-	var params = {};
-
-	params[me.confid] = PVE.Parser.printQemuNetwork(me.network);
-
-	return params;
-    },
-
-    setNetwork: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data) {
-	    data.networkmode = data.bridge ? 'bridge' : 'nat';
-	} else {
-	    data = {};
-	    data.networkmode = 'bridge';
-	}
-	me.network = data;
-	
-	me.setValues(me.network);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.bridgesel.setNodename(nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.network = {};
-	me.confid = 'net0';
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.bridgesel = Ext.create('PVE.form.BridgeSelector', {
-	    name: 'bridge',
-	    fieldLabel: gettext('Bridge'),
-	    nodename: me.nodename,
-	    autoSelect: true,
-	    allowBlank: false
-	});
-
-	me.column1 = [
-	    me.bridgesel,
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		checked: (me.insideWizard || me.isCreate)
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Disconnect'),
-		name: 'disconnect'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1.unshift({
-		xtype: 'checkbox',
-		name: 'nonetwork',
-		inputValue: 'none',
-		boxLabel: gettext('No network device'),
-		listeners: {
-		    change: function(cb, value) {
-			var fields = [
-			    'disconnect',
-			    'bridge',
-			    'tag',
-			    'firewall',
-			    'model',
-			    'macaddr',
-			    'rate',
-			    'queues'
-			];
-			fields.forEach(function(fieldname) {
-			    me.down('field[name='+fieldname+']').setDisabled(value);
-			});
-			me.down('field[name=bridge]').validate();
-		    }
-		}
-	    });
-	    me.column2.unshift({
-		xtype: 'displayfield'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'pveNetworkCardSelector',
-		name: 'model',
-		fieldLabel: gettext('Model'),
-		value: PVE.qemu.OSDefaults.generic.networkCard,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'macaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		allowBlank: true,
-		emptyText: 'auto'
-	    });
-	me.advancedColumn2 = [
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: '',
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'queues',
-		fieldLabel: 'Multiqueue',
-		minValue: 1,
-		maxValue: 8,
-		value: '',
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";	    
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.NetworkInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: me.isCreate
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Device'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		if (!me.isCreate) {
-		    var value = me.vmconfig[me.confid];
-		    var network = PVE.Parser.parseQemuNetwork(me.confid, value);
-		    if (!network) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse network options');
-			me.close();
-			return;
-		    }
-		    ipanel.setNetwork(me.confid, network);
-		} else {
-		    for (i = 0; i < 100; i++) {
-			confid = 'net' + i.toString();
-			if (!Ext.isDefined(me.vmconfig[confid])) {
-			    me.confid = confid;
-			    break;
-			}
-		    }
-		    ipanel.setNetwork(me.confid);		    
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Smbios1InputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.PVE.qemu.Smbios1InputPanel',
-
-    insideWizard: false,
-
-    smbios1: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {
-	    smbios1: PVE.Parser.printQemuSmbios1(values)
-	};
-
-	return params;
-    },
-
-    setSmbios1: function(data) {
-	var me = this;
-
-	me.smbios1 = data;
-	
-	me.setValues(me.smbios1);
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: 'UUID',
-	    regex: /^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$/,
-	    name: 'uuid'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Manufacturer'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'manufacturer'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Product'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'product'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Version'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'version'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Serial'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'serial'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: 'SKU',
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'sku'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Family'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'family'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.Smbios1Edit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.Smbios1InputPanel', {});
-
-	Ext.applyIf(me, {
-	    subject: gettext('SMBIOS settings (type1)'),
-	    width: 450,
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		var value = me.vmconfig.smbios1;
-		if (value) {
-		    var data = PVE.Parser.parseQemuSmbios1(value);
-		    if (!data) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse smbios options');
-			me.close();
-			return;
-		    }
-		    ipanel.setSmbios1(data);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.CDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuCDInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || (values.controller + values.deviceid);
-	
-	me.drive.media = 'cdrom';
-	if (values.mediaType === 'iso') {
-	    me.drive.file = values.cdimage;
-	} else if (values.mediaType === 'cdrom') {
-	    me.drive.file = 'cdrom';
-	} else {
-	    me.drive.file = 'none';
-	}
-
-	var params = {};
-		
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	
-	return params;	
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig, 'cdrom');
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	var values = {};
-	if (drive.file === 'cdrom') {
-	    values.mediaType = 'cdrom';
-	} else if (drive.file === 'none') {
-	    values.mediaType = 'none';
-	} else {
-	    values.mediaType = 'iso';
-	    var match = drive.file.match(/^([^:]+):/);
-	    if (match) {
-		values.cdstorage = match[1];
-		values.cdimage = drive.file;
-	    }
-	}
-
-	me.drive = drive;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.cdstoragesel.setNodename(nodename);
-	me.cdfilesel.setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	var items = [];
-
-	if (!me.confid) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		noVirtIO: true
-	    });
-	    items.push(me.bussel);
-	}
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'iso',
-	    boxLabel: gettext('Use CD/DVD disc image file (iso)'),
-	    checked: true,
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=cdstorage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').setDisabled(!value);
-		    me.down('field[name=cdimage]').validate();
-		}
-	    }
-	});
-
-	me.cdfilesel = Ext.create('PVE.form.FileSelector', {
-	    name: 'cdimage',
-	    nodename: me.nodename,
-	    storageContent: 'iso',
-	    fieldLabel: gettext('ISO image'),
-	    labelAlign: 'right',
-	    allowBlank: false
-	});
-	
-	me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
-	    name: 'cdstorage',
-	    nodename: me.nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'iso',
-	    allowBlank: false,
-	    autoSelect: me.insideWizard,
-	    listeners: {
-		change: function(f, value) {
-		    me.cdfilesel.setStorage(value);
-		}
-	    }
-	});
-
-	items.push(me.cdstoragesel);
-	items.push(me.cdfilesel);
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'cdrom',
-	    boxLabel: gettext('Use physical CD/DVD Drive')
-	});
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'none',
-	    boxLabel: gettext('Do not use any media')
-	});
-
-	me.items = items;
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.CDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'CD/DVD Drive',
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-	
-	me.load({
-	    success:  function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert('Error', 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-/* 'change' property is assigned a string and then a function */
-Ext.define('PVE.qemu.HDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuHDInputPanel',
-    onlineHelp: 'qm_hard_disk',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onControllerChange: function(field) {
-	    var value = field.getValue();
-
-	    var allowIOthread = value.match(/^(virtio|scsi)/);
-	    this.lookup('iothread').setDisabled(!allowIOthread);
-	    if (!allowIOthread) {
-		this.lookup('iothread').setValue(false);
-	    }
-
-	    var virtio = value.match(/^virtio/);
-	    this.lookup('discard').setDisabled(virtio);
-	    this.lookup('ssd').setDisabled(virtio);
-	    if (virtio) {
-		this.lookup('discard').setValue(false);
-		this.lookup('ssd').setValue(false);
-	    }
-
-	    this.lookup('scsiController').setVisible(value.match(/^scsi/));
-	},
-
-	control: {
-	    'field[name=controller]': {
-		change: 'onControllerChange',
-		afterrender: 'onControllerChange'
-	    },
-	    'field[name=iothread]' : {
-		change: function(f, value) {
-		    if (!this.getView().insideWizard) {
-			return;
-		    }
-		    var vmScsiType = value ? 'virtio-scsi-single': 'virtio-scsi-pci';
-		    this.lookupReference('scsiController').setValue(vmScsiType);
-		}
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {};
-	var confid = me.confid || (values.controller + values.deviceid);
-
-	if (me.unused) {
-	    me.drive.file = me.vmconfig[values.unusedId];
-	    confid = values.controller + values.deviceid;
-	} else if (me.isCreate) {
-	    if (values.hdimage) {
-		me.drive.file = values.hdimage;
-	    } else {
-		me.drive.file = values.hdstorage + ":" + values.disksize;
-	    }
-	    me.drive.format = values.diskformat;
-	}
-
-	if (values.nobackup) {
-	    me.drive.backup = 'no';
-	} else {
-	    delete me.drive.backup;
-	}
-
-	if (values.noreplicate) {
-	    me.drive.replicate = 'no';
-	} else {
-	    delete me.drive.replicate;
-	}
-
-	if (values.discard) {
-	    me.drive.discard = 'on';
-	} else {
-	    delete me.drive.discard;
-	}
-
-	if (values.ssd) {
-	    me.drive.ssd = 'on';
-	} else {
-	    delete me.drive.ssd;
-	}
-
-	if (values.iothread) {
-	    me.drive.iothread = 'on';
-	} else {
-	    delete me.drive.iothread;
-	}
-
-	if (values.cache) {
-	    me.drive.cache = values.cache;
-	} else {
-	    delete me.drive.cache;
-	}
-
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            if (values[name]) {
-                me.drive[name] = values[name];
-            } else {
-                delete me.drive[name];
-            }
-            var burst_name = name + '_max';
-            if (values[burst_name] && values[name]) {
-                me.drive[burst_name] = values[burst_name];
-            } else {
-                delete me.drive[burst_name];
-            }
-        });
-
-
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
-	return params;
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	me.vmconfig = vmconfig;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig);
-	    me.scsiController.setValue(vmconfig.scsihw);
-	}
-	if (me.unusedDisks) {
-	    var disklist = [];
-	    Ext.Object.each(vmconfig, function(key, value) {
-		if (key.match(/^unused\d+$/)) {
-		    disklist.push([key, value]);
-		}
-	    });
-	    me.unusedDisks.store.loadData(disklist);
-	    me.unusedDisks.setValue(me.confid);
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	me.drive = drive;
-
-	var values = {};
-	var match = drive.file.match(/^([^:]+):/);
-	if (match) {
-	    values.hdstorage = match[1];
-	}
-
-	values.hdimage = drive.file;
-	values.nobackup = !PVE.Parser.parseBoolean(drive.backup, 1);
-	values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
-	values.diskformat = drive.format || 'raw';
-	values.cache = drive.cache || '__default__';
-	values.discard = (drive.discard === 'on');
-	values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-	values.iothread = PVE.Parser.parseBoolean(drive.iothread);
-
-	values.mbps_rd = drive.mbps_rd;
-	values.mbps_wr = drive.mbps_wr;
-	values.iops_rd = drive.iops_rd;
-	values.iops_wr = drive.iops_wr;
-	values.mbps_rd_max = drive.mbps_rd_max;
-	values.mbps_wr_max = drive.mbps_wr_max;
-	values.iops_rd_max = drive.iops_rd_max;
-	values.iops_wr_max = drive.iops_wr_max;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var labelWidth = 140;
-
-	me.drive = {};
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.advancedColumn1 = [];
-	me.advancedColumn2 = [];
-
-	if (!me.confid || me.unused) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
-	    });
-	    me.column1.push(me.bussel);
-
-	    me.scsiController = Ext.create('Ext.form.field.Display', {
-		fieldLabel: gettext('SCSI Controller'),
-		reference: 'scsiController',
-		bind: me.insideWizard ? {
-		    value: '{current.scsihw}'
-		} : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		submitValue: false,
-		hidden: true
-	    });
-	    me.column1.push(me.scsiController);
-	}
-
-	if (me.unused) {
-	    me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
-		name: 'unusedId',
-		fieldLabel: gettext('Disk image'),
-		matchFieldWidth: false,
-		listConfig: {
-		    width: 350
-		},
-		data: [],
-		allowBlank: false
-	    });
-	    me.column1.push(me.unusedDisks);
-	} else if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveDiskStorageSelector',
-		storageContent: 'images',
-		name: 'disk',
-		nodename: me.nodename,
-		autoSelect: me.insideWizard
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'textfield',
-		disabled: true,
-		submitValue: false,
-		fieldLabel: gettext('Disk image'),
-                name: 'hdimage'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'CacheTypeSelector',
-		name: 'cache',
-		value: '__default__',
-		fieldLabel: gettext('Cache')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Discard'),
-		disabled: me.confid && me.confid.match(/^virtio/),
-		reference: 'discard',
-		name: 'discard'
-	    }
-	);
-
-	me.advancedColumn1.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && me.confid.match(/^virtio/),
-		fieldLabel: gettext('SSD emulation'),
-		labelWidth: labelWidth,
-		name: 'ssd',
-		reference: 'ssd'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && !me.confid.match(/^(virtio|scsi)/),
-		fieldLabel: 'IO thread',
-		labelWidth: labelWidth,
-		reference: 'iothread',
-		name: 'iothread'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    }
-	);
-
-	me.advancedColumn2.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('No backup'),
-		labelWidth: labelWidth,
-		name: 'nobackup'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Skip replication'),
-		labelWidth: labelWidth,
-		name: 'noreplicate'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-/*jslint confusion: false */
-
-Ext.define('PVE.qemu.HDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    backgroundDelay: 5,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    me.subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
-	} else {
-           me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
-	}
-
-	me.items = [ ipanel ];
-
-	me.callParent();
-	/*jslint confusion: true*/
-	/* 'data' is assigned an empty array in same file, and here we
-	 * use it like an object
-	 */
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-	/*jslint confusion: false*/
-    }
-});
-Ext.define('PVE.window.HDResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 140,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 250,
-	    height: 150,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-Ext.define('PVE.window.HDMove', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-
-    move_disk: function(disk, storage, format, delete_disk) {
-	var me = this;
-	var qemu = (me.type === 'qemu');
-	var params = {};
-	params.storage = storage;
-	params[qemu ? 'disk':'volume'] = disk;
-
-	if (format && qemu) {
-	    params.format = format;
-	}
-
-	if (delete_disk) {
-	    params['delete'] = 1;
-	}
-
-	var url = '/nodes/' + me.nodename + '/' + me.type + '/' + me.vmid + '/';
-	url += qemu ? 'move_disk' : 'move_volume';
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: url,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		win.on('destroy', function() { me.close(); });
-	    }
-	});
-
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var diskarray = [];
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    me.type = 'qemu';
-	}
-
-	var qemu = (me.type === 'qemu');
-
-        var items = [
-            {
-                xtype: 'displayfield',
-                name: qemu ? 'disk' : 'volume',
-                value: me.disk,
-                fieldLabel: qemu ? gettext('Disk') : gettext('Mount Point'),
-                vtype: 'StorageId',
-                allowBlank: false
-            }
-        ];
-
-	items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    storageLabel: gettext('Target Storage'),
-	    nodename: me.nodename,
-	    storageContent: qemu ? 'images' : 'rootdir',
-	    hideSize: true
-	});
-
-	items.push({
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Delete source'),
-	    name: 'deleteDisk',
-	    uncheckedValue: 0,
-	    checked: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = qemu ? gettext("Move disk") : gettext('Move Volume');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: me.title,
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.move_disk(me.disk, values.hdstorage, values.diskformat,
-				 values.deleteDisk);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 350,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	me.mon(me.formPanel, 'validitychange', function(fp, isValid) {
-	    submitBtn.setDisabled(!isValid);
-	});
-
-	me.formPanel.isValid();
-    }
-});
-Ext.define('PVE.qemu.EFIDiskInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveEFIDiskInputPanel',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = 'efidisk0';
-
-	if (values.hdimage) {
-	    me.drive.file = values.hdimage;
-	} else {
-	    // we use 1 here, because for efi the size gets overridden from the backend
-	    me.drive.file = values.hdstorage + ":1";
-	}
-
-	me.drive.format = values.diskformat;
-	var params = {};
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items= [];
-
-	me.items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    nodename: me.nodename,
-	    hideSize: true
-	});
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.EFIDiskEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-    subject: gettext('EFI Disk'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveEFIDiskInputPanel',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: true
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.DisplayInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveDisplayInputPanel',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values, 'type');
-	if (ret === '') {
-	    return {
-		'delete': 'vga'
-	    };
-	}
-	return {
-	    vga: ret
-	};
-    },
-
-    items: [{
-	name: 'type',
-	xtype: 'proxmoxKVComboBox',
-	value: '__default__',
-	deleteEmpty: false,
-	fieldLabel: gettext('Graphic card'),
-	comboItems: PVE.Utils.kvm_vga_driver_array(),
-	validator: function() {
-	    var v = this.getValue();
-	    var cfg = this.up('proxmoxWindowEdit').vmconfig || {};
-
-	    if (v.match(/^serial\d+$/) && (!cfg[v] || cfg[v] !== 'socket')) {
-		var fmt = gettext("Serial interface '{0}' is not correctly configured.");
-		return Ext.String.format(fmt, v);
-	    }
-	    return true;
-	},
-	listeners: {
-	    change: function(cb, val) {
-		var me = this.up('panel');
-		if (!val) {
-		    return;
-		}
-		var disable = false;
-		var emptyText = Proxmox.Utils.defaultText;
-		switch (val) {
-		    case "cirrus":
-			emptyText = "4";
-			break;
-		    case "std":
-			emptyText = "16";
-			break;
-		    case "qxl":
-		    case "qxl2":
-		    case "qxl3":
-		    case "qxl4":
-			emptyText = "16";
-			break;
-		    case "vmware":
-			emptyText = "16";
-			break;
-		    case "none":
-		    case "serial0":
-		    case "serial1":
-		    case "serial2":
-		    case "serial3":
-			emptyText = 'N/A';
-			disable = true;
-			break;
-		    case "virtio":
-			emptyText = "256";
-			break;
-		    default:
-			break;
-		}
-		var memoryfield = me.down('field[name=memory]');
-		memoryfield.setEmptyText(emptyText);
-		memoryfield.setDisabled(disable);
-	    }
-	}
-    },{
-	xtype: 'proxmoxintegerfield',
-	emptyText: Proxmox.Utils.defaultText,
-	fieldLabel: gettext('Memory') + ' (MiB)',
-	minValue: 4,
-	maxValue: 512,
-	step: 4,
-	name: 'memory'
-    }]
-});
-
-Ext.define('PVE.qemu.DisplayEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Display'),
-    width: 350,
-
-    items: [{
-	xtype: 'pveDisplayInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-		var vga = me.vmconfig.vga || '__default__';
-		me.setValues(PVE.Parser.parsePropertyString(vga, 'type'));
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.KeyboardEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('Keyboard Layout'),
-	    items: {
-		xtype: 'VNCKeyboardSelector',
-		name: 'keyboard',
-		value: '__default__',
-		fieldLabel: gettext('Keyboard Layout')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.HardwareView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.HardwareView'],
-
-    onlineHelp: 'qm_virtual_machines_settings',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-	var iconCls = rowdef.iconCls;
-	var icon = '';
-	var txt = (rowdef.header || key);
-
-	metaData.tdAttr = "valign=middle";
-
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') { 
-		var value = me.getObjectValue(key, '', false);
-		if (value === '') {
-		    value = me.getObjectValue(key, '', true);
-		}
-		if (value.match(/vm-.*-cloudinit/)) {
-		    metaData.tdCls = 'pve-itype-icon-cloud';
-		    return rowdef.cloudheader;
-		} else if (value.match(/media=cdrom/)) {
-		    metaData.tdCls = 'pve-itype-icon-cdrom';
-		    return rowdef.cdheader;
-		}
-	    }
-	} else if (iconCls) {
-	    icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
-	    metaData.tdCls += " pve-itype-fa";
-	}
-	return icon + txt;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	/*jslint confusion: true */
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
-		never_delete: true,
-		defaultValue: '512',
-		tdCls: 'pve-itype-icon-memory',
-		group: 2,
-		multiKey: ['memory', 'balloon', 'shares'],
-		renderer: function(value, metaData, record, ri, ci, store, pending) {
-		    var res = '';
-
-		    var max = me.getObjectValue('memory', 512, pending);
-		    var balloon =  me.getObjectValue('balloon', undefined, pending);
-		    var shares = me.getObjectValue('shares', undefined, pending);
-
-		    res  = Proxmox.Utils.format_size(max*1024*1024);
-
-		    if (balloon !== undefined && balloon > 0) {
-			res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
-
-			if (shares) {
-			    res += ' [shares=' + shares +']';
-			}
-		    } else if (balloon === 0) {
-			res += ' [balloon=0]';
-		    }
-		    return res;
-		}
-	    },
-	    sockets: {
-		header: gettext('Processors'),
-		never_delete: true,
-		editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? 
-		    'PVE.qemu.ProcessorEdit' : undefined,
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		defaultValue: '1',
-		multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
-		renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
-
-		    var sockets = me.getObjectValue('sockets', 1, pending);
-		    var model = me.getObjectValue('cpu', undefined, pending);
-		    var cores = me.getObjectValue('cores', 1, pending);
-		    var numa = me.getObjectValue('numa', undefined, pending);
-		    var vcpus = me.getObjectValue('vcpus', undefined, pending);
-		    var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
-		    var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
-
-		    var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
-			sockets*cores, sockets, cores);
-
-		    if (model) {
-			res += ' [' + model + ']';
-		    }
-
-		    if (numa) {
-			res += ' [numa=' + numa +']';
-		    }
-
-		    if (vcpus) {
-			res += ' [vcpus=' + vcpus +']';
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit +']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits +']';
-		    }
-
-		    return res;
-		}
-	    },
-	    bios: {
-		header: 'BIOS',
-		group: 4,
-		never_delete: true,
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.BiosEdit' : undefined,
-		defaultValue: '',
-		iconCls: 'microchip',
-		renderer: PVE.Utils.render_qemu_bios
-	    },
-	    vga: {
-		header: gettext('Display'),
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
-		never_delete: true,
-		tdCls: 'pve-itype-icon-display',
-		group:5,
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_vga_driver		
-	    },
-	    machine: {
-		header: gettext('Machine'),
-		editor: caps.vms['VM.Config.HWType'] ?  {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Machine'),
-		    width: 350,
-		    items: [{
-			xtype: 'proxmoxKVComboBox',
-			name: 'machine',
-			value: '__default__',
-			fieldLabel: gettext('Machine'),
-			comboItems: [
-			    ['__default__', PVE.Utils.render_qemu_machine('')],
-			    ['q35', 'q35']
-			]
-		    }]} : undefined,
-		iconCls: 'cogs',
-		never_delete: true,
-		group: 6,
-		defaultValue: '',
-		renderer: PVE.Utils.render_qemu_machine
-	    },
-	    scsihw: {
-		header: gettext('SCSI Controller'),
-		iconCls: 'database',
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.ScsiHwEdit' : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		group: 7,
-		never_delete: true,
-		defaultValue: ''
-	    },
-	    cores: {
-		visible: false
-	    },
-	    cpu: {
-		visible: false
-	    },
-	    numa: {
-		visible: false
-	    },
-	    balloon: {
-		visible: false
-	    },
-	    hotplug: {
-		visible: false
-	    },
-	    vcpus: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    shares: {
-		visible: false
-	    }
-	};
-	/*jslint confusion: false */
-
-	PVE.Utils.forEachBus(undefined, function(type, id) {
-	    var confid = type + id;
-	    rows[confid] = {
-		group: 10,
-		tdCls: 'pve-itype-icon-storage',
-		editor: 'PVE.qemu.HDEdit',
-		never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-		header: gettext('Hard Disk') + ' (' + confid +')',
-		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
-		cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
-	    };
-	});
-	for (i = 0; i < 32; i++) {
-	    confid = "net" + i.toString();
-	    rows[confid] = {
-		group: 15,
-		order: i,
-		tdCls: 'pve-itype-icon-network',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
-		never_delete: caps.vms['VM.Config.Network'] ? false : true,
-		header: gettext('Network Device') + ' (' + confid +')'
-	    };
-	}
-	rows.efidisk0 = {
-	    group: 20,
-	    tdCls: 'pve-itype-icon-storage',
-	    editor: null,
-	    never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-	    header: gettext('EFI Disk')
-	};
-	for (i = 0; i < 5; i++) {
-	    confid = "usb" + i.toString();
-	    rows[confid] = {
-		group: 25,
-		order: i,
-		tdCls: 'pve-itype-icon-usb',
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('USB Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "hostpci" + i.toString();
-	    rows[confid] = {
-		group: 30,
-		order: i,
-		tdCls: 'pve-itype-icon-pci',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
-		header: gettext('PCI Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 4; i++) {
-	    confid = "serial" + i.toString();
-	    rows[confid] = {
-		group: 35,
-		order: i,
-		tdCls: 'pve-itype-icon-serial',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('Serial Port') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < 256; i++) {
-	    rows["unused" + i.toString()] = {
-		group: 99,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
-		header: gettext('Unused Disk') + ' ' + i.toString()
-	    };
-	}
-
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-	    
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var editor = rowdef.editor;
-	    if (rowdef.tdCls == 'pve-itype-icon-storage') {
-		var value = me.getObjectValue(rec.data.key, '', true); 
-		if (value.match(/vm-.*-cloudinit/)) {
-		    return;
-		} else if (value.match(/media=cdrom/)) {
-		    editor = 'PVE.qemu.CDEdit';
-		} else if (!diskCap) {
-		    return;
-		}
-	    }
-
-	    var win;
-
-	    if (Ext.isString(editor)) {
-		win = Ext.create(editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var run_resize = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var run_move = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_editor
-        });
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_move
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    defaultText: gettext('Remove'),
-	    altText: gettext('Detach'),
-	    selModel: sm,
-	    disabled: true,
-	    dangerous: true,
-	    RESTMethod: 'PUT',
-	    confirmMsg: function(rec) {
-		var warn = gettext('Are you sure you want to remove entry {0}');
-		if (this.text === this.altText) {
-		    warn = gettext('Are you sure you want to detach entry {0}');
-		}
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		if (entry.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: function(b, e, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: b.RESTMethod,
-		    params: {
-			'delete': rec.data.key
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			if (b.RESTMethod === 'POST') {
-			    var upid = response.result.data;
-			    var win = Ext.create('Proxmox.window.TaskProgress', {
-				upid: upid,
-				listeners: {
-				    destroy: function () {
-					me.reload();
-				    }
-				}
-			    });
-			    win.show();
-			}
-		    }
-		});
-	    },
-	    listeners: {
-		render: function(btn) {
-		    // hack: calculate an optimal button width on first display
-		    // to prevent the whole toolbar to move when we switch
-		    // between the "Remove" and "Detach" labels
-		    var def = btn.getSize().width;
-
-		    btn.setText(btn.altText);
-		    var alt = btn.getSize().width;
-
-		    btn.setText(btn.defaultText);
-
-		    var optimal = alt > def ? alt : def;
-		    btn.setSize({ width: optimal });
-		}
-	    }
-	});
-
-	var revert_btn = new Proxmox.button.Button({
-	    text: gettext('Revert'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function(b, e, rec) {
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: {
-			'revert': revert
-		    },
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var efidisk_menuitem = Ext.create('Ext.menu.Item',{
-	    text: gettext('EFI Disk'),
-	    iconCls: 'pve-itype-icon-storage',
-	    disabled: !caps.vms['VM.Config.Disk'],
-	    handler: function() {
-
-		var rstoredata = me.rstore.getData().map;
-		// check if ovmf is configured
-		if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') {
-		    var win = Ext.create('PVE.qemu.EFIDiskEdit', {
-			url: '/api2/extjs/' + baseurl,
-			pveSelNode: me.pveSelNode
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		} else {
-		    Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
-		}
-
-	    }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    // disable button when we have an efidisk already
-	    // disable is ok in this case, because you can instantly
-	    // see that there is already one
-	    efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined);
-	    // en/disable usb add button
-	    var usbcount = 0;
-	    var pcicount = 0;
-	    var hasCloudInit = false;
-	    me.rstore.getData().items.forEach(function(item){
-		if (/^usb\d+/.test(item.id)) {
-		    usbcount++;
-		} else if (/^hostpci\d+/.test(item.id)) {
-		    pcicount++;
-		}
-		if (!hasCloudInit && /vm-.*-cloudinit/.test(item.data.value)) {
-		    hasCloudInit = true;
-		}
-	    });
-
-	    // heuristic only for disabling some stuff, the backend has the final word.
-	    var noSysConsolePerm = !caps.nodes['Sys.Console'];
-
-	    me.down('#addusb').setDisabled(noSysConsolePerm || (usbcount >= 5));
-	    me.down('#addpci').setDisabled(noSysConsolePerm || (pcicount >= 4));
-	    me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
-
-	    if (!rec) {
-		remove_btn.disable();
-		edit_btn.disable();
-		resize_btn.disable();
-		move_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isCDRom = (value && !!value.toString().match(/media=cdrom/));
-	    var isUnusedDisk = key.match(/^unused\d+/);
-	    var isUsedDisk = !isUnusedDisk &&
-		rowdef.tdCls == 'pve-itype-icon-storage' &&
-		!isCDRom;
-
-	    var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
-
-	    var isEfi = (key === 'efidisk0');
-
-	    remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true) || (isUnusedDisk && !diskCap));
-	    remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
-	    remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
-
-	    edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit || (!isCDRom && !diskCap));
-
-	    resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    move_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    revert_btn.setDisabled(!pending);
-
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
-	    interval: 5000,
-	    selModel: sm,
-	    run_editor: run_editor,
-	    tbar: [ 
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Hard Disk'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.HDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CD/DVD Drive'),
-				iconCls: 'pve-itype-icon-cdrom',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Network Device'),
-				iconCls: 'pve-itype-icon-network',
-				disabled: !caps.vms['VM.Config.Network'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.NetworkEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode,
-					isCreate: true
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    efidisk_menuitem,
-			    {
-				text: gettext('USB Device'),
-				itemId: 'addusb',
-				iconCls: 'pve-itype-icon-usb',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.USBEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('PCI Device'),
-				itemId: 'addpci',
-				iconCls: 'pve-itype-icon-pci',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.PCIEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Serial Port'),
-				itemId: 'addserial',
-				iconCls: 'pve-itype-icon-serial',
-				disabled: !caps.vms['VM.Config.Options'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.SerialEdit', {
-					url: '/api2/extjs/' + baseurl
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CloudInit Drive'),
-				itemId: 'addci',
-				iconCls: 'pve-itype-icon-cloud',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CIDriveEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn,
-		edit_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-	me.mon(me.rstore, 'refresh', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.qemu.ScsiHwEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('SCSI Controller Type'),
-	    items: {
-		xtype: 'pveScsiHwSelector',
-		name: 'scsihw',
-		value: '__default__',
-		fieldLabel: gettext('Type')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.BiosEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveQemuBiosEdit',
-
-    initComponent : function() {
-	var me = this;
-
-	var EFIHint = Ext.createWidget({
-	    xtype: 'displayfield', //submitValue is false, so we don't get submitted
-	    userCls: 'pve-hint',
-	    value: 'You need to add an EFI disk for storing the ' +
-	    'EFI settings. See the online help for details.',
-	    hidden: true
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'BIOS',
-	    items: [ {
-		xtype: 'pveQemuBiosSelector',
-		onlineHelp: 'qm_bios_and_uefi',
-		name: 'bios',
-		value: '__default__',
-		fieldLabel: 'BIOS',
-		listeners: {
-		    'change' : function(field, newValue) {
-			if (newValue == 'ovmf') {
-			    Proxmox.Utils.API2Request({
-				url : me.url,
-				method : 'GET',
-				failure : function(response, opts) {
-				    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				},
-				success : function(response, opts) {
-				    var vmConfig = response.result.data;
-				    // there can be only one
-				    if (!vmConfig.efidisk0) {
-					EFIHint.setVisible(true);
-				    }
-				}
-			    });
-			} else {
-			    if (EFIHint.isVisible()) {
-				EFIHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    EFIHint
-	    ] });
-
-	me.callParent();
-
-	me.load();
-
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.Options'],
-
-    onlineHelp: 'qm_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    name: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Name'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Name'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    xtype: 'textfield',
-			    name: 'name',
-			    vtype: 'DnsName',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: true
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.name === undefined ||
-				values.name === null ||
-				values.name === '') {
-				params = { 'delete':'name'};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ?
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'qm_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.OSTypeEdit' : undefined,
-		renderer: PVE.Utils.render_kvm_ostype,
-		defaultValue: 'other'
-	    },
-	    bootdisk: {
-		visible: false
-	    },
-	    boot: {
-		header: gettext('Boot Order'),
-		defaultValue: 'cdn',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.BootOrderEdit' : undefined,
-		multiKey: ['boot', 'bootdisk'],
-		renderer: function(order, metaData, record, rowIndex, colIndex, store, pending) {
-		    var i;
-		    var text = '';
-		    var bootdisk = me.getObjectValue('bootdisk', undefined, pending);
-		    order = order || 'cdn';
-		    for (i = 0; i < order.length; i++) {
-			var sel = order.substring(i, i + 1);
-			if (text) {
-			    text += ', ';
-			}
-			if (sel === 'c') {
-			    if (bootdisk) {
-				text += "Disk '" + bootdisk + "'";
-			    } else {
-				text += "Disk";
-			    }
-			} else if (sel === 'n') {
-			    text += 'Network';
-			} else if (sel === 'a') {
-			    text += 'Floppy';
-			} else if (sel === 'd') {
-			    text += 'CD-ROM';
-			} else {
-			    text += sel;
-			}
-		    }
-		    return text;
-		}
-	    },
-	    tablet: {
-		header: gettext('Use tablet for pointer'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use tablet for pointer'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'tablet',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hotplug: {
-		header: gettext('Hotplug'),
-		defaultValue: 'disk,network,usb',
-		renderer:  PVE.Utils.render_hotplug_features,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hotplug'),
-		    items: {
-			xtype: 'pveHotplugFeatureSelector',
-			name: 'hotplug',
-			value: '',
-			multiSelect: true,
-			fieldLabel: gettext('Hotplug'),
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    acpi: {
-		header: gettext('ACPI support'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('ACPI support'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'acpi',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    kvm: {
-		header: gettext('KVM hardware virtualization'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('KVM hardware virtualization'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'kvm',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    freeze: {
-		header: gettext('Freeze CPU at startup'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.PowerMgmt'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Freeze CPU at startup'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'freeze',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Freeze CPU at startup')
-		    }
-		} : undefined
-	    },
-	    localtime: {
-		header: gettext('Use local time for RTC'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use local time for RTC'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'localtime',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Use local time for RTC')
-		    }
-		} : undefined
-	    },
-	    startdate: {
-		header: gettext('RTC start date'),
-		defaultValue: 'now',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('RTC start date'),
-		    items: {
-			xtype: 'proxmoxtextfield',
-			name: 'startdate',
-			deleteEmpty: true,
-			value: 'now',
-			fieldLabel: gettext('RTC start date'),
-			vtype: 'QemuStartDate',
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    smbios1: {
-		header: gettext('SMBIOS settings (type1)'),
-		defaultValue: '',
-		renderer: Ext.String.htmlEncode,
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.Smbios1Edit' : undefined
-	    },
-	    agent: {
-		header: gettext('Qemu Agent'),
-		defaultValue: false,
-		renderer: PVE.Utils.render_qga_features,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Qemu Agent'),
-		    items: {
-			xtype: 'pveAgentFeatureSelector',
-			name: 'agent'
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-        var revert_btn = new Proxmox.button.Button({
-            text: gettext('Revert'),
-            disabled: true,
-            handler: function() {
-		var sm = me.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var rowdef = me.rows[rec.data.key] || {};
-		var keys = rowdef.multiKey ||  [ rec.data.key ];
-		var revert = keys.join(',');
-
-                Proxmox.Utils.API2Request({
-                    url: '/api2/extjs/' + baseurl,
-                    waitMsgTarget: me,
-                    method: 'PUT',
-                    params: {
-                        'revert': revert
-                    },
-                    callback: function() {
-                        me.reload();
-                    },
-                    failure: function (response, opts) {
-                        Ext.Msg.alert('Error',response.htmlStatus);
-                    }
-                });
-            }
-        });
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/pending",
-	    interval: 5000,
-	    cwidth1: 250,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.rstore.on('datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-
-Ext.define('PVE.window.Snapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname, vmstate: vmstate ? 1 : 0 };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	} else {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'vmstate',
-		uncheckedValue: 0,
-		defaultValue: 0,
-		checked: 1,
-		fieldLabel: gettext('Include RAM')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description, values.vmstate);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}	 
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + "/snapshot/" + 
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveQemuSnapshotTree'],
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-qemu-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-        var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-        Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-            method: 'GET',
-            success: function(response, options) {
-                var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-            }
-        });
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) { 
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		return Proxmox.Utils.format_task_description('qmrollback', me.vmid) +
-		    " '" +  rec.data.name + "'";
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', { 
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Snapshot', { 
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [ 
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-		{
-		    text: gettext('RAM'),
-		    align: 'center',
-		    resizable: false,
-		    dataIndex: 'vmstate',
-		    width: 50,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name !== 'current') {
-			    return Proxmox.Utils.format_boolean(value);
-			}
-		    }
-		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{ 
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true, // will work in 4.1?
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-
-Ext.define('PVE.qemu.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.qemu.Config',
-
-    onlineHelp: 'chapter_virtual_machines',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + "/qemu/" + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + '/status/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var resumeBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resume'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    hidden: true,
-	    handler: function() {
-		vm_command('resume');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'qemu',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    itemId: 'removeBtn',
-		    disabled: !caps.vms['VM.Allocate'],
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'VM', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items: [{
-		    text: gettext('Pause'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid),
-		    handler: function() {
-			vm_command("suspend");
-		    },
-		    iconCls: 'fa fa-pause'
-		},{
-		    text: gettext('Hibernate'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid),
-		    tooltip: gettext('Suspend to disk'),
-		    handler: function() {
-			vm_command("suspend", { todisk: 1 });
-		    },
-		    iconCls: 'fa fa-download'
-		},{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    dangerous: true,
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid),
-		    handler: function() {
-			vm_command("stop", { timeout: 30 });
-		    },
-		    iconCls: 'fa fa-stop'
-		},{
-		    text: gettext('Reset'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid),
-		    handler: function() {
-			vm_command("reset");
-		    },
-		    iconCls: 'fa fa-bolt'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    hidden: template,
-	    consoleType: 'kvm',
-	    consoleName: vm.name,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'kvmtab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveQemuSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push({
-		title: gettext('Console'),
-		itemId: 'console',
-		iconCls: 'fa fa-terminal',
-		xtype: 'pveNoVncConsole',
-		vmid: vmid,
-		consoleType: 'kvm',
-		nodename: nodename
-	    });
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Hardware'),
-		itemId: 'hardware',
-		iconCls: 'fa fa-desktop',
-		xtype: 'PVE.qemu.HardwareView'
-	    },
-	    {
-		title: 'Cloud-Init',
-		itemId: 'cloudinit',
-		iconCls: 'fa fa-cloud',
-		xtype: 'pveCiPanel'
-	    },
-	    {
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options',
-		xtype: 'PVE.qemu.Options'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		xtype: 'proxmoxNodeTasks',
-		iconCls: 'fa fa-list',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Monitor'] && !template) {
-	    me.items.push({
-		title: gettext('Monitor'),
-		iconCls: 'fa fa-eye',
-		itemId: 'monitor',
-		xtype: 'pveQemuMonitor'
-	    });
-	}
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveQemuSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-        me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var qmpstatus;
-	    var spice = false;
-	    var xtermjs = false;
-	    var lock;
-
-	    if (!success) {
-		status = qmpstatus = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('qmpstatus');
-		qmpstatus = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-
-		spice = s.data.get('spice') ? true : false;
-		xtermjs = s.data.get('serial') ? true : false;
-
-	    }
-
-	    if (template) {
-		return;
-	    }
-
-	    var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1);
-
-	    if (resume || lock === 'suspended') {
-		startBtn.setVisible(false);
-		resumeBtn.setVisible(true);
-	    } else {
-		startBtn.setVisible(true);
-		resumeBtn.setVisible(false);
-	    }
-
-	    consoleBtn.setEnableSpice(spice);
-	    consoleBtn.setEnableXtermJS(xtermjs);
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-   }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    alias: 'widget.pveQemuCreateWizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    current: {
-		scsihw: ''
-	    }
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('Virtual Machine'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'qm_general_settings',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid',
-		    guestType: 'qemu',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'name',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: true
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		}
-	    ],
-	    advancedColumn1: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'onboot',
-		    uncheckedValue: 0,
-		    defaultValue: 0,
-		    deleteDefaultValue: true,
-		    fieldLabel: gettext('Start at boot')
-		}
-	    ],
-	    advancedColumn2: [
-		{
-		    xtype: 'textfield',
-		    name: 'order',
-		    defaultValue: '',
-		    emptyText: 'any',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Start/Shutdown order')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'up',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Startup delay')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'down',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Shutdown timeout')
-		}
-	    ],
-	    onGetValues: function(values) {
-
-		['name', 'pool', 'onboot', 'agent'].forEach(function(field) {
-		    if (!values[field]) {
-			delete values[field];
-		    }
-		});
-
-		var res = PVE.Parser.printStartup({
-		    order: values.order,
-		    up: values.up,
-		    down: values.down
-		});
-
-		if (res) {
-		    values.startup = res;
-		}
-
-		delete values.order;
-		delete values.up;
-		delete values.down;
-
-		return values;
-	    }
-	},
-	{
-	    xtype: 'container',
-	    layout: 'hbox',
-	    defaults: {
-		flex: 1,
-		padding: '0 10'
-	    },
-	    title: gettext('OS'),
-	    items: [
-		{
-		    xtype: 'pveQemuCDInputPanel',
-		    bind: {
-			nodename: '{nodename}'
-		    },
-		    confid: 'ide2',
-		    insideWizard: true
-		},
-		{
-		    xtype: 'pveQemuOSTypePanel',
-		    insideWizard: true
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveQemuSystemPanel',
-	    title: gettext('System'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuHDInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Hard Disk'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuProcessorPanel',
-	    insideWizard: true,
-	    title: gettext('CPU')
-	},
-	{
-	    xtype: 'pveQemuMemoryPanel',
-	    insideWizard: true,
-	    title: gettext('Memory')
-	},
-	{
-	    xtype: 'pveQemuNetworkInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Network'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-			    property : 'key',
-			    direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var kv = this.up('window').getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete') { // ignore
-			    return;
-			}
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/qemu',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response){
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-
-Ext.define('PVE.qemu.USBInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    autoComplete: false,
-    onlineHelp: 'qm_usb_passthrough',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=usb]': {
-		change: function(field, newValue, oldValue) {
-		    var hwidfield = this.lookupReference('hwid');
-		    var portfield = this.lookupReference('port');
-		    var usb3field = this.lookupReference('usb3');
-		    if (field.inputValue === 'hostdevice') {
-			hwidfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'port') {
-			portfield.setDisabled(!newValue);
-		    } else if(field.inputValue === 'spice') {
-			usb3field.setDisabled(newValue);
-		    }
-		}
-	    },
-	    'pveUSBSelector': {
-		change: function(field, newValue, oldValue) {
-		    var usbval = field.getUSBValue();
-		    var usb3field = this.lookupReference('usb3');
-		    var usb3 = /usb3/.test(usbval);
-		    if(usb3 && !usb3field.isDisabled()) {
-			usb3field.savedVal = usb3field.getValue();
-			usb3field.setValue(true);
-			usb3field.setDisabled(true);
-		    } else if(!usb3 && usb3field.isDisabled()){
-			var val = (usb3field.savedVal === undefined)?usb3field.originalValue:usb3field.savedVal;
-			usb3field.setValue(val);
-			usb3field.setDisabled(false);
-		    }
-		}
-	    }
-	}
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 6; i++) {
-		if (!me.vmconfig['usb' +  i.toString()]) {
-		    me.confid = 'usb' + i.toString();
-		    break;
-		}
-	    }
-	}
-	var val = "";
-	var type = me.down('radiofield').getGroupValue();
-	switch (type) {
-	    case 'spice':
-		val = 'spice'; break;
-	    case 'hostdevice':
-	    case 'port':
-		val = me.down('pveUSBSelector[name=' + type + ']').getUSBValue();
-		if (!/usb3/.test(val) && me.down('field[name=usb3]').getValue() === true) {
-		    val += ',usb3=1';
-		}
-		break;
-	    default:
-		throw "invalid type selected";
-	}
-
-	values[me.confid] = val;
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'fieldcontainer',
-	    defaultType: 'radiofield',
-	    items:[
-		{
-		    name: 'usb',
-		    inputValue: 'spice',
-		    boxLabel: gettext('Spice Port'),
-		    submitValue: false,
-		    checked: true
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'hostdevice',
-		    boxLabel: gettext('Use USB Vendor/Device ID'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    type: 'device',
-		    name: 'hostdevice',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    reference: 'hwid',
-		    allowBlank: false,
-		    fieldLabel: 'Choose Device',
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'port',
-		    boxLabel: gettext('Use USB Port'),
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    name: 'port',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    editable: true,
-		    type: 'port',
-		    reference: 'port',
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Port'),
-		    labelAlign: 'right',
-		    submitValue: false
-		},
-		{
-		    xtype: 'checkbox',
-		    name: 'usb3',
-		    submitValue: false,
-		    reference: 'usb3',
-		    fieldLabel: gettext('Use USB3')
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.USBEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('USB Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var data = response.result.data[me.confid].split(',');
-		    var port, hostdevice, usb3 = false;
-		    var type = 'spice';
-		    var i;
-		    for (i = 0; i < data.length; i++) {
-			if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
-			    hostdevice = data[i];
-			    hostdevice = hostdevice.replace('host=', '').replace('0x','');
-			    type = 'hostdevice';
-			} else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
-			    port = data[i];
-			    port = port.replace('host=','');
-			    type = 'port';
-			}
-
-			if (/^usb3=(1|on|true)$/.test(data[i])) {
-			    usb3 = true;
-			}
-		    }
-		    var values = {
-			usb : type,
-			hostdevice: hostdevice,
-			port: port,
-			usb3: usb3
-		    };
-
-		    ipanel.setValues(values);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.PCIInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    onlineHelp: 'qm_pci_passthrough',
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-
-	var hostpci = me.vmconfig[me.confid] || '';
-
-	var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-	if (values.host && values.host.length < 6) { // 00:00 format not 00:00.0
-	    values.host += ".0";
-	    values.multifunction = true;
-	}
-	values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
-	values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
-	values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
-
-	me.setValues(values);
-	if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
-	    // machine is not set to some variant of q35, so we disable pcie
-	    var pcie = me.down('field[name=pcie]');
-	    pcie.setDisabled(true);
-	    pcie.setBoxLabel(gettext('Q35 only'));
-	}
-
-	if (values.romfile) {
-	    me.down('field[name=romfile]').setVisible(true);
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var ret = {};
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 5; i++) {
-		if (!me.vmconfig['hostpci' +  i.toString()]) {
-		    me.confid = 'hostpci' + i.toString();
-		    break;
-		}
-	    }
-	}
-	if (values.multifunction) {
-	    // modify host to skip the '.X'
-	    values.host = values.host.substring(0,5);
-	    delete values.multifunction;
-	}
-
-	if (values.rombar) {
-	    delete values.rombar;
-	} else {
-	    values.rombar = 0;
-	}
-
-	if (!values.romfile) {
-	    delete values.romfile;
-	}
-
-	ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-	return ret;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.column1 = [
-	    {
-		xtype: 'pvePCISelector',
-		fieldLabel: gettext('Device'),
-		name: 'host',
-		nodename: me.nodename,
-		allowBlank: false,
-		onLoadCallBack: function(store, records, success) {
-		    if (!success || !records.length) {
-			return;
-		    }
-
-		    var first = records[0];
-		    if (first.data.iommugroup === -1) {
-			// no iommu groups
-			var warning = Ext.create('Ext.form.field.Display', {
-			    columnWidth: 1,
-			    padding: '0 0 10 0',
-			    value: 'No IOMMU detected, please activate it.' +
-				   'See Documentation for further information.',
-			    userCls: 'pve-hint'
-			});
-			me.items.insert(0, warning);
-			me.updateLayout(); // insert does not trigger that
-		    }
-		},
-		listeners: {
-		    change: function(pcisel, value) {
-			if (!value) {
-			    return;
-			}
-			var pcidev = pcisel.getStore().getById(value);
-			var mdevfield = me.down('field[name=mdev]');
-			mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
-			if (!pcidev) {
-			    return;
-			}
-			var id = pcidev.data.id.substring(0,5); // 00:00
-			var iommu = pcidev.data.iommugroup;
-			// try to find out if there are more devices
-			// in that iommu group
-			if (iommu !== -1) {
-			    var count = 0;
-			    pcisel.getStore().each(function(record) {
-				if (record.data.iommugroup === iommu &&
-				    record.data.id.substring(0,5) !== id)
-				{
-				    count++;
-				    return false;
-				}
-			    });
-			    var warning = me.down('#iommuwarning');
-			    if (count && !warning) {
-				warning = Ext.create('Ext.form.field.Display', {
-				    columnWidth: 1,
-				    padding: '0 0 10 0',
-				    itemId: 'iommuwarning',
-				    value: 'The selected Device is not in a seperate' +
-					   'IOMMU group, make sure this is intended.',
-				    userCls: 'pve-hint'
-				});
-				me.items.insert(0, warning);
-				me.updateLayout(); // insert does not trigger that
-			    } else if (!count && warning) {
-				me.remove(warning);
-			    }
-			}
-			if (pcidev.data.mdev) {
-			    mdevfield.setPciID(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('All Functions'),
-		name: 'multifunction'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'pveMDevSelector',
-		name: 'mdev',
-		disabled: true,
-		fieldLabel: gettext('MDev Type'),
-		nodename: me.nodename,
-		listeners: {
-		    change: function(field, value) {
-			var mf = me.down('field[name=multifunction]');
-			if (!!value) {
-			    mf.setValue(false);
-			}
-			mf.setDisabled(!!value);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Primary GPU'),
-		name: 'x-vga'
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'ROM-Bar',
-		name: 'rombar'
-	    },
-	    {
-		xtype: 'displayfield',
-		submitValue: true,
-		hidden: true,
-		fieldLabel: 'ROM-File',
-		name: 'romfile'
-	    }
-	];
-
-	me.advancedColumn2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'PCI-Express',
-		name: 'pcie'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.PCIEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('PCI Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.SerialnputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    autoComplete: false,
-
-    setVMConfig: function(vmconfig) {
-	var me = this, i;
-	me.vmconfig = vmconfig;
-
-	for (i = 0; i < 4; i++) {
-	    var port = 'serial' +  i.toString();
-	    if (!me.vmconfig[port]) {
-		me.down('field[name=serialid]').setValue(i);
-		break;
-	    }
-	}
-
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id = 'serial' + values.serialid;
-	delete values.serialid;
-	values[id] = 'socket';
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'serialid',
-	    fieldLabel: gettext('Serial Port'),
-	    minValue: 0,
-	    maxValue: 3,
-	    allowBlank: false,
-	    validator: function(id) {
-		if (!this.rendered) {
-		    return true;
-		}
-		var me = this.up('panel');
-		if (me.vmconfig !== undefined && Ext.isDefined(me.vmconfig['serial' + id])) {
-			return "This device is already in use.";
-		}
-		return true;
-	    }
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.SerialEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('Serial Port'),
-
-    initComponent : function() {
-	var me = this;
-
-	// for now create of (socket) serial port only
-	me.isCreate = true;
-
-	var ipanel = Ext.create('PVE.qemu.SerialnputPanel', {});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.IPInfo', {
-    extend: 'Ext.window.Window',
-    width: 600,
-    title: gettext('Guest Agent Network Information'),
-    height: 300,
-    layout: {
-	type: 'fit'
-    },
-    modal: true,
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: gettext('No network information'),
-	    columns: [
-		{
-		    dataIndex: 'name',
-		    text: gettext('Name'),
-		    flex: 3
-		},
-		{
-		    dataIndex: 'hardware-address',
-		    text: gettext('MAC address'),
-		    width: 140
-		},
-		{
-		    dataIndex: 'ip-addresses',
-		    text: gettext('IP address'),
-		    align: 'right',
-		    flex: 4,
-		    renderer: function(val) {
-			if (!Ext.isArray(val)) {
-			    return '';
-			}
-			var ips = [];
-			val.forEach(function(ip) {
-			    var addr = ip['ip-address'];
-			    var pref = ip.prefix;
-			    if  (addr && pref) {
-				ips.push(addr + '/' + pref);
-			    }
-			});
-			return ips.join('<br>');
-		    }
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.AgentIPView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveAgentIPView',
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    nics: [],
-
-    items: [
-	{
-	    xtype: 'box',
-	    html: '<i class="fa fa-exchange"></i> IPs'
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'right',
-		pack: 'end'
-	    },
-	    items: [
-		{
-		    xtype: 'label',
-		    flex: 1,
-		    itemId: 'ipBox',
-		    style: {
-			'text-align': 'right'
-		    }
-		},
-		{
-		    xtype: 'button',
-		    itemId: 'moreBtn',
-		    hidden: true,
-		    ui: 'default-toolbar',
-		    handler: function(btn) {
-			var me = this.up('pveAgentIPView');
-
-			var win = Ext.create('PVE.window.IPInfo');
-			win.down('grid').getStore().setData(me.nics);
-			win.show();
-		    },
-		    text: gettext('More')
-		}
-	    ]
-	}
-    ],
-
-    getDefaultIps: function(nics) {
-	var me = this;
-	var ips = [];
-	nics.forEach(function(nic) {
-	    if (nic['hardware-address'] &&
-		nic['hardware-address'] != '00:00:00:00:00:00') {
-
-		var nic_ips = nic['ip-addresses'] || [];
-		nic_ips.forEach(function(ip) {
-		    var p = ip['ip-address'];
-		    // show 2 ips at maximum
-		    if (ips.length < 2) {
-			ips.push(p);
-		    }
-		});
-	    }
-	});
-
-	return ips;
-    },
-
-    startIPStore: function(store, records, success) {
-	var me = this;
-	var agentRec = store.getById('agent');
-	/*jslint confusion: true*/
-	/* value is number and string */
-	me.agent = (agentRec && agentRec.data.value === 1);
-	me.running = (store.getById('status').data.value === 'running');
-	/*jslint confusion: false*/
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!caps.vms['VM.Monitor']) {
-	    var errorText = gettext("Requires '{0}' Privileges");
-	    me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
-	    return;
-	}
-
-	if (me.agent && me.running && me.ipStore.isStopped) {
-	    me.ipStore.startUpdate();
-	} else if (me.ipStore.isStopped) {
-	    me.updateStatus();
-	}
-    },
-
-    updateStatus: function(unsuccessful, defaulttext) {
-	var me = this;
-	var text = defaulttext || gettext('No network information');
-	var more = false;
-	if (unsuccessful) {
-	    text = gettext('Guest Agent not running');
-	} else if (me.agent && me.running) {
-	    if (Ext.isArray(me.nics) && me.nics.length) {
-		more = true;
-		var ips = me.getDefaultIps(me.nics);
-		if (ips.length !== 0) {
-		    text = ips.join('<br>');
-		}
-	    } else if (me.nics && me.nics.error) {
-		var msg = gettext('Cannot get info from Guest Agent<br>Error: {0}');
-		text = Ext.String.format(text, me.nics.error.desc);
-	    }
-	} else if (me.agent) {
-	    text = gettext('Guest Agent not running');
-	} else {
-	    text = gettext('No Guest Agent configured');
-	}
-
-	var ipBox = me.down('#ipBox');
-	ipBox.update(text);
-
-	var moreBtn = me.down('#moreBtn');
-	moreBtn.setVisible(more);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw 'rstore not given';
-	}
-
-	if (!me.pveSelNode) {
-	    throw 'pveSelNode not given';
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	var vmid = me.pveSelNode.data.vmid;
-
-	me.ipStore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 10000,
-	    storeid: 'pve-qemu-agent-' + vmid,
-	    method: 'POST',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces'
-	    }
-	});
-
-	me.callParent();
-
-	me.mon(me.ipStore, 'load', function(store, records, success) {
-	    if (records && records.length) {
-		me.nics = records[0].data.result;
-	    } else {
-		me.nics = undefined;
-	    }
-	    me.updateStatus(!success);
-	});
-
-	me.on('destroy', me.ipStore.stopUpdate);
-
-	// if we already have info about the vm, use it immediately
-	if (me.rstore.getCount()) {
-	    me.startIPStore(me.rstore, me.rstore.getData(), false);
-	}
-
-	// check if the guest agent is there on every statusstore load
-	me.mon(me.rstore, 'load', me.startIPStore, me);
-    }
-});
-Ext.define('PVE.qemu.CloudInit', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    xtype: 'pveCiPanel',
-
-    onlineHelp: 'qm_cloud_init',
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var me = this.up('grid');
-		var warn = gettext('Are you sure you want to remove entry {0}');
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		return msg;
-	    },
-	    enableFn: function(record) {
-		var me = this.up('grid');
-		var caps = Ext.state.Manager.get('GuiCap');
-		if (me.rows[record.data.key].never_delete ||
-		    !caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-
-		if (record.data.key === 'cipassword' && !record.data.value) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		var records = me.getSelection();
-		if (!records ||  !records.length) {
-		    return;
-		}
-
-		var id = records[0].data.key;
-		var match = id.match(/^net(\d+)$/);
-		if (match) {
-		    id = 'ipconfig' + match[1];
-		}
-
-		var params = {};
-		params['delete'] = id;
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: params,
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    callback: function() {
-			me.reload();
-		    }
-		});
-	    },
-	    text: gettext('Remove')
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('grid');
-		me.run_editor();
-	    },
-	    text: gettext('Edit')
-	},
-	'-',
-	{
-	    xtype: 'button',
-	    itemId: 'savebtn',
-	    text: gettext('Regenerate Image'),
-	    handler: function() {
-		var me = this.up('grid');
-		var eject_params = {};
-		var insert_params = {};
-		var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
-		var storage = '';
-		var stormatch = disk.file.match(/^([^\:]+)\:/);
-		if (stormatch) {
-		    storage = stormatch[1];
-		}
-		eject_params[me.ciDriveId] = 'none,media=cdrom';
-		insert_params[me.ciDriveId] = storage + ':cloudinit';
-
-		var failure = function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		};
-
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: eject_params,
-		    failure: failure,
-		    callback: function() {
-			Proxmox.Utils.API2Request({
-			    url: me.baseurl + '/config',
-			    waitMsgTarget: me,
-			    method: 'PUT',
-			    params: insert_params,
-			    failure: failure,
-			    callback: function() {
-				me.reload();
-			    }
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    border: false,
-
-    set_button_status: function(rstore, records, success) {
-	if (!success || records.length < 1) {
-	    return;
-	}
-	var me = this;
-	var found;
-	records.forEach(function(record) {
-	    if (found) {
-		return;
-	    }
-	    var id = record.data.key;
-	    var value = record.data.value;
-	    var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
-		if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
-		    found = id;
-		    me.ciDriveId = found;
-		    me.ciDrive = value;
-		}
-	});
-
-	me.down('#savebtn').setDisabled(!found);
-	me.setDisabled(!found);
-	if (!found) {
-	    me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
-	} else {
-	    me.getView().unmask();
-	}
-    },
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-
-	var icon = "";
-	if (rowdef.iconCls) {
-	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
-	}
-	return icon + (rowdef.header || key);
-    },
-
-    listeners: {
-	activate: function () {
-	    var me = this;
-	    me.rstore.startUpdate();
-	},
-	itemdblclick: function() {
-	    var me = this;
-	    me.run_editor();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-	var caps = Ext.state.Manager.get('GuiCap');
-	me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
-	me.url =  me.baseurl + '/pending';
-	me.editorConfig.url = me.baseurl + '/config';
-	me.editorConfig.pveSelNode = me.pveSelNode;
-
-	/*jslint confusion: true*/
-	/* editor is string and object */
-	me.rows = {
-	    ciuser: {
-		header: gettext('User'),
-		iconCls: 'fa fa-user',
-		never_delete: true,
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('User'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('User'),
-			    name: 'ciuser'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.defaultText;
-		}
-	    },
-	    cipassword: {
-		header: gettext('Password'),
-		iconCls: 'fa fa-unlock',
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Password'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    inputType: 'password',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.noneText,
-			    fieldLabel: gettext('Password'),
-			    name: 'cipassword'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.noneText;
-		}
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    nameserver: {
-		header: gettext('DNS servers'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    sshkeys: {
-		header: gettext('SSH public key'),
-		iconCls: 'fa fa-key',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.SSHKeyEdit' : undefined,
-		never_delete: true,
-		renderer: function(value) {
-		    value = decodeURIComponent(value);
-		    var keys = value.split('\n');
-		    var text = [];
-		    keys.forEach(function(key) {
-			if (key.length) {
-			    // First erase all quoted strings (eg. command="foo"
-			    var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
-			    // Now try to detect the comment:
-			    var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
-			    if (res) {
-				key = Ext.String.htmlEncode(res[2]);
-				if (res[1]) {
-				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
-				}
-				text.push(key);
-				return;
-			    }
-			    // Most likely invalid at this point, so just stick to
-			    // the old value.
-			    text.push(Ext.String.htmlEncode(key));
-			}
-		    });
-		    if (text.length) {
-			return text.join('<br>');
-		    } else {
-			return Proxmox.Utils.noneText;
-		    }
-		},
-		defaultValue: ''
-	    }
-	};
-	var i;
-	var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
-	    var id = record.data.key;
-	    var match = id.match(/^net(\d+)$/);
-	    var val = '';
-	    if (match) {
-		val = me.getObjectValue('ipconfig'+match[1], '', pending);
-	    }
-	    return val;
-	};
-	for (i = 0; i < 32; i++) {
-	    // we want to show an entry for every network device
-	    // even if it is empty
-	    me.rows['net' + i.toString()] = {
-		multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
-		header: gettext('IP Config') + ' (net' + i.toString() +')',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
-		iconCls: 'fa fa-exchange',
-		renderer: ipconfig_renderer
-	    };
-	    me.rows['ipconfig' + i.toString()] = {
-		visible: false
-	    };
-	}
-	/*jslint confusion: false*/
-
-	PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
-	    me.rows[type+id] = {
-		visible: false
-	    };
-	});
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-    }
-});
-Ext.define('PVE.qemu.CIDriveInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveCIDriveInputPanel',
-
-    insideWizard: false,
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var drive = {};
-	var params = {};
-	drive.file = values.hdstorage + ":cloudinit";
-	drive.format = values.diskformat;
-	params[values.controller + values.deviceid] = PVE.Parser.printQemuDrive(drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.down('#drive').setVMConfig(config, 'cdrom');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items = [
-	    {
-		xtype: 'pveControllerSelector',
-		noVirtIO: true,
-		itemId: 'drive',
-		fieldLabel: gettext('CloudInit Drive'),
-		name: 'drive'
-	    },
-	    {
-		xtype: 'pveDiskStorageSelector',
-		itemId: 'storselector',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    }
-	];
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CIDriveEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCIDriveEdit',
-
-    isCreate: true,
-    subject: gettext('CloudInit Drive'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveCIDriveInputPanel',
-	    itemId: 'cipanel',
-	    nodename: nodename
-	}];
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		me.down('#cipanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SSHKeyInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSSHKeyInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-	if (values.sshkeys) {
-	    values.sshkeys.trim();
-	}
-	if (!values.sshkeys.length) {
-	    values = {};
-	    values['delete'] = 'sshkeys';
-	    return values;
-	} else {
-	    values.sshkeys = encodeURIComponent(values.sshkeys);
-	}
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'sshkeys',
-	    name: 'sshkeys',
-	    height: 250
-	},
-	{
-	    xtype: 'filebutton',
-	    itemId: 'filebutton',
-	    name: 'file',
-	    text: gettext('Load SSH Key File'),
-	    fieldLabel: 'test',
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('inputpanel');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    var keysField = me.down('#sshkeys');
-			    var old = keysField.getValue();
-			    keysField.setValue(old + res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-	if (!window.FileReader) {
-	    me.down('#filebutton').setVisible(false);
-	}
-
-    }
-});
-
-Ext.define('PVE.qemu.SSHKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 800,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.SSHKeyInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('SSH Keys'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.create) {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.sshkeys) {
-			data.sshkeys = decodeURIComponent(data.sshkeys);
-			ipanel.setValues(data);
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.qemu.IPConfigPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveIPConfigPanel',
-
-    insideWizard: false,
-
-    vmconfig: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-
-	var params = {};
-
-	var cfg = PVE.Parser.printIPConfig(values);
-	if (cfg === '') {
-	    params['delete'] = [me.confid];
-	} else {
-	    params[me.confid] = cfg;
-	}
-	return params;
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.vmconfig = config;
-    },
-
-    setIPConfig: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data.ip === 'dhcp') {
-	    data.ipv4mode = data.ip;
-	    data.ip = '';
-	} else {
-	    data.ipv4mode = 'static';
-	}
-	if (data.ip6 === 'dhcp' || data.ip6 === 'auto') {
-	    data.ipv6mode = data.ip6;
-	    data.ip6 = '';
-	} else {
-	    data.ipv6mode = 'static';
-	}
-
-	me.ipconfig = data;
-	me.setValues(me.ipconfig);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.ipconfig = {};
-
-	me.column1 = [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Network Device'),
-		value: me.netid
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv4') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('IPv4/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: '',
-		vtype: 'IPAddress',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv4') +')'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'displayfield'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv6') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: '',
-		vtype: 'IP6CIDRAddress',
-		disabled: true,
-		fieldLabel: gettext('IPv6/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv6') +')'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.IPConfigEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	// convert confid from netX to ipconfigX
-	var match = me.confid.match(/^net(\d+)$/);
-	if (match) {
-	    me.netid = me.confid;
-	    me.confid = 'ipconfig' + match[1];
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.IPConfigPanel', {
-	    confid: me.confid,
-	    netid: me.netid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Config'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		me.vmconfig = response.result.data;
-		var ipconfig = {};
-		var value = me.vmconfig[me.confid];
-		if (value) {
-		    ipconfig = PVE.Parser.parseIPConfig(me.confid, value);
-		    if (!ipconfig) {
-			Ext.Msg.alert(gettext('Error'), gettext('Unable to parse network configuration'));
-			me.close();
-			return;
-		    }
-		}
-		ipanel.setIPConfig(me.confid, ipconfig);
-		ipanel.setVMConfig(me.vmconfig);
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.SystemInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSystemPanel',
-
-    onlineHelp: 'qm_system_settings',
-
-    viewModel: {
-	data: {
-	    efi: false,
-	    addefi: true
-	},
-
-	formulas: {
-	    efidisk: function(get) {
-		return get('efi') && get('addefi');
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	if (values.vga && values.vga.substr(0,6) === 'serial') {
-	    values['serial' + values.vga.substr(6,1)] = 'socket';
-	}
-
-	var efidrive = {};
-	if (values.hdimage) {
-	    efidrive.file = values.hdimage;
-	} else if (values.hdstorage) {
-	    efidrive.file = values.hdstorage + ":1";
-	}
-
-	if (values.diskformat) {
-	    efidrive.format = values.diskformat;
-	}
-
-	delete values.hdimage;
-	delete values.hdstorage;
-	delete values.diskformat;
-
-	if (efidrive.file) {
-	    values.efidisk0 = PVE.Parser.printQemuDrive(efidrive);
-	}
-
-	return values;
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	scsihwChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('current.scsihw', value);
-	    }
-	},
-
-	biosChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('efi', value === 'ovmf');
-	    }
-	},
-
-	control: {
-	    'pveScsiHwSelector': {
-		change: 'scsihwChange'
-	    },
-	    'pveQemuBiosSelector': {
-		change: 'biosChange'
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: gettext('Graphic card'),
-	    name: 'vga',
-	    comboItems: PVE.Utils.kvm_vga_driver_array()
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'agent',
-	    uncheckedValue: 0,
-	    defaultValue: 0,
-	    deleteDefaultValue: true,
-	    fieldLabel: gettext('Qemu Agent')
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'pveScsiHwSelector',
-	    name: 'scsihw',
-	    value: '__default__',
-	    bind: {
-		value: '{current.scsihw}'
-	    },
-	    fieldLabel: gettext('SCSI Controller')
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    name: 'bios',
-	    value: '__default__',
-	    fieldLabel: 'BIOS'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    bind: {
-		value: '{addefi}',
-		hidden: '{!efi}',
-		disabled: '{!efi}'
-	    },
-	    hidden: true,
-	    submitValue: false,
-	    disabled: true,
-	    fieldLabel: gettext('Add EFI Disk')
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    bind: {
-		nodename: '{nodename}',
-		hidden: '{!efi}',
-		disabled: '{!efidisk}'
-	    },
-	    autoSelect: false,
-	    disabled: true,
-	    hidden: true,
-	    hideSize: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'machine',
-	    value: '__default__',
-	    fieldLabel: gettext('Machine'),
-	    comboItems: [
-		['__default__', PVE.Utils.render_qemu_machine('')],
-		['q35', 'q35']
-	    ]
-	}
-    ]
-
-});
-Ext.define('PVE.lxc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveLxcSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var width = template ? 1 : 0.5;
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		},
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		maxHeight: 320,
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-		responsiveConfig: {
-		    'width < 1900': {
-			columnWidth: width
-		    },
-		    'width >= 1900': {
-			columnWidth: width / 2
-		    }
-		}
-	    }
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/rrddata",
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'column'
-		    },
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			plugins: 'responsive',
-			responsiveConfig: {
-			    'width < 1900': {
-				columnWidth: 1
-			    },
-			    'width >= 1900': {
-				columnWidth: 0.5
-			    }
-			}
-		    },
-		    items: items
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-    }
-});
-Ext.define('PVE.lxc.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcNetworkInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_network',
-
-    setNodename: function(nodename) {
-	var me = this;
-	
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	var bridgesel = me.query("[isFormField][name=bridge]")[0];
-	bridgesel.setNodename(nodename);
-    },
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	var id;
-	if (me.isCreate) {
-	    id = values.id;
-	    delete values.id;
-	} else {
-	    id = me.ifname;
-	}
-
-	if (!id) {
-	    return {};
-	}
-
-	var newdata = {};
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-	newdata[id] = PVE.Parser.printLxcNetwork(values);
-	return newdata;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var cdata = {};
-
-	if (me.insideWizard) {
-	    me.ifname = 'net0';
-	    cdata.name = 'eth0';
-	    me.dataCache = {};
-	}
-	cdata.firewall =  (me.insideWizard || me.isCreate);
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.isCreate) {
-	    if (!me.ifname) {
-		throw "no interface name specified";
-	    }
-	    if (!me.dataCache[me.ifname]) {
-		throw "no such interface '" + me.ifname + "'";
-	    }
-
-	    cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
-	}
-
-	var i;
-	for (i = 0; i < 10; i++) {
-	    if (me.isCreate && !me.dataCache['net'+i.toString()]) {
-		me.ifname = 'net' + i.toString();
-		break;
-	    }
-	}
-
-	var idselector = {
-	    xtype: 'hidden',
-	    name: 'id',
-	    value: me.ifname
-	};
-
-	me.column1 = [
-	    idselector,
-	    {
-		xtype: 'textfield',
-		name: 'name',
-		fieldLabel: gettext('Name'),
-		emptyText: '(e.g., eth0)',
-		allowBlank: false,
-		value: cdata.name,
-		validator: function(value) {
-		    var result = '';
-		    Ext.Object.each(me.dataCache, function(key, netstr) {
-			if (!key.match(/^net\d+/) || key === me.ifname) {
-			    return; // continue
-			}
-			var net = PVE.Parser.parseLxcNetwork(netstr);
-			if (net.name === value) {
-			    result = "interface name already in use";
-			    return false;
-			}
-		    });
-		    if (result !== '') {
-			return result;
-		    }
-		    // validator can return bool/string
-		    /*jslint confusion:true*/
-		    return true;
-		}
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'hwaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		value: cdata.hwaddr,
-		allowBlank: true,
-		emptyText: 'auto'
-	    },
-	    {
-		xtype: 'PVE.form.BridgeSelector',
-		name: 'bridge',
-		nodename: me.nodename,
-		fieldLabel: gettext('Bridge'),
-		value: cdata.bridge,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: cdata.tag
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: cdata.rate,
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		value: cdata.firewall
-	    }
-	];
-
-	var dhcp4 = (cdata.ip === 'dhcp');
-	if (dhcp4) {
-	    cdata.ip = '';
-	    cdata.gw = '';
-	}
-
-	var auto6 = (cdata.ip6 === 'auto');
-	var dhcp6 = (cdata.ip6 === 'dhcp');
-	if (auto6 || dhcp6) {
-	    cdata.ip6 = '';
-	    cdata.gw6 = '';
-	}
-	
-	me.column2 = [
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv4:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: !dhcp4,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: dhcp4,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: cdata.ip,
-		disabled: dhcp4,
-		fieldLabel: 'IPv4/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: cdata.gw,
-		vtype: 'IPAddress',
-		disabled: dhcp4,
-		fieldLabel: gettext('Gateway') + ' (IPv4)',
-		margin: '0 0 3 0' // override bottom margin to account for the menuseparator
-	    },
-	    {
-		xtype: 'menuseparator',
-		height: '3',
-		margin: '0'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv6:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: !(auto6 || dhcp6),
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: dhcp6,
-			margin: '0 0 0 10'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'SLAAC', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'auto',
-			checked: auto6,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: cdata.ip6,
-		vtype: 'IP6CIDRAddress',
-		disabled: (dhcp6 || auto6),
-		fieldLabel: 'IPv6/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: cdata.gw6,
-		disabled: (dhcp6 || auto6),
-		fieldLabel: gettext('Gateway') + ' (IPv6)'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-	
-
-Ext.define('PVE.lxc.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
-	    ifname: me.ifname,
-	    nodename: me.nodename,
-	    dataCache: me.dataCache,
-	    isCreate: me.isCreate
-	});
-	   
-	Ext.apply(me, {
-	    subject: gettext('Network Device') + ' (veth)',
-	    digest: me.dataCache.digest,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveLxcNetworkView',
-
-    onlineHelp: 'pct_container_network',
-
-    dataCache: {}, // used to store result of last load
-
-    stateful: true,
-    stateId: 'grid-lxc-network',
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.setErrorMask(me, true);
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		me.dataCache = data;
-		var records = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (!key.match(/^net\d+/)) {
-			return; // continue
-		    }
-		    var net = PVE.Parser.parseLxcNetwork(value);
-		    net.id = key;
-		    records.push(net);
-		});
-		me.store.loadData(records);
-		me.down('button[name=addButton]').setDisabled((records.length >= 10));
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var store = new Ext.data.Store({
-	    model: 'pve-lxc-network',
-	    sorters: [
-		{
-		    property : 'id',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!caps.vms['VM.Config.Network'];
-	    },
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: me.url,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: { 'delete': rec.data.id,  digest: me.dataCache.digest },
-		    callback: function() {
-			me.load();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!caps.vms['VM.Config.Network']) {
-		return false;
-	    }
-
-	    var win = Ext.create('PVE.lxc.NetworkEdit', {
-		url: me.url,
-		nodename: nodename,
-		dataCache: me.dataCache,
-		ifname: rec.data.id
-	    });
-	    win.on('destroy', me.load, me);
-	    win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    name: 'addButton',
-		    disabled: !caps.vms['VM.Config.Network'],
-		    handler: function() {
-			var win = Ext.create('PVE.lxc.NetworkEdit', {
-			    url: me.url,
-			    nodename: nodename,
-			    isCreate: true,
-			    dataCache: me.dataCache
-			});
-			win.on('destroy', me.load, me);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 50,
-		    dataIndex: 'id'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 80,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Bridge'),
-		    width: 80,
-		    dataIndex: 'bridge'
-		},
-		{
-		    header: gettext('Firewall'),
-		    width: 80,
-		    dataIndex: 'firewall',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('VLAN Tag'),
-		    width: 80,
-		    dataIndex: 'tag'
-		},
-		{
-		    header: gettext('MAC address'),
-		    width: 110,
-		    dataIndex: 'hwaddr'
-		},
-		{
-		    header: gettext('IP address'),
-		    width: 150,
-		    dataIndex: 'ip',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.ip && rec.data.ip6) {
-			    return rec.data.ip + "<br>" + rec.data.ip6;
-			} else if (rec.data.ip6) {
-			    return rec.data.ip6;
-			} else {
-			    return rec.data.ip;
-			}
-		    }
-		},
-		{
-		    header: gettext('Gateway'),
-		    width: 150,
-		    dataIndex: 'gw',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.gw && rec.data.gw6) {
-			    return rec.data.gw + "<br>" + rec.data.gw6;
-			} else if (rec.data.gw6) {
-			    return rec.data.gw6;
-			} else {
-			    return rec.data.gw;
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: me.load,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-   }
-}, function() {
-
-    Ext.define('pve-lxc-network', {
-	extend: "Ext.data.Model",
-	proxy: { type: 'memory' },
-	fields: [ 'id', 'name', 'hwaddr', 'bridge',
-		  'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
-    });
-
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.RessourceView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcRessourceView'],
-
-    onlineHelp: 'pct_configuration',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rowdef = me.rows[key] || {};
-
-	metaData.tdAttr = "valign=middle";
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	}
-	return rowdef.header || key;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	var mpeditor = caps.vms['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
-
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-memory',
-		group: 1,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    swap: {
-		header: gettext('Swap'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-swap',
-		group: 2,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    cores: {
-		header: gettext('Cores'),
-		editor: caps.vms['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
-		defaultValue: '',
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		renderer: function(value) {
-		    var cpulimit = me.getObjectValue('cpulimit');
-		    var cpuunits = me.getObjectValue('cpuunits');
-		    var res;
-		    if (value) {
-			res = value;
-		    } else {
-			res = gettext('unlimited');
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit + ']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits + ']';
-		    }
-		    return res;
-		}
-	    },
-	    rootfs: {
-		header: gettext('Root Disk'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: mpeditor,
-		tdCls: 'pve-itype-icon-storage',
-		group: 4
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    unprivileged: {
-		visible: false
-	    }
-	};
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    confid = bus + i;
-	    var group = 5;
-	    var header;
-	    if (bus === 'mp') {
-		header = gettext('Mount Point') + ' (' + confid + ')';
-	    } else {
-		header = gettext('Unused Disk') + ' ' + i;
-		group += 1;
-	    }
-	    rows[confid] = {
-		group: group,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: mpeditor,
-		header: header
-	    };
-	}, true);
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	var run_resize = function() {
-	    var rec = me.selModel.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.MPResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-	};
-
-	var run_remove = function(b, e, rec) {
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/' + baseurl,
-		waitMsgTarget: me,
-		method: 'PUT',
-		params: {
-		    'delete': rec.data.key
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var run_move = function(b, e, rec) {
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid,
-		type: 'lxc'
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec) {
-		    return false;
-		}
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + me.renderKey(rec.data.key, {}, rec) + "'");
-		if (rec.data.key.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: run_remove
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move Volume'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    handler: run_move
-	});
-
-	var set_button_status = function() {
-	    var rec = me.selModel.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		remove_btn.disable();
-		resize_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var isDisk = (rowdef.tdCls == 'pve-itype-icon-storage');
-
-	    var noedit = rec.data['delete'] || !rowdef.editor;
-	    if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) {
-		var mp = PVE.Parser.parseLxcMountPoint(value);
-		if (mp.type !== 'volume') {
-		    noedit = true;
-		}
-	    }
-	    edit_btn.setDisabled(noedit);
-
-	    remove_btn.setDisabled(!isDisk || rec.data.key === 'rootfs' || !diskCap);
-	    resize_btn.setDisabled(!isDisk || !diskCap);
-	    move_btn.setDisabled(!isDisk || !diskCap);
-
-	};
-	
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + baseurl,
-	    selModel: me.selModel,
-	    interval: 2000,
-	    cwidth1: 170,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Mount Point'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.lxc.MountPointEdit', {
-					url: '/api2/extjs/' + baseurl,
-					unprivileged: me.getObjectValue('unprivileged'),
-					pveSelNode: me.pveSelNode
-				    });
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		edit_btn,
-		remove_btn,
-		resize_btn,
-		move_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    editorConfig: {
-		pveSelNode: me.pveSelNode,
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	Ext.apply(me.editorConfig, { unprivileged: me.getObjectValue('unprivileged') });
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.FeaturesInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcFeaturesInputPanel',
-
-    // used to save the mounts fstypes until sending
-    mounts: [],
-
-    fstypes: ['nfs', 'cifs'],
-
-    viewModel: {
-	parent: null,
-	data: {
-	    unprivileged: false
-	},
-	formulas: {
-	    privilegedOnly: function(get) {
-		return (get('unprivileged') ? gettext('privileged only') : '');
-	    },
-	    unprivilegedOnly: function(get) {
-		return (!get('unprivileged') ? gettext('unprivileged only') : '');
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('keyctl'),
-	    name: 'keyctl',
-	    bind: {
-		disabled: '{!unprivileged}',
-		boxLabel: '{unprivilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Nesting'),
-	    name: 'nesting'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'nfs',
-	    fieldLabel: 'NFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cifs',
-	    fieldLabel: 'CIFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'fuse',
-	    fieldLabel: 'FUSE'
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-	var mounts = me.mounts;
-	me.fstypes.forEach(function(fs) {
-	    if (values[fs]) {
-		mounts.push(fs);
-	    }
-	    delete values[fs];
-	});
-
-	if (mounts.length) {
-	    values.mount = mounts.join(';');
-	}
-
-	var featuresstring = PVE.Parser.printPropertyString(values, undefined);
-	if (featuresstring == '') {
-	    return { 'delete': 'features' };
-	}
-	return { features: featuresstring };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	me.viewModel.set({ unprivileged: values.unprivileged });
-
-	if (values.features) {
-	    var res = PVE.Parser.parsePropertyString(values.features);
-	    me.mounts = [];
-	    if (res.mount) {
-		res.mount.split(/[; ]/).forEach(function(item) {
-		    if (me.fstypes.indexOf(item) === -1) {
-			me.mounts.push(item);
-		    } else {
-			res[item] = 1;
-		    }
-		});
-	    }
-	    this.callParent([res]);
-	}
-    }
-});
-
-Ext.define('PVE.lxc.FeaturesEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveLxcFeaturesEdit',
-
-    subject: gettext('Features'),
-
-    items: [{
-	xtype: 'pveLxcFeaturesInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.lxc.Options', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcOptions'],
-
-    onlineHelp: 'pct_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ? 
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'pct_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    arch: {
-		header: gettext('Architecture'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    console: {
-		header: '/dev/console',
-		defaultValue: 1,
-		renderer: Proxmox.Utils.format_enabled_toggle,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: '/dev/console',
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'console',
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			checked: true,
-			fieldLabel: '/dev/console'
-		    }
-		} : undefined
-	    },
-	    tty: {
-		header: gettext('TTY count'),
-		defaultValue: 2,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('TTY count'),
-		    items: {
-			xtype: 'proxmoxintegerfield',
-			name: 'tty',
-			minValue: 0,
-			maxValue: 6,
-			value: 2,
-			fieldLabel: gettext('TTY count'),
-			emptyText: gettext('Default'),
-			deleteEmpty: true
-		    }
-		} : undefined
-	    },
-	    cmode: {
-		header: gettext('Console mode'),
-		defaultValue: 'tty',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Console mode'),
-		    items: {
-			xtype: 'proxmoxKVComboBox',
-			name: 'cmode',
-			deleteEmpty: true,
-			value: '__default__',
-			comboItems: [
-			    ['__default__', Proxmox.Utils.defaultText + " (tty)"],
-			    ['tty', "/dev/tty[X]"],
-			    ['console', "/dev/console"],
-			    ['shell', "shell"]
-			],
-			fieldLabel: gettext('Console mode')
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    unprivileged: {
-		header: gettext('Unprivileged container'),
-		renderer: Proxmox.Utils.format_boolean,
-		defaultValue: 0
-	    },
-	    features: {
-		header: gettext('Features'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: Proxmox.UserName === 'root@pam' ?
-		    'PVE.lxc.FeaturesEdit' : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	Ext.apply(me, {
-	    url: "/api2/json/" + baseurl,
-	    selModel: sm,
-	    interval: 5000,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-    }
-});
-
-Ext.define('PVE.lxc.DNSInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcDNSInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var deletes = [];
-	if (!values.searchdomain && !me.insideWizard) {
-	    deletes.push('searchdomain');
-	}
-
-	if (values.nameserver) {
-	    var list = values.nameserver.split(/[\ \,\;]+/);
-	    values.nameserver = list.join(' ');
-	} else if(!me.insideWizard) {
-	    deletes.push('nameserver');
-	}
-
-	if (deletes.length) {
-	    values['delete'] = deletes.join(',');
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxtextfield',
-		name: 'searchdomain',
-		skipEmptyText: true,
-		fieldLabel: gettext('DNS domain'),
-		emptyText: gettext('use host settings'),
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS servers'),
-		vtype: 'IP64AddressList',
-		allowBlank: true,
-		emptyText: gettext('use host settings'),
-		name: 'nameserver',
-		itemId: 'nameserver'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.lxc.DNSInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Resources'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-
-		    if (values.nameserver) {
-			values.nameserver.replace(/[,;]/, ' ');
-			values.nameserver.replace(/^\s+/, '');
-		    }
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.DNS', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveLxcDNS'],
-
-    onlineHelp: 'pct_container_network',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    hostname: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Hostname'),
-		editor: caps.vms['VM.Config.Network'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hostname'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    fieldLabel: gettext('Hostname'),
-			    xtype: 'textfield',
-			    name: 'hostname',
-			    vtype: 'DnsName',
-			    allowBlank: true,
-			    emptyText: 'CT' + vmid.toString()
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.hostname === undefined ||
-				values.hostname === null ||
-				values.hostname === '') {
-				params = { hostname: 'CT'+vmid.toString()};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    },
-	    nameserver: {
-		header: gettext('DNS server'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var win;
-	    if (Ext.isString(rowdef.editor)) {
-		win = Ext.create(rowdef.editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-	    //win.load();
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: run_editor
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/config",
-	    selModel: sm,
-	    cwidth1: 150,
-	    run_editor: run_editor,
-	    tbar: [ edit_btn ],
-	    rows: rows,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status,
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.lxc.Config',
-
-    onlineHelp: 'chapter_pct',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!me.pveSelNode.data.template;
-
-	var running = !!me.pveSelNode.data.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + "/status/" + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var stopBtn = Ext.create('Ext.menu.Item',{
-	    text: gettext('Stop'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
-	    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-	    dangerous: true,
-	    handler: function() {
-		vm_command("stop");
-	    },
-	    iconCls: 'fa fa-stop'
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items:[stopBtn]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'lxc',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = me.pveSelNode.data.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    guestType: 'ct',
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    disabled: !caps.vms['VM.Allocate'],
-		    itemId: 'removeBtn',
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'CT', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var vm = me.pveSelNode.data;
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    consoleType: 'lxc',
-	    consoleName: vm.name,
-	    hidden: template,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'lxctab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveLxcSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push(
-		{
-		    title: gettext('Console'),
-		    itemId: 'consolejs',
-		    iconCls: 'fa fa-terminal',
-		    xtype: 'pveNoVncConsole',
-		    vmid: vmid,
-		    consoleType: 'lxc',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Resources'),
-		itemId: 'resources',
-		expandedOnInit: true,
-		iconCls: 'fa fa-cube',
-		xtype: 'pveLxcRessourceView'
-	    },
-	    {
-		title: gettext('Network'),
-		iconCls: 'fa fa-exchange',
-		itemId: 'network',
-		xtype: 'pveLxcNetworkView'
-	    },
-	    {
-		title: gettext('DNS'),
-		iconCls: 'fa fa-globe',
-		itemId: 'dns',
-		xtype: 'pveLxcDNS'
-	    },
-	    {
-		title: gettext('Options'),
-		itemId: 'options',
-		iconCls: 'fa fa-gear',
-		xtype: 'pveLxcOptions'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		iconCls: 'fa fa-list',
-		xtype: 'proxmoxNodeTasks',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveLxcSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		itemId: 'permissions',
-		iconCls: 'fa fa-unlock',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var lock;
-	    if (!success) {
-		status = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-	    }
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    stopBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'stopped');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    storage: '',
-	    unprivileged: true
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('LXC Container'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'pct_general',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid', // backend only knows vmid
-		    guestType: 'lxc',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'hostname',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Hostname'),
-		    skipEmptyText: true,
-		    allowBlank: true
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unprivileged',
-		    value: true,
-		    bind: {
-			value: '{unprivileged}'
-		    },
-		    fieldLabel: gettext('Unprivileged container')
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'password',
-		    value: '',
-		    fieldLabel: gettext('Password'),
-		    allowBlank: false,
-		    minLength: 5,
-		    change: function(f, value) {
-			if (f.rendered) {
-			    f.up().down('field[name=confirmpw]').validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'confirmpw',
-		    value: '',
-		    fieldLabel: gettext('Confirm password'),
-		    allowBlank: true,
-		    submitValue: false,
-		    validator: function(value) {
-			var pw = this.up().down('field[name=password]').getValue();
-			if (pw !== value) {
-			    return "Passwords do not match!";
-			}
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'ssh-public-keys',
-		    value: '',
-		    fieldLabel: gettext('SSH public key'),
-		    allowBlank: true,
-		    validator: function(value) {
-			var pwfield = this.up().down('field[name=password]');
-			if (value.length) {
-			    var key = PVE.Parser.parseSSHKey(value);
-			    if (!key) {
-				return "Failed to recognize ssh key";
-			    }
-			    pwfield.allowBlank = true;
-			} else {
-			    pwfield.allowBlank = false;
-			}
-			pwfield.validate();
-			return true;
-		    },
-		    afterRender: function() {
-			if (!window.FileReader) {
-			    // No FileReader support in this browser
-			    return;
-			}
-			var cancel = function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			};
-			var field = this;
-			field.inputEl.on('dragover', cancel);
-			field.inputEl.on('dragenter', cancel);
-			field.inputEl.on('drop', function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			    var files = ev.dataTransfer.files;
-			    PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
-				field.setValue(v);
-			    });
-			});
-		    }
-		},
-		{
-		    xtype: 'filebutton',
-		    name: 'file',
-		    hidden: !window.FileReader,
-		    text: gettext('Load SSH Key File'),
-		    listeners: {
-			change: function(btn, e, value) {
-			    e = e.event;
-			    var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
-			    PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
-				field.setValue(v);
-			    });
-			    btn.reset();
-			}
-		    }
-		}
-	    ]
-	},
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('Template'),
-	    onlineHelp: 'pct_container_images',
-	    column1: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'tmplstorage',
-		    fieldLabel: gettext('Storage'),
-		    storageContent: 'vztmpl',
-		    autoSelect: true,
-		    allowBlank: false,
-		    bind: {
-			value: '{storage}',
-			nodename: '{nodename}'
-		    }
-		},
-		{
-		    xtype: 'pveFileSelector',
-		    name: 'ostemplate',
-		    storageContent: 'vztmpl',
-		    fieldLabel: gettext('Template'),
-		    bind: {
-			storage: '{storage}',
-			nodename: '{nodename}'
-		    },
-		    allowBlank: false
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveLxcMountPointInputPanel',
-	    title: gettext('Root Disk'),
-	    insideWizard: true,
-	    isCreate: true,
-	    unused: false,
-	    bind: {
-		nodename: '{nodename}',
-		unprivileged: '{unprivileged}'
-	    },
-	    confid: 'rootfs'
-	},
-	{
-	    xtype: 'pveLxcCPUInputPanel',
-	    title: gettext('CPU'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcMemoryInputPanel',
-	    title: gettext('Memory'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcNetworkInputPanel',
-	    title: gettext('Network'),
-	    insideWizard: true,
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    isCreate: true
-	},
-	{
-	    xtype: 'pveLxcDNSInputPanel',
-	    title: gettext('DNS'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-				property : 'key',
-				direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var wizard = this.up('window');
-		    var kv = wizard.getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete' || key === 'tmplstorage') { // ignore
-			    return;
-			}
-			if (key === 'password') { // don't show pw
-			    return;
-			}
-			var html = Ext.htmlEncode(Ext.JSON.encode(value));
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-		delete kv.tmplstorage;
-
-		if (!kv.pool.length) {
-		    delete kv.pool;
-		}
-
-		if (!kv.password.length && kv['ssh-public-keys']) {
-		    delete kv.password;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/lxc',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response, opts){
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid
-			});
-			win.show();
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-Ext.define('PVE.lxc.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveLxcSnapshotTree'],
-
-    onlineHelp: 'pct_snapshots',
-
-    load_delay: 3000,
-
-    old_digest: 'invalid',
-
-    stateful: true,
-    stateId: 'grid-lxc-snapshots',
-
-    sorterFn: function(rec1, rec2) {
-	var v1 = rec1.data.snaptime;
-	var v2 = rec2.data.snaptime;
-
-	if (rec1.data.name === 'current') {
-	    return 1;
-	}
-	if (rec2.data.name === 'current') {
-	    return -1;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    reload: function(repeat) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var digest = 'invalid';
-		var idhash = {};
-		var root = { name: '__root', expanded: true, children: [] };
-		Ext.Array.each(response.result.data, function(item) {
-		    item.leaf = true;
-		    item.children = [];
-		    if (item.name === 'current') {
-			digest = item.digest + item.running;
-			if (item.running) {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree-running';
-			} else {
-			    item.iconCls = 'fa fa-fw fa-desktop x-fa-tree';
-			}
-		    } else {
-			item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-		    }
-		    idhash[item.name] = item;
-		});
-
-		if (digest !== me.old_digest) {
-		    me.old_digest = digest;
-
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.parent && idhash[item.parent]) {
-			    var parent_item = idhash[item.parent];
-			    parent_item.children.push(item);
-			    parent_item.leaf = false;
-			    parent_item.expanded = true;
-			    parent_item.expandable = false;
-			} else {
-			    root.children.push(item);
-			}
-		    });
-
-		    me.setRootNode(root);
-		}
-
-		me.load_task.delay(me.load_delay);
-	    }
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/feature',
-	    params: { feature: 'snapshot' },
-	    method: 'GET',
-	    success: function(response, options) {
-		var res = response.result.data;
-		if (res.hasFeature) {
-		    var snpBtns = Ext.ComponentQuery.query('#snapshotBtn');
-		    snpBtns.forEach(function(item){
-			item.enable();
-		    });
-		}
-	    }
-	});
-
-
-    },
-
-    listeners: {
-	beforestatesave: function(grid, state, eopts) {
-	    // extjs cannot serialize functions,
-	    // so a the sorter with only the sorterFn will
-	    // not be a valid sorter when restoring the state
-	    delete state.storeState.sorters;
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.vmid = me.pveSelNode.data.vmid;
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var valid_snapshot = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current';
-	};
-
-	var valid_snapshot_rollback = function(record) {
-	    return record && record.data && record.data.name &&
-		record.data.name !== 'current' && !record.data.snapstate;
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (valid_snapshot(rec)) {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    snapname: rec.data.name,
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-		me.mon(win, 'close', me.reload, me);
-	    }
-	};
-
-	var editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot,
-	    handler: run_editor
-	});
-
-	var rollbackBtn = new Proxmox.button.Button({
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    dangerous: true,
-	    selModel: sm,
-	    enableFn: valid_snapshot_rollback,
-	    confirmMsg: function(rec) {
-		var taskdescription = Proxmox.Utils.format_task_description('vzrollback', me.vmid);
-		var snaptime = Ext.Date.format(rec.data.snaptime,'Y-m-d H:i:s');
-		var snapname = rec.data.name;
-
-		var msg = Ext.String.format(gettext('{0} to {1} ({2})'),
-		                            taskdescription, snapname, snaptime);
-		msg += '<p>' + gettext('Note: Rollback stops CT') + '</p>';
-
-		return msg;
-	    },
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname + '/rollback',
-		    method: 'POST',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var removeBtn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.name + "'");
-		return msg;
-	    },
-	    enableFn: valid_snapshot,
-	    handler: function(btn, event) {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-		var snapname = rec.data.name;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/snapshot/' + snapname,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			me.reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var snapshotBtn = Ext.create('Ext.Button', {
-	    itemId: 'snapshotBtn',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.window.LxcSnapshot', {
-		    nodename: me.nodename,
-		    vmid: me.vmid
-		});
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    tbar: [ snapshotBtn, rollbackBtn, removeBtn, editBtn ],
-	    fields: [
-		'name', 'description', 'snapstate', 'vmstate', 'running',
-		{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' }
-	    ],
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    text: gettext('Name'),
-		    dataIndex: 'name',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value === 'current') {
-			    return "NOW";
-			} else {
-			    return value;
-			}
-		    }
-		},
-//		{
-//		    text: gettext('RAM'),
-//		    align: 'center',
-//		    resizable: false,
-//		    dataIndex: 'vmstate',
-//		    width: 50,
-//		    renderer: function(value, metaData, record) {
-//			if (record.data.name !== 'current') {
-//			    return Proxmox.Utils.format_boolean(value);
-//			}
-//		    }
-//		},
-		{
-		    text: gettext('Date') + "/" + gettext("Status"),
-		    dataIndex: 'snaptime',
-		    resizable: false,
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.snapstate) {
-			    return record.data.snapstate;
-			}
-			if (value) {
-			    return Ext.Date.format(value,'Y-m-d H:i:s');
-			}
-		    }
-		},
-		{
-		    text: gettext('Description'),
-		    dataIndex: 'description',
-		    flex: 1,
-		    renderer: function(value, metaData, record) {
-			if (record.data.name === 'current') {
-			    return gettext("You are here!");
-			} else {
-			    return Ext.String.htmlEncode(value);
-			}
-		    }
-		}
-	    ],
-	    columnLines: true,
-	    listeners: {
-		activate: me.reload,
-		destroy: me.load_task.cancel,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-Ext.define('PVE.window.LxcSnapshot', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-    defaultFocus: 'field',
-
-    take_snapshot: function(snapname, descr, vmstate) {
-	var me = this;
-	var params = { snapname: snapname };
-	if (descr) {
-	    params.description = descr;
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot",
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    update_snapshot: function(snapname, descr) {
-	var me = this;
-	Proxmox.Utils.API2Request({
-	    params: { description: descr },
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var summarystore = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-	    sorters: [
-		{
-		    property : 'key',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var items = [
-	    {
-		xtype: me.snapname ? 'displayfield' : 'textfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    }
-	];
-
-	if (me.snapname) {
-	    items.push({
-		xtype: 'displayfield',
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    });
-	}
-
-	items.push({
-	    xtype: 'textareafield',
-	    grow: true,
-	    name: 'description',
-	    fieldLabel: gettext('Description')
-	});
-
-	if (me.snapname) {
-	    items.push({
-		title: gettext('Settings'),
-		xtype: 'grid',
-		height: 200,
-		store: summarystore,
-		columns: [
-		    {header: gettext('Key'), width: 150, dataIndex: 'key'},
-		    {header: gettext('Value'), flex: 1, dataIndex: 'value'}
-		]
-	    });
-	}
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	if (me.snapname) {
-	    me.title = gettext('Edit') + ': ' + gettext('Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Update'),
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.update_snapshot(me.snapname, values.description);
-		    }
-		}
-	    });
-	} else {
-	    me.title ="VM " + me.vmid + ': ' + gettext('Take Snapshot');
-	    submitBtn = Ext.create('Ext.Button', {
-		text: gettext('Take Snapshot'),
-		reference: 'submitbutton',
-		handler: function() {
-		    if (form.isValid()) {
-			var values = form.getValues();
-			me.take_snapshot(values.snapname, values.description);
-		    }
-		}
-	    });
-	}
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 450,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-	if (me.snapname) {
-	    Ext.apply(me, {
-		width: 620,
-		height: 420
-	    });
-	}
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	// else load data
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + "/snapshot/" +
-		me.snapname + '/config',
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		me.close();
-	    },
-	    success: function(response, options) {
-		var data = response.result.data;
-		var kvarray = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		form.findField('snaptime').setValue(data.snaptime);
-		form.findField('description').setValue(data.description);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-var labelWidth = 120;
-
-Ext.define('PVE.lxc.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: Ext.create('PVE.lxc.MemoryInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-
-Ext.define('PVE.lxc.CPUEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('CPU'),
-	    items: Ext.create('PVE.lxc.CPUInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.lxc.CPUInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcCPUInputPanel',
-
-    onlineHelp: 'pct_cpu',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	PVE.Utils.delete_if_default(values, 'cores', '', me.insideWizard);
-	// cpu{limit,unit} aren't in the wizard so create is always false
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	return values;
-    },
-
-    advancedColumn1: [
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    value: 1024,
-	    minValue: 8,
-	    maxValue: 500000,
-	    labelWidth: labelWidth,
-	    allowBlank: false
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'cores',
-		minValue: 1,
-		maxValue: 128,
-		value: me.insideWizard ? 1 : '',
-		fieldLabel: gettext('Cores'),
-		allowBlank: true,
-		deleteEmpty: true,
-		emptyText: gettext('unlimited')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcMemoryInputPanel',
-
-    onlineHelp: 'pct_memory',
-
-    insideWizard: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'memory',
-		minValue: 16,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'swap',
-		minValue: 0,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Swap') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
- 
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.MPResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 120,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-/*jslint confusion: true*/
-/* hidden: boolean and string
- * bind: function and object
- * disabled: boolean and string
- */
-Ext.define('PVE.lxc.MountPointInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcMountPointInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_storage',
-
-    unused: false, // add unused disk imaged
-
-    unprivileged: false,
-
-    vmconfig: {}, // used to select unused disks
-
-    setUnprivileged: function(unprivileged) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.unprivileged = unprivileged;
-	vm.set('unpriv', unprivileged);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || "mp"+values.mpid;
-	values.file = me.down('field[name=file]').getValue();
-	if (values.mountoptions) {
-	    values.mountoptions = values.mountoptions.join(';');
-	}
-
-	if (me.unused) {
-	    confid = "mp"+values.mpid;
-	} else if (me.isCreate) {
-	    values.file = values.hdstorage + ':' + values.disksize;
-	}
-
-	// delete unnecessary fields
-	delete values.mpid;
-	delete values.hdstorage;
-	delete values.disksize;
-	delete values.diskformat;
-
-	var res = {};
-	res[confid] = PVE.Parser.printLxcMountPoint(values);
-	return res;
-    },
-
-
-    setMountPoint: function(mp) {
-	var me = this;
-	var vm = this.getViewModel();
-	vm.set('mptype', mp.type);
-	if (mp.mountoptions) {
-	    mp.mountoptions = mp.mountoptions.split(';');
-	}
-
-	if (this.confid === 'rootfs') {
-	    var field = me.down('field[name=mountoptions]');
-	    var forbidden = ['nodev', 'noexec'];
-	    var filtered = field.comboItems.filter(e => !forbidden.includes(e[0]));
-	    field.setComboItems(filtered);
-	}
-
-	me.setValues(mp);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.vmconfig = vmconfig;
-	vm.set('unpriv', vmconfig.unprivileged);
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    var name = "mp" + i.toString();
-	    if (!Ext.isDefined(vmconfig[name])) {
-		me.down('field[name=mpid]').setValue(i);
-		return false;
-	    }
-	});
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var vm = me.getViewModel();
-	vm.set('node', nodename);
-	me.down('#diskstorage').setNodename(nodename);
-    },
-
-    controller:  {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=mpid]': {
-		change: function(field, value) {
-		    field.validate();
-		}
-	    },
-	    '#hdstorage': {
-		change: function(field, newValue) {
-		    var me = this;
-		    if (!newValue) {
-			return;
-		    }
-
-		    var rec = field.store.getById(newValue);
-		    if (!rec) {
-			return;
-		    }
-
-		    var vm = me.getViewModel();
-		    vm.set('type', rec.data.type);
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    vm.set('confid', view.confid);
-	    vm.set('unused', view.unused);
-	    vm.set('node', view.nodename);
-	    vm.set('unpriv', view.unprivileged);
-	    vm.set('hideStorSelector', view.unused || !view.isCreate);
-	}
-    },
-
-    viewModel: {
-	data: {
-	    unpriv: false,
-	    unused: false,
-	    showStorageSelector: false,
-	    mptype: '',
-	    type: '',
-	    confid: '',
-	    node: ''
-	},
-
-	formulas: {
-	    quota: function(get) {
-		return !(get('type') === 'zfs' ||
-			 get('type') === 'zfspool' ||
-			 get('unpriv') ||
-			 get('isBind'));
-	    },
-	    hasMP: function(get) {
-		return !!get('confid') && !get('unused');
-	    },
-	    isRoot: function(get) {
-		return get('confid') === 'rootfs';
-	    },
-	    isBind: function(get) {
-		return get('mptype') === 'bind';
-	    },
-	    isBindOrRoot: function(get) {
-		return get('isBind') || get('isRoot');
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'mpid',
-	    fieldLabel: gettext('Mount Point ID'),
-	    minValue: 0,
-	    maxValue: PVE.Utils.mp_counts.mps - 1,
-	    hidden: true,
-	    allowBlank: false,
-	    disabled: true,
-	    bind: {
-		hidden: '{hasMP}',
-		disabled: '{hasMP}'
-	    },
-	    validator: function(value) {
-		var me = this.up('inputpanel');
-		if (!me.rendered) {
-		    return;
-		}
-		if (Ext.isDefined(me.vmconfig["mp"+value])) {
-		    return "Mount point is already in use.";
-		}
-		/*jslint confusion: true*/
-		/* returns a string above */
-		return true;
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    itemId: 'diskstorage',
-	    storageContent: 'rootdir',
-	    hidden: true,
-	    autoSelect: true,
-	    selectformat: false,
-	    defaultSize: 8,
-	    bind: {
-		hidden: '{hideStorSelector}',
-		disabled: '{hideStorSelector}',
-		nodename: '{node}'
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    disabled: true,
-	    submitValue: false,
-	    fieldLabel: gettext('Disk image'),
-	    name: 'file',
-	    bind: {
-		hidden: '{!hideStorSelector}'
-	    }
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'textfield',
-	    name: 'mp',
-	    value: '',
-	    emptyText:  gettext('/some/path'),
-	    allowBlank: false,
-	    disabled: true,
-	    fieldLabel: gettext('Path'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'backup',
-	    fieldLabel: gettext('Backup'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isBindOrRoot}'
-	    }
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'quota',
-	    defaultValue: 0,
-	    bind: {
-		disabled: '{!quota}'
-	    },
-	    fieldLabel: gettext('Enable quota'),
-	    listeners: {
-		disable: function() {
-		    this.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'ro',
-	    defaultValue: 0,
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    },
-	    fieldLabel: gettext('Read-only')
-	},
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'mountoptions',
-	    fieldLabel: gettext('Mount options'),
-	    deleteEmpty: false,
-	    comboItems: [
-		['noatime', 'noatime'],
-		['nodev', 'nodev'],
-		['noexec', 'noexec'],
-		['nosuid', 'nosuid']
-	    ],
-	    multiSelect: true,
-	    value: [],
-	    allowBlank: true
-	},
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'acl',
-	    fieldLabel: 'ACLs',
-	    deleteEmpty: false,
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText],
-		['1', Proxmox.Utils.enabledText],
-		['0', Proxmox.Utils.disabledText]
-	    ],
-	    value: '__default__',
-	    bind: {
-		disabled: '{isBind}'
-	    },
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    inputValue: '0', // reverses the logic
-	    name: 'replicate',
-	    fieldLabel: gettext('Skip replication')
-	}
-    ]
-});
-
-Ext.define('PVE.lxc.MountPointEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    unprivileged: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    unprivileged: me.unprivileged,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-	    subject = gettext('Mount Point');
-	} else {
-	    subject = gettext('Mount Point') + ' (' + me.confid + ')';
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    /*jslint confusion: true*/
-		    /*data is defined as array above*/
-		    var value = response.result.data[me.confid];
-		    /*jslint confusion: false*/
-		    var mp = PVE.Parser.parseLxcMountPoint(value);
-
-		    if (!mp) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
-			me.close();
-			return;
-		    }
-
-		    ipanel.setMountPoint(mp);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.pool.StatusView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-    disabled: true,
-
-    title: gettext('Status'),
-    cwidth1: 150,
-    interval: 30000,
-    //height: 195,
-    initComponent : function() {
-	var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var rows = {
-	    comment: {
-		header: gettext('Comment'), 
-		renderer: Ext.String.htmlEncode,
-		required: true
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/pools/" + pool,
-	    rows: rows
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var statusview = Ext.create('PVE.pool.StatusView', {
-	    pveSelNode: me.pveSelNode,
-	    style: 'padding-top:0px'
-	});
-
-	var rstore = statusview.rstore;
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    defaults: {
-		style: 'padding-top:10px',
-		width: 800
-	    },
-	    items: [ statusview ]
-	});
-
-	me.on('activate', rstore.startUpdate);
-	me.on('destroy', rstore.stopUpdate);	
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    onlineHelp: 'pveum_pools',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-	    hstateid: 'pooltab',
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    xtype: 'pvePoolSummary',
-		    itemId: 'summary'
-		},
-		{
-		    title: gettext('Members'),
-		    xtype: 'pvePoolMembers',
-		    iconCls: 'fa fa-th',
-		    pool: pool,
-		    itemId: 'members'
-		},
-		{
-		    xtype: 'pveACLView',
-		    title: gettext('Permissions'),
-		    iconCls: 'fa fa-unlock',
-		    itemId: 'permissions',
-		    path: '/pool/' + pool
-		}
-	    ]
-	});
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.panel.StorageBase', {
-    extend: 'Proxmox.panel.InputPanel',
-    controller: 'storageEdit',
-
-    type: '',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = me.type;
-	} else {
-	    delete values.storage;
-	}
-
-	values.disable = values.enable ? 0 : 1;
-	delete values.enable;
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1.unshift({
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    name: 'storage',
-	    value: me.storageId || '',
-	    fieldLabel: 'ID',
-	    vtype: 'StorageId',
-	    allowBlank: false
-	});
-
-	me.column2.unshift(
-	    {
-		xtype: 'pveNodeSelector',
-		name: 'nodes',
-		disabled: me.storageId === 'local',
-		fieldLabel: gettext('Nodes'),
-		emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
-		multiSelect: true,
-		autoSelect: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.storageId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/storage';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/storage/' + me.storageId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create(me.paneltype, {
-	    type: me.type,
-	    isCreate: me.isCreate,
-	    storageId: me.storageId
-	});
-
-	Ext.apply(me, {
-            subject: PVE.Utils.format_storage_type(me.type),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    var ctypes = values.content || '';
-
-		    values.content = ctypes.split(',');
-
-		    if (values.nodes) {
-			values.nodes = values.nodes.split(',');
-		    }
-		    values.enable = values.disable ? 0 : 1;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.Upload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveStorageUpload',
-
-    resizable: false,
-
-    modal: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var xhr;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
-
-	var pbar = Ext.create('Ext.ProgressBar', {
-            text: 'Ready',
-	    hidden: true
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    method: 'POST',
-	    waitMsgTarget: true,
-	    bodyPadding: 10,
-	    border: false,
-	    width: 300,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-            },
-	    items: [
-		{
-		    xtype: 'pveContentTypeSelector',
-		    cts: me.contents,
-		    fieldLabel: gettext('Content'),
-		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
-		    allowBlank: false
-		},
-		pbar
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doStandardSubmit = function() {
-	    form.submit({
-		url: "/api2/htmljs" + baseurl,
-		waitMsg: gettext('Uploading file...'),
-		success: function(f, action) {
-		    me.close();
-		},
-		failure: function(f, action) {
-		    var msg = PVE.Utils.extractFormActionError(action);
-                    Ext.Msg.alert(gettext('Error'), msg);
-		}
-	    });
-	};
-
-	var updateProgress = function(per, bytes) {
-	    var text = (per * 100).toFixed(2) + '%';
-	    if (bytes) {
-		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
-	    }
-	    pbar.updateProgress(per, text);
-	};
-
-	var abortBtn = Ext.create('Ext.Button', {
-	    text: gettext('Abort'),
-	    disabled: true,
-	    handler: function() {
-		me.close();
-	    }
-	});
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Upload'),
-	    disabled: true,
-	    handler: function(button) {
-		var fd;
-		try {
-		    fd = new FormData();
-		} catch (err) {
-		    doStandardSubmit();
-		    return;
-		}
-
-		button.setDisabled(true);
-		abortBtn.setDisabled(false);
-
-		var field = form.findField('content');
-		fd.append("content", field.getValue());
-		field.setDisabled(true);
-
-		field = form.findField('filename');
-		var file = field.fileInputEl.dom;
-		fd.append("filename", file.files[0]);
-		field.setDisabled(true);
-
-		pbar.setVisible(true);
-		updateProgress(0);
-
-		xhr = new XMLHttpRequest();
-
-		xhr.addEventListener("load", function(e) {
-		    if (xhr.status == 200) {
-			me.close();
-		    } else {
-			var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
-			if (xhr.responseText !== "") {
-			    var result = Ext.decode(xhr.responseText);
-			    result.message = msg;
-			    msg = Proxmox.Utils.extractRequestError(result, true);
-			}
-			Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			    me.close();
-			});
-		    }
-		}, false);
-
-		xhr.addEventListener("error", function(e) {
-		    var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
-		    Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			me.close();
-		    });
-		});
-
-		xhr.upload.addEventListener("progress", function(evt) {
-		    if (evt.lengthComputable) {
-			var percentComplete = evt.loaded / evt.total;
-			updateProgress(percentComplete, evt.loaded);
-		    }
-		}, false);
-
-		xhr.open("POST", "/api2/json" + baseurl, true);
-		xhr.send(fd);
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-        Ext.apply(me, {
-            title: gettext('Upload'),
-	    items: me.formPanel,
-	    buttons: [ abortBtn, submitBtn ],
-	    listeners: {
-		close: function() {
-		    if (xhr) {
-			xhr.abort();
-		    }
-		}
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ContentView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveStorageContentView',
-
-    stateful: true,
-    stateId: 'grid-storage-content',
-    viewConfig: {
-	trackOver: false,
-	loadMask: false
-    },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-storage-content',
-	    groupField: 'content',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    },
-	    sorters: {
-		property: 'volid',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	    me.statusStore.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-
-	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
-	    text: gettext('Upload'),
-	    handler: function() {
-		var me = this;
-		var win = Ext.create('PVE.storage.Upload', {
-		    nodename: nodename,
-		    storage: storage,
-		    contents: me.contents
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var imageRemoveButton;
-	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: baseurl + '/'
-	});
-
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && rec.data.content === 'images') {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		me = this;
-
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
-		    reload();
-
-		});
-	    }
-	});
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (rec.data.volid.match(/vzdump-qemu-/)) {
-			    vmtype = 'qemu';
-			} else if (rec.data.volid.match(/vzdump-openvz-/) || rec.data.volid.match(/vzdump-lxc-/)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
-		    }
-		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
-    }
-}, function() {
-
-    Ext.define('pve-storage-content', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'volid', 'content', 'format', 'size', 'used', 'vmid',
-	    'channel', 'id', 'lun',
-	    {
-		name: 'text',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    return PVE.Utils.render_storage_content(value, {}, record);
-		}
-	    }
-	],
-	idProperty: 'volid'
-    });
-
-});
-Ext.define('PVE.storage.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveStorageStatusView',
-
-    height: 230,
-    title: gettext('Status'),
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 30 5 30'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 30
-	},
-	{
-	    itemId: 'enabled',
-	    title: gettext('Enabled'),
-	    printBar: false,
-	    textField: 'disabled',
-	    renderer: Proxmox.Utils.format_neg_boolean
-	},
-	{
-	    itemId: 'active',
-	    title: gettext('Active'),
-	    printBar: false,
-	    textField: 'active',
-	    renderer: Proxmox.Utils.format_boolean
-	},
-	{
-	    itemId: 'content',
-	    title: gettext('Content'),
-	    printBar: false,
-	    textField: 'content',
-	    renderer: PVE.Utils.format_content_types
-	},
-	{
-	    itemId: 'type',
-	    title: gettext('Type'),
-	    printBar: false,
-	    textField: 'type',
-	    renderer: PVE.Utils.format_storage_type
-	},
-	{
-	    xtype: 'box',
-	    height: 10
-	},
-	{
-	    itemId: 'usage',
-	    title: gettext('Usage'),
-	    valueField: 'used',
-	    maxField: 'total'
-	}
-    ],
-
-    updateTitle: function() {
-	return;
-    }
-});
-Ext.define('PVE.storage.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStorageSummary',
-    scrollable: true,
-    bodyPadding: 5,
-    tbar: [
-	'->',
-	{
-	    xtype: 'proxmoxRRDTypeSelector'
-	}
-    ],
-    layout: {
-	type: 'column'
-    },
-    defaults: {
-	padding: 5,
-	columnWidth: 1
-    },
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var rstore  = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/storage/" + storage + "/status",
-	    interval: 1000
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl:  "/api2/json/nodes/" + nodename + "/storage/" + storage + "/rrddata",
-	    model: 'pve-rrd-storage'
-	});
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'pveStorageStatusView',
-		    pveSelNode: me.pveSelNode,
-		    rstore: rstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Usage'),
-		    fields: ['total','used'],
-		    fieldTitles: ['Total Size', 'Used Size'],
-		    store: rrdstore
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.Browser', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.storage.Browser',
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storeid = me.pveSelNode.data.storage;
-	if (!storeid) {
-	    throw "no storage ID specified";
-	}
-
-
-	me.items = [
-	    {
-		title: gettext('Summary'),
-		xtype: 'pveStorageSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    }
-	];
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Storage {0} on node {1}"),
-				     "'" + storeid + "'", "'" + nodename + "'"),
-	    hstateid: 'storagetab'
-	});
-
-	if (caps.storage['Datastore.Allocate'] ||
-	    caps.storage['Datastore.AllocateSpace'] ||
-	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
-	}
-
-	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.storage.DirInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_directory',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'path',
-		value: '',
-		fieldLabel: gettext('Directory'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.NFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveNFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'path',
-    displayField: 'path',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.nfsServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.nfsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.nfsServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'path', 'options' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/nfs'
-	    }
-	});
-
-	store.sort('path', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.NFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_nfs',
-
-    options : [],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var i;
-	var res = [];
-	for (i = 0; i < me.options.length; i++) {
-	    var item = me.options[i];
-	    if (!item.match(/^vers=(.*)$/)) {
-		res.push(item);
-	    }
-	}
-	if (values.nfsversion && values.nfsversion !== '__default__') {
-	    res.push('vers=' + values.nfsversion);
-	}
-	delete values.nfsversion;
-	values.options = res.join(',');
-	if (values.options === '') {
-	    delete values.options;
-	    if (!me.isCreate) {
-		values["delete"] = "options";
-	    }
-	}
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	var me = this;
-	if (values.options) {
-	    var res = values.options;
-	    me.options = values.options.split(',');
-	    me.options.forEach(function(item) {
-		var match = item.match(/^vers=(.*)$/);
-		if (match) {
-		    values.nfsversion = match[1];
-		}
-	    });
-	}
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=export]');
-			    exportField.setServer(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'pveNFSScan' : 'displayfield',
-		name: 'export',
-		value: '',
-		fieldLabel: 'Export',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxKVComboBox',
-		fieldLabel: gettext('NFS Version'),
-		name: 'nfsversion',
-		value: '__default__',
-		deleteEmpty: false,
-		comboItems: [
-			['__default__', Proxmox.Utils.defaultText],
-			['3', '3'],
-			['4', '4'],
-			['4.1', '4.1'],
-			['4.2', '4.2']
-		]
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.CIFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCIFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'share',
-    displayField: 'share',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.cifsServer) {
-	    me.store.removeAll();
-	}
-
-	var params = {};
-	if (me.cifsUsername && me.cifsPassword) {
-	    params.username =  me.cifsUsername;
-	    params.password = me.cifsPassword;
-	}
-
-	if (me.cifsDomain) {
-	    params.domain = me.cifsDomain;
-	}
-
-	me.store.getProxy().setExtraParams(params);
-	me.allQuery = me.cifsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	this.cifsServer = server;
-    },
-
-    setUsername: function(username) {
-	this.cifsUsername = username;
-    },
-
-    setPassword: function(password) {
-	this.cifsPassword = password;
-    },
-
-    setDomain: function(domain) {
-	this.cifsDomain = domain;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['description', 'share'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/cifs'
-	    }
-	});
-	store.sort('share', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.CIFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_cifs',
-
-    initComponent : function() {
-	var me = this;
-
-	var passwordfield = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    inputType: 'password',
-	    name: 'password',
-	    value: me.isCreate ? '' : '********',
-	    fieldLabel: gettext('Password'),
-	    allowBlank: false,
-	    disabled: me.isCreate,
-	    minLength: 1,
-	    listeners: {
-		change: function(f, value) {
-
-		    if (me.isCreate) {
-			var exportField = me.down('field[name=share]');
-			exportField.setPassword(value);
-		    }
-		}
-	    }
-	});
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=share]');
-			    exportField.setServer(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: '',
-		fieldLabel: gettext('Username'),
-		emptyText: gettext('Guest user'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (!me.isCreate) {
-			    return;
-			}
-			var exportField = me.down('field[name=share]');
-			exportField.setUsername(value);
-
-			if (value == "") {
-			    passwordfield.disable();
-			} else {
-			    passwordfield.enable();
-			}
-			passwordfield.validate();
-		    }
-		}
-	    },
-	    passwordfield,
-	    {
-		xtype: me.isCreate ? 'pveCIFSScan' : 'displayfield',
-		name: 'share',
-		value: '',
-		fieldLabel: 'Share',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'domain',
-		value: me.isCreate ? '' : undefined,
-		fieldLabel: gettext('Domain'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-
-			    var exportField = me.down('field[name=share]');
-			    exportField.setDomain(value);
-			}
-		    }
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.GlusterFsScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveGlusterFsScan',
-
-    queryParam: 'server',
-
-    valueField: 'volname',
-    displayField: 'volname',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: 'Scanning...',
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.glusterServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.glusterServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.glusterServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'volname' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/glusterfs'
-	    }
-	});
-
-	store.sort('volname', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.GlusterFsInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_glusterfs',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var volumeField = me.down('field[name=volume]');
-			    volumeField.setServer(value);
-			    volumeField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		name: 'server2',
-		value: '',
-		fieldLabel: gettext('Second Server'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'pveGlusterFsScan' : 'displayfield',
-		name: 'volume',
-		value: '',
-		fieldLabel: 'Volume name',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'iso', 'backup', 'vztmpl', 'snippets'],
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.IScsiScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveIScsiScan',
-
-    queryParam: 'portal',
-    valueField: 'target',
-    displayField: 'target',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.portal) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.portal;
-
-	me.callParent();
-    },
-
-    setPortal: function(portal) {
-	var me = this;
-
-	me.portal = portal;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'target', 'portal' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/iscsi'
-	    }
-	});
-
-	store.sort('target', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.IScsiInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_open_iscsi',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	values.content = values.luns ? 'images' : 'none';
-	delete values.luns;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	values.luns = (values.content.indexOf('images') !== -1) ? true : false;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: 'Portal',
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=target]');
-			    exportField.setPortal(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		readOnly: !me.isCreate,
-		xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: 'Target',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'checkbox',
-		name: 'luns',
-		checked: true,
-		fieldLabel: gettext('Use LUNs directly')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.VgSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveVgSelector',
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'vg', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	store.sort('vg', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseStorageSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseStorageSelector',
-
-    existingGroupsText: gettext("Existing volume groups"),
-    queryMode: 'local',
-    editable: false,
-    value: '',
-    valueField: 'storage',
-    displayField: 'text',
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {
-		addRecords: true,
-		params: {
-		    type: 'iscsi'
-		}
-	    },
-	    fields: [ 'storage', 'type', 'content',
-		      {
-			  name: 'text',
-			  convert: function(value, record) {
-			      if (record.data.storage) {
-				  return record.data.storage + " (iSCSI)";
-			      } else {
-				  return me.existingGroupsText;
-			      }
-			  }
-		      }],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/storage/'
-	    }
-	});
-
-	store.loadData([{ storage: '' }], true);
-
-	store.sort('storage', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LVMInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvm',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.VgSelector', {
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		allowBlank: false
-	    });
-
-	    var baseField = Ext.createWidget('pveFileSelector', {
-		name: 'base',
-		hidden: true,
-		disabled: true,
-		nodename: 'localhost',
-		storageContent: 'images',
-		fieldLabel: gettext('Base volume'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseStorageSelector',
-		name: 'basesel',
-		fieldLabel: gettext('Base storage'),
-		submitValue: false,
-		listeners: {
-		    change: function(f, value) {
-			if (value) {
-			    vgnameField.setVisible(true);
-			    vgnameField.setDisabled(false);
-			    vgField.setVisible(false);
-			    vgField.setDisabled(true);
-			    baseField.setVisible(true);
-			    baseField.setDisabled(false);
-			} else {
-			    vgnameField.setVisible(false);
-			    vgnameField.setDisabled(true);
-			    vgField.setVisible(true);
-			    vgField.setDisabled(false);
-			    baseField.setVisible(false);
-			    baseField.setDisabled(true);
-			}
-			baseField.setStorage(value);
-		    }
-		}
-	    });
-
-	    me.column1.push(baseField);
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	// here value is an array, 
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.TPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveTPSelector',
-
-    queryParam: 'vg',
-    valueField: 'lv',
-    displayField: 'lv',
-    editable: false,
-
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.vg) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.vg;
-
-	me.callParent();
-    },
-
-    setVG: function(myvg) {
-	var me = this;
-
-	me.vg = myvg;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'lv' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin'
-	    }
-	});
-
-	store.sort('lv', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseVGSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseVGSelector',
-
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {},
-	    fields: [ 'vg', 'size', 'free'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LvmThinInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvmthin',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	var thinpoolField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'thinpool',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Thin Pool'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.TPoolSelector', {
-		name: 'thinpool',
-		fieldLabel: gettext('Thin Pool'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseVGSelector',
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    vgField.setVG(value);
-			    vgField.setValue('');
-			}
-		    }
-		}
-	    });
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	me.column1.push(thinpoolField);
-
-	// here value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.CephFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'storage_cephfs',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'cephfs';
-
-	me.column1 = [];
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		value: '',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: 'admin',
-		bind:  {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['backup', 'iso', 'vztmpl', 'snippets'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: 'backup',
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged cephFS')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.Ceph.Model', {
-    extend: 'Ext.app.ViewModel',
-    alias: 'viewmodel.cephstorage',
-
-    data: {
-	pveceph: true,
-	pvecephPossible: true
-    }
-});
-
-Ext.define('PVE.storage.Ceph.Controller', {
-    extend: 'PVE.controller.StorageEdit',
-    alias: 'controller.cephstorage',
-
-    control: {
-	'#': {
-	    afterrender: 'queryMonitors'
-	},
-	'textfield[name=username]': {
-	    disable: 'resetField'
-	},
-	'displayfield[name=monhost]': {
-	    enable: 'queryMonitors'
-	},
-	'textfield[name=monhost]': {
-	    disable: 'resetField',
-	    enable: 'resetField'
-	}
-    },
-    resetField: function(field) {
-	field.reset();
-    },
-    queryMonitors: function(field, newVal, oldVal) {
-	// we get called with two signatures, the above one for a field
-	// change event and the afterrender from the view, this check only
-	// can be true for the field change one and omit the API request if
-	// pveceph got unchecked - as it's not needed there.
-	if (field && !newVal && oldVal) {
-	    return;
-	}
-	var view = this.getView();
-	var vm = this.getViewModel();
-	if (!(view.isCreate || vm.get('pveceph'))) {
-	    return; // only query on create or if editing a pveceph store
-	}
-
-	var monhostField = this.lookupReference('monhost');
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/json/nodes/localhost/ceph/mon',
-	    method: 'GET',
-	    scope: this,
-	    callback: function(options, success, response) {
-		var data = response.result.data;
-		if (response.status === 200) {
-		    if (data.length > 0) {
-			var monhost = Ext.Array.pluck(data, 'name').sort().join(',');
-			monhostField.setValue(monhost);
-			monhostField.resetOriginalValue();
-			if (view.isCreate) {
-			    vm.set('pvecephPossible', true);
-			}
-		    } else {
-			vm.set('pveceph', false);
-		    }
-		} else {
-		    vm.set('pveceph', false);
-		    vm.set('pvecephPossible', false);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.storage.RBDInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'ceph_rados_block_devices',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'rbd';
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveCephPoolSelector',
-		nodename: me.nodename,
-		name: 'pool',
-		bind: {
-		    disabled: '{!pveceph}',
-		    submitValue: '{pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },{
-		xtype: 'textfield',
-		name: 'pool',
-		value: 'rbd',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		nodename: me.nodename,
-		name: 'pool',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		value: 'admin',
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'rootdir'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: ['images'],
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'krbd',
-		uncheckedValue: 0,
-		fieldLabel: 'KRBD'
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.ZFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    isLIO: false,
-	    isComstar: true,
-	    hasWriteCacheOption: true
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[name=iscsiprovider]': {
-		change: 'changeISCSIProvider'
-	    }
-	},
-	changeISCSIProvider: function(f, newVal, oldVal) {
-	    var vm = this.getViewModel();
-	    vm.set('isLIO', newVal === 'LIO');
-	    vm.set('isComstar', newVal === 'comstar');
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.content = 'images';
-	}
-
-	values.nowritecache = values.writecache ? 0 : 1;
-	delete values.writecache;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function diff(values) {
-	values.writecache = values.nowritecache ? 0 : 1;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: gettext('Portal'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'blocksize',
-		value: '4k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: gettext('Target'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_tg',
-		value: '',
-		fieldLabel: gettext('Target group'),
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		allowBlank: true
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: me.isCreate ? 'pveiScsiProviderSelector' : 'displayfield',
-		name: 'iscsiprovider',
-		value: 'comstar',
-		fieldLabel: gettext('iSCSI Provider'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'writecache',
-		checked: true,
-		bind: me.isCreate ? { disabled: '{!hasWriteCacheOption}' } : { hidden: '{!hasWriteCacheOption}' },
-		uncheckedValue: 0,
-		fieldLabel: gettext('Write cache')
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_hg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		fieldLabel: gettext('Host group'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'lio_tpg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
-		allowBlank: false,
-		fieldLabel: gettext('Target portal group')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.ZFSPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveZFSPoolSelector',
-    valueField: 'pool',
-    displayField: 'pool',
-    queryMode: 'local',
-    editable: false,
-    listConfig: {
-	loadingText: gettext('Scanning...')
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'pool', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/zfs'
-	    }
-	});
-
-	store.sort('pool', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ZFSPoolInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_zfspool',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
-		name: 'pool',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	} else {
-	    me.column1.push(Ext.createWidget('displayfield', {
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	}
-
-	// value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push(
-	    {xtype: 'pveContentTypeSelector',
-	     cts: ['images', 'rootdir'],
-	     fieldLabel: gettext('Content'),
-	     name: 'content',
-	     value: ['images', 'rootdir'],
-	     multiSelect: true,
-	     allowBlank: false
-	});
-	/*jslint confusion: false*/
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'blocksize',
-		emptyText: '8k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.StatusView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAStatusView'],
-
-    onlineHelp: 'chapter_ha_manager',
-
-    sortPriority: {
-	quorum: 1,
-	master: 2,
-	lrm: 3,
-	service: 4
-    },
-    
-    initComponent : function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sortAfterUpdate: true,
-	    sorters: [{
-		sorterFn: function(rec1, rec2) {
-		    var p1 = me.sortPriority[rec1.data.type];
-		    var p2 = me.sortPriority[rec2.data.type];
-		    return (p1 !== p2) ? ((p1 > p2) ? 1 : -1) : 0;
-		}
-	    }],
-	    filters: {
-		property: 'type',
-		value: 'service',
-		operator: '!='
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 80,
-		    flex: 1,
-		    dataIndex: 'status'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-    }
-}, function() {
-
-    Ext.define('pve-ha-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'type', 'node', 'status', 'sid',
-	    'state', 'group', 'comment',
-	    'max_restart', 'max_relocate', 'type',
-	    'crm_state', 'request_state'
-	],
-	idProperty: 'id'
-    });
-
-});
-Ext.define('PVE.ha.Status', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveHAStatus',
-
-    onlineHelp: 'chapter_ha_manager',
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-	    interval: me.interval,
-	    model: 'pve-ha-status',
-	    storeid: 'pve-store-' + (++Ext.idSeed),
-	    groupField: 'type',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/ha/status/current'
-	    }
-	});
-
-	me.items = [{
-	    xtype: 'pveHAStatusView',
-	    title: gettext('Status'),
-	    rstore: me.rstore,
-	    border: 0,
-	    collapsible: true,
-	    padding: '0 0 20 0'
-	},{
-	    xtype: 'pveHAResourcesView',
-	    flex: 1,
-	    collapsible: true,
-	    title: gettext('Resources'),
-	    border: 0,
-	    rstore: me.rstore
-	}];
-
-	me.callParent();
-	me.on('activate', me.rstore.startUpdate);
-    }
-});
-Ext.define('PVE.ha.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveHAGroupSelector'],
-
-    value: [],
-    autoSelect: false,
-    valueField: 'group',
-    displayField: 'group',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		width: 100,
-		sortable: true,
-		dataIndex: 'group'
-	    },
-	    {
-		header: gettext('Nodes'),
-		width: 100,
-		sortable: false,
-		dataIndex: 'nodes'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 1,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode
-	    }
-	]
-    },
-    store: {
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getStore().load();
-    }
-
-}, function() {
-
-    Ext.define('pve-ha-groups', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'group', 'type', 'digest', 'nodes', 'comment',
-	    {
-		name : 'restricted',
-		type: 'boolean'
-	    },
-	    {
-		name : 'nofailback',
-		type: 'boolean'
-	    }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/cluster/ha/groups"
-	},
-	idProperty: 'group'
-    });
-});
-Ext.define('PVE.ha.VMResourceInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_resource_config',
-    vmid: undefined,
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.vmid) {
-	    values.sid = values.vmid;
-	}
-	delete values.vmid;
-
-	PVE.Utils.delete_if_default(values, 'group', '', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_restart', '1', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_relocate', '1', me.isCreate);
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var MIN_QUORUM_VOTES = 3;
-
-	var disabledHint = Ext.createWidget({
-	    xtype: 'displayfield', // won't get submitted by default
-	    userCls: 'pve-hint',
-	    value: 'Disabling the resource will stop the guest system. ' +
-	    'See the online help for details.',
-	    hidden: true
-	});
-
-	var fewVotesHint = Ext.createWidget({
-	    itemId: 'fewVotesHint',
-	    xtype: 'displayfield',
-	    userCls: 'pve-hint',
-	    value: 'At least three quorum votes are recommended for reliable HA.',
-	    hidden: true
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/config/nodes',
-	    method: 'GET',
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var nodes = response.result.data;
-		var votes = 0;
-		Ext.Array.forEach(nodes, function(node) {
-		    var vote = parseInt(node.quorum_votes, 10); // parse as base 10
-		    votes += vote || 0; // parseInt might return NaN, which is false
-		});
-
-		if (votes < MIN_QUORUM_VOTES) {
-		    fewVotesHint.setVisible(true);
-		}
-	    }
-	});
-
-	/*jslint confusion: true */
-	var vmidStore = (me.vmid) ? {} : {
-	    model: 'PVEResources',
-	    autoLoad: true,
-	    sorters: 'vmid',
-	    filters: [
-		{
-		    property: 'type',
-		    value: /lxc|qemu/
-		},
-		{
-		    property: 'hastate',
-		    value: /unmanaged/
-		}
-	    ]
-	};
-
-	// value is a string above, but a number below
-	me.column1 = [
-	    {
-		xtype: me.vmid ? 'displayfield' : 'vmComboSelector',
-		submitValue: me.isCreate,
-		name: 'vmid',
-		fieldLabel: (me.vmid && me.guestType === 'ct') ? 'CT' : 'VM',
-		value: me.vmid,
-		store: vmidStore,
-		validateExists: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_restart',
-		fieldLabel: gettext('Max. Restart'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_relocate',
-		fieldLabel: gettext('Max. Relocate'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.column2 = [
-	    {
-		xtype: 'pveHAGroupSelector',
-		name: 'group',
-		fieldLabel: gettext('Group')
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'state',
-		value: 'started',
-		fieldLabel: gettext('Request State'),
-		comboItems: [
-		    ['started', 'started'],
-		    ['stopped', 'stopped'],
-		    ['ignored', 'ignored'],
-		    ['disabled', 'disabled']
-		],
-		listeners: {
-		    'change': function(field, newValue) {
-			if (newValue === 'disabled') {
-			    disabledHint.setVisible(true);
-			}
-			else {
-			    if (disabledHint.isVisible()) {
-				disabledHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    disabledHint
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    fewVotesHint
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.VMResourceEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmid: undefined,
-    guestType: undefined,
-    isCreate: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	if (me.isCreate === undefined) {
-	    me.isCreate = !me.vmid;
-	}
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/resources';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/resources/' + me.vmid;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.VMResourceInputPanel', {
-	    isCreate: me.isCreate,
-	    vmid: me.vmid,
-	    guestType: me.guestType
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Resource') + ': ' + gettext('Container') +
-	    '/' + gettext('Virtual Machine'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    var regex =  /^(\S+):(\S+)$/;
-		    var res = regex.exec(values.sid);
-
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			throw "got unexpected resource type";
-		    }
-
-		    values.vmid = res[2];
-		    
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.ResourcesView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAResourcesView'],
-
-    onlineHelp: 'ha_manager_resources',
-
-    stateful: true,
-    stateId: 'grid-ha-resources',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!me.rstore) {
-	    throw "no store given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    filters: {
-		property: 'type',
-		value: 'service'
-	    }
-	});
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var render_error = function(dataIndex, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors[dataIndex];
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    var sid = rec.data.sid;
-	    
-	    var regex =  /^(\S+):(\S+)$/;
-	    var res = regex.exec(sid);
-
-	    if (res[1] !== 'vm' && res[1] !== 'ct') {
-		return;
-	    }
-	    var guestType = res[1];
-	    var vmid = res[2];
-	    
-            var win = Ext.create('PVE.ha.VMResourceEdit',{
-                guestType: guestType,
-                vmid: vmid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/resources/',
-	    getUrl: function(rec) {
-		var me = this;
-		return me.baseurl + '/' + rec.get('sid');
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.VMResourceEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'sid'
-		},
-		{
-		    header: gettext('State'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Request State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'started';
-		    },
-		    dataIndex: 'request_state'
-		},
-		{
-		    header: gettext('CRM State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    dataIndex: 'crm_state'
-		},
-		{
-		    header: gettext('Max. Restart'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_restart'
-		},
-		{
-		    header: gettext('Max. Relocate'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_relocate'
-		},
-		{
-		    header: gettext('Group'),
-		    width: 200,
-		    sortable: true,
-		    renderer: function(value, metaData, record) {
-			return render_error('group', value, metaData, record);
-		    },
-		    dataIndex: 'group'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-resources', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	  'sid', 'state', 'digest', 'errors', 'group', 'comment',
-	  'max_restart', 'max_relocate', 'type', 'status', 'node',
-	  'crm_state', 'request_state'
-	],
-	idProperty: 'sid'
-    });
-
-});
-Ext.define('PVE.ha.GroupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_groups',
-
-    groupId: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = 'group';
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var update_nodefield, update_node_selection;
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    update_nodefield(selected);
-		}
-	    }
-	});
-
-	// use already cached data to avoid an API call
-	var data = PVE.data.ResourceStore.getNodes();
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'node', 'mem', 'cpu', 'priority' ],
-	    data: data,
-	    proxy: {
-		type: 'memory',
-		reader: {type: 'json'}
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var nodegrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Node'),
-		    flex: 1,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Memory usage') + " %",
-		    renderer: PVE.Utils.render_mem_usage_percent,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'mem'
-		},
-		{
-		    header: gettext('CPU usage'),
-		    renderer: PVE.Utils.render_cpu,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'cpu'
-		},
-		{
-		    header: 'Priority',
-		    xtype: 'widgetcolumn',
-		    dataIndex: 'priority',
-		    sortable: true,
-		    stopSelection: true,
-		    widget: {
-			xtype: 'proxmoxintegerfield',
-			minValue: 0,
-			maxValue: 1000,
-			isFormField: false,
-			listeners: {
-			    change: function(numberfield, value, old_value) {
-				var record = numberfield.getWidgetRecord();
-				record.set('priority', value);
-				update_nodefield(sm.getSelection());
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	var nodefield = Ext.create('Ext.form.field.Hidden', {
-	    name: 'nodes',
-	    value: '',
-	    listeners: {
-		change: function (nodefield, value) {
-		    update_node_selection(value);
-		}
-	    },
-	    isValid: function () {
-		var value = nodefield.getValue();
-		return (value && 0 !== value.length);
-	    }
-	});
-
-	update_node_selection = function(string) {
-	    sm.deselectAll(true);
-
-	    string.split(',').forEach(function (e, idx, array) {
-		var res = e.split(':');
-
-		store.each(function(record) {
-		    var node = record.get('node');
-
-		    if (node == res[0]) {
-			sm.select(record, true);
-			record.set('priority', res[1]);
-			record.commit();
-		    }
-		});
-	    });
-	    nodegrid.reconfigure(store);
-
-	};
-
-	update_nodefield = function(selected) {
-	    var nodes = '';
-	    var first_iteration = true;
-	    Ext.Array.each(selected, function(record) {
-		if (!first_iteration) {
-		    nodes += ',';
-		}
-		first_iteration = false;
-
-		nodes += record.data.node;
-		if (record.data.priority) {
-		    nodes += ':' + record.data.priority;
-		}
-	    });
-
-	    // nodefield change listener calls us again, which results in a
-	    // endless recursion, suspend the event temporary to avoid this
-	    nodefield.suspendEvent('change');
-	    nodefield.setValue(nodes);
-	    nodefield.resumeEvent('change');
-	};
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'group',
-		value: me.groupId || '',
-		fieldLabel: 'ID',
-		vtype: 'StorageId',
-		allowBlank: false
-	    },
-	    nodefield
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'restricted',
-		uncheckedValue: 0,
-		fieldLabel: 'restricted'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'nofailback',
-		uncheckedValue: 0,
-		fieldLabel: 'nofailback'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    nodegrid
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    groupId: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	me.isCreate = !me.groupId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/groups';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
-	    isCreate: me.isCreate,
-	    groupId: me.groupId
-	});
-
-	Ext.apply(me, {
-            subject: gettext('HA Group'),
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.GroupsView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAGroupsView'],
-
-    onlineHelp: 'ha_manager_groups',
-
-    stateful: true,
-    stateId: 'grid-ha-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-	});
-	
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-            var win = Ext.create('PVE.ha.GroupEdit',{
-                groupId: rec.data.group
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/groups/',
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.GroupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Group'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'group'
-		},
-		{
-		    header: 'restricted',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'restricted'
-		},
-		{
-		    header: 'nofailback',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'nofailback'
-		},
-		{
-		    header: gettext('Nodes'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'nodes'
-		},
-		{
-		    header: gettext('Comment'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.FencingView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveFencingView'],
-
-    onlineHelp: 'ha_manager_fencing',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-fencing',
-	    data: []
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false,
-		deferEmptyText: false,
-		emptyText: 'Use watchdog based fencing.'
-	    },
-	    columns: [
-		{
-		    header: 'Node',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Command'),
-		    flex: 1,
-		    dataIndex: 'command'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-fencing', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'node', 'command', 'digest'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSummary',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: 'column',
-
-    defaults: {
-	padding: 5,
-	plugins: 'responsive',
-	responsiveConfig: {
-	    'width < 1900': {
-		columnWidth: 1
-	    },
-	    'width >= 1900': {
-		columnWidth: 0.5
-	    }
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'dcHealth',
-	    xtype: 'pveDcHealth'
-	},
-	{
-	    itemId: 'dcGuests',
-	    xtype: 'pveDcGuests'
-	},
-	{
-	    title: gettext('Resources'),
-	    xtype: 'panel',
-	    minHeight: 250,
-	    bodyPadding: 5,
-	    layout: 'hbox',
-	    defaults: {
-		xtype: 'proxmoxGauge',
-		flex: 1
-	    },
-	    items:[
-		{
-		    title: gettext('CPU'),
-		    itemId: 'cpu'
-		},
-		{
-		    title: gettext('Memory'),
-		    itemId: 'memory'
-		},
-		{
-		    title: gettext('Storage'),
-		    itemId: 'storage'
-		}
-	    ]
-	},
-	{
-	    itemId: 'nodeview',
-	    xtype: 'pveDcNodeView',
-	    height: 250
-	},
-	{
-	    title: gettext('Subscriptions'),
-	    height: 220,
-	    items: [
-		{
-		    itemId: 'subscriptions',
-		    xtype: 'pveHealthWidget',
-		    userCls: 'pointer',
-		    listeners: {
-			element: 'el',
-			click: function() {
-			    if (this.component.userCls === 'pointer') {
-				window.open('https://www.proxmox.com/en/proxmox-ve/pricing', '_blank');
-			    }
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-status',
-	    model: 'pve-dc-nodes',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/cluster/status"
-	    }
-	});
-
-	var gridstore = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    filters: {
-		property: 'type',
-		value: 'node'
-	    },
-	    sorters: {
-		property: 'id',
-		direction: 'ASC'
-	    }
-	});
-
-	me.callParent();
-
-	me.getComponent('nodeview').setStore(gridstore);
-
-	var gueststatus = me.getComponent('dcGuests');
-
-	var cpustat = me.down('#cpu');
-	var memorystat = me.down('#memory');
-	var storagestat = me.down('#storage');
-	var sp = Ext.state.Manager.getProvider();
-
-	me.mon(PVE.data.ResourceStore, 'load', function(curstore, results) {
-	    me.suspendLayout = true;
-
-	    var cpu = 0;
-	    var maxcpu = 0;
-
-	    var nodes = 0;
-
-	    var memory = 0;
-	    var maxmem = 0;
-
-	    var countedStorages = {};
-	    var used = 0;
-	    var total = 0;
-	    var usableStorages = {};
-	    var storages = sp.get('dash-storages') || '';
-	    storages.split(',').forEach(function(storage){
-		if (storage !== '') {
-		    usableStorages[storage] = true;
-		}
-	    });
-
-	    var qemu = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var lxc = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var error = 0;
-
-	    var i;
-
-	    for (i = 0; i < results.length; i++) {
-		var item = results[i];
-		switch(item.data.type) {
-		    case 'node':
-			cpu += (item.data.cpu * item.data.maxcpu);
-			maxcpu += item.data.maxcpu || 0;
-			memory += item.data.mem || 0;
-			maxmem += item.data.maxmem || 0;
-			nodes++;
-
-			// update grid also
-			var griditem = gridstore.getById(item.data.id);
-			if (griditem) {
-			    griditem.set('cpuusage', item.data.cpu);
-			    var max = item.data.maxmem || 1;
-			    var val = item.data.mem || 0;
-			    griditem.set('memoryusage', val/max);
-			    griditem.set('uptime', item.data.uptime);
-			    griditem.commit(); //else it marks the fields as dirty
-			}
-			break;
-		    case 'storage':
-			if (!Ext.Object.isEmpty(usableStorages)) {
-			    if (usableStorages[item.data.id] === true) {
-				used += item.data.disk;
-				total += item.data.maxdisk;
-			    }
-			    break;
-			}
-			if (!countedStorages[item.data.storage] ||
-			    (item.data.storage === 'local' &&
-			    !countedStorages[item.data.id])) {
-			    used += item.data.disk;
-			    total += item.data.maxdisk;
-
-			    countedStorages[item.data.storage === 'local'?item.data.id:item.data.storage] = true;
-			}
-			break;
-		    case 'qemu':
-			qemu[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    case 'lxc':
-			lxc[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    default: break;
-		}
-	    }
-
-	    var text = Ext.String.format(gettext('of {0} CPU(s)'), maxcpu);
-	    cpustat.updateValue((cpu/maxcpu), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(memory), PVE.Utils.render_size(maxmem));
-	    memorystat.updateValue((memory/maxmem), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(used), PVE.Utils.render_size(total));
-	    storagestat.updateValue((used/total), text);
-
-	    gueststatus.updateValues(qemu,lxc,error);
-
-	    me.suspendLayout = false;
-	    me.updateLayout(true);
-	});
-
-	var dcHealth = me.getComponent('dcHealth');
-	me.mon(rstore, 'load', dcHealth.updateStatus, dcHealth);
-
-	var subs = me.down('#subscriptions');
-	me.mon(rstore, 'load', function(store, records, success) {
-	    var i;
-	    var level;
-	    var mixed = false;
-	    for (i = 0; i < records.length; i++) {
-		if (records[i].get('type') !== 'node') {
-		    continue;
-		}
-		var node = records[i];
-		if (node.get('status') === 'offline') {
-		    continue;
-		}
-
-		var curlevel = node.get('level');
-
-		if (curlevel === '') { // no subscription trumps all, set and break
-		    level = '';
-		    break;
-		}
-
-		if (level === undefined) { // save level
-		    level = curlevel;
-		} else if (level !== curlevel) { // detect different levels
-		    mixed = true;
-		}
-	    }
-
-	    var data = {
-		title: Proxmox.Utils.unknownText,
-		text: Proxmox.Utils.unknownText,
-		iconCls: PVE.Utils.get_health_icon(undefined, true)
-	    };
-	    if (level === '') {
-		data = {
-		    title: gettext('No Subscription'),
-		    iconCls: PVE.Utils.get_health_icon('critical', true),
-		    text: gettext('You have at least one node without subscription.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (mixed) {
-		data = {
-		    title: gettext('Mixed Subscriptions'),
-		    iconCls: PVE.Utils.get_health_icon('warning', true),
-		    text: gettext('Warning: Your subscription levels are not the same.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (level) {
-		data = {
-		    title: PVE.Utils.render_support_level(level),
-		    iconCls: PVE.Utils.get_health_icon('good', true),
-		    text: gettext('Your subscription status is valid.')
-		};
-		subs.setUserCls('');
-	    }
-
-	    subs.setData(data);
-	});
-
-	me.on('destroy', function(){
-	    rstore.stopUpdate();
-	});
-
-	rstore.startUpdate();
-    }
-
-});
-Ext.define('PVE.window.ReplicaEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveReplicaEdit',
-
-    subject: gettext('Replication Job'),
-
-
-    url: '/cluster/replication',
-    method: 'POST',
-
-    initComponent: function() {
-	var me = this;
-
-	var vmid = me.pveSelNode.data.vmid;
-	var nodename = me.pveSelNode.data.node;
-
-	var items = [];
-
-	items.push({
-	    xtype: (me.isCreate && !vmid)?'pveGuestIDSelector':'displayfield',
-	    name: 'guest',
-	    fieldLabel: 'CT/VM ID',
-	    value: vmid || ''
-	});
-
-	items.push(
-	    {
-		xtype: me.isCreate ? 'pveNodeSelector':'displayfield',
-		name: 'target',
-		disallowedNodes: [nodename],
-		allowBlank: false,
-		onlineValidator: true,
-		fieldLabel: gettext("Target")
-	    },
-	    {
-		xtype: 'pveCalendarEvent',
-		fieldLabel: gettext('Schedule'),
-		emptyText: '*/15 - ' + Ext.String.format(gettext('Every {0} minutes'), 15),
-		name: 'schedule'
-	    },
-	    {
-		xtype: 'numberfield',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		step: 1,
-		minValue: 1,
-		emptyText: gettext('unlimited'),
-		name: 'rate'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Comment'),
-		name: 'comment'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enabled',
-		defaultValue: 'on',
-		checked: true,
-		fieldLabel: gettext('Enabled')
-	    }
-	);
-
-	me.items = [
-	    {
-		xtype: 'inputpanel',
-		itemId: 'ipanel',
-		onlineHelp: 'pvesr_schedule_time_format',
-
-		onGetValues: function(values) {
-		    var me = this.up('window');
-
-		    values.disable = values.enabled ? 0 : 1;
-		    delete values.enabled;
-
-		    PVE.Utils.delete_if_default(values, 'rate', '', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'disable', 0, me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'schedule', '*/15', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'comment', '', me.isCreate);
-
-		    if (me.isCreate) {
-			values.type = 'local';
-			var vm = vmid || values.guest;
-			var id = -1;
-			if (me.highestids[vm] !== undefined) {
-			    id = me.highestids[vm];
-			}
-			id++;
-			values.id = vm + '-' + id.toString();
-			delete values.guest;
-		    }
-		    return values;
-		},
-		items: items
-	    }
-	];
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var jobs = response.result.data;
-		    var highestids = {};
-		    Ext.Array.forEach(jobs, function(job) {
-			var match = /^([0-9]+)\-([0-9]+)$/.exec(job.id);
-			if (match) {
-			    var vmid = parseInt(match[1],10);
-			    var id = parseInt(match[2],10);
-			    if (highestids[vmid] < id ||
-				highestids[vmid] === undefined) {
-				highestids[vmid] = id;
-			    }
-			}
-		    });
-
-		    me.highestids = highestids;
-		}
-	    });
-
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    response.result.data.enabled = !response.result.data.disable;
-		    me.setValues(response.result.data);
-		    me.digest = response.result.data.digest;
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-/* callback is a function and string */
-Ext.define('PVE.grid.ReplicaView', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveReplicaView',
-
-    onlineHelp: 'chapter_pvesr',
-
-    stateful: true,
-    stateId: 'grid-pve-replication-status',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	addJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		isCreate: true,
-		method: 'POST',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	editJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var data = rec.data;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		url: '/cluster/replication/' + data.id,
-		method: 'PUT',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	scheduleJobNow: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-
-	    Proxmox.Utils.API2Request({
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/schedule_now",
-		method: 'POST',
-		waitMsgTarget: me,
-		callback: function() { controller.reload(); },
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	showLog: function(button, event, rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var logView = Ext.create('Proxmox.panel.LogView', {
-		border: false,
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/log"
-	    });
-	    var win = Ext.create('Ext.window.Window', {
-		items: [ logView ],
-		layout: 'fit',
-		width: 800,
-		height: 400,
-		modal: true,
-		title: gettext("Replication Log")
-	    });
-	    var task = {
-		run: function() {
-		    logView.requestUpdate();
-		},
-		interval: 1000
-	    };
-	    Ext.TaskManager.start(task);
-	    win.on('destroy', function() {
-		Ext.TaskManager.stop(task);
-		controller.reload();
-	    });
-	    win.show();
-	},
-
-	reload: function() {
-	    var me = this.getView();
-	    me.rstore.load();
-	},
-
-	dblClick: function(grid, record, item) {
-	    var me = this;
-	    me.editJob(undefined, undefined, record);
-	},
-
-	// check for cluster
-	// currently replication is for cluster only, so we disable the whole
-	// component
-	checkPrerequisites: function() {
-	    var me = this.getView();
-	    if (PVE.data.ResourceStore.getNodes().length < 2) {
-		me.mask(gettext("Replication needs at least two nodes"), ['pve-static-mask']);
-	    }
-	},
-
-	control: {
-	    '#': {
-		itemdblclick: 'dblClick',
-		afterlayout: 'checkPrerequisites'
-	    }
-	}
-    },
-
-    tbar: [
-	{
-	    text: gettext('Add'),
-	    itemId: 'addButton',
-	    handler: 'addJob'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    itemId: 'editButton',
-	    handler: 'editJob',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxStdRemoveButton',
-	    itemId: 'removeButton',
-	    baseurl: '/api2/extjs/cluster/replication/',
-	    dangerous: true,
-	    callback: 'reload'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Log'),
-	    itemId: 'logButton',
-	    handler: 'showLog',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Schedule now'),
-	    itemId: 'scheduleNowButton',
-	    handler: 'scheduleJobNow',
-	    disabled: true
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	var mode = '';
-	var url = '/cluster/replication';
-
-	me.nodename = me.pveSelNode.data.node;
-	me.vmid = me.pveSelNode.data.vmid;
-
-	me.columns = [
-	    {
-		text: gettext('Enabled'),
-		dataIndex: 'enabled',
-		xtype: 'checkcolumn',
-		sortable: true,
-		disabled: true
-	    },
-	    {
-		text: 'ID',
-		dataIndex: 'id',
-		width: 60,
-		hidden: true
-	    },
-	    {
-		text: gettext('Guest'),
-		dataIndex: 'guest',
-		width: 75
-	    },
-	    {
-		text: gettext('Job'),
-		dataIndex: 'jobnum',
-		width: 60
-	    },
-	    {
-		text: gettext('Target'),
-		dataIndex: 'target'
-	    }
-	];
-
-	if (!me.nodename) {
-	    mode = 'dc';
-	    me.stateId = 'grid-pve-replication-dc';
-	} else if (!me.vmid) {
-	    mode = 'node';
-	    url = '/nodes/' + me.nodename + '/replication';
-	} else {
-	    mode = 'vm';
-	    url = '/nodes/' + me.nodename + '/replication' + '?guest=' + me.vmid;
-	}
-
-	if (mode !== 'dc') {
-	    me.columns.push(
-		{
-		    text: gettext('Status'),
-		    dataIndex: 'state',
-		    minWidth: 160,
-		    flex: 1,
-		    renderer: function(value, metadata, record) {
-
-			if (record.data.pid) {
-			    metadata.tdCls = 'x-grid-row-loading';
-			    return '';
-			}
-
-			var icons = [];
-			var states = [];
-
-			if (record.data.remove_job) {
-			    icons.push('<i class="fa fa-ban warning" title="'
-					+ gettext("Removal Scheduled") + '"></i>');
-			    states.push(gettext("Removal Scheduled"));
-			}
-
-			if (record.data.error) {
-			    icons.push('<i class="fa fa-times critical" title="'
-					+ gettext("Error") + '"></i>');
-			    states.push(record.data.error);
-			}
-
-			if (icons.length == 0) {
-			    icons.push('<i class="fa fa-check good"></i>');
-			    states.push(gettext('OK'));
-			}
-
-			return icons.join(',') + ' ' + states.join(',');
-		    }
-		},
-		{
-		    text: gettext('Last Sync'),
-		    dataIndex: 'last_sync',
-		    width: 150,
-		    renderer: function(value, metadata, record) {
-			if (!value) {
-			    return '-';
-			}
-
-			if (record.data.pid) {
-			    return gettext('syncing');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		},
-		{
-		    text: gettext('Duration'),
-		    dataIndex: 'duration',
-		    width: 60,
-		    renderer: PVE.Utils.render_duration
-		},
-		{
-		    text: gettext('Next Sync'),
-		    dataIndex: 'next_sync',
-		    width: 150,
-		    renderer: function(value) {
-			if (!value) {
-			    return '-';
-			}
-
-			var now = new Date();
-			var next = new Date(value*1000);
-
-			if (next < now) {
-			    return gettext('pending');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		}
-	    );
-	}
-
-	me.columns.push(
-	    {
-		text: gettext('Schedule'),
-		width: 75,
-		dataIndex: 'schedule'
-	    },
-	    {
-		text: gettext('Rate limit'),
-		dataIndex: 'rate',
-		renderer: function(value) {
-		    if (!value) {
-			return gettext('unlimited');
-		    }
-
-		    return value.toString() + ' MB/s';
-		},
-		hidden: true
-	    },
-	    {
-		text: gettext('Comment'),
-		dataIndex: 'comment',
-		renderer: Ext.htmlEncode
-	    }
-	);
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-replica-' + me.nodename + me.vmid,
-	    model: (mode === 'dc')? 'pve-replication' : 'pve-replication-state',
-	    interval: 3000,
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + url
-	    }
-	});
-
-	me.store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sorters: [
-		{
-		    property: 'guest'
-		},
-		{
-		    property: 'jobnum'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	// we cannot access the log and scheduleNow button
-	// in the datacenter, because
-	// we do not know where/if the jobs runs
-	if (mode === 'dc') {
-	    me.down('#logButton').setHidden(true);
-	    me.down('#scheduleNowButton').setHidden(true);
-	}
-
-	// if we set the warning mask, we do not want to load
-	// or set the mask on store errors
-	if (PVE.data.ResourceStore.getNodes().length < 2) {
-	    return;
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.on('destroy', me.rstore.stopUpdate);
-	me.rstore.startUpdate();
-    }
-}, function() {
-
-    Ext.define('pve-replication', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'target', 'comment', 'rate', 'type',
-	    { name: 'guest', type: 'integer' },
-	    { name: 'jobnum', type: 'integer' },
-	    { name: 'schedule', defaultValue: '*/15' },
-	    { name: 'disable', defaultValue: '' },
-	    { name: 'enabled', calculate: function(data) { return !data.disable; } }
-	]
-    });
-
-    Ext.define('pve-replication-state', {
-	extend: 'pve-replication',
-	fields: [
-	    'last_sync', 'next_sync', 'error', 'duration', 'state',
-	    'fail_count', 'remove_job', 'pid'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Health', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcHealth',
-
-    title: gettext('Health'),
-
-    bodyPadding: 10,
-    height: 220,
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	flex: 1,
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    nodeList: [],
-    nodeIndex: 0,
-
-    updateStatus: function(store, records, success) {
-	var me = this;
-	if (!success) {
-	    return;
-	}
-
-	var cluster = {
-	    iconCls: PVE.Utils.get_health_icon('good', true),
-	    text: gettext("Standalone node - no cluster defined")
-	};
-
-	var nodes = {
-	    online: 0,
-	    offline: 0
-	};
-
-	// by default we have one node
-	var numNodes = 1;
-	var i;
-
-	for (i = 0; i < records.length; i++) {
-	    var item = records[i];
-	    if (item.data.type === 'node') {
-		nodes[item.data.online === 1 ? 'online':'offline']++;
-	    } else if(item.data.type === 'cluster') {
-		cluster.text = gettext("Cluster") + ": ";
-		cluster.text += item.data.name + ", ";
-		cluster.text += gettext("Quorate") + ": ";
-		cluster.text += Proxmox.Utils.format_boolean(item.data.quorate);
-		if (item.data.quorate != 1) {
-		    cluster.iconCls = PVE.Utils.get_health_icon('critical', true);
-		}
-
-		numNodes = item.data.nodes;
-	    }
-	}
-
-	if (numNodes !== (nodes.online + nodes.offline)) {
-	    nodes.offline = numNodes - nodes.online;
-	}
-
-	me.getComponent('clusterstatus').updateHealth(cluster);
-	me.getComponent('nodestatus').update(nodes);
-    },
-
-    updateCeph: function(store, records, success) {
-	var me = this;
-	var cephstatus = me.getComponent('ceph');
-	if (!success || records.length < 1) {
-
-	    // if ceph status is already visible
-	    // don't stop to update
-	    if (cephstatus.isVisible()) {
-		return;
-	    }
-
-	    // try all nodes until we either get a successful api call,
-	    // or we tried all nodes
-	    if (++me.nodeIndex >= me.nodeList.length) {
-		me.cephstore.stopUpdate();
-	    } else {
-		store.getProxy().setUrl('/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status');
-	    }
-
-	    return;
-	}
-
-	var state = PVE.Utils.render_ceph_health(records[0].data.health || {});
-	cephstatus.updateHealth(state);
-	cephstatus.setVisible(true);
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    me.cephstore.stopUpdate();
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'clusterstatus',
-	    xtype: 'pveHealthWidget',
-	    title: gettext('Status')
-	},
-	{
-	    itemId: 'nodestatus',
-	    data: {
-		online: 0,
-		offline: 0
-	    },
-	    tpl: [
-		'<h3>' + gettext('Nodes') + '</h3><br />',
-		'<div style="width: 150px;margin: auto;font-size: 12pt">',
-		'<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-check">&nbsp;</i>',
-		gettext('Online'),
-		'</div>',
-		'<div class="right-aligned">{online}</div>',
-		'<br /><br />',
-		'<div class="left-aligned">',
-		'<i class="critical fa fa-fw fa-times">&nbsp;</i>',
-		gettext('Offline'),
-		'</div>',
-		'<div class="right-aligned">{offline}</div>',
-		'</div>'
-	    ]
-	},
-	{
-	    itemId: 'ceph',
-	    width: 250,
-	    columnWidth: undefined,
-	    userCls: 'pointer',
-	    title: 'Ceph',
-	    xtype: 'pveHealthWidget',
-	    hidden: true,
-	    listeners: {
-		element: 'el',
-		click: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    sp.set('dctab', {value:'ceph'}, true);
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodeList = PVE.data.ResourceStore.getNodes();
-	me.nodeIndex = 0;
-	me.cephstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-ceph',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status'
-	    }
-	});
-	me.callParent();
-	me.mon(me.cephstore, 'load', me.updateCeph, me);
-	me.cephstore.startUpdate();
-    }
-});
-Ext.define('PVE.dc.Guests', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcGuests',
-
-
-    title: gettext('Guests'),
-    height: 220,
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-    bodyPadding: '0 20 20 20',
-
-    defaults: {
-	xtype: 'box',
-	padding: '0 50 0 50',
-	style: {
-	    'text-align':'center',
-	    'line-height':'1.2'
-	}
-    },
-    items: [{
-	itemId: 'qemu',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("Virtual Machines") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'lxc',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("LXC Container") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'error',
-	colspan: 2,
-	data: {
-	    num: 0
-	},
-	columnWidth: 1,
-	padding: '10 250 0 250',
-	tpl: [
-	    '<tpl if="num &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="critical fa fa-fw fa-times-circle">&nbsp;</i>',
-		    gettext('Error'),
-		'</div>',
-		'<div class="right-aligned">{num}</div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateValues: function(qemu, lxc, error) {
-	var me = this;
-	me.getComponent('qemu').update(qemu);
-	me.getComponent('lxc').update(lxc);
-	me.getComponent('error').update({num: error});
-    }
-});
- /*jslint confusion: true*/
-Ext.define('PVE.dc.OptionView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    onlineHelp: 'datacenter_configuration_file',
-
-    monStoreErrors: true,
-
-    add_inputpanel_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	var canEdit = (opts.caps === undefined || opts.caps);
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: canEdit ? {
-		xtype: 'proxmoxWindowEdit',
-		width: 350,
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		setValues: function(values) {
-		    // FIXME: run through parsePropertyString if not an object?
-		    var edit_value = values[name];
-		    Ext.Array.each(this.query('inputpanel'), function(panel) {
-			panel.setValues(edit_value);
-		    });
-		},
-		url: opts.url,
-		items: [{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			if (values === undefined || Object.keys(values).length === 0) {
-			    return { 'delete': name };
-			}
-			var ret_val = {};
-			ret_val[name] = PVE.Parser.printPropertyString(values);
-			return ret_val;
-		    },
-		    items: opts.items
-		}]
-	    } : undefined
-	};
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.add_combobox_row('keyboard', gettext('Keyboard Layout'), {
-	    renderer: PVE.Utils.render_kvm_language,
-	    comboItems: PVE.Utils.kvm_keymap_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('http_proxy', gettext('HTTP proxy'), {
-	    defaultValue: Proxmox.Utils.noneText,
-	    vtype: 'HttpProxy',
-	    deleteEmpty: true
-	});
-	me.add_combobox_row('console', gettext('Console Viewer'), {
-	    renderer: PVE.Utils.render_console_viewer,
-	    comboItems: PVE.Utils.console_viewer_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('email_from', gettext('Email from address'), {
-	    deleteEmpty: true,
-	    vtype: 'proxmoxMail',
-	    defaultValue: 'root@$hostname'
-	});
-	me.add_text_row('mac_prefix', gettext('MAC address prefix'), {
-	    deleteEmpty: true,
-	    vtype: 'MacPrefix',
-	    defaultValue: Proxmox.Utils.noneText
-	});
-	me.add_inputpanel_row('migration', gettext('Migration Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    defaultKey: 'type',
-	    items: [{
-		xtype: 'displayfield',
-		name: 'type',
-		fieldLabel: gettext('Type'),
-		value: 'secure',
-		submitValue: true,
-	    }, {
-		xtype: 'proxmoxNetworkSelector',
-		name: 'network',
-		fieldLabel: gettext('Network'),
-		value: null,
-		emptyText: Proxmox.Utils.defaultText,
-		autoSelect: false,
-		skipEmptyText: true
-	    }]
-	});
-	me.add_inputpanel_row('ha', gettext('HA Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    items: [{
-		xtype: 'proxmoxKVComboBox',
-		name: 'shutdown_policy',
-		fieldLabel: gettext('Shutdown Policy'),
-		deleteEmpty: false,
-		value: '__default__',
-		comboItems: [
-		    ['__default__', Proxmox.Utils.defaultText + ' (conditional)' ],
-		    ['freeze', 'freeze'],
-		    ['failover', 'failover'],
-		    ['conditional', 'conditional']
-		],
-		defaultValue: '__default__'
-	    }]
-	});
-
-	// TODO: bwlimits, u2f?
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    tbar: [{
-		text: gettext('Edit'),
-		xtype: 'proxmoxButton',
-		disabled: true,
-		handler: function() { me.run_editor(); },
-		selModel: me.selModel
-	    }],
-	    url: "/api2/json/cluster/options",
-	    editorConfig: {
-		url: "/api2/extjs/cluster/options"
-	    },
-	    interval: 5000,
-	    cwidth1: 200,
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	// set the new value for the default console
-	me.mon(me.rstore, 'load', function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-
-	    var rec = store.getById('console');
-	    PVE.VersionInfo.console = rec.data.value;
-	    if (rec.data.value === '__default__') {
-		delete PVE.VersionInfo.console;
-	    }
-	});
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    onlineHelp: 'chapter_storage',
-
-    stateful: true,
-    stateId: 'grid-dc-storage',
-
-    createStorageEditWindow: function(type, sid) {
-	var schema = PVE.Utils.storageSchema[type];
-	if (!schema || !schema.ipanel) {
-	    throw "no editor registered for storage type: " + type;
-	}
-
-	Ext.create('PVE.storage.BaseEdit', {
-	    paneltype: 'PVE.storage.' + schema.ipanel,
-	    type: type,
-	    storageId: sid,
-	    autoShow: true,
-	    listeners: {
-		destroy: this.reloadStore
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-storage',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/storage"
-	    },
-	    sorters: {
-		property: 'storage',
-		order: 'DESC'
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type,
-	        sid = rec.data.storage;
-
-	    me.createStorageEditWindow(type, sid);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/storage/',
-	    callback: reload
-	});
-
-	// else we cannot dynamically generate the add menu handlers
-	var addHandleGenerator = function(type) {
-	    return function() { me.createStorageEditWindow(type); };
-	};
-	var addMenuItems = [], type;
-	/*jslint forin: true */
-	for (type in PVE.Utils.storageSchema) {
-	    var storage = PVE.Utils.storageSchema[type];
-	    if (storage.hideAdd) {
-		continue;
-	    }
-	    addMenuItems.push({
-		text:  PVE.Utils.format_storage_type(type),
-		iconCls: 'fa fa-fw fa-' + storage.faIcon,
-		handler: addHandleGenerator(type)
-	    });
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    reloadStore: reload,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: addMenuItems
-		    })
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Type'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'type',
-		    renderer: PVE.Utils.format_storage_type
-		},
-		{
-		    header: gettext('Content'),
-		    flex: 3,
-		    sortable: true,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Path') + '/' + gettext('Target'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'path',
-		    renderer: function(value, metaData, record) {
-			if (record.data.target) {
-			    return record.data.target;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Shared'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'shared',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Enabled'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'disable',
-		    renderer: Proxmox.Utils.format_neg_boolean
-		},
-		{
-		    header: gettext('Bandwidth Limit'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'bwlimit'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-	    { name: 'shared', type: 'boolean'},
-	    { name: 'disable', type: 'boolean'}
-	],
-	idProperty: 'storage'
-    });
-
-});
-/*global u2f,QRCode,Uint8Array*/
-/*jslint confusion: true*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' + encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer)
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    PVE.Utils.render_u2f_error(error)
-	);
-    },
-
-    doU2FChallenge: function(response) {
-	var me = this;
-
-	var data = response.result.data;
-	me.lookup('password').setDisabled(true);
-	var msg = Ext.Msg.show({
-	    title: 'U2F: '+gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: []
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(data.appId, [data], [], function(data) {
-		msg.close();
-		if (data.errorCode) {
-		    me.showError(data.errorCode);
-		} else {
-		    me.respondToU2FChallenge(data);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data)
-	};
-	if (Proxmox.UserName !== 'root@pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    tfa_type: null, // dependencies of formulas should not be undefined
-	    valid: false,
-	    u2f_available: true
-	},
-	formulas: {
-	    canDeleteTFA: function(get) {
-		return (get('tfa_type') !== null && !get('tfa_required'));
-	    },
-	    canSetupTOTP: function(get) {
-		var tfa = get('tfa_type');
-		return (tfa === null || tfa === 'totp' || tfa === 1);
-	    },
-	    canSetupU2F: function(get) {
-		var tfa = get('tfa_type');
-		return (get('u2f_available') && (tfa === null || tfa === 'u2f' || tfa === 1));
-	    }
-	}
-    },
-
-    afterLoading: function(realm_tfa_type, user_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (user_tfa_type === 'oath') {
-	    user_tfa_type = 'totp';
-	}
-	viewmodel.set('tfa_type', user_tfa_type || null);
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    if (user_tfa_type !== 'totp' && user_tfa_type !== null) {
-		// user had a different tfa method, so
-		// we have to change back to the totp tab and
-		// generate a secret
-		viewmodel.set('tfa_type', null);
-		me.lookup('tfatabs').setActiveTab(me.lookup('totp_panel'));
-		me.getController().randomizeSecret();
-	    }
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type
-		)
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    var me = this.getView();
-		    me.updateQrCode();
-		}
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		}
-	    },
-	    '#': {
-		show: function() {
-		    var me = this.getView();
-		    var viewmodel = this.getViewModel();
-
-		    var loadMaskContainer = me.down('#tfatabs');
-		    Proxmox.Utils.API2Request({
-			url: '/access/users/' + encodeURIComponent(me.userid) + '/tfa',
-			waitMsgTarget: loadMaskContainer,
-			method: 'GET',
-			success: function(response, opts) {
-			    var data = response.result.data;
-			    me.afterLoading(data.realm, data.user);
-			},
-			failure: function(response, opts) {
-			    Proxmox.Utils.setErrorMask(loadMaskContainer, response.htmlStatus);
-			}
-		    });
-
-		    me.qrdiv = document.createElement('center');
-		    me.qrcode = new QRCode(me.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M
-		    });
-		    me.down('#qrbox').getEl().appendChild(me.qrdiv);
-
-		    viewmodel.set('tfa_type', me.tfa_type || null);
-		    if (!me.tfa_type) {
-			this.randomizeSecret();
-		    } else {
-			me.down('#qrbox').setVisible(false);
-			me.lookup('challenge').setVisible(false);
-			if (me.tfa_type === 'u2f') {
-			    var u2f_panel = me.lookup('u2f_panel');
-			    me.lookup('tfatabs').setActiveTab(u2f_panel);
-			}
-		    }
-
-		    if (Proxmox.UserName === 'root@pam') {
-			me.lookup('password').setVisible(false);
-			me.lookup('password').setDisabled(true);
-		    }
-		}
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    var viewmodel = this.getViewModel();
-		    viewmodel.set('in_totp_tab', newcard.itemId === 'totp-panel');
-		}
-	    }
-	},
-
-	applySettings: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	deleteTFA: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'delete'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	randomizeSecret: function() {
-	    var me = this;
-	    var rnd = new Uint8Array(16);
-	    window.crypto.getRandomValues(rnd);
-	    var data = '';
-	    rnd.forEach(function(b) {
-		// secret must be base32, so just use the first 5 bits
-		b = b & 0x1f;
-		if (b < 26) {
-		    // A..Z
-		    data += String.fromCharCode(b + 0x41);
-		} else {
-		    // 2..7
-		    data += String.fromCharCode(b-26 + 0x32);
-		}
-	    });
-	    me.lookup('tfa_secret').setValue(data);
-	},
-
-	startU2FRegistration: function() {
-	    var me = this;
-
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    reference: 'tfatabs',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    reference: 'totp_panel',
-		    tfa_type: 'totp',
-		    border: false,
-		    bind: {
-			disabled: '{!canSetupTOTP}'
-		    },
-		    layout: {
-			type: 'vbox',
-			align: 'stretch'
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5'
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    cbind: {
-					value: '{userid}'
-				    }
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					flex: 4
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1
-				    }]
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true
-				}
-			    ]
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    style: {
-				'background-color': 'white',
-				padding: '5px',
-				width: '266px',
-				height: '266px'
-			    }
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify')
-			}
-		    ]
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    tfa_type: 'u2f',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle'
-		    },
-		    bind: {
-			disabled: '{!canSetupU2F}'
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.')
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password')
-	}
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton'
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}'
-	    }
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}',
-		disabled: '{tfa_type}'
-	    }
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    disabled: true,
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}'
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid given";
-	}
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    }
-});
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + encodeURIComponent(me.userid);
-            method = 'PUT';
-	}
-
-	var verifypw;
-	var pwfield;
-
-	var validate_pw = function() {
-	    if (verifypw.getValue() !== pwfield.getValue()) {
-		return gettext("Passwords do not match");
-	    }
-	    return true;
-	};
-
-	verifypw = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'), 
-	    name: 'verifypassword',
-	    submitValue: false,
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	pwfield = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'), 
-	    minLength: 5,
-	    name: 'password',
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	var update_passwd_field = function(realm) {
-	    if (realm === 'pve') {
-		pwfield.setVisible(true);
-		pwfield.setDisabled(false);
-		verifypw.setVisible(true);
-		verifypw.setDisabled(false);
-	    } else {
-		pwfield.setVisible(false);
-		pwfield.setDisabled(true);
-		verifypw.setVisible(false);
-		verifypw.setDisabled(true);
-	    }
-
-	};
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.isCreate ? true : false
-            },
-	    pwfield, verifypw,
-	    {
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		multiSelect: true,
-		allowBlank: true,
-		fieldLabel: gettext('Group')
-	    },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-		emptyText: 'never',
-		format: 'Y-m-d',
-		submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enabled'),
-		name: 'enable',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    }
-        ];
-
-        var column2 = [
-	    {
-		xtype: 'textfield',
-		name: 'firstname',
-		fieldLabel: gettext('First Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'lastname',
-		fieldLabel: gettext('Last Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'email',
-		fieldLabel: gettext('E-Mail'),
-		vtype: 'proxmoxMail'
-	    }
-	];
-
-        if (me.isCreate) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-		matchFieldWidth: false,
-		listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-			update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    fieldLabel: gettext('Comment')
-		}
-	    ],
-	    advancedItems: [
-		{
-		    xtype: 'textfield',
-		    name: 'keys',
-		    fieldLabel: gettext('Key IDs')
-		}
-	    ],
-	    onGetValues: function(values) {
-		// hack: ExtJS datefield does not submit 0, so we need to set that
-		if (!values.expire) {
-		    values.expire = 0;
-		}
-
-		if (realm) {
-		    values.userid = values.userid + '@' + realm;
-		}
-
-		if (!values.password) {
-		    delete values.password;
-		}
-
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 110 // for spanish translation 
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (Ext.isDefined(data.expire)) {
-			if (data.expire) {
-			    data.expire = new Date(data.expire * 1000);
-			} else {
-			    // display 'never' instead of '1970-01-01'
-			    data.expire = null;
-			}
-		    }
-		    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    onlineHelp: 'pveum_users',
-
-    stateful: true,
-    stateId: 'grid-users',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-            id: "users",
-	    model: 'pve-users',
-	    sorters: { 
-		property: 'userid', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/access/users/',
-	    enableFn: function(rec) {
-		if (!caps.access['User.Modify']) {
-		    return false;
-		}
-		return rec.data.userid !== 'root@pam';
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
- 
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec || !caps.access['User.Modify']) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    enableFn: function(rec) {
-		return !!caps.access['User.Modify'];
-	    },
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var pwchange_btn = new Proxmox.button.Button({
-	    text: gettext('Password'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('Proxmox.window.PasswordEdit', {
-                    userid: rec.data.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var tfa_type = PVE.Parser.parseTfaType(d.keys);
-		var win = Ext.create('PVE.window.TFAEdit',{
-		    tfa_type: tfa_type,
-		    userid: d.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-        var tbar = [
-            {
-		text: gettext('Add'),
-		disabled: !caps.access['User.Modify'],
-		handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-		}
-            },
-	    edit_btn, remove_btn, pwchange_btn, tfachange_btn
-        ];
-
-	var render_username = function(userid) {
-	    return userid.match(/^(.+)(@[^@]+)$/)[1];
-	};
-
-	var render_realm = function(userid) {
-	    return userid.match(/@([^@]+)$/)[1];
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('User name'),
-		    width: 200,
-		    sortable: true,
-		    renderer: render_username,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    renderer: render_realm,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'enable'
-		},
-		{
-		    header: gettext('Expire'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_expire, 
-		    dataIndex: 'expire'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    renderer: PVE.Utils.render_full_name,
-		    dataIndex: 'firstname'
-		},
-		{
-		    header: 'TFA',
-		    width: 50,
-		    sortable: true,
-		    renderer: function(v) {
-			var tfa_type = PVE.Parser.parseTfaType(v);
-			if (tfa_type === undefined) {
-			    return Proxmox.Utils.noText;
-			} else if (tfa_type === 1) {
-			    return Proxmox.Utils.yesText;
-			} else {
-			    return tfa_type;
-			}
-		    },
-		    dataIndex: 'keys'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    onlineHelp: 'pveum_pools',
-
-    stateful: true,
-    stateId: 'grid-pools',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: { 
-		property: 'poolid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/pools/',
-	    callback: function () {
-		reload();
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.PoolEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'poolid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'poolid',
-		    value: me.poolid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    onlineHelp: 'pveum_groups',
-
-    stateful: true,
-    stateId: 'grid-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: { 
-		property: 'groupid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: '/access/groups/'
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.GroupEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'groupid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'groupid',
-		    value: me.groupid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    onlineHelp: 'pveum_roles',
-
-    stateful: true,
-    stateId: 'grid-roles',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: {
-		property: 'roleid',
-		order: 'DESC'
-	    }
-	});
-
-	var render_privs = function(value, metaData) {
-
-	    if (!value) {
-		return '-';
-	    }
-
-	    // allow word wrap
-	    metaData.style = 'white-space:normal;';
-
-	    return value.replace(/\,/g, ' ');
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-		store.load();
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (rec.data.special === "1") {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.RoleEdit',{
-		roleid: rec.data.roleid,
-		privs: rec.data.privs
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Built-In'),
-		    width: 65,
-		    sortable: true,
-		    dataIndex: 'special',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'roleid'
-		},
-		{
-		    itemid: 'privs',
-		    header: gettext('Privileges'),
-		    sortable: false,
-		    renderer: render_privs,
-		    dataIndex: 'privs',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: function() {
-		    store.load();
-		},
-		itemdblclick: run_editor
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.RoleEdit', {});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Edit'),
-		    disabled: true,
-		    selModel: sm,
-		    handler: run_editor,
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		},
-		{
-		    xtype: 'proxmoxStdRemoveButton',
-		    selModel: sm,
-		    callback: function() {
-			reload();
-		    },
-		    baseurl: '/access/roles/',
-		    enableFn: function(record) {
-			return record.data.special !== '1';
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.RoleEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveDcRoleEdit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.roleid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = '/api2/extjs/access/roles';
-	    method = 'POST';
-	} else {
-	    url = '/api2/extjs/access/roles/' + me.roleid;
-	    method = 'PUT';
-	}
-
-	Ext.applyIf(me, {
-	    subject: gettext('Role'),
-	    url: url,
-	    method: method,
-	    items: [
-		{
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    name: 'roleid',
-		    value: me.roleid,
-		    allowBlank: false,
-		    fieldLabel: gettext('Name')
-		},
-		{
-		    xtype: 'pvePrivilegesSelector',
-		    name: 'privs',
-		    value: me.privs,
-		    allowBlank: false,
-		    fieldLabel: gettext('Privileges')
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var data = response.result.data;
-		    var keys = Ext.Object.getKeys(data);
-
-		    me.setValues({
-			privs: keys,
-			roleid: me.roleid
-		    });
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveACLAdd'],
-    url: '/access/acl',
-    method: 'PUT',
-    isAdd: true,
-    initComponent : function() {
-
-        var me = this;
-
-	me.isCreate = true;
-
-	var items = [
-	    {
-		xtype: me.path ? 'hiddenfield' : 'pvePermPathSelector',
-		name: 'path',
-		value: me.path,
-		allowBlank: false,
-		fieldLabel: gettext('Path')
-	    }
-	];
-
-	if (me.aclType === 'group') {
-	    me.subject = gettext("Group Permission");
-	    items.push({
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		fieldLabel: gettext('Group')
-	    });
-	} else if (me.aclType === 'user') {
-	    me.subject = gettext("User Permission");
-	    items.push({
-		xtype: 'pveUserSelector',
-		name: 'users',
-		fieldLabel: gettext('User')
-	    });
-	} else {
-	    throw "unknown ACL type";
-	}
-
-	items.push({
-	    xtype: 'pveRoleSelector',
-	    name: 'roles',
-	    value: 'NoAccess',
-	    fieldLabel: gettext('Role')
-	});
-
-	if (!me.path) {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'propagate',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Propagate')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    items: items,
-	    onlineHelp: 'pveum_permission_management'
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    onlineHelp: 'chapter_user_management',
-
-    stateful: true,
-    stateId: 'grid-acls',
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-acl',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/access/acl"
-	    },
-	    sorters: {
-		property: 'path',
-		order: 'DESC'
-	    }
-	});
-
-	if (me.path) {
-	    store.addFilter(Ext.create('Ext.util.Filter',{
-		filterFn: function(item) {
-		    if (item.data.path === me.path) {
-			return true;
-		    }
-		}
-	    }));
-	}
-
-	var render_ugid = function(ugid, metaData, record) {
-	    if (record.data.type == 'group') {
-		return '@' + ugid;
-	    }
-
-	    return ugid;
-	};
-
-	var columns = [
-	    {
-		header: gettext('User') + '/' + gettext('Group'),
-		flex: 1,
-		sortable: true,
-		renderer: render_ugid,
-		dataIndex: 'ugid'
-	    },
-	    {
-		header: gettext('Role'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'roleid'
-	    }
-	];
-
-	if (!me.path) {
-	    columns.unshift({
-		header: gettext('Path'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'path'
-	    });
-	    columns.push({
-		header: gettext('Propagate'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'propagate'
-	    });
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: gettext('Are you sure you want to remove this entry'),
-	    handler: function(btn, event, rec) {
-		var params = {
-		    'delete': 1,
-		    path: rec.data.path,
-		    roles: rec.data.roleid
-		};
-		if (rec.data.type === 'group') {
-		    params.groups = rec.data.ugid;
-		} else if (rec.data.type === 'user') {
-		    params.users = rec.data.ugid;
-		} else {
-		    throw 'unknown data type';
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/access/acl',
-		    params: params,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: {
-			xtype: 'menu',
-			items: [
-			    {
-				text: gettext('Group Permission'),
-				iconCls: 'fa fa-fw fa-group',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'group',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('User Permission'),
-				iconCls: 'fa fa-fw fa-user',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'user',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    }
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'ugid', 'roleid',
-	    {
-		name: 'propagate',
-		type: 'boolean'
-	    }
-	]
-    });
-
-});
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    onlineHelp: 'pveum_authentication_realms',
-
-    stateful: true,
-    stateId: 'grid-authrealms',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    sorters: { 
-		property: 'realm', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-		authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    baseurl: '/access/domains/',
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
-
-        var tbar = [
-	    {
-		text: gettext('Add'),
-		menu: new Ext.menu.Menu({
-		    items: [
-			{
-			    text: gettext('Active Directory Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit', {
-				    authType: 'ad'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			},
-			{
-			    text: gettext('LDAP Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit',{
-				    authType: 'ldap'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			}
-		    ]
-		})
-	    },
-	    edit_btn, remove_btn
-        ];
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-            tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'realm'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('TFA'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'tfa'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-	];
-
-	if (me.authType === 'ad') {
-
-	    me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-	} else if (me.authType === 'ldap') {
-
-	    me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-		emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-	} else if (me.authType === 'pve') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'Proxmox VE authentication server';
-
-	} else if (me.authType === 'pam') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'linux PAM';
-
-	} else {
-	    throw 'unknown auth type ';
-	}
-
-        column1.push({
-            xtype: 'proxmoxcheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-	if (me.authType === 'ldap' || me.authType === 'ad') {
-	    column2.push(
-		{
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-		},
-		{
-                    xtype: 'proxmoxtextfield',
-                    fieldLabel: gettext('Fallback Server'),
-		    deleteEmpty: !me.isCreate,
-		    name: 'server2'
-		},
-		{
-                    xtype: 'proxmoxintegerfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-		    emptyText: gettext('Default'),
-		    submitEmptyText: false
-		},
-		{
-                    xtype: 'proxmoxcheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-		}
-            );
-	}
-
-	// Two Factor Auth settings
-
-        column2.push({
-            xtype: 'proxmoxKVComboBox',
-            name: 'tfa',
-	    deleteEmpty: !me.isCreate,
-	    value: '',
-            fieldLabel: gettext('TFA'),
-	    comboItems: [ ['__default__', Proxmox.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=oath_step]').setVisible(value === 'oath');
-		    me.down('field[name=oath_digits]').setVisible(value === 'oath');
-		    me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-		}
-	    }
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_step',
-	    value: '',
-	    minValue: 10,
-	    emptyText: Proxmox.Utils.defaultText + ' (30)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_digits',
-	    value: '',
-	    minValue: 6,
-	    maxValue: 8,
-	    emptyText: Proxmox.Utils.defaultText + ' (6)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-	    hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-	    hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-	    hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [{
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-            }],
-	    onGetValues: function(values) {
-		if (!values.port) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'port' });
-		    }
-		    delete values.port;
-		}
-
-		if (me.isCreate) {
-		    values.type = me.authType;
-		}
-
-		if (values.tfa === 'oath') {
-		    values.tfa = "type=oath";
-		    if (values.oath_step) {
-			values.tfa += ",step=" + values.oath_step;
-		    }
-		    if (values.oath_digits) {
-			values.tfa += ",digits=" + values.oath_digits;
-		    }
-		} else if (values.tfa === 'yubico') {
-		    values.tfa = "type=yubico";
-		    values.tfa += ",id=" + values.yubico_api_id;
-		    values.tfa += ",key=" + values.yubico_api_key;
-		    if (values.yubico_url) {
-			values.tfa += ",url=" + values.yubico_url;
-		    }
-		} else {
-		    delete values.tfa;
-		}
-
-		delete values.oath_step;
-		delete values.oath_digits;
-		delete values.yubico_api_id;
-		delete values.yubico_api_key;
-		delete values.yubico_url;
-		
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-                success: function(response, options) {
-		    var data = response.result.data || {};
-		    // just to be sure (should not happen)
-		    if (data.type !== me.authType) {
-			me.close();
-			throw "got wrong auth type";
-		    }
-
-		    if (data.tfa) {
-			var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-			data.tfa = tfacfg.type;
-			if (tfacfg.type === 'yubico') {
-			    data.yubico_api_key = tfacfg.key;
-			    data.yubico_api_id = tfacfg.id;
-			    data.yubico_url = tfacfg.url;
-			} else if (tfacfg.type === 'oath') {
-			    // step is a number before
-			    /*jslint confusion: true*/
-			    data.oath_step = tfacfg.step;
-			    data.oath_digits = tfacfg.digits;
-			    /*jslint confusion: false*/
-			}
-		    }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    defaultFocus: undefined,
-
-    initComponent : function() {
-         var me = this;
-
-        me.isCreate = !me.jobid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-	var vmidField = Ext.create('Ext.form.field.Hidden', {
-	    name: 'vmid'
-	});
-
-	/*jslint confusion: true*/
-	// 'value' can be assigned a string or an array
-	var selModeField =  Ext.create('Proxmox.form.KVComboBox', {
-	    xtype: 'proxmoxKVComboBox',
-	    comboItems: [
-		['include', gettext('Include selected VMs')],
-		['all', gettext('All')],
-		['exclude', gettext('Exclude selected VMs')],
-		['pool', gettext('Pool based')]
-	    ],
-	    fieldLabel: gettext('Selection mode'),
-	    name: 'selMode',
-	    value: ''
-	});
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    var sel = [];
-		    Ext.Array.each(selected, function(record) {
-			sel.push(record.data.vmid);
-		    });
-
-		    // to avoid endless recursion suspend the vmidField change
-		    // event temporary as it calls us again
-		    vmidField.suspendEvent('change');
-		    vmidField.setValue(sel);
-		    vmidField.resumeEvent('change');
-		}
-	    }
-	});
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    fieldLabel: gettext('Storage'),
-	    nodename: 'localhost',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    name: 'storage'
-	});
-
-	var store = new Ext.data.Store({
-	    model: 'PVEResources',
-	    sorters: {
-		property: 'vmid',
-		order: 'ASC'
-	    }
-	});
-
-	var vmgrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    disabled: true,
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-
-	var selectPoolMembers = function(poolid) {
-	    if (!poolid) {
-		return;
-	    }
-	    sm.deselectAll(true);
-	    store.filter([
-		{
-		    id: 'poolFilter',
-		    property: 'pool',
-		    value: poolid
-		}
-	    ]);
-	    sm.selectAll(true);
-	};
-
-	var selPool = Ext.create('PVE.form.PoolSelector', {
-	    fieldLabel: gettext('Pool to backup'),
-	    hidden: true,
-	    allowBlank: true,
-	    name: 'pool',
-	    listeners: {
-		change: function( selpool, newValue, oldValue) {
-		    selectPoolMembers(newValue);
-		}
-	    }
-	});
-
-	var nodesel = Ext.create('PVE.form.NodeSelector', {
-	    name: 'node',
-	    fieldLabel: gettext('Node'),
-	    allowBlank: true,
-	    editable: true,
-	    autoSelect: false,
-	    emptyText: '-- ' + gettext('All') + ' --',
-	    listeners: {
-		change: function(f, value) {
-		    storagesel.setNodename(value || 'localhost');
-		    var mode = selModeField.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!value || rec.get('node') === value);
-		    });
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    }
-
-		    if (mode === 'pool') {
-			selectPoolMembers(selPool.value);
-		    }
-		}
-	    }
-	});
-
-	var column1 = [
-	    nodesel,
-	    storagesel,
-	    {
-		xtype: 'pveDayOfWeekSelector',
-		name: 'dow',
-		fieldLabel: gettext('Day of week'),
-		multiSelect: true,
-		value: ['sat'],
-		allowBlank: false
-	    },
-	    {
-		xtype: 'timefield',
-		fieldLabel: gettext('Start Time'),
-		name: 'starttime',
-		format: 'H:i',
-		formatText: 'HH:MM',
-		value: '00:00',
-		allowBlank: false
-	    },
-	    selModeField,
-	    selPool
-	];
-
-	var column2 = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Send email to'),
-		name: 'mailto'
-	    },
-	    {
-		xtype: 'pveEmailNotificationSelector',
-		fieldLabel: gettext('Email notification'),
-		name: 'mailnotification',
-		deleteEmpty: me.isCreate ? false : true,
-		value: me.isCreate ? 'always' : ''
-	    },
-	    {
-		xtype: 'pveCompressionSelector',
-		fieldLabel: gettext('Compression'),
-		name: 'compress',
-		deleteEmpty: me.isCreate ? false : true,
-		value: 'lzo'
-	    },
-	    {
-		xtype: 'pveBackupModeSelector',
-		fieldLabel: gettext('Mode'),
-		value: 'snapshot',
-		name: 'mode'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enable'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    },
-	    vmidField
-	];
-	/*jslint confusion: false*/
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    onlineHelp: 'chapter_vzdump',
-	    column1: column1,
-	    column2:  column2,
-	    onGetValues: function(values) {
-		if (!values.node) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'node' });
-		    }
-		    delete values.node;
-		}
-
-		var selMode = values.selMode;
-		delete values.selMode;
-
-		if (selMode === 'all') {
-		    values.all = 1;
-		    values.exclude = '';
-		    delete values.vmid;
-		} else if (selMode === 'exclude') {
-		    values.all = 1;
-		    values.exclude = values.vmid;
-		    delete values.vmid;
-		} else if (selMode === 'pool') {
-		    delete values.vmid;
-		}
-
-		if (selMode !== 'pool') {
-		    delete values.pool;
-		}
-		return values;
-	    }
-	});
-
-	var update_vmid_selection = function(list, mode) {
-	    if (mode !== 'all' && mode !== 'pool') {
-		sm.deselectAll(true);
-		if (list) {
-		    Ext.Array.each(list.split(','), function(vmid) {
-			var rec = store.findRecord('vmid', vmid);
-			if (rec) {
-			    sm.select(rec, true);
-			}
-		    });
-		}
-	    }
-	};
-
-	vmidField.on('change', function(f, value) {
-	    var mode = selModeField.getValue();
-	    update_vmid_selection(value, mode);
-	});
-
-	selModeField.on('change', function(f, value, oldValue) {
-	    if (oldValue === 'pool') {
-		store.removeFilter('poolFilter');
-	    }
-
-	    if (oldValue === 'all') {
-		sm.deselectAll(true);
-		vmidField.setValue('');
-	    }
-
-	    if (value === 'all') {
-		sm.selectAll(true);
-		vmgrid.setDisabled(true);
-	    } else {
-		vmgrid.setDisabled(false);
-	    }
-
-	    if (value === 'pool') {
-		vmgrid.setDisabled(true);
-		vmidField.setValue('');
-		selPool.setVisible(true);
-		selPool.allowBlank = false;
-		selectPoolMembers(selPool.value);
-
-	    } else {
-		selPool.setVisible(false);
-		selPool.allowBlank = true;
-	    }
-	    var list = vmidField.getValue();
-	    update_vmid_selection(list, value);
-	});
-
-	var reload = function() {
-	    store.load({
-		params: { type: 'vm' },
-		callback: function() {
-		    var node = nodesel.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!node || node.length === 0 || rec.get('node') === node);
-		    });
-		    var list = vmidField.getValue();
-		    var mode = selModeField.getValue();
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    } else if (mode === 'pool'){
-			selectPoolMembers(selPool.value);
-		    } else {
-			update_vmid_selection(list, mode);
-		    }
-		}
-	    });
-	};
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-	    items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.isCreate) {
-	    selModeField.setValue('include');
-	} else {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-
-		    data.dow = data.dow.split(',');
-
-		    if (data.all || data.exclude) {
-			if (data.exclude) {
-			    data.vmid = data.exclude;
-			    data.selMode = 'exclude';
-			} else {
-			    data.vmid = '';
-			    data.selMode = 'all';
-			}
-		    } else if (data.pool) {
-			data.selMode = 'pool';
-			data.selPool = data.pool;
-		    } else {
-			data.selMode = 'include';
-		    }
-
-		    me.setValues(data);
-               }
-            });
-        }
-
-	reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-cluster-backup',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/cluster/backup"
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.BackupEdit',{
-                jobid: rec.data.id
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/backup',
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    stateful: true,
-	    stateId: 'grid-dc-backup',
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.BackupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    dataIndex: 'enabled',
-		    xtype: 'checkcolumn',
-		    sortable: true,
-		    disabled: true,
-		    disabledCls: 'x-item-enabled',
-		    stopSelection: false
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node',
-		    renderer: function(value) {
-			if (value) {
-			    return value;
-			}
-			return me.allText;
-		    }
-		},
-		{
-		    header: gettext('Day of week'),
-		    width: 200,
-		    sortable: false,
-		    dataIndex: 'dow',
-		    renderer: function(val) {
-			var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-			var selected = [];
-			var cur = -1;
-			val.split(',').forEach(function(day){
-			    cur++;
-			    var dow = (dows.indexOf(day)+6)%7;
-			    if (cur === dow) {
-				if (selected.length === 0 || selected[selected.length-1] === 0) {
-				    selected.push(1);
-				} else {
-				    selected[selected.length-1]++;
-				}
-			    } else {
-				while (cur < dow) {
-				    cur++;
-				    selected.push(0);
-				}
-				selected.push(1);
-			    }
-			});
-
-			cur = -1;
-			var days = [];
-			selected.forEach(function(item) {
-			    cur++;
-			    if (item > 2) {
-				days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
-				cur += item-1;
-			    } else if (item == 2) {
-				days.push(Ext.Date.dayNames[cur+1]);
-				days.push(Ext.Date.dayNames[(cur+2)%7]);
-				cur++;
-			    } else if (item == 1) {
-				days.push(Ext.Date.dayNames[(cur+1)%7]);
-			    }
-			});
-			return days.join(', ');
-		    }
-		},
-		{
-		    header: gettext('Start Time'),
-		    width: 60,
-		    sortable: true,
-		    dataIndex: 'starttime'
-		},
-		{
-		    header: gettext('Storage'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Selection'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'vmid',
-		    renderer: function(value, metaData, record) {
-			/*jslint confusion: true */
-			if (record.data.all) {
-			    if (record.data.exclude) {
-				return Ext.String.format(me.allExceptText, record.data.exclude);
-			    }
-			    return me.allText;
-			}
-			if (record.data.vmid) {
-			    return record.data.vmid;
-			}
-
-			if (record.data.pool) {
-			    return "Pool '"+ record.data.pool + "'";
-			}
-
-			return "-";
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'starttime', 'dow',
-	    'storage', 'node', 'vmid', 'exclude',
-	    'mailto', 'pool',
-	    { name: 'enabled', type: 'boolean' },
-	    { name: 'all', type: 'boolean' },
-	    { name: 'snapshot', type: 'boolean' },
-	    { name: 'stop', type: 'boolean' },
-	    { name: 'suspend', type: 'boolean' },
-	    { name: 'compress', type: 'boolean' }
-	]
-    });
-});
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-    pveGuidePath: '/pve-docs/index.html',
-    onlineHelp: 'getting_help',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: function() {
-	var me = this;
-	var guideUrl = window.location.origin + me.pveGuidePath;
-	var text = Ext.String.format('<h1>Documentation</h1>'
-	+ 'The official Proxmox VE Administration Guide'
-	+ ' is included with this installation and can be browsed at '
-	+ '<a target="_blank" href="{0}">{0}</a>', guideUrl);
-	return text;
-    },
-
-    updateActive: function(data) {
-	var me = this;
-	
-	var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-
-    updateCommunity: function(data) {
-	var me = this;
-
-	var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-	 
-    updateInactive: function(data) {
-	var me = this;
-	me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/localhost/subscription',
-		method: 'GET',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.update('Unable to load subscription status' + ": " + response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-
-		    if (data.status === 'Active') {
-			if (data.level === 'c') {
-			    me.updateCommunity(data);
-			} else {
-			    me.updateActive(data);
-			}
-		    } else {
-			me.updateInactive(data);
-		    }
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('pve-security-groups', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'group', 'comment', 'digest' ],
-    idProperty: 'group'
-});
-
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = (me.group_name === undefined);
-
-	var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-	
-	var items = [	    
-	    {
-		xtype: 'textfield',
-		name: 'group',
-		value: me.group_name || '',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: me.group_comment || '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	if (me.isCreate) {
-	    subject = gettext('Security Group');
-        } else {
-	    subject = gettext('Security Group') + " '" + me.group_name + "'";
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'rename',
-		value: me.group_name
-	    });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	// InputPanel does not have a 'create' property, does it need a 'isCreate'
-	    isCreate: me.isCreate,
-	    items: items 
-	});
-
-
-	Ext.apply(me, {
-            subject: subject,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    stateful: true,
-    stateId: 'grid-securitygroups',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (me.rule_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-security-groups',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json' + me.base_url
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('group', oldrec.data.group);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.SecurityGroupEdit', {
-		digest: rec.data.digest,
-		group_name: rec.data.group,
-		group_comment: rec.data.comment
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('PVE.SecurityGroupEdit', {});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    enableFn: function(rec) {
-		return (rec && me.base_url);
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Group'), dataIndex: 'group', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = '/cluster/firewall/groups/' + rec.data.group;
-		    me.rule_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.rule_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-	var me = this;
-
-	var rule_panel = Ext.createWidget('pveFirewallRules', {
-	    region: 'center',
-	    allow_groups: false,
-	    list_refs_url: '/cluster/firewall/refs',
-	    tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-	    border: false
-	});
-
-	var sglist = Ext.createWidget('pveSecurityGroupList', {
-	    region: 'west',
-	    rule_panel: rule_panel,
-	    width: '25%',
-	    border: false,
-	    split: true
-	});
-
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-	    listeners: {
-		show: function() {
-		    sglist.fireEvent('show', sglist);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    onlineHelp: 'pve_admin_guide',
-
-    initComponent: function() {
-        var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext("Datacenter"),
-	    hstateid: 'dctab'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		title: gettext('Summary'),
-		xtype: 'pveDcSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    },
-	    {
-		title: gettext('Cluster'),
-		xtype: 'pveClusterAdministration',
-		iconCls: 'fa fa-server',
-		itemId: 'cluster'
-	    },
-	    {
-		title: 'Ceph',
-		itemId: 'ceph',
-		iconCls: 'fa fa-ceph',
-		xtype: 'pveNodeCephStatus'
-	    },
-	    {
-		xtype: 'pveDcOptionView',
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options'
-	    });
-	}
-
-	if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageView',
-		title: gettext('Storage'),
-		iconCls: 'fa fa-database',
-		itemId: 'storage'
-	    });
-	}
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveDcBackupView',
-		iconCls: 'fa fa-floppy-o',
-		title: gettext('Backup'),
-		itemId: 'backup'
-	    },
-	    {
-		xtype: 'pveReplicaView',
-		iconCls: 'fa fa-retweet',
-		title: gettext('Replication'),
-		itemId: 'replication'
-	    },
-	    {
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		expandedOnInit: true
-	    });
-	}
-
-	me.items.push({
-	    xtype: 'pveUserView',
-	    groups: ['permissions'],
-	    iconCls: 'fa fa-user',
-	    title: gettext('Users'),
-	    itemId: 'users'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveGroupView',
-		title: gettext('Groups'),
-		iconCls: 'fa fa-users',
-		groups: ['permissions'],
-		itemId: 'groups'
-	    },
-	    {
-		xtype: 'pvePoolView',
-		title: gettext('Pools'),
-		iconCls: 'fa fa-tags',
-		groups: ['permissions'],
-		itemId: 'pools'
-	    },
-	    {
-		xtype: 'pveRoleView',
-		title: gettext('Roles'),
-		iconCls: 'fa fa-male',
-		groups: ['permissions'],
-		itemId: 'roles'
-	    },
-	    {
-		xtype: 'pveAuthView',
-		title: gettext('Authentication'),
-		groups: ['permissions'],
-		iconCls: 'fa fa-key',
-		itemId: 'domains'
-	    },
-	    {
-		xtype: 'pveHAStatus',
-		title: 'HA',
-		iconCls: 'fa fa-heartbeat',
-		itemId: 'ha'
-	    },
-	    {
-		title: gettext('Groups'),
-		groups: ['ha'],
-		xtype: 'pveHAGroupsView',
-		iconCls: 'fa fa-object-group',
-		itemId: 'ha-groups'
-	    },
-	    {
-		title: gettext('Fencing'),
-		groups: ['ha'],
-		iconCls: 'fa fa-bolt',
-		xtype: 'pveFencingView',
-		itemId: 'ha-fencing'
-	    },
-	    {
-		xtype: 'pveFirewallRules',
-		title: gettext('Firewall'),
-		allow_iface: true,
-		base_url: '/cluster/firewall/rules',
-		list_refs_url: '/cluster/firewall/refs',
-		iconCls: 'fa fa-shield',
-		itemId: 'firewall'
-	    },
-	    {
-		xtype: 'pveFirewallOptions',
-		title: gettext('Options'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-gear',
-		base_url: '/cluster/firewall/options',
-		onlineHelp: 'pve_firewall_cluster_wide_setup',
-		fwtype: 'dc',
-		itemId: 'firewall-options'
-	    },
-	    {
-		xtype: 'pveSecurityGroups',
-		title: gettext('Security Group'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-group',
-		itemId: 'firewall-sg'
-	    },
-	    {
-		xtype: 'pveFirewallAliases',
-		title: gettext('Alias'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-external-link',
-		base_url: '/cluster/firewall/aliases',
-		itemId: 'firewall-aliases'
-	    },
-	    {
-		xtype: 'pveIPSet',
-		title: 'IPSet',
-		groups: ['firewall'],
-		iconCls: 'fa fa-list-ol',
-		base_url: '/cluster/firewall/ipset',
-		list_refs_url: '/cluster/firewall/refs',
-		itemId: 'firewall-ipset'
-	    },
-	    {
-		xtype: 'pveDcSupport',
-		title: gettext('Support'),
-		itemId: 'support',
-		iconCls: 'fa fa-comments-o'
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveDcNodeView',
-
-    title: gettext('Nodes'),
-    disableSelection: true,
-    scrollable: true,
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    dataIndex: 'name'
-	},
-	{
-	    header: 'ID',
-	    width: 40,
-	    sortable: true,
-	    dataIndex: 'nodeid'
-	},
-	{
-	    header: gettext('Online'),
-	    width: 60,
-	    sortable: true,
-	    dataIndex: 'online',
-	    renderer: function(value) {
-		var cls = (value)?'good':'critical';
-		return  '<i class="fa ' + PVE.Utils.get_health_icon(cls) + '"><i/>';
-	    }
-	},
-	{
-	    header: gettext('Support'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'level',
-	    renderer: PVE.Utils.render_support_level
-	},
-	{
-	    header: gettext('Server Address'),
-	    width: 115,
-	    sortable: true,
-	    dataIndex: 'ip'
-	},
-	{
-	    header: gettext('CPU usage'),
-	    sortable: true,
-	    width: 110,
-	    dataIndex: 'cpuusage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Memory usage'),
-	    width: 110,
-	    sortable: true,
-	    tdCls: 'x-progressbar-default-cell',
-	    dataIndex: 'memoryusage',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Uptime'),
-	    sortable: true,
-	    dataIndex: 'uptime',
-	    align: 'right',
-	    renderer: Proxmox.Utils.render_uptime
-	}
-    ],
-
-    stateful: true,
-    stateId: 'grid-cluster-nodes',
-    tools: [
-	{
-	    type: 'up',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = Math.max(me.getHeight()-50, 250);
-		me.setHeight(height);
-	    }
-	},
-	{
-	    type: 'down',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = me.getHeight()+50;
-		me.setHeight(height);
-	    }
-	}
-    ]
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-	extend: 'Ext.data.Model',
-	fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-	idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.widget.ProgressBar',{
-    extend: 'Ext.Progress',
-    alias: 'widget.pveProgressBar',
-
-    animate: true,
-    textTpl: [
-	'{percent}%'
-    ],
-
-    setValue: function(value){
-	var me = this;
-	me.callParent([value]);
-
-	me.removeCls(['warning', 'critical']);
-
-	if (value > 0.89) {
-	    me.addCls('critical');
-	} else if (value > 0.59) {
-	    me.addCls('warning');
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('pve-cluster-nodes', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
-	{ type: 'integer', name: 'quorum_votes' }
-    ],
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/nodes"
-    },
-    idProperty: 'nodeid'
-});
-
-Ext.define('pve-cluster-info', {
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/join"
-    }
-});
-
-Ext.define('PVE.ClusterAdministration', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveClusterAdministration',
-
-    title: gettext('Cluster Administration'),
-    onlineHelp: 'chapter_pvecm',
-
-    border: false,
-    defaults: { border: false },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    totem: {},
-	    nodelist: [],
-	    preferred_node: {
-		name: '',
-		fp: '',
-		addr: ''
-	    },
-	    isInCluster: false,
-	    nodecount: 0
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Cluster Information'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.store = Ext.create('Proxmox.data.UpdateStore', {
-			autoStart: true,
-			interval: 15 * 1000,
-			storeid: 'pve-cluster-info',
-			model: 'pve-cluster-info'
-		    });
-		    view.store.on('load', this.onLoad, this);
-		    view.on('destroy', view.store.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records || !records[0].data) {
-			vm.set('totem', {});
-			vm.set('isInCluster', false);
-			vm.set('nodelist', []);
-			vm.set('preferred_node', {
-			    name: '',
-			    addr: '',
-			    fp: ''
-			});
-			return;
-		    }
-		    var data = records[0].data;
-		    vm.set('totem', data.totem);
-		    vm.set('isInCluster', !!data.totem.cluster_name);
-		    vm.set('nodelist', data.nodelist);
-
-		    var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
-			return el.name === data.preferred_node;
-		    });
-
-		    vm.set('preferred_node', {
-			name: data.preferred_node,
-			addr: nodeinfo.pve_addr,
-			ring_addr: [ nodeinfo.ring0_addr, nodeinfo.ring1_addr ],
-			fp: nodeinfo.pve_fp
-		    });
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterCreateWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onClusterInfo: function() {
-		    var vm = this.getViewModel();
-		    var win = Ext.create('PVE.ClusterInfoWindow', {
-			joinInfo: {
-			    ipAddress: vm.get('preferred_node.addr'),
-			    fingerprint: vm.get('preferred_node.fp'),
-			    ring_addr: vm.get('preferred_node.ring_addr'),
-			    totem: vm.get('totem')
-			}
-		    });
-		    win.show();
-		},
-
-		onJoin: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create Cluster'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Information'),
-		    reference: 'addButton',
-		    handler: 'onClusterInfo',
-		    bind: {
-			disabled: '{!isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Cluster'),
-		    reference: 'joinButton',
-		    handler: 'onJoin',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		}
-	    ],
-	    layout: 'hbox',
-	    bodyPadding: 5,
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Cluster Name'),
-		    bind: {
-			value: '{totem.cluster_name}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Config Version'),
-		    bind: {
-			value: '{totem.config_version}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Number of Nodes'),
-		    labelWidth: 120,
-		    bind: {
-			value: '{nodecount}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    value: gettext('Standalone node - no cluster defined'),
-		    bind: {
-			hidden: '{isInCluster}'
-		    },
-		    flex: 1
-		}
-	    ]
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Cluster Nodes'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-cluster-nodes',
-			model: 'pve-cluster-nodes'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'nodeid',
-			    order: 'DESC'
-			}
-		    }));
-		    Proxmox.Utils.monStoreErrors(view, view.rstore);
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records) {
-			vm.set('nodecount', 0);
-			return;
-		    }
-		    vm.set('nodecount', records.length);
-		}
-	    },
-	    columns: [
-		{
-		    header: gettext('Nodename'),
-		    flex: 2,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('ID'),
-		    flex: 1,
-		    dataIndex: 'nodeid'
-		},
-		{
-		    header: gettext('Votes'),
-		    flex: 1,
-		    dataIndex: 'quorum_votes'
-		},
-		{
-		    header: Ext.String.format(gettext('Link {0}'), 0),
-		    flex: 2,
-		    dataIndex: 'ring0_addr'
-		},
-		{
-		    header: Ext.String.format(gettext('Link {0}'), 1),
-		    flex: 2,
-		    dataIndex: 'ring1_addr'
-		}
-	    ]
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ClusterCreateWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterCreateWindow',
-
-    title: gettext('Create Cluster'),
-    width: 600,
-
-    method: 'POST',
-    url: '/cluster/config',
-
-    isCreate: true,
-    subject: gettext('Cluster'),
-    showTaskViewer: true,
-
-    onlineHelp: 'pvecm_create_cluster',
-
-    items: {
-	xtype: 'inputpanel',
-	items: [{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Cluster Name'),
-	    allowBlank: false,
-	    name: 'clustername'
-	},
-	{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-	    emptyText: gettext("Optional, defaults to IP resolved by node's hostname"),
-	    name: 'link0',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}],
-	advancedItems: [{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-	    emptyText: gettext("Optional second link for redundancy"),
-	    name: 'link1',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}]
-    }
-});
-
-Ext.define('PVE.ClusterInfoWindow', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveClusterInfoWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 800,
-    modal: true,
-    resizable: false,
-    title: gettext('Cluster Join Information'),
-
-    joinInfo: {
-	ipAddress: undefined,
-	fingerprint: undefined,
-	totem: {}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    border: false,
-	    padding: '10 10 10 10',
-	    html: gettext("Copy the Join Information here and use it on the node you want to add.")
-	},
-	{
-	    xtype: 'container',
-	    layout: 'form',
-	    border: false,
-	    padding: '0 10 10 10',
-	    items: [
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('IP Address'),
-		    cbind: { value: '{joinInfo.ipAddress}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Fingerprint'),
-		    cbind: { value: '{joinInfo.fingerprint}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textarea',
-		    inputId: 'pveSerializedClusterInfo',
-		    fieldLabel: gettext('Join Information'),
-		    grow: true,
-		    cbind: { joinInfo: '{joinInfo}' },
-		    editable: false,
-		    listeners: {
-			afterrender: function(field) {
-			    if (!field.joinInfo) {
-				return;
-			    }
-			    var jsons = Ext.JSON.encode(field.joinInfo);
-			    var base64s = Ext.util.Base64.encode(jsons);
-			    field.setValue(base64s);
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-    dockedItems: [{
-	dock: 'bottom',
-	xtype: 'toolbar',
-	items: [{
-	    xtype: 'button',
-	    handler: function(b) {
-		var el = document.getElementById('pveSerializedClusterInfo');
-		el.select();
-		document.execCommand("copy");
-	    },
-	    text: gettext('Copy Information')
-	}]
-    }]
-});
-
-Ext.define('PVE.ClusterJoinNodeWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterJoinNodeWindow',
-
-    title: gettext('Cluster Join'),
-    width: 800,
-
-    method: 'POST',
-    url: '/cluster/config/join',
-
-    defaultFocus: 'textarea[name=serializedinfo]',
-    isCreate: true,
-    submitText: gettext('Join'),
-    showTaskViewer: true,
-
-    onlineHelp: 'chapter_pvecm',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    info: {
-		fp: '',
-		ip: '',
-		ring0Needed: false,
-		ring1Possible: false,
-		ring1Needed: false
-	    }
-	},
-	formulas: {
-	    ring0EmptyText: function(get) {
-		if (get('info.ring0Needed')) {
-		    return gettext("Cannot use default address safely");
-		} else {
-		    return gettext("Default: IP resolved by node's hostname");
-		}
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#': {
-		close: function() {
-		    delete PVE.Utils.silenceAuthFailures;
-		}
-	    },
-	    'proxmoxcheckbox[name=assistedEntry]': {
-		change: 'onInputTypeChange'
-	    },
-	    'textarea[name=serializedinfo]': {
-		change: 'recomputeSerializedInfo',
-		enable: 'resetField'
-	    },
-	    'proxmoxtextfield[name=ring1_addr]': {
-		enable: 'ring1Needed'
-	    },
-	    'textfield': {
-		disable: 'resetField'
-	    }
-	},
-	resetField: function(field) {
-	    field.reset();
-	},
-	ring1Needed: function(f) {
-	    var vm = this.getViewModel();
-	    f.allowBlank = !vm.get('info.ring1Needed');
-	},
-	onInputTypeChange: function(field, assistedInput) {
-	    var vm = this.getViewModel();
-	    if (!assistedInput) {
-		vm.set('info.ring1Possible', true);
-	    }
-	},
-	recomputeSerializedInfo: function(field, value) {
-	    var vm = this.getViewModel();
-	    var jsons = Ext.util.Base64.decode(value);
-	    var joinInfo = Ext.JSON.decode(jsons, true);
-
-	    var info = {
-		fp: '',
-		ring1Needed: false,
-		ring1Possible: false,
-		ip: ''
-	    };
-
-	    var totem = {};
-	    if (!(joinInfo && joinInfo.totem)) {
-		field.valid = false;
-	    } else {
-		var ring0Needed = false;
-		if (joinInfo.ring_addr !== undefined) {
-		    ring0Needed = joinInfo.ring_addr[0] !== joinInfo.ipAddress;
-		}
-
-		info = {
-		    ip: joinInfo.ipAddress,
-		    fp: joinInfo.fingerprint,
-		    ring0Needed: ring0Needed,
-		    ring1Possible: !!joinInfo.totem['interface']['1'],
-		    ring1Needed: !!joinInfo.totem['interface']['1']
-		};
-		totem = joinInfo.totem;
-		field.valid = true;
-	    }
-
-	    vm.set('info', info);
-	}
-    },
-
-    submit: function() {
-	// joining may produce temporarily auth failures, ignore as long the task runs
-	PVE.Utils.silenceAuthFailures = true;
-	this.callParent();
-    },
-
-    taskDone: function(success) {
-	delete PVE.Utils.silenceAuthFailures;
-	if (success) {
-	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
-	    // ensure user cannot do harm
-	    Ext.getBody().mask(txt, ['pve-static-mask']);
-	    // TaskView may hide above mask, so tell him directly
-	    Ext.Msg.show({
-		title: gettext('Join Task Finished'),
-		icon: Ext.Msg.INFO,
-		msg: txt
-	    });
-	    // reload always (if user wasn't faster), but wait a bit for pveproxy
-	    Ext.defer(function() {
-		window.location.reload(true);
-	    }, 5000);
-	}
-    },
-
-    items: [{
-	xtype: 'proxmoxcheckbox',
-	reference: 'assistedEntry',
-	name: 'assistedEntry',
-	submitValue: false,
-	value: true,
-	autoEl: {
-	    tag: 'div',
-	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
-	},
-	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
-    },
-    {
-	xtype: 'textarea',
-	name: 'serializedinfo',
-	submitValue: false,
-	allowBlank: false,
-	fieldLabel: gettext('Information'),
-	emptyText: gettext('Paste encoded Cluster Information here'),
-	validator: function(val) {
-	    return val === '' || this.valid ||
-	       gettext('Does not seem like a valid encoded Cluster Information!');
-	},
-	bind: {
-	    disabled: '{!assistedEntry.checked}',
-	    hidden: '{!assistedEntry.checked}'
-	},
-	value: ''
-    },
-    {
-	xtype: 'inputpanel',
-	column1: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Peer Address'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.ip}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'hostname'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		emptyText: gettext("Peer's root password"),
-		fieldLabel: gettext('Password'),
-		allowBlank: false,
-		name: 'password'
-	    }
-	],
-	column2: [
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-		bind: {
-		    emptyText: '{ring0EmptyText}',
-		    allowBlank: '{!info.ring0Needed}'
-		},
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		name: 'link0'
-	    },
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		bind: {
-		    disabled: '{!info.ring1Possible}',
-		    allowBlank: '{!info.ring1Needed}',
-		},
-		name: 'link1'
-	    }
-	],
-	columnB: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Fingerprint'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.fp}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'fingerprint'
-	    }
-	]
-    }]
-});
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-	var me = this;
-	me.loginData = loginData;
-	Proxmox.Utils.setAuthData(loginData);
-
-	var rt = me.down('pveResourceTree');
-	rt.setDatacenterText(loginData.clustername);
-
-	if (loginData.cap) {
-	    Ext.state.Manager.set('GuiCap', loginData.cap);
-	}
-	me.response401count = 0;
-
-	me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-	var me = this;
-
-	Proxmox.Utils.authClear();
-	Proxmox.UserName = null;
-	me.loginData = null;
-
-	if (!me.login) {
-	    me.login = Ext.create('PVE.window.LoginWindow', {
-		handler: function(data) {
-		    me.login = null;
-		    me.updateLoginData(data);
-		    Proxmox.Utils.checked_command(function() {}); // display subscription status
-		}
-	    });
-	}
-	me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.tip.QuickTipManager.init();
-
-	// fixme: what about other errors
-	Ext.Ajax.on('requestexception', function(conn, response, options) {
-	    if (response.status == 401 && !PVE.Utils.silenceAuthFailures) { // auth failure
-		// don't immediately show as logged out to cope better with some big
-		// upgrades, which may temporarily produce a false positive 401 err
-		me.response401count++;
-		if (me.response401count > 5) {
-		    me.showLogin();
-		}
-	    }
-	});
-
-	me.callParent();
-
-        if (!Proxmox.Utils.authOK()) {
-	    me.showLogin();
-	} else { 
-	    if (me.loginData) {
-		me.onLogin(me.loginData);
-	    }
-	}
-
-	Ext.TaskManager.start({
-	    run: function() {
-		var ticket = Proxmox.Utils.authOK();
-		if (!ticket || !Proxmox.UserName) {
-		    return;
-		}
-
-		Ext.Ajax.request({
-		    params: { 
-			username: Proxmox.UserName,
-			password: ticket
-		    },
-		    url: '/api2/json/access/ticket',
-		    method: 'POST',
-		    success: function(response, opts) {
-			var obj = Ext.decode(response.responseText);
-			me.updateLoginData(obj.data);
-		    }
-		});
-	    },
-	    interval: 15*60*1000
-	});
-
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-	var me = this;
-	
-	var cont = me.child('#content');
-
-	var lay = cont.getLayout();
-
-	var cur = lay.getActiveItem();
-
-	if (comp) {
-	    Proxmox.Utils.setErrorMask(cont, false);
-	    comp.border = false;
-	    cont.add(comp);
-	    if (cur !== null && lay.getNext()) {
-		lay.next();
-		var task = Ext.create('Ext.util.DelayedTask', function(){
-		    cont.remove(cur);
-		});
-		task.delay(10);
-	    }
-	}
-	else {
-	    // helper for cleaning the content when logging out
-	    cont.removeAll();
-	}
-    },
-
-    selectById: function(nodeid) {
-	var me = this;
-	var tree = me.down('pveResourceTree');
-	tree.selectById(nodeid);
-    },
-
-    onLogin: function(loginData) {
-	var me = this;
-
-	me.updateUserInfo();
-
-	if (loginData) {
-	    PVE.data.ResourceStore.startUpdate();
-
-	    Proxmox.Utils.API2Request({
-		url: '/version',
-		method: 'GET',
-		success: function(response) {
-		    PVE.VersionInfo = response.result.data;
-		    me.updateVersionInfo();
-		}
-	    });
-	}
-    },
-
-    updateUserInfo: function() {
-	var me = this;
-	var ui = me.query('#userinfo')[0];
-	ui.setText(Proxmox.UserName || '');
-	ui.updateLayout();
-    },
-
-    updateVersionInfo: function() {
-	var me = this;
-
-	var ui = me.query('#versioninfo')[0];
-
-	if (PVE.VersionInfo) {
-	    var version = PVE.VersionInfo.version;
-	    ui.update('Virtual Environment ' + version);
-	} else {
-	    ui.update('Virtual Environment');
-	}
-	ui.updateLayout();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.History.init();
-
-	var sprovider = Ext.create('PVE.StateProvider');
-	Ext.state.Manager.setProvider(sprovider);
-
-	var selview = Ext.create('PVE.form.ViewSelector');
-
-	var rtree = Ext.createWidget('pveResourceTree', {
-	    viewFilter: selview.getViewFilter(),
-	    flex: 1,
-	    selModel: {
-		selType: 'treemodel',
-		listeners: {
-		    selectionchange: function(sm, selected) {
-			if (selected.length > 0) {
-			    var n = selected[0];
-			    var tlckup = {
-				root: 'PVE.dc.Config',
-				node: 'PVE.node.Config',
-				qemu: 'PVE.qemu.Config',
-				lxc: 'PVE.lxc.Config',
-				storage: 'PVE.storage.Browser',
-				pool: 'pvePoolConfig'
-			    };
-			    var comp = {
-				xtype: tlckup[n.data.type || 'root'] || 
-				    'pvePanelConfig',
-				showSearch: (n.data.id === 'root') ||
-				    Ext.isDefined(n.data.groupbyid),
-				pveSelNode: n,
-				workspace: me,
-				viewFilter: selview.getViewFilter()
-			    };
-			    PVE.curSelectedNode = n;
-			    me.setContent(comp);
-			}
-		    }
-		}
-	    }
-	});
-
-	selview.on('select', function(combo, records) { 
-	    if (records) {
-		var view = combo.getViewFilter();
-		rtree.setViewFilter(view);
-	    }
-	});
-
-	var caps = sprovider.get('GuiCap');
-
-	var createVM = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-desktop',
-	    text: gettext("Create VM"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	var createCT = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-cube',
-	    text: gettext("Create CT"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	sprovider.on('statechange', function(sp, key, value) {
-	    if (key === 'GuiCap' && value) {
-		caps = value;
-		createVM.setDisabled(!caps.vms['VM.Allocate']);
-		createCT.setDisabled(!caps.vms['VM.Allocate']);
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		{
-		    region: 'north',
-		    layout: { 
-			type: 'hbox',
-			align: 'middle'
-		    },
-		    baseCls: 'x-plain',		
-		    defaults: {
-			baseCls: 'x-plain'			
-		    },
-		    border: false,
-		    margin: '2 0 2 5',
-		    items: [
-			{
-			    html: '<a class="x-unselectable" target=_blank href="https://www.proxmox.com">' +
-				'<img style="padding-top:4px;padding-right:5px" src="/pve2/images/proxmox_logo.png"/></a>'
-			},
-			{
-			    minWidth: 150,
-			    id: 'versioninfo',
-			    html: 'Virtual Environment'
-			},
-			{
-			    xtype: 'pveGlobalSearchField',
-			    tree: rtree
-			},
-			{
-			    flex: 1
-			},
-			{
-			    xtype: 'proxmoxHelpButton',
-			    hidden: false,
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
-			    listenToGlobalEvent: false,
-			    onlineHelp: 'pve_documentation_index',
-			    text: gettext('Documentation'),
-			    margin: '0 5 0 0'
-			},
-			createVM, 
-			createCT,
-			{
-			    pack: 'end',
-			    margin: '0 5 0 0',
-			    id: 'userinfo',
-			    xtype: 'button',
-			    baseCls: 'x-btn',
-			    style: {
-				// proxmox dark grey p light grey as border
-				backgroundColor: '#464d4d',
-				borderColor: '#ABBABA'
-			    },
-			    iconCls: 'fa fa-user',
-			    menu: [
-				{
-				    iconCls: 'fa fa-gear',
-				    text: gettext('My Settings'),
-				    handler: function() {
-					var win = Ext.create('PVE.window.Settings');
-					win.show();
-				    }
-				},
-				{
-				    text: gettext('Password'),
-				    iconCls: 'fa fa-fw fa-key',
-				    handler: function() {
-					var win = Ext.create('Proxmox.window.PasswordEdit', {
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				{
-				    text: 'TFA',
-				    iconCls: 'fa fa-fw fa-lock',
-				    handler: function(btn, event, rec) {
-					var win = Ext.create('PVE.window.TFAEdit',{
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				'-',
-				{
-				    iconCls: 'fa fa-fw fa-sign-out',
-				    text: gettext("Logout"),
-				    handler: function() {
-					PVE.data.ResourceStore.loadData([], false);
-					me.showLogin();
-					me.setContent(null);
-					var rt = me.down('pveResourceTree');
-					rt.setDatacenterText(undefined);
-					rt.clearTree();
-
-					// empty the stores of the StatusPanel child items
-					var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
-					Ext.Array.forEach(statusPanels, function(comp) {
-					    if (comp.getStore()) {
-						comp.getStore().loadData([], false);
-					    }
-					});
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    region: 'center',
-		    stateful: true,
-		    stateId: 'pvecenter',
-		    minWidth: 100,
-		    minHeight: 100,
-		    id: 'content',
-		    xtype: 'container',
-		    layout: { type: 'card' },
-		    border: false,
-		    margin: '0 5 0 0',
-		    items: []
-		},
-		{
-		    region: 'west',
-		    stateful: true,
-		    stateId: 'pvewest',
-		    itemId: 'west',
-		    xtype: 'container',
-		    border: false,
-		    layout: { type: 'vbox', align: 'stretch' },
-		    margin: '0 0 0 5',
-		    split: true,
-		    width: 200,
-		    items: [ selview, rtree ],
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewWidth = me.getSize().width;
-			    if (width > viewWidth - 100) {
-				panel.setWidth(viewWidth - 100);
-			    }
-			}
-		    }
-		},
-		{
-		    xtype: 'pveStatusPanel',
-		    stateful: true,
-		    stateId: 'pvesouth',
-		    itemId: 'south',
-		    region: 'south',
-		    margin:'0 5 5 5',
-		    title: gettext('Logs'),
-		    collapsible: true,
-		    header: false,
-		    height: 200,
-		    split:true,
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewHeight = me.getSize().height;
-			    if (height > (viewHeight - 150)) {
-				panel.setHeight(viewHeight - 150);
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.updateUserInfo();
-
-	// on resize, center all modal windows
-	Ext.on('resize', function(){
-	    var wins = Ext.ComponentQuery.query('window[modal]');
-	    if (wins.length > 0) {
-		wins.forEach(function(win){
-		    win.alignTo(me, 'c-c');
-		});
-	    }
-	});
-    }
-});
-
diff --git a/serverside/jsmod/6.1-3.sh b/serverside/jsmod/6.1-3.sh
deleted file mode 100644
index b0575a848da95d01fc6a53e187626c2a927ef104..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.1-3.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-Say () {
-    printf "\e[1;34m $1  \e[0m \n";
-}
-
-DotSay () {
-    printf "[\e[1;34m*\e[0m] \e[1;34m $1  \e[0m \n"; 
-}
-
-
-Say '[PVE Discord Dark UI Theme JSMOD Installer]'
-Say 'Internet connection REQUIRED.'
-Say '!!ONLY FOR PVE 6.0-4 - 6.1-x!!'
-Say '>Press any key to begin installation'
-read -p ""
-Say ' '
-DotSay 'Backing up files'
-cp /usr/share/pve-manager/js/pvemanagerlib.js /usr/share/pve-manager/js/pvemanagerlib.js.bak 
-cp /usr/share/javascript/extjs/charts.js /usr/share/javascript/extjs/charts.js.bak
-cp /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.bak
-DotSay 'Modding files'
-#replace white with #23272a
-sed -i -e "s/'white'/'#23272a'/g" /usr/share/pve-manager/js/pvemanagerlib.js
-
-#Proxmox changed nothing here to last version, so we can use it without modifications
-rm /usr/share/javascript/extjs/charts.js
-wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/serverside/jsmod/6.0-4/charts.js -P /usr/share/javascript/extjs/ &> /dev/null 
-
-sed -i -e "s/#c2ddf2/#7289DA/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
-sed -i -e "s/#f5f5f5/#2C2F33/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
-
-DotSay 'Applied patch successfully.'
-Say ''
-Say 'Installation finished!'
-Say 'o7'  
diff --git a/serverside/jsmod/6.1-3/charts.js b/serverside/jsmod/6.1-3/charts.js
deleted file mode 100644
index 713bec3b2c8b56c8dac86cc7955bb464a438bf3d..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.1-3/charts.js
+++ /dev/null
@@ -1,22013 +0,0 @@
-Ext.define("Ext.draw.ContainerBase", {
-    extend: "Ext.panel.Panel",
-    requires: ["Ext.window.Window"],
-    previewTitleText: "Chart Preview",
-    previewAltText: "Chart preview",
-    layout: "container",
-    addElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.on.apply(b.el, a)
-        } else {
-            b.on("render", function() {
-                b.el.on.apply(b.el, a)
-            })
-        }
-    },
-    removeElementListener: function() {
-        var b = this,
-            a = arguments;
-        if (b.rendered) {
-            b.el.un.apply(b.el, a)
-        }
-    },
-    afterRender: function() {
-        this.callParent(arguments);
-        this.initAnimator()
-    },
-    getItems: function() {
-        var b = this,
-            a = b.items;
-        if (!a || !a.isMixedCollection) {
-            b.initItems()
-        }
-        return b.items
-    },
-    onRender: function() {
-        this.callParent(arguments);
-        this.element = this.el;
-        this.innerElement = this.body
-    },
-    setItems: function(a) {
-        this.items = a;
-        return a
-    },
-    setSurfaceSize: function(b, a) {
-        this.resizeHandler({
-            width: b,
-            height: a
-        });
-        this.renderFrame()
-    },
-    onResize: function(c, a, b, e) {
-        var d = this;
-        d.callParent([c, a, b, e]);
-        d.setBodySize({
-            width: c,
-            height: a
-        })
-    },
-    preview: function() {
-        var a = this.getImage();
-        new Ext.window.Window({
-            title: this.previewTitleText,
-            closeable: true,
-            renderTo: Ext.getBody(),
-            autoShow: true,
-            maximizeable: true,
-            maximized: true,
-            border: true,
-            layout: {
-                type: "hbox",
-                pack: "center",
-                align: "middle"
-            },
-            items: {
-                xtype: "container",
-                items: {
-                    xtype: "image",
-                    mode: "img",
-                    cls: Ext.baseCSSPrefix + "chart-image",
-                    alt: this.previewAltText,
-                    src: a.data,
-                    listeners: {
-                        afterrender: function() {
-                            var e = this,
-                                b = e.imgEl.dom,
-                                d = a.type === "svg" ? 1 : (window.devicePixelRatio || 1),
-                                c;
-                            if (!b.naturalWidth || !b.naturalHeight) {
-                                b.onload = function() {
-                                    var g = b.naturalWidth,
-                                        f = b.naturalHeight;
-                                    e.setWidth(Math.floor(g / d));
-                                    e.setHeight(Math.floor(f / d))
-                                }
-                            } else {
-                                c = e.getSize();
-                                e.setWidth(Math.floor(c.width / d));
-                                e.setHeight(Math.floor(c.height / d))
-                            }
-                        }
-                    }
-                }
-            }
-        })
-    },
-    privates: {
-        getTargetEl: function() {
-            return this.innerElement
-        },
-        reattachToBody: function() {
-            var a = this;
-            if (a.pendingDetachSize) {
-                a.onBodyResize()
-            }
-            a.pendingDetachSize = false;
-            a.callParent()
-        }
-    }
-});
-Ext.define("Ext.draw.SurfaceBase", {
-    extend: "Ext.Widget",
-    getOwnerBody: function() {
-        return this.ownerCt.body
-    },
-    destroy: function() {
-        var a = this;
-        if (a.hasListeners.destroy) {
-            a.fireEvent("destroy", a)
-        }
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.Color", {
-    statics: {
-        colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbToHexRe: /\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
-        rgbaToHexRe: /\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,
-        hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,
-        NONE: "none",
-        RGBA_NONE: "rgba(0, 0, 0, 0)"
-    },
-    isColor: true,
-    lightnessFactor: 0.2,
-    constructor: function(d, b, a, c) {
-        this.setRGB(d, b, a, c)
-    },
-    setRGB: function(e, c, a, d) {
-        var b = this;
-        b.r = Math.min(255, Math.max(0, e));
-        b.g = Math.min(255, Math.max(0, c));
-        b.b = Math.min(255, Math.max(0, a));
-        if (d === undefined) {
-            b.a = 1
-        } else {
-            b.a = Math.min(1, Math.max(0, d))
-        }
-    },
-    getGrayscale: function() {
-        return this.r * 0.3 + this.g * 0.59 + this.b * 0.11
-    },
-    getHSL: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            m = k - d,
-            e, n = 0,
-            c = 0.5 * (k + d);
-        if (d !== k) {
-            n = (c <= 0.5) ? m / (k + d) : m / (2 - k - d);
-            if (a === k) {
-                e = 60 * (f - j) / m
-            } else {
-                if (f === k) {
-                    e = 120 + 60 * (j - a) / m
-                } else {
-                    e = 240 + 60 * (a - f) / m
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, n, c]
-    },
-    getHSV: function() {
-        var i = this,
-            a = i.r / 255,
-            f = i.g / 255,
-            j = i.b / 255,
-            k = Math.max(a, f, j),
-            d = Math.min(a, f, j),
-            c = k - d,
-            e, m = 0,
-            l = k;
-        if (d != k) {
-            m = l ? c / l : 0;
-            if (a === k) {
-                e = 60 * (f - j) / c
-            } else {
-                if (f === k) {
-                    e = 60 * (j - a) / c + 120
-                } else {
-                    e = 60 * (a - f) / c + 240
-                }
-            }
-            if (e < 0) {
-                e += 360
-            }
-            if (e >= 360) {
-                e -= 360
-            }
-        }
-        return [e, m, l]
-    },
-    setHSL: function(g, f, e) {
-        var i = this,
-            d = Math.abs,
-            j, b, a;
-        g = (g % 360 + 360) % 360;
-        f = f > 1 ? 1 : f < 0 ? 0 : f;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        if (f === 0 || g === null) {
-            e *= 255;
-            i.setRGB(e, e, e)
-        } else {
-            g /= 60;
-            j = f * (1 - d(2 * e - 1));
-            b = j * (1 - d(g % 2 - 1));
-            a = e - j / 2;
-            a *= 255;
-            j *= 255;
-            b *= 255;
-            switch (Math.floor(g)) {
-                case 0:
-                    i.setRGB(j + a, b + a, a);
-                    break;
-                case 1:
-                    i.setRGB(b + a, j + a, a);
-                    break;
-                case 2:
-                    i.setRGB(a, j + a, b + a);
-                    break;
-                case 3:
-                    i.setRGB(a, b + a, j + a);
-                    break;
-                case 4:
-                    i.setRGB(b + a, a, j + a);
-                    break;
-                case 5:
-                    i.setRGB(j + a, a, b + a);
-                    break
-            }
-        }
-        return i
-    },
-    setHSV: function(f, e, d) {
-        var g = this,
-            i, b, a;
-        f = (f % 360 + 360) % 360;
-        e = e > 1 ? 1 : e < 0 ? 0 : e;
-        d = d > 1 ? 1 : d < 0 ? 0 : d;
-        if (e === 0 || f === null) {
-            d *= 255;
-            g.setRGB(d, d, d)
-        } else {
-            f /= 60;
-            i = d * e;
-            b = i * (1 - Math.abs(f % 2 - 1));
-            a = d - i;
-            a *= 255;
-            i *= 255;
-            b *= 255;
-            switch (Math.floor(f)) {
-                case 0:
-                    g.setRGB(i + a, b + a, a);
-                    break;
-                case 1:
-                    g.setRGB(b + a, i + a, a);
-                    break;
-                case 2:
-                    g.setRGB(a, i + a, b + a);
-                    break;
-                case 3:
-                    g.setRGB(a, b + a, i + a);
-                    break;
-                case 4:
-                    g.setRGB(b + a, a, i + a);
-                    break;
-                case 5:
-                    g.setRGB(i + a, a, b + a);
-                    break
-            }
-        }
-        return g
-    },
-    createLighter: function(b) {
-        if (!b && b !== 0) {
-            b = this.lightnessFactor
-        }
-        var a = this.getHSL();
-        a[2] = Ext.Number.constrain(a[2] + b, 0, 1);
-        return Ext.draw.Color.fromHSL(a[0], a[1], a[2])
-    },
-    createDarker: function(a) {
-        if (!a && a !== 0) {
-            a = this.lightnessFactor
-        }
-        return this.createLighter(-a)
-    },
-    toString: function() {
-        var f = this,
-            c = Math.round;
-        if (f.a === 1) {
-            var e = c(f.r).toString(16),
-                d = c(f.g).toString(16),
-                a = c(f.b).toString(16);
-            e = (e.length === 1) ? "0" + e : e;
-            d = (d.length === 1) ? "0" + d : d;
-            a = (a.length === 1) ? "0" + a : a;
-            return ["#", e, d, a].join("")
-        } else {
-            return "rgba(" + [c(f.r), c(f.g), c(f.b), f.a === 0 ? 0 : f.a.toFixed(15)].join(", ") + ")"
-        }
-    },
-    toHex: function(b) {
-        if (Ext.isArray(b)) {
-            b = b[0]
-        }
-        if (!Ext.isString(b)) {
-            return ""
-        }
-        if (b.substr(0, 1) === "#") {
-            return b
-        }
-        var e = Ext.draw.Color.colorToHexRe.exec(b);
-        if (Ext.isArray(e)) {
-            var f = parseInt(e[2], 10),
-                d = parseInt(e[3], 10),
-                a = parseInt(e[4], 10),
-                c = a | (d << 8) | (f << 16);
-            return e[1] + "#" + ("000000" + c.toString(16)).slice(-6)
-        } else {
-            return ""
-        }
-    },
-    setFromString: function(j) {
-        var e, h, f, c, d = 1,
-            i = parseInt;
-        if (j === Ext.draw.Color.NONE) {
-            this.r = this.g = this.b = this.a = 0;
-            return this
-        }
-        if ((j.length === 4 || j.length === 7) && j.substr(0, 1) === "#") {
-            e = j.match(Ext.draw.Color.hexRe);
-            if (e) {
-                h = i(e[1], 16) >> 0;
-                f = i(e[2], 16) >> 0;
-                c = i(e[3], 16) >> 0;
-                if (j.length === 4) {
-                    h += (h * 16);
-                    f += (f * 16);
-                    c += (c * 16)
-                }
-            }
-        } else {
-            if ((e = j.match(Ext.draw.Color.rgbToHexRe))) {
-                h = +e[1];
-                f = +e[2];
-                c = +e[3]
-            } else {
-                if ((e = j.match(Ext.draw.Color.rgbaToHexRe))) {
-                    h = +e[1];
-                    f = +e[2];
-                    c = +e[3];
-                    d = +e[4]
-                } else {
-                    if (Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())) {
-                        return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])
-                    }
-                }
-            }
-        }
-        if (typeof h === "undefined") {
-            return this
-        }
-        this.r = h;
-        this.g = f;
-        this.b = c;
-        this.a = d;
-        return this
-    }
-}, function() {
-    var a = new this();
-    this.addStatics({
-        fly: function(f, e, c, d) {
-            switch (arguments.length) {
-                case 1:
-                    a.setFromString(f);
-                    break;
-                case 3:
-                case 4:
-                    a.setRGB(f, e, c, d);
-                    break;
-                default:
-                    return null
-            }
-            return a
-        },
-        ColorList: {
-            aliceblue: "#f0f8ff",
-            antiquewhite: "#faebd7",
-            aqua: "#00ffff",
-            aquamarine: "#7fffd4",
-            azure: "#f0ffff",
-            beige: "#f5f5dc",
-            bisque: "#ffe4c4",
-            black: "#000000",
-            blanchedalmond: "#ffebcd",
-            blue: "#0000ff",
-            blueviolet: "#8a2be2",
-            brown: "#a52a2a",
-            burlywood: "#deb887",
-            cadetblue: "#5f9ea0",
-            chartreuse: "#7fff00",
-            chocolate: "#d2691e",
-            coral: "#ff7f50",
-            cornflowerblue: "#6495ed",
-            cornsilk: "#fff8dc",
-            crimson: "#dc143c",
-            cyan: "#00ffff",
-            darkblue: "#00008b",
-            darkcyan: "#008b8b",
-            darkgoldenrod: "#b8860b",
-            darkgray: "#a9a9a9",
-            darkgreen: "#006400",
-            darkkhaki: "#bdb76b",
-            darkmagenta: "#8b008b",
-            darkolivegreen: "#556b2f",
-            darkorange: "#ff8c00",
-            darkorchid: "#9932cc",
-            darkred: "#8b0000",
-            darksalmon: "#e9967a",
-            darkseagreen: "#8fbc8f",
-            darkslateblue: "#483d8b",
-            darkslategray: "#2f4f4f",
-            darkturquoise: "#00ced1",
-            darkviolet: "#9400d3",
-            deeppink: "#ff1493",
-            deepskyblue: "#00bfff",
-            dimgray: "#696969",
-            dodgerblue: "#1e90ff",
-            firebrick: "#b22222",
-            floralwhite: "#fffaf0",
-            forestgreen: "#228b22",
-            fuchsia: "#ff00ff",
-            gainsboro: "#dcdcdc",
-            ghostwhite: "#f8f8ff",
-            gold: "#ffd700",
-            goldenrod: "#daa520",
-            gray: "#808080",
-            green: "#008000",
-            greenyellow: "#adff2f",
-            honeydew: "#f0fff0",
-            hotpink: "#ff69b4",
-            indianred: "#cd5c5c",
-            indigo: "#4b0082",
-            ivory: "#fffff0",
-            khaki: "#f0e68c",
-            lavender: "#e6e6fa",
-            lavenderblush: "#fff0f5",
-            lawngreen: "#7cfc00",
-            lemonchiffon: "#fffacd",
-            lightblue: "#add8e6",
-            lightcoral: "#f08080",
-            lightcyan: "#e0ffff",
-            lightgoldenrodyellow: "#fafad2",
-            lightgray: "#d3d3d3",
-            lightgrey: "#d3d3d3",
-            lightgreen: "#90ee90",
-            lightpink: "#ffb6c1",
-            lightsalmon: "#ffa07a",
-            lightseagreen: "#20b2aa",
-            lightskyblue: "#87cefa",
-            lightslategray: "#778899",
-            lightsteelblue: "#b0c4de",
-            lightyellow: "#ffffe0",
-            lime: "#00ff00",
-            limegreen: "#32cd32",
-            linen: "#faf0e6",
-            magenta: "#ff00ff",
-            maroon: "#800000",
-            mediumaquamarine: "#66cdaa",
-            mediumblue: "#0000cd",
-            mediumorchid: "#ba55d3",
-            mediumpurple: "#9370d8",
-            mediumseagreen: "#3cb371",
-            mediumslateblue: "#7b68ee",
-            mediumspringgreen: "#00fa9a",
-            mediumturquoise: "#48d1cc",
-            mediumvioletred: "#c71585",
-            midnightblue: "#191970",
-            mintcream: "#f5fffa",
-            mistyrose: "#ffe4e1",
-            moccasin: "#ffe4b5",
-            navajowhite: "#ffdead",
-            navy: "#000080",
-            oldlace: "#fdf5e6",
-            olive: "#808000",
-            olivedrab: "#6b8e23",
-            orange: "#ffa500",
-            orangered: "#ff4500",
-            orchid: "#da70d6",
-            palegoldenrod: "#eee8aa",
-            palegreen: "#98fb98",
-            paleturquoise: "#afeeee",
-            palevioletred: "#d87093",
-            papayawhip: "#ffefd5",
-            peachpuff: "#ffdab9",
-            peru: "#cd853f",
-            pink: "#ffc0cb",
-            plum: "#dda0dd",
-            powderblue: "#b0e0e6",
-            purple: "#800080",
-            red: "#ff0000",
-            rosybrown: "#bc8f8f",
-            royalblue: "#4169e1",
-            saddlebrown: "#8b4513",
-            salmon: "#fa8072",
-            sandybrown: "#f4a460",
-            seagreen: "#2e8b57",
-            seashell: "#fff5ee",
-            sienna: "#a0522d",
-            silver: "#c0c0c0",
-            skyblue: "#87ceeb",
-            slateblue: "#6a5acd",
-            slategray: "#708090",
-            snow: "#fffafa",
-            springgreen: "#00ff7f",
-            steelblue: "#4682b4",
-            tan: "#d2b48c",
-            teal: "#008080",
-            thistle: "#d8bfd8",
-            tomato: "#ff6347",
-            turquoise: "#40e0d0",
-            violet: "#ee82ee",
-            wheat: "#f5deb3",
-            white: "#ffffff",
-            whitesmoke: "#f5f5f5",
-            yellow: "#ffff00",
-            yellowgreen: "#9acd32"
-        },
-        fromHSL: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromHSV: function(d, c, b) {
-            return (new this(0, 0, 0, 0)).setHSL(d, c, b)
-        },
-        fromString: function(b) {
-            return (new this(0, 0, 0, 0)).setFromString(b)
-        },
-        create: function(b) {
-            if (b instanceof this) {
-                return b
-            } else {
-                if (Ext.isArray(b)) {
-                    return new Ext.draw.Color(b[0], b[1], b[2], b[3])
-                } else {
-                    if (Ext.isString(b)) {
-                        return Ext.draw.Color.fromString(b)
-                    } else {
-                        if (arguments.length > 2) {
-                            return new Ext.draw.Color(arguments[0], arguments[1], arguments[2], arguments[3])
-                        } else {
-                            return new Ext.draw.Color(0, 0, 0, 0)
-                        }
-                    }
-                }
-            }
-        }
-    })
-});
-Ext.define("Ext.draw.sprite.AnimationParser", function() {
-    function a(d, c, b) {
-        return d + (c - d) * b
-    }
-    return {
-        singleton: true,
-        attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-        requires: ["Ext.draw.Color"],
-        color: {
-            parseInitial: function(c, b) {
-                if (Ext.isString(c)) {
-                    c = Ext.draw.Color.create(c)
-                }
-                if (Ext.isString(b)) {
-                    b = Ext.draw.Color.create(b)
-                }
-                if ((c instanceof Ext.draw.Color) && (b instanceof Ext.draw.Color)) {
-                    return [
-                        [c.r, c.g, c.b, c.a],
-                        [b.r, b.g, b.b, b.a]
-                    ]
-                } else {
-                    return [c || b, b || c]
-                }
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isArray(d) || !Ext.isArray(c)) {
-                    return c || d
-                } else {
-                    return [a(d[0], c[0], b), a(d[1], c[1], b), a(d[2], c[2], b), a(d[3], c[3], b)]
-                }
-            },
-            serve: function(c) {
-                var b = Ext.draw.Color.fly(c[0], c[1], c[2], c[3]);
-                return b.toString()
-            }
-        },
-        number: {
-            parse: function(b) {
-                return b === null ? null : +b
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        angle: {
-            parseInitial: function(c, b) {
-                if (b - c > Math.PI) {
-                    b -= Math.PI * 2
-                } else {
-                    if (b - c < -Math.PI) {
-                        b += Math.PI * 2
-                    }
-                }
-                return [c, b]
-            },
-            compute: function(d, c, b) {
-                if (!Ext.isNumber(d) || !Ext.isNumber(c)) {
-                    return c || d
-                } else {
-                    return a(d, c, b)
-                }
-            }
-        },
-        path: {
-            parseInitial: function(m, n) {
-                var c = m.toStripes(),
-                    o = n.toStripes(),
-                    e, d, k = c.length,
-                    p = o.length,
-                    h, f, b, g = o[p - 1],
-                    l = [g[g.length - 2], g[g.length - 1]];
-                for (e = k; e < p; e++) {
-                    c.push(c[k - 1].slice(0))
-                }
-                for (e = p; e < k; e++) {
-                    o.push(l.slice(0))
-                }
-                b = c.length;
-                o.path = n;
-                o.temp = new Ext.draw.Path();
-                for (e = 0; e < b; e++) {
-                    h = c[e];
-                    f = o[e];
-                    k = h.length;
-                    p = f.length;
-                    o.temp.commands.push("M");
-                    for (d = p; d < k; d += 6) {
-                        f.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    g = o[o.length - 1];
-                    l = [g[g.length - 2], g[g.length - 1]];
-                    for (d = k; d < p; d += 6) {
-                        h.push(l[0], l[1], l[0], l[1], l[0], l[1])
-                    }
-                    for (e = 0; e < f.length; e++) {
-                        f[e] -= h[e]
-                    }
-                    for (e = 2; e < f.length; e += 6) {
-                        o.temp.commands.push("C")
-                    }
-                }
-                return [c, o]
-            },
-            compute: function(c, l, m) {
-                if (m >= 1) {
-                    return l.path
-                }
-                var e = 0,
-                    f = c.length,
-                    d = 0,
-                    b, k, h, n = l.temp.params,
-                    g = 0;
-                for (; e < f; e++) {
-                    k = c[e];
-                    h = l[e];
-                    b = k.length;
-                    for (d = 0; d < b; d++) {
-                        n[g++] = h[d] * m + k[d]
-                    }
-                }
-                return l.temp
-            }
-        },
-        data: {
-            compute: function(h, j, k, g) {
-                var m = h.length - 1,
-                    b = j.length - 1,
-                    e = Math.max(m, b),
-                    d, l, c;
-                if (!g || g === h) {
-                    g = []
-                }
-                g.length = e + 1;
-                for (c = 0; c <= e; c++) {
-                    d = h[Math.min(c, m)];
-                    l = j[Math.min(c, b)];
-                    if (Ext.isNumber(d)) {
-                        if (!Ext.isNumber(l)) {
-                            l = 0
-                        }
-                        g[c] = (l - d) * k + d
-                    } else {
-                        g[c] = l
-                    }
-                }
-                return g
-            }
-        },
-        text: {
-            compute: function(d, c, b) {
-                return d.substr(0, Math.round(d.length * (1 - b))) + c.substr(Math.round(c.length * (1 - b)))
-            }
-        },
-        limited: "number",
-        limited01: "number"
-    }
-});
-(function() {
-    if (!Ext.global.Float32Array) {
-        var a = function(d) {
-            if (typeof d === "number") {
-                this.length = d
-            } else {
-                if ("length" in d) {
-                    this.length = d.length;
-                    for (var c = 0, b = d.length; c < b; c++) {
-                        this[c] = +d[c]
-                    }
-                }
-            }
-        };
-        a.prototype = [];
-        Ext.global.Float32Array = a
-    }
-})();
-Ext.define("Ext.draw.Draw", {
-    singleton: true,
-    radian: Math.PI / 180,
-    pi2: Math.PI * 2,
-    reflectFn: function(b) {
-        return b
-    },
-    rad: function(a) {
-        return (a % 360) * this.radian
-    },
-    degrees: function(a) {
-        return (a / this.radian) % 360
-    },
-    isBBoxIntersect: function(b, a, c) {
-        c = c || 0;
-        return (Math.max(b.x, a.x) - c > Math.min(b.x + b.width, a.x + a.width)) || (Math.max(b.y, a.y) - c > Math.min(b.y + b.height, a.y + a.height))
-    },
-    isPointInBBox: function(a, c, b) {
-        return !!b && a >= b.x && a <= (b.x + b.width) && c >= b.y && c <= (b.y + b.height)
-    },
-    spline: function(m) {
-        var e, c, k = m.length,
-            b, h, l, f, a = 0,
-            g = new Float32Array(m.length),
-            n = new Float32Array(m.length * 3 - 2);
-        g[0] = 0;
-        g[k - 1] = 0;
-        for (e = 1; e < k - 1; e++) {
-            g[e] = (m[e + 1] + m[e - 1] - 2 * m[e]) - g[e - 1];
-            a = 1 / (4 - a);
-            g[e] *= a
-        }
-        for (e = k - 2; e > 0; e--) {
-            a = 3.732050807568877 + 48.248711305964385 / (-13.928203230275537 + Math.pow(0.07179676972449123, e));
-            g[e] -= g[e + 1] * a
-        }
-        f = m[0];
-        b = f - g[0];
-        for (e = 0, c = 0; e < k - 1; c += 3) {
-            l = f;
-            h = b;
-            e++;
-            f = m[e];
-            b = f - g[e];
-            n[c] = l;
-            n[c + 1] = (b + 2 * h) / 3;
-            n[c + 2] = (b * 2 + h) / 3
-        }
-        n[c] = f;
-        return n
-    },
-    getAnchors: function(e, d, i, h, t, s, o) {
-        o = o || 4;
-        var n = Math.PI,
-            p = n / 2,
-            k = Math.abs,
-            a = Math.sin,
-            b = Math.cos,
-            f = Math.atan,
-            r, q, g, j, m, l, v, u, c;
-        r = (i - e) / o;
-        q = (t - i) / o;
-        if ((h >= d && h >= s) || (h <= d && h <= s)) {
-            g = j = p
-        } else {
-            g = f((i - e) / k(h - d));
-            if (d < h) {
-                g = n - g
-            }
-            j = f((t - i) / k(h - s));
-            if (s < h) {
-                j = n - j
-            }
-        }
-        c = p - ((g + j) % (n * 2)) / 2;
-        if (c > p) {
-            c -= n
-        }
-        g += c;
-        j += c;
-        m = i - r * a(g);
-        l = h + r * b(g);
-        v = i + q * a(j);
-        u = h + q * b(j);
-        if ((h > d && l < d) || (h < d && l > d)) {
-            m += k(d - l) * (m - i) / (l - h);
-            l = d
-        }
-        if ((h > s && u < s) || (h < s && u > s)) {
-            v -= k(s - u) * (v - i) / (u - h);
-            u = s
-        }
-        return {
-            x1: m,
-            y1: l,
-            x2: v,
-            y2: u
-        }
-    },
-    smooth: function(l, j, o) {
-        var k = l.length,
-            h, g, c, b, q, p, n, m, f = [],
-            e = [],
-            d, a;
-        for (d = 0; d < k - 1; d++) {
-            h = l[d];
-            g = j[d];
-            if (d === 0) {
-                n = h;
-                m = g;
-                f.push(n);
-                e.push(m);
-                if (k === 1) {
-                    break
-                }
-            }
-            c = l[d + 1];
-            b = j[d + 1];
-            q = l[d + 2];
-            p = j[d + 2];
-            if (!Ext.isNumber(q + p)) {
-                f.push(n, c, c);
-                e.push(m, b, b);
-                break
-            }
-            a = this.getAnchors(h, g, c, b, q, p, o);
-            f.push(n, a.x1, c);
-            e.push(m, a.y1, b);
-            n = a.x2;
-            m = a.y2
-        }
-        return {
-            smoothX: f,
-            smoothY: e
-        }
-    },
-    beginUpdateIOS: Ext.os.is.iOS ? function() {
-        this.iosUpdateEl = Ext.getBody().createChild({
-            style: "position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"
-        })
-    } : Ext.emptyFn,
-    endUpdateIOS: function() {
-        this.iosUpdateEl = Ext.destroy(this.iosUpdateEl)
-    }
-});
-Ext.define("Ext.draw.gradient.Gradient", {
-    requires: ["Ext.draw.Color"],
-    isGradient: true,
-    config: {
-        stops: []
-    },
-    applyStops: function(f) {
-        var e = [],
-            d = f.length,
-            c, b, a;
-        for (c = 0; c < d; c++) {
-            b = f[c];
-            a = b.color;
-            if (!(a && a.isColor)) {
-                a = Ext.draw.Color.fly(a || Ext.draw.Color.NONE)
-            }
-            e.push({
-                offset: Math.min(1, Math.max(0, "offset" in b ? b.offset : b.position || 0)),
-                color: a.toString()
-            })
-        }
-        e.sort(function(h, g) {
-            return h.offset - g.offset
-        });
-        return e
-    },
-    onClassExtended: function(a, b) {
-        if (!b.alias && b.type) {
-            b.alias = "gradient." + b.type
-        }
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    generateGradient: Ext.emptyFn
-});
-Ext.define("Ext.draw.gradient.GradientDefinition", {
-    singleton: true,
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    gradients: {},
-    add: function(a) {
-        var b = this.gradients,
-            c, e, d;
-        for (c = 0, e = a.length; c < e; c++) {
-            d = a[c];
-            if (Ext.isString(d.id)) {
-                b[d.id] = d
-            }
-        }
-    },
-    get: function(d) {
-        var a = this.gradients,
-            b = d.match(this.urlStringRe),
-            c;
-        if (b && b[1] && (c = a[b[1]])) {
-            return c || d
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeParser", {
-    singleton: true,
-    attributeRe: /^url\(#([a-zA-Z\-]+)\)$/,
-    requires: ["Ext.draw.Color", "Ext.draw.gradient.GradientDefinition"],
-    "default": Ext.identityFn,
-    string: function(a) {
-        return String(a)
-    },
-    number: function(a) {
-        if (Ext.isNumber(+a)) {
-            return a
-        }
-    },
-    angle: function(a) {
-        if (Ext.isNumber(a)) {
-            a %= Math.PI * 2;
-            if (a < -Math.PI) {
-                a += Math.PI * 2
-            } else {
-                if (a >= Math.PI) {
-                    a -= Math.PI * 2
-                }
-            }
-            return a
-        }
-    },
-    data: function(a) {
-        if (Ext.isArray(a)) {
-            return a.slice()
-        } else {
-            if (a instanceof Float32Array) {
-                return new Float32Array(a)
-            }
-        }
-    },
-    bool: function(a) {
-        return !!a
-    },
-    color: function(a) {
-        if (a instanceof Ext.draw.Color) {
-            return a.toString()
-        } else {
-            if (a instanceof Ext.draw.gradient.Gradient) {
-                return a
-            } else {
-                if (!a) {
-                    return Ext.draw.Color.NONE
-                } else {
-                    if (Ext.isString(a)) {
-                        if (a.substr(0, 3) === "url") {
-                            a = Ext.draw.gradient.GradientDefinition.get(a);
-                            if (Ext.isString(a)) {
-                                return a
-                            }
-                        } else {
-                            return Ext.draw.Color.fly(a).toString()
-                        }
-                    }
-                }
-            }
-        }
-        if (a.type === "linear") {
-            return Ext.create("Ext.draw.gradient.Linear", a)
-        } else {
-            if (a.type === "radial") {
-                return Ext.create("Ext.draw.gradient.Radial", a)
-            } else {
-                if (a.type === "pattern") {
-                    return Ext.create("Ext.draw.gradient.Pattern", a)
-                } else {
-                    return Ext.draw.Color.NONE
-                }
-            }
-        }
-    },
-    limited: function(a, b) {
-        return function(c) {
-            c = +c;
-            return Ext.isNumber(c) ? Math.min(Math.max(c, a), b) : undefined
-        }
-    },
-    limited01: function(a) {
-        a = +a;
-        return Ext.isNumber(a) ? Math.min(Math.max(a, 0), 1) : undefined
-    },
-    enums: function() {
-        var d = {},
-            a = Array.prototype.slice.call(arguments, 0),
-            b, c;
-        for (b = 0, c = a.length; b < c; b++) {
-            d[a[b]] = true
-        }
-        return function(e) {
-            return e in d ? e : undefined
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.AttributeDefinition", {
-    requires: ["Ext.draw.sprite.AttributeParser", "Ext.draw.sprite.AnimationParser"],
-    config: {
-        defaults: {
-            $value: {},
-            lazy: true
-        },
-        aliases: {},
-        animationProcessors: {},
-        processors: {
-            $value: {},
-            lazy: true
-        },
-        dirtyTriggers: {},
-        triggers: {},
-        updaters: {}
-    },
-    inheritableStatics: {
-        processorFactoryRe: /^(\w+)\(([\w\-,]*)\)$/
-    },
-    spriteClass: null,
-    constructor: function(a) {
-        var b = this;
-        b.initConfig(a)
-    },
-    applyDefaults: function(b, a) {
-        a = Ext.apply(a || {}, this.normalize(b));
-        return a
-    },
-    applyAliases: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    applyProcessors: function(e, i) {
-        this.getAnimationProcessors();
-        var j = i || {},
-            h = Ext.draw.sprite.AttributeParser,
-            a = this.self.processorFactoryRe,
-            g = {},
-            d, b, c, f;
-        for (b in e) {
-            f = e[b];
-            if (typeof f === "string") {
-                c = f.match(a);
-                if (c) {
-                    f = h[c[1]].apply(h, c[2].split(","))
-                } else {
-                    if (h[f]) {
-                        g[b] = f;
-                        d = true;
-                        f = h[f]
-                    }
-                }
-            }
-            j[b] = f
-        }
-        if (d) {
-            this.setAnimationProcessors(g)
-        }
-        return j
-    },
-    applyAnimationProcessors: function(c, a) {
-        var e = Ext.draw.sprite.AnimationParser,
-            b, d;
-        if (!a) {
-            a = {}
-        }
-        for (b in c) {
-            d = c[b];
-            if (d === "none") {
-                a[b] = null
-            } else {
-                if (Ext.isString(d) && !(b in a)) {
-                    if (d in e) {
-                        while (Ext.isString(e[d])) {
-                            d = e[d]
-                        }
-                        a[b] = e[d]
-                    }
-                } else {
-                    if (Ext.isObject(d)) {
-                        a[b] = d
-                    }
-                }
-            }
-        }
-        return a
-    },
-    updateDirtyTriggers: function(a) {
-        this.setTriggers(a)
-    },
-    applyTriggers: function(b, c) {
-        if (!c) {
-            c = {}
-        }
-        for (var a in b) {
-            c[a] = b[a].split(",")
-        }
-        return c
-    },
-    applyUpdaters: function(b, a) {
-        return Ext.apply(a || {}, b)
-    },
-    batchedNormalize: function(f, n) {
-        if (!f) {
-            return {}
-        }
-        var j = this.getProcessors(),
-            d = this.getAliases(),
-            a = f.translation || f.translate,
-            o = {},
-            g, h, b, e, p, c, m, l, k;
-        if ("rotation" in f) {
-            p = f.rotation
-        } else {
-            p = ("rotate" in f) ? f.rotate : undefined
-        }
-        if ("scaling" in f) {
-            c = f.scaling
-        } else {
-            c = ("scale" in f) ? f.scale : undefined
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                o.scalingX = c;
-                o.scalingY = c
-            } else {
-                if ("x" in c) {
-                    o.scalingX = c.x
-                }
-                if ("y" in c) {
-                    o.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    o.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    o.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof p !== "undefined") {
-            if (Ext.isNumber(p)) {
-                p = Ext.draw.Draw.rad(p);
-                o.rotationRads = p
-            } else {
-                if ("rads" in p) {
-                    o.rotationRads = p.rads
-                } else {
-                    if ("degrees" in p) {
-                        if (Ext.isArray(p.degrees)) {
-                            o.rotationRads = Ext.Array.map(p.degrees, function(i) {
-                                return Ext.draw.Draw.rad(i)
-                            })
-                        } else {
-                            o.rotationRads = Ext.draw.Draw.rad(p.degrees)
-                        }
-                    }
-                }
-                if ("centerX" in p) {
-                    o.rotationCenterX = p.centerX
-                }
-                if ("centerY" in p) {
-                    o.rotationCenterY = p.centerY
-                }
-            }
-        }
-        if (typeof a !== "undefined") {
-            if ("x" in a) {
-                o.translationX = a.x
-            }
-            if ("y" in a) {
-                o.translationY = a.y
-            }
-        }
-        if ("matrix" in f) {
-            m = Ext.draw.Matrix.create(f.matrix);
-            k = m.split();
-            o.matrix = m;
-            o.rotationRads = k.rotation;
-            o.rotationCenterX = 0;
-            o.rotationCenterY = 0;
-            o.scalingX = k.scaleX;
-            o.scalingY = k.scaleY;
-            o.scalingCenterX = 0;
-            o.scalingCenterY = 0;
-            o.translationX = k.translateX;
-            o.translationY = k.translateY
-        }
-        for (b in f) {
-            e = f[b];
-            if (typeof e === "undefined") {
-                continue
-            } else {
-                if (Ext.isArray(e)) {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        o[b] = [];
-                        for (g = 0, h = e.length; g < h; g++) {
-                            l = j[b].call(this, e[g]);
-                            if (typeof l !== "undefined") {
-                                o[b][g] = l
-                            }
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                } else {
-                    if (b in d) {
-                        b = d[b]
-                    }
-                    if (b in j) {
-                        e = j[b].call(this, e);
-                        if (typeof e !== "undefined") {
-                            o[b] = e
-                        }
-                    } else {
-                        if (n) {
-                            o[b] = e
-                        }
-                    }
-                }
-            }
-        }
-        return o
-    },
-    normalize: function(i, j) {
-        if (!i) {
-            return {}
-        }
-        var f = this.getProcessors(),
-            d = this.getAliases(),
-            a = i.translation || i.translate,
-            k = {},
-            b, e, l, c, h, g;
-        if ("rotation" in i) {
-            l = i.rotation
-        } else {
-            l = ("rotate" in i) ? i.rotate : undefined
-        }
-        if ("scaling" in i) {
-            c = i.scaling
-        } else {
-            c = ("scale" in i) ? i.scale : undefined
-        }
-        if (a) {
-            if ("x" in a) {
-                k.translationX = a.x
-            }
-            if ("y" in a) {
-                k.translationY = a.y
-            }
-        }
-        if (typeof c !== "undefined") {
-            if (Ext.isNumber(c)) {
-                k.scalingX = c;
-                k.scalingY = c
-            } else {
-                if ("x" in c) {
-                    k.scalingX = c.x
-                }
-                if ("y" in c) {
-                    k.scalingY = c.y
-                }
-                if ("centerX" in c) {
-                    k.scalingCenterX = c.centerX
-                }
-                if ("centerY" in c) {
-                    k.scalingCenterY = c.centerY
-                }
-            }
-        }
-        if (typeof l !== "undefined") {
-            if (Ext.isNumber(l)) {
-                l = Ext.draw.Draw.rad(l);
-                k.rotationRads = l
-            } else {
-                if ("rads" in l) {
-                    k.rotationRads = l.rads
-                } else {
-                    if ("degrees" in l) {
-                        k.rotationRads = Ext.draw.Draw.rad(l.degrees)
-                    }
-                }
-                if ("centerX" in l) {
-                    k.rotationCenterX = l.centerX
-                }
-                if ("centerY" in l) {
-                    k.rotationCenterY = l.centerY
-                }
-            }
-        }
-        if ("matrix" in i) {
-            h = Ext.draw.Matrix.create(i.matrix);
-            g = h.split();
-            k.matrix = h;
-            k.rotationRads = g.rotation;
-            k.rotationCenterX = 0;
-            k.rotationCenterY = 0;
-            k.scalingX = g.scaleX;
-            k.scalingY = g.scaleY;
-            k.scalingCenterX = 0;
-            k.scalingCenterY = 0;
-            k.translationX = g.translateX;
-            k.translationY = g.translateY
-        }
-        for (b in i) {
-            e = i[b];
-            if (typeof e === "undefined") {
-                continue
-            }
-            if (b in d) {
-                b = d[b]
-            }
-            if (b in f) {
-                e = f[b].call(this, e);
-                if (typeof e !== "undefined") {
-                    k[b] = e
-                }
-            } else {
-                if (j) {
-                    k[b] = e
-                }
-            }
-        }
-        return k
-    },
-    setBypassingNormalization: function(a, c, b) {
-        return c.pushDown(a, b)
-    },
-    set: function(a, c, b) {
-        b = this.normalize(b);
-        return this.setBypassingNormalization(a, c, b)
-    }
-});
-Ext.define("Ext.draw.Matrix", {
-    isMatrix: true,
-    statics: {
-        createAffineMatrixFromTwoPair: function(h, t, g, s, k, o, i, j) {
-            var v = g - h,
-                u = s - t,
-                e = i - k,
-                q = j - o,
-                d = 1 / (v * v + u * u),
-                p = v * e + u * q,
-                n = e * u - v * q,
-                m = -p * h - n * t,
-                l = n * h - p * t;
-            return new this(p * d, -n * d, n * d, p * d, m * d + k, l * d + o)
-        },
-        createPanZoomFromTwoPair: function(q, e, p, c, h, s, n, g) {
-            if (arguments.length === 2) {
-                return this.createPanZoomFromTwoPair.apply(this, q.concat(e))
-            }
-            var k = p - q,
-                j = c - e,
-                d = (q + p) * 0.5,
-                b = (e + c) * 0.5,
-                o = n - h,
-                a = g - s,
-                f = (h + n) * 0.5,
-                l = (s + g) * 0.5,
-                m = k * k + j * j,
-                i = o * o + a * a,
-                t = Math.sqrt(i / m);
-            return new this(t, 0, 0, t, f - t * d, l - t * b)
-        },
-        fly: (function() {
-            var a = null,
-                b = function(c) {
-                    a.elements = c;
-                    return a
-                };
-            return function(c) {
-                if (!a) {
-                    a = new Ext.draw.Matrix()
-                }
-                a.elements = c;
-                Ext.draw.Matrix.fly = b;
-                return a
-            }
-        })(),
-        create: function(a) {
-            if (a instanceof this) {
-                return a
-            }
-            return new this(a)
-        }
-    },
-    constructor: function(e, d, a, f, c, b) {
-        if (e && e.length === 6) {
-            this.elements = e.slice()
-        } else {
-            if (e !== undefined) {
-                this.elements = [e, d, a, f, c, b]
-            } else {
-                this.elements = [1, 0, 0, 1, 0, 0]
-            }
-        }
-    },
-    prepend: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + h * j;
-        b[1] = l * d + g * j;
-        b[2] = a * e + h * c;
-        b[3] = l * e + g * c;
-        b[4] = a * i + h * f + m;
-        b[5] = l * i + g * f + k;
-        return this
-    },
-    prependMatrix: function(a) {
-        return this.prepend.apply(this, a.elements)
-    },
-    append: function(a, l, h, g, m, k) {
-        var b = this.elements,
-            d = b[0],
-            j = b[1],
-            e = b[2],
-            c = b[3],
-            i = b[4],
-            f = b[5];
-        b[0] = a * d + l * e;
-        b[1] = a * j + l * c;
-        b[2] = h * d + g * e;
-        b[3] = h * j + g * c;
-        b[4] = m * d + k * e + i;
-        b[5] = m * j + k * c + f;
-        return this
-    },
-    appendMatrix: function(a) {
-        return this.append.apply(this, a.elements)
-    },
-    set: function(f, e, a, g, c, b) {
-        var d = this.elements;
-        d[0] = f;
-        d[1] = e;
-        d[2] = a;
-        d[3] = g;
-        d[4] = c;
-        d[5] = b;
-        return this
-    },
-    inverse: function(i) {
-        var g = this.elements,
-            o = g[0],
-            m = g[1],
-            l = g[2],
-            k = g[3],
-            j = g[4],
-            h = g[5],
-            n = 1 / (o * k - m * l);
-        o *= n;
-        m *= n;
-        l *= n;
-        k *= n;
-        if (i) {
-            i.set(k, -m, -l, o, l * h - k * j, m * j - o * h);
-            return i
-        } else {
-            return new Ext.draw.Matrix(k, -m, -l, o, l * h - k * j, m * j - o * h)
-        }
-    },
-    translate: function(a, c, b) {
-        if (b) {
-            return this.prepend(1, 0, 0, 1, a, c)
-        } else {
-            return this.append(1, 0, 0, 1, a, c)
-        }
-    },
-    scale: function(f, e, c, a, b) {
-        var d = this;
-        if (e == null) {
-            e = f
-        }
-        if (c === undefined) {
-            c = 0
-        }
-        if (a === undefined) {
-            a = 0
-        }
-        if (b) {
-            return d.prepend(f, 0, 0, e, c - c * f, a - a * e)
-        } else {
-            return d.append(f, 0, 0, e, c - c * f, a - a * e)
-        }
-    },
-    rotate: function(g, e, c, b) {
-        var d = this,
-            f = Math.cos(g),
-            a = Math.sin(g);
-        e = e || 0;
-        c = c || 0;
-        if (b) {
-            return d.prepend(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        } else {
-            return d.append(f, a, -a, f, e - f * e + c * a, c - f * c - e * a)
-        }
-    },
-    rotateFromVector: function(a, h, c) {
-        var e = this,
-            g = Math.sqrt(a * a + h * h),
-            f = a / g,
-            b = h / g;
-        if (c) {
-            return e.prepend(f, b, -b, f, 0, 0)
-        } else {
-            return e.append(f, b, -b, f, 0, 0)
-        }
-    },
-    clone: function() {
-        return new Ext.draw.Matrix(this.elements)
-    },
-    flipX: function() {
-        return this.append(-1, 0, 0, 1, 0, 0)
-    },
-    flipY: function() {
-        return this.append(1, 0, 0, -1, 0, 0)
-    },
-    skewX: function(a) {
-        return this.append(1, 0, Math.tan(a), 1, 0, 0)
-    },
-    skewY: function(a) {
-        return this.append(1, Math.tan(a), 0, 1, 0, 0)
-    },
-    shearX: function(a) {
-        return this.append(1, 0, a, 1, 0, 0)
-    },
-    shearY: function(a) {
-        return this.append(1, a, 0, 1, 0, 0)
-    },
-    reset: function() {
-        return this.set(1, 0, 0, 1, 0, 0)
-    },
-    precisionCompensate: function(j, g) {
-        var c = this.elements,
-            f = c[0],
-            e = c[1],
-            i = c[2],
-            h = c[3],
-            d = c[4],
-            b = c[5],
-            a = e * i - f * h;
-        g.b = j * e / f;
-        g.c = j * i / h;
-        g.d = j;
-        g.xx = f / j;
-        g.yy = h / j;
-        g.dx = (b * f * i - d * f * h) / a / j;
-        g.dy = (d * e * h - b * f * h) / a / j
-    },
-    precisionCompensateRect: function(j, g) {
-        var b = this.elements,
-            f = b[0],
-            e = b[1],
-            i = b[2],
-            h = b[3],
-            c = b[4],
-            a = b[5],
-            d = i / f;
-        g.b = j * e / f;
-        g.c = j * d;
-        g.d = j * h / f;
-        g.xx = f / j;
-        g.yy = f / j;
-        g.dx = (a * i - c * h) / (e * d - h) / j;
-        g.dy = -(a * f - c * e) / (e * d - h) / j
-    },
-    x: function(a, c) {
-        var b = this.elements;
-        return a * b[0] + c * b[2] + b[4]
-    },
-    y: function(a, c) {
-        var b = this.elements;
-        return a * b[1] + c * b[3] + b[5]
-    },
-    get: function(b, a) {
-        return +this.elements[b + a * 2].toFixed(4)
-    },
-    transformPoint: function(b) {
-        var c = this.elements,
-            a, d;
-        if (b.isPoint) {
-            a = b.x;
-            d = b.y
-        } else {
-            a = b[0];
-            d = b[1]
-        }
-        return [a * c[0] + d * c[2] + c[4], a * c[1] + d * c[3] + c[5]]
-    },
-    transformBBox: function(q, i, j) {
-        var b = this.elements,
-            d = q.x,
-            r = q.y,
-            g = q.width * 0.5,
-            o = q.height * 0.5,
-            a = b[0],
-            s = b[1],
-            n = b[2],
-            k = b[3],
-            e = d + g,
-            c = r + o,
-            p, f, m;
-        if (i) {
-            g -= i;
-            o -= i;
-            m = [Math.sqrt(b[0] * b[0] + b[2] * b[2]), Math.sqrt(b[1] * b[1] + b[3] * b[3])];
-            p = Math.abs(g * a) + Math.abs(o * n) + Math.abs(m[0] * i);
-            f = Math.abs(g * s) + Math.abs(o * k) + Math.abs(m[1] * i)
-        } else {
-            p = Math.abs(g * a) + Math.abs(o * n);
-            f = Math.abs(g * s) + Math.abs(o * k)
-        }
-        if (!j) {
-            j = {}
-        }
-        j.x = e * a + c * n + b[4] - p;
-        j.y = e * s + c * k + b[5] - f;
-        j.width = p + p;
-        j.height = f + f;
-        return j
-    },
-    transformList: function(e) {
-        var b = this.elements,
-            a = b[0],
-            h = b[2],
-            l = b[4],
-            k = b[1],
-            g = b[3],
-            j = b[5],
-            f = e.length,
-            c, d;
-        for (d = 0; d < f; d++) {
-            c = e[d];
-            e[d] = [c[0] * a + c[1] * h + l, c[0] * k + c[1] * g + j]
-        }
-        return e
-    },
-    isIdentity: function() {
-        var a = this.elements;
-        return a[0] === 1 && a[1] === 0 && a[2] === 0 && a[3] === 1 && a[4] === 0 && a[5] === 0
-    },
-    isEqual: function(a) {
-        var c = a && a.isMatrix ? a.elements : a,
-            b = this.elements;
-        return b[0] === c[0] && b[1] === c[1] && b[2] === c[2] && b[3] === c[3] && b[4] === c[4] && b[5] === c[5]
-    },
-    equals: function(a) {
-        return this.isEqual(a)
-    },
-    toArray: function() {
-        var a = this.elements;
-        return [a[0], a[2], a[4], a[1], a[3], a[5]]
-    },
-    toVerticalArray: function() {
-        return this.elements.slice()
-    },
-    toString: function() {
-        var a = this;
-        return [a.get(0, 0), a.get(0, 1), a.get(1, 0), a.get(1, 1), a.get(2, 0), a.get(2, 1)].join(",")
-    },
-    toContext: function(a) {
-        a.transform.apply(a, this.elements);
-        return this
-    },
-    toSvg: function() {
-        var a = this.elements;
-        return "matrix(" + a[0].toFixed(9) + "," + a[1].toFixed(9) + "," + a[2].toFixed(9) + "," + a[3].toFixed(9) + "," + a[4].toFixed(9) + "," + a[5].toFixed(9) + ")"
-    },
-    getScaleX: function() {
-        var a = this.elements;
-        return Math.sqrt(a[0] * a[0] + a[2] * a[2])
-    },
-    getScaleY: function() {
-        var a = this.elements;
-        return Math.sqrt(a[1] * a[1] + a[3] * a[3])
-    },
-    getXX: function() {
-        return this.elements[0]
-    },
-    getXY: function() {
-        return this.elements[1]
-    },
-    getYX: function() {
-        return this.elements[2]
-    },
-    getYY: function() {
-        return this.elements[3]
-    },
-    getDX: function() {
-        return this.elements[4]
-    },
-    getDY: function() {
-        return this.elements[5]
-    },
-    split: function() {
-        var b = this.elements,
-            d = b[0],
-            c = b[1],
-            e = b[3],
-            a = {
-                translateX: b[4],
-                translateY: b[5]
-            };
-        a.rotate = a.rotation = Math.atan2(c, d);
-        a.scaleX = d / Math.cos(a.rotate);
-        a.scaleY = e / d * a.scaleX;
-        return a
-    }
-}, function() {
-    function b(e, c, d) {
-        e[c] = {
-            get: function() {
-                return this.elements[d]
-            },
-            set: function(f) {
-                this.elements[d] = f
-            }
-        }
-    }
-    if (Object.defineProperties) {
-        var a = {};
-        b(a, "a", 0);
-        b(a, "b", 1);
-        b(a, "c", 2);
-        b(a, "d", 3);
-        b(a, "e", 4);
-        b(a, "f", 5);
-        Object.defineProperties(this.prototype, a)
-    }
-    this.prototype.multiply = this.prototype.appendMatrix
-});
-Ext.define("Ext.draw.modifier.Modifier", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        previous: null,
-        next: null,
-        sprite: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    updateNext: function(a) {
-        if (a) {
-            a.setPrevious(this)
-        }
-    },
-    updatePrevious: function(a) {
-        if (a) {
-            a.setNext(this)
-        }
-    },
-    prepareAttributes: function(a) {
-        if (this._previous) {
-            this._previous.prepareAttributes(a)
-        }
-    },
-    popUp: function(a, b) {
-        if (this._next) {
-            this._next.popUp(a, b)
-        } else {
-            Ext.apply(a, b)
-        }
-    },
-    pushDown: function(a, c) {
-        if (this._previous) {
-            return this._previous.pushDown(a, c)
-        } else {
-            for (var b in c) {
-                if (c[b] === a[b]) {
-                    delete c[b]
-                }
-            }
-            return c
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Target", {
-    requires: ["Ext.draw.Matrix"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.target",
-    statics: {
-        uniqueId: 0
-    },
-    prepareAttributes: function(a) {
-        var b = this.getPrevious();
-        if (b) {
-            b.prepareAttributes(a)
-        }
-        a.attributeId = "attribute-" + Ext.draw.modifier.Target.uniqueId++;
-        if (!a.hasOwnProperty("canvasAttributes")) {
-            a.bbox = {
-                plain: {
-                    dirty: true
-                },
-                transform: {
-                    dirty: true
-                }
-            };
-            a.dirty = true;
-            a.pendingUpdaters = {};
-            a.canvasAttributes = {};
-            a.matrix = new Ext.draw.Matrix();
-            a.inverseMatrix = new Ext.draw.Matrix()
-        }
-    },
-    applyChanges: function(f, k) {
-        Ext.apply(f, k);
-        var l = this.getSprite(),
-            o = f.pendingUpdaters,
-            h = l.self.def.getTriggers(),
-            p, a, m, b, e, n, d, c, g;
-        for (b in k) {
-            e = true;
-            if ((p = h[b])) {
-                l.scheduleUpdaters(f, p, [b])
-            }
-            if (f.template && k.removeFromInstance && k.removeFromInstance[b]) {
-                delete f[b]
-            }
-        }
-        if (!e) {
-            return
-        }
-        if (o.canvas) {
-            n = o.canvas;
-            delete o.canvas;
-            for (d = 0, g = n.length; d < g; d++) {
-                b = n[d];
-                f.canvasAttributes[b] = f[b]
-            }
-        }
-        if (f.hasOwnProperty("children")) {
-            a = f.children;
-            for (d = 0, g = a.length; d < g; d++) {
-                m = a[d];
-                Ext.apply(m.pendingUpdaters, o);
-                if (n) {
-                    for (c = 0; c < n.length; c++) {
-                        b = n[c];
-                        m.canvasAttributes[b] = m[b]
-                    }
-                }
-                l.callUpdaters(m)
-            }
-        }
-        l.setDirty(true);
-        l.callUpdaters(f)
-    },
-    popUp: function(a, b) {
-        this.applyChanges(a, b)
-    },
-    pushDown: function(a, b) {
-        var c = this.getPrevious();
-        if (c) {
-            b = c.pushDown(a, b)
-        }
-        this.applyChanges(a, b);
-        return b
-    }
-});
-Ext.define("Ext.draw.TimingFunctions", function() {
-    var g = Math.pow,
-        j = Math.sin,
-        m = Math.cos,
-        l = Math.sqrt,
-        e = Math.PI,
-        b = ["quad", "cube", "quart", "quint"],
-        c = {
-            pow: function(o, i) {
-                return g(o, i || 6)
-            },
-            expo: function(i) {
-                return g(2, 8 * (i - 1))
-            },
-            circ: function(i) {
-                return 1 - l(1 - i * i)
-            },
-            sine: function(i) {
-                return 1 - j((1 - i) * e / 2)
-            },
-            back: function(i, o) {
-                o = o || 1.616;
-                return i * i * ((o + 1) * i - o)
-            },
-            bounce: function(q) {
-                for (var o = 0, i = 1; 1; o += i, i /= 2) {
-                    if (q >= (7 - 4 * o) / 11) {
-                        return i * i - g((11 - 6 * o - 11 * q) / 4, 2)
-                    }
-                }
-            },
-            elastic: function(o, i) {
-                return g(2, 10 * --o) * m(20 * o * e * (i || 1) / 3)
-            }
-        },
-        k = {},
-        a, f, d;
-
-    function h(i) {
-        return function(o) {
-            return g(o, i)
-        }
-    }
-
-    function n(i, o) {
-        k[i + "In"] = function(p) {
-            return o(p)
-        };
-        k[i + "Out"] = function(p) {
-            return 1 - o(1 - p)
-        };
-        k[i + "InOut"] = function(p) {
-            return (p <= 0.5) ? o(2 * p) / 2 : (2 - o(2 * (1 - p))) / 2
-        }
-    }
-    for (d = 0, f = b.length; d < f; ++d) {
-        c[b[d]] = h(d + 2)
-    }
-    for (a in c) {
-        n(a, c[a])
-    }
-    k.linear = Ext.identityFn;
-    k.easeIn = k.quadIn;
-    k.easeOut = k.quadOut;
-    k.easeInOut = k.quadInOut;
-    return {
-        singleton: true,
-        easingMap: k
-    }
-}, function(a) {
-    Ext.apply(a, a.easingMap)
-});
-Ext.define("Ext.draw.Animator", {
-    uses: ["Ext.draw.Draw"],
-    singleton: true,
-    frameCallbacks: {},
-    frameCallbackId: 0,
-    scheduled: 0,
-    frameStartTimeOffset: Ext.now(),
-    animations: [],
-    running: false,
-    animationTime: function() {
-        return Ext.AnimationQueue.frameStartTime - this.frameStartTimeOffset
-    },
-    add: function(b) {
-        var a = this;
-        if (!a.contains(b)) {
-            a.animations.push(b);
-            a.ignite();
-            if ("fireEvent" in b) {
-                b.fireEvent("animationstart", b)
-            }
-        }
-    },
-    remove: function(d) {
-        var c = this,
-            e = c.animations,
-            b = 0,
-            a = e.length;
-        for (; b < a; ++b) {
-            if (e[b] === d) {
-                e.splice(b, 1);
-                if ("fireEvent" in d) {
-                    d.fireEvent("animationend", d)
-                }
-                return
-            }
-        }
-    },
-    contains: function(a) {
-        return Ext.Array.indexOf(this.animations, a) > -1
-    },
-    empty: function() {
-        return this.animations.length === 0
-    },
-    step: function(d) {
-        var c = this,
-            f = c.animations,
-            e, a = 0,
-            b = f.length;
-        for (; a < b; a++) {
-            e = f[a];
-            e.step(d);
-            if (!e.animating) {
-                f.splice(a, 1);
-                a--;
-                b--;
-                if (e.fireEvent) {
-                    e.fireEvent("animationend", e)
-                }
-            }
-        }
-    },
-    schedule: function(c, a) {
-        a = a || this;
-        var b = "frameCallback" + (this.frameCallbackId++);
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a,
-            once: true
-        };
-        this.scheduled++;
-        Ext.draw.Animator.ignite();
-        return b
-    },
-    scheduleIf: function(e, b) {
-        b = b || this;
-        var c = Ext.draw.Animator.frameCallbacks,
-            a, d;
-        if (Ext.isString(e)) {
-            e = b[e]
-        }
-        for (d in c) {
-            a = c[d];
-            if (a.once && a.fn === e && a.scope === b) {
-                return null
-            }
-        }
-        return this.schedule(e, b)
-    },
-    cancel: function(a) {
-        if (Ext.draw.Animator.frameCallbacks[a] && Ext.draw.Animator.frameCallbacks[a].once) {
-            this.scheduled--;
-            delete Ext.draw.Animator.frameCallbacks[a]
-        }
-    },
-    addFrameCallback: function(c, a) {
-        a = a || this;
-        if (Ext.isString(c)) {
-            c = a[c]
-        }
-        var b = "frameCallback" + (this.frameCallbackId++);
-        Ext.draw.Animator.frameCallbacks[b] = {
-            fn: c,
-            scope: a
-        };
-        return b
-    },
-    removeFrameCallback: function(a) {
-        delete Ext.draw.Animator.frameCallbacks[a]
-    },
-    fireFrameCallbacks: function() {
-        var c = this.frameCallbacks,
-            d, b, a;
-        for (d in c) {
-            a = c[d];
-            b = a.fn;
-            if (Ext.isString(b)) {
-                b = a.scope[b]
-            }
-            b.call(a.scope);
-            if (c[d] && a.once) {
-                this.scheduled--;
-                delete c[d]
-            }
-        }
-    },
-    handleFrame: function() {
-        this.step(this.animationTime());
-        this.fireFrameCallbacks();
-        if (!this.scheduled && this.empty()) {
-            Ext.AnimationQueue.stop(this.handleFrame, this);
-            this.running = false;
-            Ext.draw.Draw.endUpdateIOS()
-        }
-    },
-    ignite: function() {
-        if (!this.running) {
-            this.running = true;
-            Ext.AnimationQueue.start(this.handleFrame, this);
-            Ext.draw.Draw.beginUpdateIOS()
-        }
-    }
-});
-Ext.define("Ext.draw.modifier.Animation", {
-    requires: ["Ext.draw.TimingFunctions", "Ext.draw.Animator"],
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.animation",
-    config: {
-        easing: Ext.identityFn,
-        duration: 0,
-        customEasings: {},
-        customDurations: {},
-        customDuration: null
-    },
-    constructor: function(a) {
-        var b = this;
-        b.anyAnimation = b.anySpecialAnimations = false;
-        b.animating = 0;
-        b.animatingPool = [];
-        b.callParent([a])
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("timers")) {
-            a.animating = false;
-            a.timers = {};
-            a.animationOriginal = Ext.Object.chain(a);
-            a.animationOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.animationOriginal)
-        }
-    },
-    updateSprite: function(a) {
-        this.setConfig(a.config.fx)
-    },
-    updateDuration: function(a) {
-        this.anyAnimation = a > 0
-    },
-    applyEasing: function(a) {
-        if (typeof a === "string") {
-            a = Ext.draw.TimingFunctions.easingMap[a]
-        }
-        return a
-    },
-    applyCustomEasings: function(a, e) {
-        e = e || {};
-        var g, d, b, h, c, f;
-        for (d in a) {
-            g = true;
-            h = a[d];
-            b = d.split(",");
-            if (typeof h === "string") {
-                h = Ext.draw.TimingFunctions.easingMap[h]
-            }
-            for (c = 0, f = b.length; c < f; c++) {
-                e[b[c]] = h
-            }
-        }
-        if (g) {
-            this.anySpecialAnimations = g
-        }
-        return e
-    },
-    setEasingOn: function(a, e) {
-        a = Ext.Array.from(a).slice();
-        var c = {},
-            d = a.length,
-            b = 0;
-        for (; b < d; b++) {
-            c[a[b]] = e
-        }
-        this.setCustomEasings(c)
-    },
-    clearEasingOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customEasings[a[b]]
-        }
-    },
-    applyCustomDurations: function(g, h) {
-        h = h || {};
-        var e, c, f, a, b, d;
-        for (c in g) {
-            e = true;
-            f = g[c];
-            a = c.split(",");
-            for (b = 0, d = a.length; b < d; b++) {
-                h[a[b]] = f
-            }
-        }
-        if (e) {
-            this.anySpecialAnimations = e
-        }
-        return h
-    },
-    applyCustomDuration: function(a, b) {
-        if (a) {
-            this.getCustomDurations();
-            this.setCustomDurations(a)
-        }
-    },
-    setDurationOn: function(b, e) {
-        b = Ext.Array.from(b).slice();
-        var a = {},
-            c = 0,
-            d = b.length;
-        for (; c < d; c++) {
-            a[b[c]] = e
-        }
-        this.setCustomDurations(a)
-    },
-    clearDurationOn: function(a) {
-        a = Ext.Array.from(a, true);
-        var b = 0,
-            c = a.length;
-        for (; b < c; b++) {
-            delete this._customDurations[a[b]]
-        }
-    },
-    setAnimating: function(a, b) {
-        var e = this,
-            d = e.animatingPool;
-        if (a.animating !== b) {
-            a.animating = b;
-            if (b) {
-                d.push(a);
-                if (e.animating === 0) {
-                    Ext.draw.Animator.add(e)
-                }
-                e.animating++
-            } else {
-                for (var c = d.length; c--;) {
-                    if (d[c] === a) {
-                        d.splice(c, 1)
-                    }
-                }
-                e.animating = d.length
-            }
-        }
-    },
-    setAttrs: function(r, t) {
-        var s = this,
-            m = r.timers,
-            h = s._sprite.self.def._animationProcessors,
-            f = s._easing,
-            e = s._duration,
-            j = s._customDurations,
-            i = s._customEasings,
-            g = s.anySpecialAnimations,
-            n = s.anyAnimation || g,
-            o = r.animationOriginal,
-            d = false,
-            k, u, l, p, c, q, a;
-        if (!n) {
-            for (u in t) {
-                if (r[u] === t[u]) {
-                    delete t[u]
-                } else {
-                    r[u] = t[u]
-                }
-                delete o[u];
-                delete m[u]
-            }
-            return t
-        } else {
-            for (u in t) {
-                l = t[u];
-                p = r[u];
-                if (l !== p && p !== undefined && p !== null && (c = h[u])) {
-                    q = f;
-                    a = e;
-                    if (g) {
-                        if (u in i) {
-                            q = i[u]
-                        }
-                        if (u in j) {
-                            a = j[u]
-                        }
-                    }
-                    if (p && p.isGradient || l && l.isGradient) {
-                        a = 0
-                    }
-                    if (a) {
-                        if (!m[u]) {
-                            m[u] = {}
-                        }
-                        k = m[u];
-                        k.start = 0;
-                        k.easing = q;
-                        k.duration = a;
-                        k.compute = c.compute;
-                        k.serve = c.serve || Ext.identityFn;
-                        k.remove = t.removeFromInstance && t.removeFromInstance[u];
-                        if (c.parseInitial) {
-                            var b = c.parseInitial(p, l);
-                            k.source = b[0];
-                            k.target = b[1]
-                        } else {
-                            if (c.parse) {
-                                k.source = c.parse(p);
-                                k.target = c.parse(l)
-                            } else {
-                                k.source = p;
-                                k.target = l
-                            }
-                        }
-                        o[u] = l;
-                        delete t[u];
-                        d = true;
-                        continue
-                    } else {
-                        delete o[u]
-                    }
-                } else {
-                    delete o[u]
-                }
-                delete m[u]
-            }
-        }
-        if (d && !r.animating) {
-            s.setAnimating(r, true)
-        }
-        return t
-    },
-    updateAttributes: function(g) {
-        if (!g.animating) {
-            return {}
-        }
-        var h = {},
-            e = false,
-            d = g.timers,
-            f = g.animationOriginal,
-            c = Ext.draw.Animator.animationTime(),
-            a, b, i;
-        if (g.lastUpdate === c) {
-            return null
-        }
-        for (a in d) {
-            b = d[a];
-            if (!b.start) {
-                b.start = c;
-                i = 0
-            } else {
-                i = (c - b.start) / b.duration
-            }
-            if (i >= 1) {
-                h[a] = f[a];
-                delete f[a];
-                if (d[a].remove) {
-                    h.removeFromInstance = h.removeFromInstance || {};
-                    h.removeFromInstance[a] = true
-                }
-                delete d[a]
-            } else {
-                h[a] = b.serve(b.compute(b.source, b.target, b.easing(i), g[a]));
-                e = true
-            }
-        }
-        g.lastUpdate = c;
-        this.setAnimating(g, e);
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.animationOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    },
-    step: function(g) {
-        var f = this,
-            c = f.animatingPool.slice(),
-            e = c.length,
-            b = 0,
-            a, d;
-        for (; b < e; b++) {
-            a = c[b];
-            d = f.updateAttributes(a);
-            if (d && f._next) {
-                f._next.popUp(a, d)
-            }
-        }
-    },
-    stop: function() {
-        this.step();
-        var d = this,
-            b = d.animatingPool,
-            a, c;
-        for (a = 0, c = b.length; a < c; a++) {
-            b[a].animating = false
-        }
-        d.animatingPool.length = 0;
-        d.animating = 0;
-        Ext.draw.Animator.remove(d)
-    },
-    destroy: function() {
-        this.animatingPool.length = 0;
-        this.animating = 0;
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.modifier.Highlight", {
-    extend: "Ext.draw.modifier.Modifier",
-    alias: "modifier.highlight",
-    config: {
-        enabled: false,
-        highlightStyle: null
-    },
-    preFx: true,
-    applyHighlightStyle: function(b, a) {
-        a = a || {};
-        if (this.getSprite()) {
-            Ext.apply(a, this.getSprite().self.def.normalize(b))
-        } else {
-            Ext.apply(a, b)
-        }
-        return a
-    },
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("highlightOriginal")) {
-            a.highlighted = false;
-            a.highlightOriginal = Ext.Object.chain(a);
-            a.highlightOriginal.prototype = a;
-            a.highlightOriginal.removeFromInstance = {}
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.highlightOriginal)
-        }
-    },
-    updateSprite: function(b, a) {
-        if (b) {
-            if (this.getHighlightStyle()) {
-                this._highlightStyle = b.self.def.normalize(this.getHighlightStyle())
-            }
-            this.setHighlightStyle(b.config.highlight)
-        }
-        b.self.def.setConfig({
-            defaults: {
-                highlighted: false
-            },
-            processors: {
-                highlighted: "bool"
-            }
-        });
-        this.setSprite(b)
-    },
-    filterChanges: function(a, d) {
-        var e = this,
-            f = a.highlightOriginal,
-            c = e.getHighlightStyle(),
-            b;
-        if (a.highlighted) {
-            for (b in d) {
-                if (c.hasOwnProperty(b)) {
-                    f[b] = d[b];
-                    delete d[b]
-                }
-            }
-        }
-        for (b in d) {
-            if (b !== "highlighted" && f[b] === d[b]) {
-                delete d[b]
-            }
-        }
-        return d
-    },
-    pushDown: function(e, g) {
-        var f = this.getHighlightStyle(),
-            c = e.highlightOriginal,
-            i = c.removeFromInstance,
-            d, a, h, b;
-        if (g.hasOwnProperty("highlighted")) {
-            d = g.highlighted;
-            delete g.highlighted;
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g);
-            if (d !== e.highlighted) {
-                if (d) {
-                    for (a in f) {
-                        if (a in g) {
-                            c[a] = g[a]
-                        } else {
-                            h = e.template && e.template.ownAttr;
-                            if (h && !e.prototype.hasOwnProperty(a)) {
-                                i[a] = true;
-                                c[a] = h.animationOriginal[a]
-                            } else {
-                                b = c.timers[a];
-                                if (b && b.remove) {
-                                    i[a] = true
-                                }
-                                c[a] = e[a]
-                            }
-                        }
-                        if (c[a] !== f[a]) {
-                            g[a] = f[a]
-                        }
-                    }
-                } else {
-                    for (a in f) {
-                        if (!(a in g)) {
-                            g[a] = c[a]
-                        }
-                        delete c[a]
-                    }
-                    g.removeFromInstance = g.removeFromInstance || {};
-                    Ext.apply(g.removeFromInstance, i);
-                    c.removeFromInstance = {}
-                }
-                g.highlighted = d
-            }
-        } else {
-            if (this._previous) {
-                g = this._previous.pushDown(c, g)
-            }
-            g = this.filterChanges(e, g)
-        }
-        return g
-    },
-    popUp: function(a, b) {
-        b = this.filterChanges(a, b);
-        Ext.draw.modifier.Modifier.prototype.popUp.call(this, a, b)
-    }
-});
-Ext.define("Ext.draw.sprite.Sprite", {
-    alias: "sprite.sprite",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.draw.Draw", "Ext.draw.gradient.Gradient", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.modifier.Target", "Ext.draw.modifier.Animation", "Ext.draw.modifier.Highlight"],
-    isSprite: true,
-    statics: {
-        defaultHitTestOptions: {
-            fill: true,
-            stroke: true
-        }
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                strokeStyle: "color",
-                fillStyle: "color",
-                strokeOpacity: "limited01",
-                fillOpacity: "limited01",
-                lineWidth: "number",
-                lineCap: "enums(butt,round,square)",
-                lineJoin: "enums(round,bevel,miter)",
-                lineDash: "data",
-                lineDashOffset: "number",
-                miterLimit: "number",
-                shadowColor: "color",
-                shadowOffsetX: "number",
-                shadowOffsetY: "number",
-                shadowBlur: "number",
-                globalAlpha: "limited01",
-                globalCompositeOperation: "enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",
-                hidden: "bool",
-                transformFillStroke: "bool",
-                zIndex: "number",
-                translationX: "number",
-                translationY: "number",
-                rotationRads: "number",
-                rotationCenterX: "number",
-                rotationCenterY: "number",
-                scalingX: "number",
-                scalingY: "number",
-                scalingCenterX: "number",
-                scalingCenterY: "number",
-                constrainGradients: "bool"
-            },
-            aliases: {
-                stroke: "strokeStyle",
-                fill: "fillStyle",
-                color: "fillStyle",
-                "stroke-width": "lineWidth",
-                "stroke-linecap": "lineCap",
-                "stroke-linejoin": "lineJoin",
-                "stroke-miterlimit": "miterLimit",
-                "text-anchor": "textAlign",
-                opacity: "globalAlpha",
-                translateX: "translationX",
-                translateY: "translationY",
-                rotateRads: "rotationRads",
-                rotateCenterX: "rotationCenterX",
-                rotateCenterY: "rotationCenterY",
-                scaleX: "scalingX",
-                scaleY: "scalingY",
-                scaleCenterX: "scalingCenterX",
-                scaleCenterY: "scalingCenterY"
-            },
-            defaults: {
-                hidden: false,
-                zIndex: 0,
-                strokeStyle: "none",
-                fillStyle: "none",
-                lineWidth: 1,
-                lineDash: [],
-                lineDashOffset: 0,
-                lineCap: "butt",
-                lineJoin: "miter",
-                miterLimit: 10,
-                shadowColor: "none",
-                shadowOffsetX: 0,
-                shadowOffsetY: 0,
-                shadowBlur: 0,
-                globalAlpha: 1,
-                strokeOpacity: 1,
-                fillOpacity: 1,
-                transformFillStroke: false,
-                translationX: 0,
-                translationY: 0,
-                rotationRads: 0,
-                rotationCenterX: null,
-                rotationCenterY: null,
-                scalingX: 1,
-                scalingY: 1,
-                scalingCenterX: null,
-                scalingCenterY: null,
-                constrainGradients: false
-            },
-            triggers: {
-                zIndex: "zIndex",
-                globalAlpha: "canvas",
-                globalCompositeOperation: "canvas",
-                transformFillStroke: "canvas",
-                strokeStyle: "canvas",
-                fillStyle: "canvas",
-                strokeOpacity: "canvas",
-                fillOpacity: "canvas",
-                lineWidth: "canvas",
-                lineCap: "canvas",
-                lineJoin: "canvas",
-                lineDash: "canvas",
-                lineDashOffset: "canvas",
-                miterLimit: "canvas",
-                shadowColor: "canvas",
-                shadowOffsetX: "canvas",
-                shadowOffsetY: "canvas",
-                shadowBlur: "canvas",
-                translationX: "transform",
-                translationY: "transform",
-                rotationRads: "transform",
-                rotationCenterX: "transform",
-                rotationCenterY: "transform",
-                scalingX: "transform",
-                scalingY: "transform",
-                scalingCenterX: "transform",
-                scalingCenterY: "transform",
-                constrainGradients: "canvas"
-            },
-            updaters: {
-                bbox: "bboxUpdater",
-                zIndex: function(a) {
-                    a.dirtyZIndex = true
-                },
-                transform: function(a) {
-                    a.dirtyTransform = true;
-                    a.bbox.transform.dirty = true
-                }
-            }
-        }
-    },
-    config: {
-        parent: null,
-        surface: null
-    },
-    onClassExtended: function(d, c) {
-        var b = d.superclass.self.def.initialConfig,
-            e = c.inheritableStatics && c.inheritableStatics.def,
-            a;
-        if (e) {
-            a = Ext.Object.merge({}, b, e);
-            d.def = new Ext.draw.sprite.AttributeDefinition(a);
-            delete c.inheritableStatics.def
-        } else {
-            d.def = new Ext.draw.sprite.AttributeDefinition(b)
-        }
-        d.def.spriteClass = d
-    },
-    constructor: function(b) {
-        var d = this,
-            c = d.self.def,
-            e = c.getDefaults(),
-            a;
-        b = Ext.isObject(b) ? b : {};
-        d.id = b.id || Ext.id(null, "ext-sprite-");
-        d.attr = {};
-        d.mixins.observable.constructor.apply(d, arguments);
-        a = Ext.Array.from(b.modifiers, true);
-        d.prepareModifiers(a);
-        d.initializeAttributes();
-        d.setAttributes(e, true);
-        d.setAttributes(b)
-    },
-    getDirty: function() {
-        return this.attr.dirty
-    },
-    setDirty: function(b) {
-        this.attr.dirty = b;
-        if (b) {
-            var a = this.getParent();
-            if (a) {
-                a.setDirty(true)
-            }
-        }
-    },
-    addModifier: function(a, b) {
-        var c = this;
-        if (!(a instanceof Ext.draw.modifier.Modifier)) {
-            a = Ext.factory(a, null, null, "modifier")
-        }
-        a.setSprite(c);
-        if (a.preFx || a.config && a.config.preFx) {
-            if (c.fx.getPrevious()) {
-                c.fx.getPrevious().setNext(a)
-            }
-            a.setNext(c.fx)
-        } else {
-            c.topModifier.getPrevious().setNext(a);
-            a.setNext(c.topModifier)
-        }
-        if (b) {
-            c.initializeAttributes()
-        }
-        return a
-    },
-    prepareModifiers: function(d) {
-        var c = this,
-            a, b;
-        c.topModifier = new Ext.draw.modifier.Target({
-            sprite: c
-        });
-        c.fx = new Ext.draw.modifier.Animation({
-            sprite: c
-        });
-        c.fx.setNext(c.topModifier);
-        for (a = 0, b = d.length; a < b; a++) {
-            c.addModifier(d[a], false)
-        }
-    },
-    getAnimation: function() {
-        return this.fx
-    },
-    setAnimation: function(a) {
-        this.fx.setConfig(a)
-    },
-    initializeAttributes: function() {
-        this.topModifier.prepareAttributes(this.attr)
-    },
-    callUpdaters: function(d) {
-        var e = this,
-            h = d.pendingUpdaters,
-            i = e.self.def.getUpdaters(),
-            c = false,
-            a = false,
-            b, g, f;
-        e.callUpdaters = Ext.emptyFn;
-        do {
-            c = false;
-            for (g in h) {
-                c = true;
-                b = h[g];
-                delete h[g];
-                f = i[g];
-                if (typeof f === "string") {
-                    f = e[f]
-                }
-                if (f) {
-                    f.call(e, d, b)
-                }
-            }
-            a = a || c
-        } while (c);
-        delete e.callUpdaters;
-        if (a) {
-            e.setDirty(true)
-        }
-    },
-    scheduleUpdaters: function(a, e, c) {
-        var f;
-        if (c) {
-            for (var b = 0, d = e.length; b < d; b++) {
-                f = e[b];
-                this.scheduleUpdater(a, f, c)
-            }
-        } else {
-            for (f in e) {
-                c = e[f];
-                this.scheduleUpdater(a, f, c)
-            }
-        }
-    },
-    scheduleUpdater: function(a, c, b) {
-        b = b || [];
-        var d = a.pendingUpdaters;
-        if (c in d) {
-            if (b.length) {
-                d[c] = Ext.Array.merge(d[c], b)
-            }
-        } else {
-            d[c] = b
-        }
-    },
-    setAttributes: function(d, g, c) {
-        var a = this.attr,
-            b, e, f;
-        if (g) {
-            if (c) {
-                this.topModifier.pushDown(a, d)
-            } else {
-                f = {};
-                for (b in d) {
-                    e = d[b];
-                    if (e !== a[b]) {
-                        f[b] = e
-                    }
-                }
-                this.topModifier.pushDown(a, f)
-            }
-        } else {
-            this.topModifier.pushDown(a, this.self.def.normalize(d))
-        }
-    },
-    setAttributesBypassingNormalization: function(b, a) {
-        return this.setAttributes(b, true, a)
-    },
-    bboxUpdater: function(b) {
-        var c = b.rotationRads !== 0,
-            a = b.scalingX !== 1 || b.scalingY !== 1,
-            d = b.rotationCenterX === null || b.rotationCenterY === null,
-            e = b.scalingCenterX === null || b.scalingCenterY === null;
-        b.bbox.plain.dirty = true;
-        b.bbox.transform.dirty = true;
-        if (c && d || a && e) {
-            this.scheduleUpdater(b, "transform")
-        }
-    },
-    getBBox: function(d) {
-        var e = this,
-            a = e.attr,
-            f = a.bbox,
-            c = f.plain,
-            b = f.transform;
-        if (c.dirty) {
-            e.updatePlainBBox(c);
-            c.dirty = false
-        }
-        if (!d) {
-            e.applyTransformations();
-            if (b.dirty) {
-                e.updateTransformedBBox(b, c);
-                b.dirty = false
-            }
-            return b
-        }
-        return c
-    },
-    updatePlainBBox: Ext.emptyFn,
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, 0, a)
-    },
-    getBBoxCenter: function(a) {
-        var b = this.getBBox(a);
-        if (b) {
-            return [b.x + b.width * 0.5, b.y + b.height * 0.5]
-        } else {
-            return [0, 0]
-        }
-    },
-    hide: function() {
-        this.attr.hidden = true;
-        this.setDirty(true);
-        return this
-    },
-    show: function() {
-        this.attr.hidden = false;
-        this.setDirty(true);
-        return this
-    },
-    useAttributes: function(i, f) {
-        this.applyTransformations();
-        var d = this.attr,
-            h = d.canvasAttributes,
-            e = h.strokeStyle,
-            g = h.fillStyle,
-            b = h.lineDash,
-            c = h.lineDashOffset,
-            a;
-        if (e) {
-            if (e.isGradient) {
-                i.strokeStyle = "black";
-                i.strokeGradient = e
-            } else {
-                i.strokeGradient = false
-            }
-        }
-        if (g) {
-            if (g.isGradient) {
-                i.fillStyle = "black";
-                i.fillGradient = g
-            } else {
-                i.fillGradient = false
-            }
-        }
-        if (b) {
-            i.setLineDash(b)
-        }
-        if (Ext.isNumber(c + i.lineDashOffset)) {
-            i.lineDashOffset = c
-        }
-        for (a in h) {
-            if (h[a] !== undefined && h[a] !== i[a]) {
-                i[a] = h[a]
-            }
-        }
-        this.setGradientBBox(i, f)
-    },
-    setGradientBBox: function(b, c) {
-        var a = this.attr;
-        if (a.constrainGradients) {
-            b.setGradientBBox({
-                x: c[0],
-                y: c[1],
-                width: c[2],
-                height: c[3]
-            })
-        } else {
-            b.setGradientBBox(this.getBBox(a.transformFillStroke))
-        }
-    },
-    applyTransformations: function(b) {
-        if (!b && !this.attr.dirtyTransform) {
-            return
-        }
-        var r = this,
-            k = r.attr,
-            p = r.getBBoxCenter(true),
-            g = p[0],
-            f = p[1],
-            q = k.translationX,
-            o = k.translationY,
-            j = k.scalingX,
-            i = k.scalingY === null ? k.scalingX : k.scalingY,
-            m = k.scalingCenterX === null ? g : k.scalingCenterX,
-            l = k.scalingCenterY === null ? f : k.scalingCenterY,
-            s = k.rotationRads,
-            e = k.rotationCenterX === null ? g : k.rotationCenterX,
-            d = k.rotationCenterY === null ? f : k.rotationCenterY,
-            c = Math.cos(s),
-            a = Math.sin(s),
-            n, h;
-        if (j === 1 && i === 1) {
-            m = 0;
-            l = 0
-        }
-        if (s === 0) {
-            e = 0;
-            d = 0
-        }
-        n = m * (1 - j) - e;
-        h = l * (1 - i) - d;
-        k.matrix.elements = [c * j, a * j, -a * i, c * i, c * n - a * h + e + q, a * n + c * h + d + o];
-        k.matrix.inverse(k.inverseMatrix);
-        k.dirtyTransform = false;
-        k.bbox.transform.dirty = true
-    },
-    transform: function(b, c) {
-        var a = this.attr,
-            e = a.matrix,
-            d;
-        if (b && b.isMatrix) {
-            d = b.elements
-        } else {
-            d = b
-        }
-        e.prepend.apply(e, d.slice());
-        e.inverse(a.inverseMatrix);
-        if (c) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    updateTransformAttributes: function() {
-        var a = this.attr,
-            b = a.matrix.split();
-        a.rotationRads = b.rotate;
-        a.rotationCenterX = 0;
-        a.rotationCenterY = 0;
-        a.scalingX = b.scaleX;
-        a.scalingY = b.scaleY;
-        a.scalingCenterX = 0;
-        a.scalingCenterY = 0;
-        a.translationX = b.translateX;
-        a.translationY = b.translateY
-    },
-    resetTransform: function(b) {
-        var a = this.attr;
-        a.matrix.reset();
-        a.inverseMatrix.reset();
-        if (!b) {
-            this.updateTransformAttributes()
-        }
-        a.dirtyTransform = false;
-        a.bbox.transform.dirty = true;
-        this.setDirty(true);
-        return this
-    },
-    setTransform: function(a, b) {
-        this.resetTransform(true);
-        this.transform.call(this, a, b);
-        return this
-    },
-    preRender: Ext.emptyFn,
-    render: Ext.emptyFn,
-    hitTest: function(b, c) {
-        if (this.isVisible()) {
-            var a = b[0],
-                f = b[1],
-                e = this.getBBox(),
-                d = e && a >= e.x && a <= (e.x + e.width) && f >= e.y && f <= (e.y + e.height);
-            if (d) {
-                return {
-                    sprite: this
-                }
-            }
-        }
-        return null
-    },
-    isVisible: function() {
-        var e = this.attr,
-            f = this.getParent(),
-            g = f && (f.isSurface || f.isVisible()),
-            d = g && !e.hidden && e.globalAlpha,
-            b = Ext.draw.Color.NONE,
-            a = Ext.draw.Color.RGBA_NONE,
-            c = e.fillOpacity && e.fillStyle !== b && e.fillStyle !== a,
-            i = e.strokeOpacity && e.strokeStyle !== b && e.strokeStyle !== a,
-            h = d && (c || i);
-        return !!h
-    },
-    repaint: function() {
-        var a = this.getSurface();
-        if (a) {
-            a.renderFrame()
-        }
-    },
-    remove: function() {
-        var a = this.getSurface();
-        if (a && a.isSurface) {
-            return a.remove(this)
-        }
-        return null
-    },
-    destroy: function() {
-        var b = this,
-            a = b.topModifier,
-            c;
-        while (a) {
-            c = a;
-            a = a.getPrevious();
-            c.destroy()
-        }
-        delete b.attr;
-        b.remove();
-        if (b.fireEvent("beforedestroy", b) !== false) {
-            b.fireEvent("destroy", b)
-        }
-        b.callParent()
-    }
-}, function() {
-    this.def = new Ext.draw.sprite.AttributeDefinition(this.def);
-    this.def.spriteClass = this
-});
-Ext.define("Ext.draw.Path", {
-    requires: ["Ext.draw.Draw"],
-    statics: {
-        pathRe: /,?([achlmqrstvxz]),?/gi,
-        pathRe2: /-/gi,
-        pathSplitRe: /\s|,/g
-    },
-    svgString: "",
-    constructor: function(a) {
-        var b = this;
-        b.commands = [];
-        b.params = [];
-        b.cursor = null;
-        b.startX = 0;
-        b.startY = 0;
-        if (a) {
-            b.fromSvgString(a)
-        }
-    },
-    clear: function() {
-        var a = this;
-        a.params.length = 0;
-        a.commands.length = 0;
-        a.cursor = null;
-        a.startX = 0;
-        a.startY = 0;
-        a.dirt()
-    },
-    dirt: function() {
-        this.svgString = ""
-    },
-    moveTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c]
-        }
-        b.params.push(a, c);
-        b.commands.push("M");
-        b.startX = a;
-        b.startY = c;
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    lineTo: function(a, c) {
-        var b = this;
-        if (!b.cursor) {
-            b.cursor = [a, c];
-            b.params.push(a, c);
-            b.commands.push("M")
-        } else {
-            b.params.push(a, c);
-            b.commands.push("L")
-        }
-        b.cursor[0] = a;
-        b.cursor[1] = c;
-        b.dirt()
-    },
-    bezierCurveTo: function(c, e, b, d, a, g) {
-        var f = this;
-        if (!f.cursor) {
-            f.moveTo(c, e)
-        }
-        f.params.push(c, e, b, d, a, g);
-        f.commands.push("C");
-        f.cursor[0] = a;
-        f.cursor[1] = g;
-        f.dirt()
-    },
-    quadraticCurveTo: function(b, e, a, d) {
-        var c = this;
-        if (!c.cursor) {
-            c.moveTo(b, e)
-        }
-        c.bezierCurveTo((2 * b + c.cursor[0]) / 3, (2 * e + c.cursor[1]) / 3, (2 * b + a) / 3, (2 * e + d) / 3, a, d)
-    },
-    closePath: function() {
-        var a = this;
-        if (a.cursor) {
-            a.cursor = null;
-            a.commands.push("Z");
-            a.dirt()
-        }
-    },
-    arcTo: function(A, f, z, d, j, i, v) {
-        var E = this;
-        if (i === undefined) {
-            i = j
-        }
-        if (v === undefined) {
-            v = 0
-        }
-        if (!E.cursor) {
-            E.moveTo(A, f);
-            return
-        }
-        if (j === 0 || i === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        z -= A;
-        d -= f;
-        var B = E.cursor[0] - A,
-            g = E.cursor[1] - f,
-            C = z * g - d * B,
-            b, a, l, r, k, q, x = Math.sqrt(B * B + g * g),
-            u = Math.sqrt(z * z + d * d),
-            t, e, c;
-        if (C === 0) {
-            E.lineTo(A, f);
-            return
-        }
-        if (i !== j) {
-            b = Math.cos(v);
-            a = Math.sin(v);
-            l = b / j;
-            r = a / i;
-            k = -a / j;
-            q = b / i;
-            var D = l * B + r * g;
-            g = k * B + q * g;
-            B = D;
-            D = l * z + r * d;
-            d = k * z + q * d;
-            z = D
-        } else {
-            B /= j;
-            g /= i;
-            z /= j;
-            d /= i
-        }
-        e = B * u + z * x;
-        c = g * u + d * x;
-        t = 1 / (Math.sin(Math.asin(Math.abs(C) / (x * u)) * 0.5) * Math.sqrt(e * e + c * c));
-        e *= t;
-        c *= t;
-        var o = (e * B + c * g) / (B * B + g * g),
-            m = (e * z + c * d) / (z * z + d * d);
-        var n = B * o - e,
-            p = g * o - c,
-            h = z * m - e,
-            y = d * m - c,
-            w = Math.atan2(p, n),
-            s = Math.atan2(y, h);
-        if (C > 0) {
-            if (s < w) {
-                s += Math.PI * 2
-            }
-        } else {
-            if (w < s) {
-                w += Math.PI * 2
-            }
-        }
-        if (i !== j) {
-            e = b * e * j - a * c * i + A;
-            c = a * c * i + b * c * i + f;
-            E.lineTo(b * j * n - a * i * p + e, a * j * n + b * i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        } else {
-            e = e * j + A;
-            c = c * i + f;
-            E.lineTo(j * n + e, i * p + c);
-            E.ellipse(e, c, j, i, v, w, s, C < 0)
-        }
-    },
-    ellipse: function(h, f, c, a, q, n, d, e) {
-        var o = this,
-            g = o.params,
-            b = g.length,
-            m, l, k;
-        if (d - n >= Math.PI * 2) {
-            o.ellipse(h, f, c, a, q, n, n + Math.PI, e);
-            o.ellipse(h, f, c, a, q, n + Math.PI, d, e);
-            return
-        }
-        if (!e) {
-            if (d < n) {
-                d += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, n, d)
-        } else {
-            if (n < d) {
-                n += Math.PI * 2
-            }
-            m = o.approximateArc(g, h, f, c, a, q, d, n);
-            for (l = b, k = g.length - 2; l < k; l += 2, k -= 2) {
-                var p = g[l];
-                g[l] = g[k];
-                g[k] = p;
-                p = g[l + 1];
-                g[l + 1] = g[k + 1];
-                g[k + 1] = p
-            }
-        }
-        if (!o.cursor) {
-            o.cursor = [g[g.length - 2], g[g.length - 1]];
-            o.commands.push("M")
-        } else {
-            o.cursor[0] = g[g.length - 2];
-            o.cursor[1] = g[g.length - 1];
-            o.commands.push("L")
-        }
-        for (l = 2; l < m; l += 6) {
-            o.commands.push("C")
-        }
-        o.dirt()
-    },
-    arc: function(b, f, a, d, c, e) {
-        this.ellipse(b, f, a, a, 0, d, c, e)
-    },
-    rect: function(b, e, c, a) {
-        if (c == 0 || a == 0) {
-            return
-        }
-        var d = this;
-        d.moveTo(b, e);
-        d.lineTo(b + c, e);
-        d.lineTo(b + c, e + a);
-        d.lineTo(b, e + a);
-        d.closePath()
-    },
-    approximateArc: function(s, i, f, o, n, d, x, v) {
-        var e = Math.cos(d),
-            z = Math.sin(d),
-            k = Math.cos(x),
-            l = Math.sin(x),
-            q = e * k * o - z * l * n,
-            y = -e * l * o - z * k * n,
-            p = z * k * o + e * l * n,
-            w = -z * l * o + e * k * n,
-            m = Math.PI / 2,
-            r = 2,
-            j = q,
-            u = y,
-            h = p,
-            t = w,
-            b = 0.547443256150549,
-            C, g, A, a, B, c;
-        v -= x;
-        if (v < 0) {
-            v += Math.PI * 2
-        }
-        s.push(q + i, p + f);
-        while (v >= m) {
-            s.push(j + u * b + i, h + t * b + f, j * b + u + i, h * b + t + f, u + i, t + f);
-            r += 6;
-            v -= m;
-            C = j;
-            j = u;
-            u = -C;
-            C = h;
-            h = t;
-            t = -C
-        }
-        if (v) {
-            g = (0.3294738052815987 + 0.012120855841304373 * v) * v;
-            A = Math.cos(v);
-            a = Math.sin(v);
-            B = A + g * a;
-            c = a - g * A;
-            s.push(j + u * g + i, h + t * g + f, j * B + u * c + i, h * B + t * c + f, j * A + u * a + i, h * A + t * a + f);
-            r += 6
-        }
-        return r
-    },
-    arcSvg: function(j, h, r, m, w, t, c) {
-        if (j < 0) {
-            j = -j
-        }
-        if (h < 0) {
-            h = -h
-        }
-        var x = this,
-            u = x.cursor[0],
-            f = x.cursor[1],
-            a = (u - t) / 2,
-            y = (f - c) / 2,
-            d = Math.cos(r),
-            s = Math.sin(r),
-            o = a * d + y * s,
-            v = -a * s + y * d,
-            i = o / j,
-            g = v / h,
-            p = i * i + g * g,
-            e = (u + t) * 0.5,
-            b = (f + c) * 0.5,
-            l = 0,
-            k = 0;
-        if (p >= 1) {
-            p = Math.sqrt(p);
-            j *= p;
-            h *= p
-        } else {
-            p = Math.sqrt(1 / p - 1);
-            if (m === w) {
-                p = -p
-            }
-            l = p * j * g;
-            k = -p * h * i;
-            e += d * l - s * k;
-            b += s * l + d * k
-        }
-        var q = Math.atan2((v - k) / h, (o - l) / j),
-            n = Math.atan2((-v - k) / h, (-o - l) / j) - q;
-        if (w) {
-            if (n <= 0) {
-                n += Math.PI * 2
-            }
-        } else {
-            if (n >= 0) {
-                n -= Math.PI * 2
-            }
-        }
-        x.ellipse(e, b, j, h, r, q, q + n, 1 - w)
-    },
-    fromSvgString: function(e) {
-        if (!e) {
-            return
-        }
-        var m = this,
-            h, l = {
-                a: 7,
-                c: 6,
-                h: 1,
-                l: 2,
-                m: 2,
-                q: 4,
-                s: 4,
-                t: 2,
-                v: 1,
-                z: 0,
-                A: 7,
-                C: 6,
-                H: 1,
-                L: 2,
-                M: 2,
-                Q: 4,
-                S: 4,
-                T: 2,
-                V: 1,
-                Z: 0
-            },
-            k = "",
-            g, f, c = 0,
-            b = 0,
-            d = false,
-            j, n, a;
-        if (Ext.isString(e)) {
-            h = e.replace(Ext.draw.Path.pathRe, " $1 ").replace(Ext.draw.Path.pathRe2, " -").split(Ext.draw.Path.pathSplitRe)
-        } else {
-            if (Ext.isArray(e)) {
-                h = e.join(",").split(Ext.draw.Path.pathSplitRe)
-            }
-        }
-        for (j = 0, n = 0; j < h.length; j++) {
-            if (h[j] !== "") {
-                h[n++] = h[j]
-            }
-        }
-        h.length = n;
-        m.clear();
-        for (j = 0; j < h.length;) {
-            k = d;
-            d = h[j];
-            a = (d.toUpperCase() !== d);
-            j++;
-            switch (d) {
-                case "M":
-                    m.moveTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "L":
-                    m.lineTo(c = +h[j], b = +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b = +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "A":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c = +h[j + 5], b = +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "C":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(+h[j], +h[j + 1], g = +h[j + 2], f = +h[j + 3], c = +h[j + 4], b = +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "Z":
-                    m.closePath();
-                    break;
-                case "m":
-                    m.moveTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "l":
-                    m.lineTo(c += +h[j], b += +h[j + 1]);
-                    j += 2;
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b += +h[j + 1]);
-                        j += 2
-                    }
-                    break;
-                case "a":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.arcSvg(+h[j], +h[j + 1], +h[j + 2] * Math.PI / 180, +h[j + 3], +h[j + 4], c += +h[j + 5], b += +h[j + 6]);
-                        j += 7
-                    }
-                    break;
-                case "c":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + (+h[j]), b + (+h[j + 1]), g = c + (+h[j + 2]), f = b + (+h[j + 3]), c += +h[j + 4], b += +h[j + 5]);
-                        j += 6
-                    }
-                    break;
-                case "z":
-                    m.closePath();
-                    break;
-                case "s":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "S":
-                    if (!(k === "c" || k === "C" || k === "s" || k === "S")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.bezierCurveTo(c + c - g, b + b - f, g = +h[j], f = +h[j + 1], c = (+h[j + 2]), b = (+h[j + 3]));
-                        j += 4
-                    }
-                    break;
-                case "q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + (+h[j]), f = b + (+h[j + 1]), c += +h[j + 2], b += +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "Q":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = +h[j], f = +h[j + 1], c = +h[j + 2], b = +h[j + 3]);
-                        j += 4
-                    }
-                    break;
-                case "t":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c += +h[j + 1], b += +h[j + 2]);
-                        j += 2
-                    }
-                    break;
-                case "T":
-                    if (!(k === "q" || k === "Q" || k === "t" || k === "T")) {
-                        g = c;
-                        f = b
-                    }
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.quadraticCurveTo(g = c + c - g, f = b + b - f, c = (+h[j + 1]), b = (+h[j + 2]));
-                        j += 2
-                    }
-                    break;
-                case "h":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c += +h[j], b);
-                        j++
-                    }
-                    break;
-                case "H":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c = +h[j], b);
-                        j++
-                    }
-                    break;
-                case "v":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b += +h[j]);
-                        j++
-                    }
-                    break;
-                case "V":
-                    while (j < n && !l.hasOwnProperty(h[j])) {
-                        m.lineTo(c, b = +h[j]);
-                        j++
-                    }
-                    break
-            }
-        }
-    },
-    clone: function() {
-        var a = this,
-            b = new Ext.draw.Path();
-        b.params = a.params.slice(0);
-        b.commands = a.commands.slice(0);
-        b.cursor = a.cursor ? a.cursor.slice(0) : null;
-        b.startX = a.startX;
-        b.startY = a.startY;
-        b.svgString = a.svgString;
-        return b
-    },
-    transform: function(j) {
-        if (j.isIdentity()) {
-            return
-        }
-        var a = j.getXX(),
-            f = j.getYX(),
-            m = j.getDX(),
-            l = j.getXY(),
-            e = j.getYY(),
-            k = j.getDY(),
-            b = this.params,
-            c = 0,
-            d = b.length,
-            h, g;
-        for (; c < d; c += 2) {
-            h = b[c];
-            g = b[c + 1];
-            b[c] = h * a + g * f + m;
-            b[c + 1] = h * l + g * e + k
-        }
-        this.dirt()
-    },
-    getDimension: function(f) {
-        if (!f) {
-            f = {}
-        }
-        if (!this.commands || !this.commands.length) {
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var d = 0,
-            c = 0,
-            b = this.commands,
-            g = this.params,
-            e = b.length,
-            a, h;
-        for (; d < e; d++) {
-            switch (b[d]) {
-                case "M":
-                case "L":
-                    a = g[c];
-                    h = g[c + 1];
-                    f.left = Math.min(a, f.left);
-                    f.top = Math.min(h, f.top);
-                    f.right = Math.max(a, f.right);
-                    f.bottom = Math.max(h, f.bottom);
-                    c += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, a, h, g[c], g[c + 1], g[c + 2], g[c + 3], a = g[c + 4], h = g[c + 5]);
-                    c += 6;
-                    break
-            }
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    getDimensionWithTransform: function(n, f) {
-        if (!this.commands || !this.commands.length) {
-            if (!f) {
-                f = {}
-            }
-            f.x = 0;
-            f.y = 0;
-            f.width = 0;
-            f.height = 0;
-            return f
-        }
-        f.left = Infinity;
-        f.top = Infinity;
-        f.right = -Infinity;
-        f.bottom = -Infinity;
-        var a = n.getXX(),
-            k = n.getYX(),
-            q = n.getDX(),
-            p = n.getXY(),
-            h = n.getYY(),
-            o = n.getDY(),
-            e = 0,
-            d = 0,
-            b = this.commands,
-            c = this.params,
-            g = b.length,
-            m, l;
-        for (; e < g; e++) {
-            switch (b[e]) {
-                case "M":
-                case "L":
-                    m = c[d] * a + c[d + 1] * k + q;
-                    l = c[d] * p + c[d + 1] * h + o;
-                    f.left = Math.min(m, f.left);
-                    f.top = Math.min(l, f.top);
-                    f.right = Math.max(m, f.right);
-                    f.bottom = Math.max(l, f.bottom);
-                    d += 2;
-                    break;
-                case "C":
-                    this.expandDimension(f, m, l, c[d] * a + c[d + 1] * k + q, c[d] * p + c[d + 1] * h + o, c[d + 2] * a + c[d + 3] * k + q, c[d + 2] * p + c[d + 3] * h + o, m = c[d + 4] * a + c[d + 5] * k + q, l = c[d + 4] * p + c[d + 5] * h + o);
-                    d += 6;
-                    break
-            }
-        }
-        if (!f) {
-            f = {}
-        }
-        f.x = f.left;
-        f.y = f.top;
-        f.width = f.right - f.left;
-        f.height = f.bottom - f.top;
-        return f
-    },
-    expandDimension: function(i, d, p, k, g, j, e, c, o) {
-        var m = this,
-            f = i.left,
-            a = i.right,
-            q = i.top,
-            n = i.bottom,
-            h = m.dim || (m.dim = []);
-        m.curveDimension(d, k, j, c, h);
-        f = Math.min(f, h[0]);
-        a = Math.max(a, h[1]);
-        m.curveDimension(p, g, e, o, h);
-        q = Math.min(q, h[0]);
-        n = Math.max(n, h[1]);
-        i.left = f;
-        i.right = a;
-        i.top = q;
-        i.bottom = n
-    },
-    curveDimension: function(p, n, k, j, h) {
-        var i = 3 * (-p + 3 * (n - k) + j),
-            g = 6 * (p - 2 * n + k),
-            f = -3 * (p - n),
-            o, m, e = Math.min(p, j),
-            l = Math.max(p, j),
-            q;
-        if (i === 0) {
-            if (g === 0) {
-                h[0] = e;
-                h[1] = l;
-                return
-            } else {
-                o = -f / g;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-            }
-        } else {
-            q = g * g - 4 * i * f;
-            if (q >= 0) {
-                q = Math.sqrt(q);
-                o = (q - g) / 2 / i;
-                if (0 < o && o < 1) {
-                    m = this.interpolate(p, n, k, j, o);
-                    e = Math.min(e, m);
-                    l = Math.max(l, m)
-                }
-                if (q > 0) {
-                    o -= q / i;
-                    if (0 < o && o < 1) {
-                        m = this.interpolate(p, n, k, j, o);
-                        e = Math.min(e, m);
-                        l = Math.max(l, m)
-                    }
-                }
-            }
-        }
-        h[0] = e;
-        h[1] = l
-    },
-    interpolate: function(f, e, j, i, g) {
-        if (g === 0) {
-            return f
-        }
-        if (g === 1) {
-            return i
-        }
-        var h = (1 - g) / g;
-        return g * g * g * (i + h * (3 * j + h * (3 * e + h * f)))
-    },
-    fromStripes: function(g) {
-        var e = this,
-            c = 0,
-            d = g.length,
-            b, a, f;
-        e.clear();
-        for (; c < d; c++) {
-            f = g[c];
-            e.params.push.apply(e.params, f);
-            e.commands.push("M");
-            for (b = 2, a = f.length; b < a; b += 6) {
-                e.commands.push("C")
-            }
-        }
-        if (!e.cursor) {
-            e.cursor = []
-        }
-        e.cursor[0] = e.params[e.params.length - 2];
-        e.cursor[1] = e.params[e.params.length - 1];
-        e.dirt()
-    },
-    toStripes: function(k) {
-        var o = k || [],
-            p, n, m, b, a, h, g, f, e, c = this.commands,
-            d = this.params,
-            l = c.length;
-        for (f = 0, e = 0; f < l; f++) {
-            switch (c[f]) {
-                case "M":
-                    p = [h = b = d[e++], g = a = d[e++]];
-                    o.push(p);
-                    break;
-                case "L":
-                    n = d[e++];
-                    m = d[e++];
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break;
-                case "C":
-                    p.push(d[e++], d[e++], d[e++], d[e++], b = d[e++], a = d[e++]);
-                    break;
-                case "Z":
-                    n = h;
-                    m = g;
-                    p.push((b + b + n) / 3, (a + a + m) / 3, (b + n + n) / 3, (a + m + m) / 3, b = n, a = m);
-                    break
-            }
-        }
-        return o
-    },
-    updateSvgString: function() {
-        var b = [],
-            a = this.commands,
-            f = this.params,
-            e = a.length,
-            d = 0,
-            c = 0;
-        for (; d < e; d++) {
-            switch (a[d]) {
-                case "M":
-                    b.push("M" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "L":
-                    b.push("L" + f[c] + "," + f[c + 1]);
-                    c += 2;
-                    break;
-                case "C":
-                    b.push("C" + f[c] + "," + f[c + 1] + " " + f[c + 2] + "," + f[c + 3] + " " + f[c + 4] + "," + f[c + 5]);
-                    c += 6;
-                    break;
-                case "Z":
-                    b.push("Z");
-                    break
-            }
-        }
-        this.svgString = b.join("")
-    },
-    toString: function() {
-        if (!this.svgString) {
-            this.updateSvgString()
-        }
-        return this.svgString
-    }
-});
-Ext.define("Ext.draw.overrides.Path", {
-    override: "Ext.draw.Path",
-    rayOrigin: {
-        x: -10000,
-        y: -10000
-    },
-    isPointInPath: function(o, n) {
-        var m = this,
-            c = m.commands,
-            q = Ext.draw.PathUtil,
-            p = m.rayOrigin,
-            f = m.params,
-            l = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            k = 0,
-            h, g;
-        for (h = 0, g = 0; h < l; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (q.linesIntersection(b, a, f[g], f[g + 1], p.x, p.y, o, n)) {
-                        k += 1
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    k += q.cubicLineIntersections(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], p.x, p.y, o, n).length;
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (q.linesIntersection(e, d, b, a, p.x, p.y, o, n)) {
-                            k += 1
-                        }
-                    }
-                    break
-            }
-        }
-        return k % 2 === 1
-    },
-    isPointOnPath: function(n, m) {
-        var l = this,
-            c = l.commands,
-            o = Ext.draw.PathUtil,
-            f = l.params,
-            k = c.length,
-            e = null,
-            d = null,
-            b = 0,
-            a = 0,
-            h, g;
-        for (h = 0, g = 0; h < k; h++) {
-            switch (c[h]) {
-                case "M":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    e = b = f[g];
-                    d = a = f[g + 1];
-                    g += 2;
-                    break;
-                case "L":
-                    if (o.pointOnLine(b, a, f[g], f[g + 1], n, m)) {
-                        return true
-                    }
-                    b = f[g];
-                    a = f[g + 1];
-                    g += 2;
-                    break;
-                case "C":
-                    if (o.pointOnCubic(b, f[g], f[g + 2], f[g + 4], a, f[g + 1], f[g + 3], f[g + 5], n, m)) {
-                        return true
-                    }
-                    b = f[g + 4];
-                    a = f[g + 5];
-                    g += 6;
-                    break;
-                case "Z":
-                    if (e !== null) {
-                        if (o.pointOnLine(e, d, b, a, n, m)) {
-                            return true
-                        }
-                    }
-                    break
-            }
-        }
-        return false
-    },
-    getSegmentIntersections: function(t, d, s, c, r, b, o, a) {
-        var w = this,
-            g = arguments.length,
-            v = Ext.draw.PathUtil,
-            f = w.commands,
-            u = w.params,
-            k = f.length,
-            m = null,
-            l = null,
-            h = 0,
-            e = 0,
-            x = [],
-            q, n, p;
-        for (q = 0, n = 0; q < k; q++) {
-            switch (f[q]) {
-                case "M":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    m = h = u[n];
-                    l = e = u[n + 1];
-                    n += 2;
-                    break;
-                case "L":
-                    switch (g) {
-                        case 4:
-                            p = v.linesIntersection(h, e, u[n], u[n + 1], t, d, s, c);
-                            if (p) {
-                                x.push(p)
-                            }
-                            break;
-                        case 8:
-                            p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, h, e, u[n], u[n + 1]);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n];
-                    e = u[n + 1];
-                    n += 2;
-                    break;
-                case "C":
-                    switch (g) {
-                        case 4:
-                            p = v.cubicLineIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, d, s, c);
-                            x.push.apply(x, p);
-                            break;
-                        case 8:
-                            p = v.cubicsIntersections(h, u[n], u[n + 2], u[n + 4], e, u[n + 1], u[n + 3], u[n + 5], t, s, r, o, d, c, b, a);
-                            x.push.apply(x, p);
-                            break
-                    }
-                    h = u[n + 4];
-                    e = u[n + 5];
-                    n += 6;
-                    break;
-                case "Z":
-                    if (m !== null) {
-                        switch (g) {
-                            case 4:
-                                p = v.linesIntersection(m, l, h, e, t, d, s, c);
-                                if (p) {
-                                    x.push(p)
-                                }
-                                break;
-                            case 8:
-                                p = v.cubicLineIntersections(t, s, r, o, d, c, b, a, m, l, h, e);
-                                x.push.apply(x, p);
-                                break
-                        }
-                    }
-                    break
-            }
-        }
-        return x
-    },
-    getIntersections: function(o) {
-        var m = this,
-            c = m.commands,
-            g = m.params,
-            l = c.length,
-            f = null,
-            e = null,
-            b = 0,
-            a = 0,
-            d = [],
-            k, h, n;
-        for (k = 0, h = 0; k < l; k++) {
-            switch (c[k]) {
-                case "M":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    f = b = g[h];
-                    e = a = g[h + 1];
-                    h += 2;
-                    break;
-                case "L":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1]);
-                    d.push.apply(d, n);
-                    b = g[h];
-                    a = g[h + 1];
-                    h += 2;
-                    break;
-                case "C":
-                    n = o.getSegmentIntersections.call(o, b, a, g[h], g[h + 1], g[h + 2], g[h + 3], g[h + 4], g[h + 5]);
-                    d.push.apply(d, n);
-                    b = g[h + 4];
-                    a = g[h + 5];
-                    h += 6;
-                    break;
-                case "Z":
-                    if (f !== null) {
-                        n = o.getSegmentIntersections.call(o, f, e, b, a);
-                        d.push.apply(d, n)
-                    }
-                    break
-            }
-        }
-        return d
-    }
-});
-Ext.define("Ext.draw.sprite.Path", {
-    extend: "Ext.draw.sprite.Sprite",
-    requires: ["Ext.draw.Draw", "Ext.draw.Path"],
-    alias: ["sprite.path", "Ext.draw.Sprite"],
-    type: "path",
-    isPath: true,
-    inheritableStatics: {
-        def: {
-            processors: {
-                path: function(b, a) {
-                    if (!(b instanceof Ext.draw.Path)) {
-                        b = new Ext.draw.Path(b)
-                    }
-                    return b
-                }
-            },
-            aliases: {
-                d: "path"
-            },
-            triggers: {
-                path: "bbox"
-            },
-            updaters: {
-                path: function(a) {
-                    var b = a.path;
-                    if (!b || b.bindAttr !== a) {
-                        b = new Ext.draw.Path();
-                        b.bindAttr = a;
-                        a.path = b
-                    }
-                    b.clear();
-                    this.updatePath(b, a);
-                    this.scheduleUpdater(a, "bbox", ["path"])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimension(a)
-        }
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.path) {
-            this.attr.path.getDimensionWithTransform(this.attr.matrix, a)
-        }
-    },
-    render: function(b, c) {
-        var d = this.attr.matrix,
-            a = this.attr;
-        if (!a.path || a.path.params.length === 0) {
-            return
-        }
-        d.toContext(c);
-        c.appendPath(a.path);
-        c.fillStroke(a)
-    },
-    updatePath: function(b, a) {}
-});
-Ext.define("Ext.draw.overrides.sprite.Path", {
-    override: "Ext.draw.sprite.Path",
-    requires: ["Ext.draw.Color"],
-    isPointInPath: function(c, g) {
-        var b = this.attr;
-        if (b.fillStyle === Ext.draw.Color.RGBA_NONE) {
-            return this.isPointOnPath(c, g)
-        }
-        var e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointInPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    isPointOnPath: function(c, g) {
-        var b = this.attr,
-            e = b.path,
-            d = b.matrix,
-            f, a;
-        if (!d.isIdentity()) {
-            f = e.params.slice(0);
-            e.transform(b.matrix)
-        }
-        a = e.isPointOnPath(c, g);
-        if (f) {
-            e.params = f
-        }
-        return a
-    },
-    hitTest: function(i, l) {
-        var e = this,
-            c = e.attr,
-            k = c.path,
-            g = c.matrix,
-            h = i[0],
-            f = i[1],
-            d = e.callParent([i, l]),
-            j = null,
-            a, b;
-        if (!d) {
-            return j
-        }
-        l = l || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        if (!g.isIdentity()) {
-            a = k.params.slice(0);
-            k.transform(c.matrix)
-        }
-        if (l.fill && l.stroke) {
-            b = c.fillStyle !== Ext.draw.Color.NONE && c.fillStyle !== Ext.draw.Color.RGBA_NONE;
-            if (b) {
-                if (k.isPointInPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (k.isPointInPath(h, f) || k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            }
-        } else {
-            if (l.stroke && !l.fill) {
-                if (k.isPointOnPath(h, f)) {
-                    j = {
-                        sprite: e
-                    }
-                }
-            } else {
-                if (l.fill && !l.stroke) {
-                    if (k.isPointInPath(h, f)) {
-                        j = {
-                            sprite: e
-                        }
-                    }
-                }
-            }
-        }
-        if (a) {
-            k.params = a
-        }
-        return j
-    },
-    getIntersections: function(j) {
-        if (!(j.isSprite && j.isPath)) {
-            return []
-        }
-        var e = this.attr,
-            d = j.attr,
-            i = e.path,
-            h = d.path,
-            g = e.matrix,
-            a = d.matrix,
-            c, f, b;
-        if (!g.isIdentity()) {
-            c = i.params.slice(0);
-            i.transform(e.matrix)
-        }
-        if (!a.isIdentity()) {
-            f = h.params.slice(0);
-            h.transform(d.matrix)
-        }
-        b = i.getIntersections(h);
-        if (c) {
-            i.params = c
-        }
-        if (f) {
-            h.params = f
-        }
-        return b
-    }
-});
-Ext.define("Ext.draw.sprite.Circle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.circle",
-    type: "circle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                r: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                r: 4
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                r: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            e = b.cy,
-            d = b.r;
-        c.x = a - d;
-        c.y = e - d;
-        c.width = d + d;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var g = this.attr,
-            f = g.cx,
-            e = g.cy,
-            a = g.r,
-            h = g.matrix,
-            j = h.getScaleX(),
-            i = h.getScaleY(),
-            c, b;
-        c = j * a;
-        b = i * a;
-        d.x = h.x(f, e) - c;
-        d.y = h.y(f, e) - b;
-        d.width = c + c;
-        d.height = b + b
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.Arc", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "sprite.arc",
-    type: "arc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.arc(a.cx, a.cy, a.r, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Arrow", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.arrow",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.5,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c * 0.7, ",", e - c * 0.4, "l", [c * 0.6, 0, 0, -c * 0.4, c, c * 0.8, -c, c * 0.8, 0, -c * 0.4, -c * 0.6, 0], "z"))
-    }
-});
-Ext.define("Ext.draw.sprite.Composite", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.composite",
-    type: "composite",
-    isComposite: true,
-    config: {
-        sprites: []
-    },
-    constructor: function() {
-        this.sprites = [];
-        this.sprites.map = {};
-        this.callParent(arguments)
-    },
-    add: function(c) {
-        if (!c) {
-            return null
-        }
-        if (!c.isSprite) {
-            c = Ext.create("sprite." + c.type, c);
-            c.setParent(this);
-            c.setSurface(this.getSurface())
-        }
-        var d = this,
-            a = d.attr,
-            b = c.applyTransformations;
-        c.applyTransformations = function() {
-            if (c.attr.dirtyTransform) {
-                a.dirtyTransform = true;
-                a.bbox.plain.dirty = true;
-                a.bbox.transform.dirty = true
-            }
-            b.call(c)
-        };
-        d.sprites.push(c);
-        d.sprites.map[c.id] = c.getId();
-        a.bbox.plain.dirty = true;
-        a.bbox.transform.dirty = true;
-        return c
-    },
-    updateSurface: function(a) {
-        for (var b = 0, c = this.sprites.length; b < c; b++) {
-            this.sprites[b].setSurface(a)
-        }
-    },
-    addAll: function(b) {
-        if (b.isSprite || b.type) {
-            this.add(b)
-        } else {
-            if (Ext.isArray(b)) {
-                var a = 0;
-                while (a < b.length) {
-                    this.add(b[a++])
-                }
-            }
-        }
-    },
-    updatePlainBBox: function(g) {
-        var e = this,
-            b = Infinity,
-            h = -Infinity,
-            f = Infinity,
-            a = -Infinity,
-            j, k, c, d;
-        for (c = 0, d = e.sprites.length; c < d; c++) {
-            j = e.sprites[c];
-            j.applyTransformations();
-            k = j.getBBox();
-            if (b > k.x) {
-                b = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (f > k.y) {
-                f = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        g.x = b;
-        g.y = f;
-        g.width = h - b;
-        g.height = a - f
-    },
-    render: function(a, b, f) {
-        var d = this.attr.matrix,
-            c, e;
-        d.toContext(b);
-        for (c = 0, e = this.sprites.length; c < e; c++) {
-            a.renderSprite(this.sprites[c], f)
-        }
-    },
-    destroy: function() {
-        var c = this,
-            d = c.sprites,
-            b = d.length,
-            a;
-        c.callParent();
-        for (a = 0; a < b; a++) {
-            d[a].destroy()
-        }
-        d.length = 0
-    }
-});
-Ext.define("Ext.draw.sprite.Cross", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.cross",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.7,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c, ",", e, "l", [-c, -c, c, -c, c, c, c, -c, c, c, -c, c, c, c, -c, c, -c, -c, -c, c, -c, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Diamond", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.diamond",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 1.25,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString(["M", a, e - c, "l", c, c, -c, c, -c, -c, c, -c, "z"])
-    }
-});
-Ext.define("Ext.draw.sprite.Ellipse", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.ellipse",
-    type: "ellipse",
-    inheritableStatics: {
-        def: {
-            processors: {
-                cx: "number",
-                cy: "number",
-                rx: "number",
-                ry: "number",
-                axisRotation: "number"
-            },
-            aliases: {
-                radius: "r",
-                x: "cx",
-                y: "cy",
-                centerX: "cx",
-                centerY: "cy",
-                radiusX: "rx",
-                radiusY: "ry"
-            },
-            defaults: {
-                cx: 0,
-                cy: 0,
-                rx: 1,
-                ry: 1,
-                axisRotation: 0
-            },
-            triggers: {
-                cx: "path",
-                cy: "path",
-                rx: "path",
-                ry: "path",
-                axisRotation: "path"
-            }
-        }
-    },
-    updatePlainBBox: function(c) {
-        var b = this.attr,
-            a = b.cx,
-            f = b.cy,
-            e = b.rx,
-            d = b.ry;
-        c.x = a - e;
-        c.y = f - d;
-        c.width = e + e;
-        c.height = d + d
-    },
-    updateTransformedBBox: function(d) {
-        var i = this.attr,
-            f = i.cx,
-            e = i.cy,
-            c = i.rx,
-            b = i.ry,
-            l = b / c,
-            m = i.matrix.clone(),
-            a, q, k, j, p, o, n, g;
-        m.append(1, 0, 0, l, 0, e * (1 - l));
-        a = m.getXX();
-        k = m.getYX();
-        p = m.getDX();
-        q = m.getXY();
-        j = m.getYY();
-        o = m.getDY();
-        n = Math.sqrt(a * a + k * k) * c;
-        g = Math.sqrt(q * q + j * j) * c;
-        d.x = f * a + e * k + p - n;
-        d.y = f * q + e * j + o - g;
-        d.width = n + n;
-        d.height = g + g
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, 0, Math.PI * 2, false)
-    }
-});
-Ext.define("Ext.draw.sprite.EllipticalArc", {
-    extend: "Ext.draw.sprite.Ellipse",
-    alias: "sprite.ellipticalArc",
-    type: "ellipticalArc",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startAngle: "number",
-                endAngle: "number",
-                anticlockwise: "bool"
-            },
-            aliases: {
-                from: "startAngle",
-                to: "endAngle",
-                start: "startAngle",
-                end: "endAngle"
-            },
-            defaults: {
-                startAngle: 0,
-                endAngle: Math.PI * 2,
-                anticlockwise: false
-            },
-            triggers: {
-                startAngle: "path",
-                endAngle: "path",
-                anticlockwise: "path"
-            }
-        }
-    },
-    updatePath: function(b, a) {
-        b.ellipse(a.cx, a.cy, a.rx, a.ry, a.axisRotation, a.startAngle, a.endAngle, a.anticlockwise)
-    }
-});
-Ext.define("Ext.draw.sprite.Rect", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.rect",
-    type: "rect",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                radius: "number"
-            },
-            aliases: {},
-            triggers: {
-                x: "path",
-                y: "path",
-                width: "path",
-                height: "path",
-                radius: "path"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                radius: 0
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.x;
-        b.y = a.y;
-        b.width = a.width;
-        b.height = a.height
-    },
-    updateTransformedBBox: function(a, b) {
-        this.attr.matrix.transformBBox(b, this.attr.radius, a)
-    },
-    updatePath: function(f, d) {
-        var c = d.x,
-            g = d.y,
-            e = d.width,
-            b = d.height,
-            a = Math.min(d.radius, Math.abs(d.height) * 0.5, Math.abs(d.width) * 0.5);
-        if (a === 0) {
-            f.rect(c, g, e, b)
-        } else {
-            f.moveTo(c + a, g);
-            f.arcTo(c + e, g, c + e, g + b, a);
-            f.arcTo(c + e, g + b, c, g + b, a);
-            f.arcTo(c, g + b, c, g, a);
-            f.arcTo(c, g, c + a, g, a)
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Image", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.image",
-    type: "image",
-    statics: {
-        imageLoaders: {}
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                src: "string"
-            },
-            defaults: {
-                src: "",
-                width: null,
-                height: null
-            }
-        }
-    },
-    render: function(c, o) {
-        var j = this,
-            h = j.attr,
-            n = h.matrix,
-            a = h.src,
-            l = h.x,
-            k = h.y,
-            b = h.width,
-            m = h.height,
-            g = Ext.draw.sprite.Image.imageLoaders[a],
-            f, d, e;
-        if (g && g.done) {
-            n.toContext(o);
-            d = g.image;
-            o.drawImage(d, l, k, b || (d.naturalWidth || d.width) / c.devicePixelRatio, m || (d.naturalHeight || d.height) / c.devicePixelRatio)
-        } else {
-            if (!g) {
-                f = new Image();
-                g = Ext.draw.sprite.Image.imageLoaders[a] = {
-                    image: f,
-                    done: false,
-                    pendingSprites: [j],
-                    pendingSurfaces: [c]
-                };
-                f.width = b;
-                f.height = m;
-                f.onload = function() {
-                    if (!g.done) {
-                        g.done = true;
-                        for (e = 0; e < g.pendingSprites.length; e++) {
-                            g.pendingSprites[e].setDirty(true)
-                        }
-                        for (e in g.pendingSurfaces) {
-                            g.pendingSurfaces[e].renderFrame()
-                        }
-                    }
-                };
-                f.src = a
-            } else {
-                Ext.Array.include(g.pendingSprites, j);
-                Ext.Array.include(g.pendingSurfaces, c)
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Instancing", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.instancing",
-    type: "instancing",
-    isInstancing: true,
-    config: {
-        template: null
-    },
-    instances: null,
-    applyTemplate: function(a) {
-        if (!a.isSprite) {
-            if (!a.xclass && !a.type) {
-                a.type = "circle"
-            }
-            a = Ext.create(a.xclass || "sprite." + a.type, a)
-        }
-        a.setParent(this);
-        return a
-    },
-    updateTemplate: function(a, b) {
-        if (b) {
-            delete b.ownAttr
-        }
-        a.setSurface(this.getSurface());
-        a.ownAttr = a.attr;
-        this.clearAll()
-    },
-    updateSurface: function(a) {
-        var b = this.getTemplate();
-        if (b) {
-            b.setSurface(a)
-        }
-    },
-    get: function(a) {
-        return this.instances[a]
-    },
-    getCount: function() {
-        return this.instances.length
-    },
-    clearAll: function() {
-        var a = this.getTemplate();
-        a.attr.children = this.instances = [];
-        this.position = 0
-    },
-    createInstance: function(d, f, c) {
-        var e = this.getTemplate(),
-            b = e.attr,
-            a = Ext.Object.chain(b);
-        e.topModifier.prepareAttributes(a);
-        e.attr = a;
-        e.setAttributes(d, f, c);
-        a.template = e;
-        this.instances.push(a);
-        e.attr = b;
-        this.position++;
-        return a
-    },
-    getBBox: function() {
-        return null
-    },
-    getBBoxFor: function(b, d) {
-        var c = this.getTemplate(),
-            a = c.attr,
-            e;
-        c.attr = this.instances[b];
-        e = c.getBBox(d);
-        c.attr = a;
-        return e
-    },
-    isVisible: function() {
-        var b = this.attr,
-            c = this.getParent(),
-            a;
-        a = c && c.isSurface && !b.hidden && b.globalAlpha;
-        return !!a
-    },
-    isInstanceVisible: function(c) {
-        var e = this,
-            d = e.getTemplate(),
-            b = d.attr,
-            f = e.instances,
-            a = false;
-        if (!Ext.isNumber(c) || c < 0 || c >= f.length || !e.isVisible()) {
-            return a
-        }
-        d.attr = f[c];
-        a = d.isVisible(point, options);
-        d.attr = b;
-        return a
-    },
-    render: function(b, l, d, h) {
-        var g = this,
-            j = g.getTemplate(),
-            k = g.attr.matrix,
-            c = j.attr,
-            a = g.instances,
-            e, f = g.position;
-        k.toContext(l);
-        j.preRender(b, l, d, h);
-        j.useAttributes(l, h);
-        for (e = 0; e < f; e++) {
-            if (a[e].dirtyZIndex) {
-                break
-            }
-        }
-        for (e = 0; e < f; e++) {
-            if (a[e].hidden) {
-                continue
-            }
-            l.save();
-            j.attr = a[e];
-            j.useAttributes(l, h);
-            j.render(b, l, d, h);
-            l.restore()
-        }
-        j.attr = c
-    },
-    setAttributesFor: function(c, e, f) {
-        var d = this.getTemplate(),
-            b = d.attr,
-            a = this.instances[c];
-        if (!a) {
-            return
-        }
-        d.attr = a;
-        if (f) {
-            e = Ext.apply({}, e)
-        } else {
-            e = d.self.def.normalize(e)
-        }
-        d.topModifier.pushDown(a, e);
-        d.attr = b
-    },
-    destroy: function() {
-        var b = this,
-            a = b.getTemplate();
-        b.instances = null;
-        if (a) {
-            a.destroy()
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.sprite.Instancing", {
-    override: "Ext.draw.sprite.Instancing",
-    hitTest: function(f, j) {
-        var e = this,
-            g = e.getTemplate(),
-            b = g.attr,
-            a = e.instances,
-            d = a.length,
-            c = 0,
-            h = null;
-        if (!e.isVisible()) {
-            return h
-        }
-        for (; c < d; c++) {
-            g.attr = a[c];
-            h = g.hitTest(f, j);
-            if (h) {
-                h.isInstance = true;
-                h.template = h.sprite;
-                h.sprite = this;
-                h.instance = a[c];
-                h.index = c;
-                return h
-            }
-        }
-        g.attr = b;
-        return h
-    }
-});
-Ext.define("Ext.draw.sprite.Line", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.line",
-    type: "line",
-    inheritableStatics: {
-        def: {
-            processors: {
-                fromX: "number",
-                fromY: "number",
-                toX: "number",
-                toY: "number"
-            },
-            defaults: {
-                fromX: 0,
-                fromY: 0,
-                toX: 1,
-                toY: 1,
-                strokeStyle: "black"
-            },
-            aliases: {
-                x1: "fromX",
-                y1: "fromY",
-                x2: "toX",
-                y2: "toY"
-            }
-        }
-    },
-    updateLineBBox: function(b, i, s, g, r, f) {
-        var o = this.attr,
-            q = o.matrix,
-            h = o.lineWidth / 2,
-            m, l, d, c, k, j, n;
-        if (i) {
-            n = q.transformPoint([s, g]);
-            s = n[0];
-            g = n[1];
-            n = q.transformPoint([r, f]);
-            r = n[0];
-            f = n[1]
-        }
-        m = Math.min(s, r);
-        d = Math.max(s, r);
-        l = Math.min(g, f);
-        c = Math.max(g, f);
-        var t = Math.atan2(d - m, c - l),
-            a = Math.sin(t),
-            e = Math.cos(t),
-            k = h * e,
-            j = h * a;
-        m -= k;
-        l -= j;
-        d += k;
-        c += j;
-        b.x = m;
-        b.y = l;
-        b.width = d - m;
-        b.height = c - l
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        this.updateLineBBox(b, false, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    updateTransformedBBox: function(b, c) {
-        var a = this.attr;
-        this.updateLineBBox(b, true, a.fromX, a.fromY, a.toX, a.toY)
-    },
-    render: function(b, c) {
-        var a = this.attr,
-            d = this.attr.matrix;
-        d.toContext(c);
-        c.beginPath();
-        c.moveTo(a.fromX, a.fromY);
-        c.lineTo(a.toX, a.toY);
-        c.stroke()
-    }
-});
-Ext.define("Ext.draw.sprite.Plus", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.plus",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size / 1.3,
-            a = b.x - b.lineWidth / 2,
-            e = b.y;
-        d.fromSvgString("M".concat(a - c / 2, ",", e - c / 2, "l", [0, -c, c, 0, 0, c, c, 0, 0, c, -c, 0, 0, c, -c, 0, 0, -c, -c, 0, 0, -c, "z"]))
-    }
-});
-Ext.define("Ext.draw.sprite.Sector", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.sector",
-    type: "sector",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,bbox",
-                endAngle: "path,bbox",
-                startRho: "path,bbox",
-                endRho: "path,bbox",
-                margin: "path,bbox"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: 0,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                path: "M 0,0"
-            }
-        }
-    },
-    getMidAngle: function() {
-        return this.midAngle || 0
-    },
-    updatePath: function(j, h) {
-        var g = Math.min(h.startAngle, h.endAngle),
-            c = Math.max(h.startAngle, h.endAngle),
-            b = this.midAngle = (g + c) * 0.5,
-            d = h.margin,
-            f = h.centerX,
-            e = h.centerY,
-            i = Math.min(h.startRho, h.endRho),
-            a = Math.max(h.startRho, h.endRho);
-        if (d) {
-            f += d * Math.cos(b);
-            e += d * Math.sin(b)
-        }
-        j.moveTo(f + i * Math.cos(g), e + i * Math.sin(g));
-        j.lineTo(f + a * Math.cos(g), e + a * Math.sin(g));
-        j.arc(f, e, a, g, c, false);
-        j.lineTo(f + i * Math.cos(c), e + i * Math.sin(c));
-        j.arc(f, e, i, c, g, true)
-    }
-});
-Ext.define("Ext.draw.sprite.Square", {
-    extend: "Ext.draw.sprite.Rect",
-    alias: "sprite.square",
-    inheritableStatics: {
-        def: {
-            processors: {
-                size: "number"
-            },
-            defaults: {
-                size: 4
-            },
-            triggers: {
-                size: "size"
-            },
-            updaters: {
-                size: function(a) {
-                    var c = a.size,
-                        b = a.lineWidth / 2;
-                    this.setAttributes({
-                        x: a.x - c - b,
-                        y: a.y - c,
-                        height: 2 * c,
-                        width: 2 * c
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.TextMeasurer", {
-    singleton: true,
-    requires: ["Ext.util.TextMetrics"],
-    measureDiv: null,
-    measureCache: {},
-    precise: Ext.isIE8,
-    measureDivTpl: {
-        tag: "div",
-        style: {
-            overflow: "hidden",
-            position: "relative",
-            "float": "left",
-            width: 0,
-            height: 0
-        },
-        children: {
-            tag: "div",
-            style: {
-                display: "block",
-                position: "absolute",
-                x: -100000,
-                y: -100000,
-                padding: 0,
-                margin: 0,
-                "z-index": -100000,
-                "white-space": "nowrap"
-            }
-        }
-    },
-    actualMeasureText: function(g, b) {
-        var e = Ext.draw.TextMeasurer,
-            f = e.measureDiv,
-            a = 100000,
-            c;
-        if (!f) {
-            var d = Ext.Element.create({
-                style: {
-                    overflow: "hidden",
-                    position: "relative",
-                    "float": "left",
-                    width: 0,
-                    height: 0
-                }
-            });
-            e.measureDiv = f = Ext.Element.create({
-                style: {
-                    position: "absolute",
-                    x: a,
-                    y: a,
-                    "z-index": -a,
-                    "white-space": "nowrap",
-                    display: "block",
-                    padding: 0,
-                    margin: 0
-                }
-            });
-            Ext.getBody().appendChild(d);
-            d.appendChild(f)
-        }
-        if (b) {
-            f.setStyle({
-                font: b,
-                lineHeight: "normal"
-            })
-        }
-        f.setText("(" + g + ")");
-        c = f.getSize();
-        f.setText("()");
-        c.width -= f.getSize().width;
-        return c
-    },
-    measureTextSingleLine: function(h, d) {
-        if (this.precise) {
-            return this.preciseMeasureTextSingleLine(h, d)
-        }
-        h = h.toString();
-        var a = this.measureCache,
-            g = h.split(""),
-            c = 0,
-            j = 0,
-            l, b, e, f, k;
-        if (!a[d]) {
-            a[d] = {}
-        }
-        a = a[d];
-        if (a[h]) {
-            return a[h]
-        }
-        for (e = 0, f = g.length; e < f; e++) {
-            b = g[e];
-            if (!(l = a[b])) {
-                k = this.actualMeasureText(b, d);
-                l = a[b] = k
-            }
-            c += l.width;
-            j = Math.max(j, l.height)
-        }
-        return a[h] = {
-            width: c,
-            height: j
-        }
-    },
-    preciseMeasureTextSingleLine: function(c, a) {
-        c = c.toString();
-        var b = this.measureDiv || (this.measureDiv = Ext.getBody().createChild(this.measureDivTpl).down("div"));
-        b.setStyle({
-            font: a || ""
-        });
-        return Ext.util.TextMetrics.measure(b, c)
-    },
-    measureText: function(e, b) {
-        var h = e.split("\n"),
-            d = h.length,
-            f = 0,
-            a = 0,
-            j, c, g;
-        if (d === 1) {
-            return this.measureTextSingleLine(e, b)
-        }
-        g = [];
-        for (c = 0; c < d; c++) {
-            j = this.measureTextSingleLine(h[c], b);
-            g.push(j);
-            f += j.height;
-            a = Math.max(a, j.width)
-        }
-        return {
-            width: a,
-            height: f,
-            sizes: g
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Text", function() {
-    var d = {
-        "xx-small": true,
-        "x-small": true,
-        small: true,
-        medium: true,
-        large: true,
-        "x-large": true,
-        "xx-large": true
-    };
-    var b = {
-        normal: true,
-        bold: true,
-        bolder: true,
-        lighter: true,
-        100: true,
-        200: true,
-        300: true,
-        400: true,
-        500: true,
-        600: true,
-        700: true,
-        800: true,
-        900: true
-    };
-    var a = {
-        start: "start",
-        left: "start",
-        center: "center",
-        middle: "center",
-        end: "end",
-        right: "end"
-    };
-    var c = {
-        top: "top",
-        hanging: "hanging",
-        middle: "middle",
-        center: "middle",
-        alphabetic: "alphabetic",
-        ideographic: "ideographic",
-        bottom: "bottom"
-    };
-    return {
-        extend: "Ext.draw.sprite.Sprite",
-        requires: ["Ext.draw.TextMeasurer", "Ext.draw.Color"],
-        alias: "sprite.text",
-        type: "text",
-        lineBreakRe: /\r?\n/g,
-        inheritableStatics: {
-            def: {
-                animationProcessors: {
-                    text: "text"
-                },
-                processors: {
-                    x: "number",
-                    y: "number",
-                    text: "string",
-                    fontSize: function(e) {
-                        if (Ext.isNumber(+e)) {
-                            return e + "px"
-                        } else {
-                            if (e.match(Ext.dom.Element.unitRe)) {
-                                return e
-                            } else {
-                                if (e in d) {
-                                    return e
-                                }
-                            }
-                        }
-                    },
-                    fontStyle: "enums(,italic,oblique)",
-                    fontVariant: "enums(,small-caps)",
-                    fontWeight: function(e) {
-                        if (e in b) {
-                            return String(e)
-                        } else {
-                            return ""
-                        }
-                    },
-                    fontFamily: "string",
-                    textAlign: function(e) {
-                        return a[e] || "center"
-                    },
-                    textBaseline: function(e) {
-                        return c[e] || "alphabetic"
-                    },
-                    font: "string"
-                },
-                aliases: {
-                    "font-size": "fontSize",
-                    "font-family": "fontFamily",
-                    "font-weight": "fontWeight",
-                    "font-variant": "fontVariant",
-                    "text-anchor": "textAlign"
-                },
-                defaults: {
-                    fontStyle: "",
-                    fontVariant: "",
-                    fontWeight: "",
-                    fontSize: "10px",
-                    fontFamily: "sans-serif",
-                    font: "10px sans-serif",
-                    textBaseline: "alphabetic",
-                    textAlign: "start",
-                    strokeStyle: "rgba(0, 0, 0, 0)",
-                    fillStyle: "#000",
-                    x: 0,
-                    y: 0,
-                    text: ""
-                },
-                triggers: {
-                    fontStyle: "fontX,bbox",
-                    fontVariant: "fontX,bbox",
-                    fontWeight: "fontX,bbox",
-                    fontSize: "fontX,bbox",
-                    fontFamily: "fontX,bbox",
-                    font: "font,bbox,canvas",
-                    textBaseline: "bbox",
-                    textAlign: "bbox",
-                    x: "bbox",
-                    y: "bbox",
-                    text: "bbox"
-                },
-                updaters: {
-                    fontX: "makeFontShorthand",
-                    font: "parseFontShorthand"
-                }
-            }
-        },
-        constructor: function(e) {
-            if (e && e.font) {
-                e = Ext.clone(e);
-                for (var f in e) {
-                    if (f !== "font" && f.indexOf("font") === 0) {
-                        delete e[f]
-                    }
-                }
-            }
-            Ext.draw.sprite.Sprite.prototype.constructor.call(this, e)
-        },
-        fontValuesMap: {
-            italic: "fontStyle",
-            oblique: "fontStyle",
-            "small-caps": "fontVariant",
-            bold: "fontWeight",
-            bolder: "fontWeight",
-            lighter: "fontWeight",
-            "100": "fontWeight",
-            "200": "fontWeight",
-            "300": "fontWeight",
-            "400": "fontWeight",
-            "500": "fontWeight",
-            "600": "fontWeight",
-            "700": "fontWeight",
-            "800": "fontWeight",
-            "900": "fontWeight",
-            "xx-small": "fontSize",
-            "x-small": "fontSize",
-            small: "fontSize",
-            medium: "fontSize",
-            large: "fontSize",
-            "x-large": "fontSize",
-            "xx-large": "fontSize"
-        },
-        makeFontShorthand: function(e) {
-            var f = [];
-            if (e.fontStyle) {
-                f.push(e.fontStyle)
-            }
-            if (e.fontVariant) {
-                f.push(e.fontVariant)
-            }
-            if (e.fontWeight) {
-                f.push(e.fontWeight)
-            }
-            if (e.fontSize) {
-                f.push(e.fontSize)
-            }
-            if (e.fontFamily) {
-                f.push(e.fontFamily)
-            }
-            this.setAttributes({
-                font: f.join(" ")
-            }, true)
-        },
-        parseFontShorthand: function(j) {
-            var m = j.font,
-                k = m.length,
-                l = {},
-                n = this.fontValuesMap,
-                e = 0,
-                i, g, f, h;
-            while (e < k && i !== -1) {
-                i = m.indexOf(" ", e);
-                if (i < 0) {
-                    f = m.substr(e)
-                } else {
-                    if (i > e) {
-                        f = m.substr(e, i - e)
-                    } else {
-                        continue
-                    }
-                }
-                g = f.indexOf("/");
-                if (g > 0) {
-                    f = f.substr(0, g)
-                } else {
-                    if (g === 0) {
-                        continue
-                    }
-                }
-                if (f !== "normal" && f !== "inherit") {
-                    h = n[f];
-                    if (h) {
-                        l[h] = f
-                    } else {
-                        if (f.match(Ext.dom.Element.unitRe)) {
-                            l.fontSize = f
-                        } else {
-                            l.fontFamily = m.substr(e);
-                            break
-                        }
-                    }
-                }
-                e = i + 1
-            }
-            if (!l.fontStyle) {
-                l.fontStyle = ""
-            }
-            if (!l.fontVariant) {
-                l.fontVariant = ""
-            }
-            if (!l.fontWeight) {
-                l.fontWeight = ""
-            }
-            this.setAttributes(l, true)
-        },
-        fontProperties: {
-            fontStyle: true,
-            fontVariant: true,
-            fontWeight: true,
-            fontSize: true,
-            fontFamily: true
-        },
-        setAttributes: function(g, i, e) {
-            var f, h;
-            if (g && g.font) {
-                h = {};
-                for (f in g) {
-                    if (!(f in this.fontProperties)) {
-                        h[f] = g[f]
-                    }
-                }
-                g = h
-            }
-            this.callParent([g, i, e])
-        },
-        getBBox: function(g) {
-            var h = this,
-                f = h.attr.bbox.plain,
-                e = h.getSurface();
-            if (f.dirty) {
-                h.updatePlainBBox(f);
-                f.dirty = false
-            }
-            if (e.getInherited().rtl && e.getFlipRtlText()) {
-                h.updatePlainBBox(f, true)
-            }
-            return h.callParent([g])
-        },
-        rtlAlignments: {
-            start: "end",
-            center: "center",
-            end: "start"
-        },
-        updatePlainBBox: function(k, B) {
-            var C = this,
-                w = C.attr,
-                o = w.x,
-                n = w.y,
-                q = [],
-                t = w.font,
-                r = w.text,
-                s = w.textBaseline,
-                l = w.textAlign,
-                u = (B && C.oldSize) ? C.oldSize : (C.oldSize = Ext.draw.TextMeasurer.measureText(r, t)),
-                z = C.getSurface(),
-                p = z.getInherited().rtl,
-                v = p && z.getFlipRtlText(),
-                h = z.getRect(),
-                f = u.sizes,
-                g = u.height,
-                j = u.width,
-                m = f ? f.length : 0,
-                e, A = 0;
-            switch (s) {
-                case "hanging":
-                case "top":
-                    break;
-                case "ideographic":
-                case "bottom":
-                    n -= g;
-                    break;
-                case "alphabetic":
-                    n -= g * 0.8;
-                    break;
-                case "middle":
-                    n -= g * 0.5;
-                    break
-            }
-            if (v) {
-                o = h[2] - h[0] - o;
-                l = C.rtlAlignments[l]
-            }
-            switch (l) {
-                case "start":
-                    if (p) {
-                        for (; A < m; A++) {
-                            e = f[A].width;
-                            q.push(-(j - e))
-                        }
-                    }
-                    break;
-                case "end":
-                    o -= j;
-                    if (p) {
-                        break
-                    }
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push(j - e)
-                    }
-                    break;
-                case "center":
-                    o -= j * 0.5;
-                    for (; A < m; A++) {
-                        e = f[A].width;
-                        q.push((p ? -1 : 1) * (j - e) * 0.5)
-                    }
-                    break
-            }
-            w.textAlignOffsets = q;
-            k.x = o;
-            k.y = n;
-            k.width = j;
-            k.height = g
-        },
-        setText: function(e) {
-            this.setAttributes({
-                text: e
-            }, true)
-        },
-        render: function(e, q, k) {
-            var h = this,
-                g = h.attr,
-                p = Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),
-                o = h.getBBox(true),
-                s = g.textAlignOffsets,
-                m = Ext.draw.Color.RGBA_NONE,
-                l, j, f, r, n;
-            if (g.text.length === 0) {
-                return
-            }
-            r = g.text.split(h.lineBreakRe);
-            n = o.height / r.length;
-            l = g.bbox.plain.x;
-            j = g.bbox.plain.y + n * 0.78;
-            p.toContext(q);
-            if (e.getInherited().rtl) {
-                l += g.bbox.plain.width
-            }
-            for (f = 0; f < r.length; f++) {
-                if (q.fillStyle !== m) {
-                    q.fillText(r[f], l + (s[f] || 0), j + n * f)
-                }
-                if (q.strokeStyle !== m) {
-                    q.strokeText(r[f], l + (s[f] || 0), j + n * f)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Tick", {
-    extend: "Ext.draw.sprite.Line",
-    alias: "sprite.tick",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "tick",
-                y: "tick",
-                size: "tick"
-            },
-            updaters: {
-                tick: function(b) {
-                    var d = b.size * 1.5,
-                        c = b.lineWidth / 2,
-                        a = b.x,
-                        e = b.y;
-                    this.setAttributes({
-                        fromX: a - c,
-                        fromY: e - d,
-                        toX: a - c,
-                        toY: e + d
-                    })
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.draw.sprite.Triangle", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "sprite.triangle",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                size: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                size: 4
-            },
-            triggers: {
-                x: "path",
-                y: "path",
-                size: "path"
-            }
-        }
-    },
-    updatePath: function(d, b) {
-        var c = b.size * 2.2,
-            a = b.x,
-            e = b.y;
-        d.fromSvgString("M".concat(a, ",", e, "m0-", c * 0.58, "l", c * 0.5, ",", c * 0.87, "-", c, ",0z"))
-    }
-});
-Ext.define("Ext.draw.gradient.Linear", {
-    extend: "Ext.draw.gradient.Gradient",
-    requires: ["Ext.draw.Color"],
-    type: "linear",
-    config: {
-        degrees: 0,
-        radians: 0
-    },
-    applyRadians: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    applyDegrees: function(b, a) {
-        if (Ext.isNumber(b)) {
-            return b
-        }
-        return a
-    },
-    updateRadians: function(a) {
-        this.setDegrees(Ext.draw.Draw.degrees(a))
-    },
-    updateDegrees: function(a) {
-        this.setRadians(Ext.draw.Draw.rad(a))
-    },
-    generateGradient: function(q, o) {
-        var c = this.getRadians(),
-            p = Math.cos(c),
-            j = Math.sin(c),
-            m = o.width,
-            f = o.height,
-            d = o.x + m * 0.5,
-            b = o.y + f * 0.5,
-            n = this.getStops(),
-            g = n.length,
-            k, a, e;
-        if (Ext.isNumber(d + b) && f > 0 && m > 0) {
-            a = (Math.sqrt(f * f + m * m) * Math.abs(Math.cos(c - Math.atan(f / m)))) / 2;
-            k = q.createLinearGradient(d + p * a, b + j * a, d - p * a, b - j * a);
-            for (e = 0; e < g; e++) {
-                k.addColorStop(n[e].offset, n[e].color)
-            }
-            return k
-        }
-        return Ext.draw.Color.NONE
-    }
-});
-Ext.define("Ext.draw.gradient.Radial", {
-    extend: "Ext.draw.gradient.Gradient",
-    type: "radial",
-    config: {
-        start: {
-            x: 0,
-            y: 0,
-            r: 0
-        },
-        end: {
-            x: 0,
-            y: 0,
-            r: 1
-        }
-    },
-    applyStart: function(a, b) {
-        if (!b) {
-            return a
-        }
-        var c = {
-            x: b.x,
-            y: b.y,
-            r: b.r
-        };
-        if ("x" in a) {
-            c.x = a.x
-        } else {
-            if ("centerX" in a) {
-                c.x = a.centerX
-            }
-        }
-        if ("y" in a) {
-            c.y = a.y
-        } else {
-            if ("centerY" in a) {
-                c.y = a.centerY
-            }
-        }
-        if ("r" in a) {
-            c.r = a.r
-        } else {
-            if ("radius" in a) {
-                c.r = a.radius
-            }
-        }
-        return c
-    },
-    applyEnd: function(b, a) {
-        if (!a) {
-            return b
-        }
-        var c = {
-            x: a.x,
-            y: a.y,
-            r: a.r
-        };
-        if ("x" in b) {
-            c.x = b.x
-        } else {
-            if ("centerX" in b) {
-                c.x = b.centerX
-            }
-        }
-        if ("y" in b) {
-            c.y = b.y
-        } else {
-            if ("centerY" in b) {
-                c.y = b.centerY
-            }
-        }
-        if ("r" in b) {
-            c.r = b.r
-        } else {
-            if ("radius" in b) {
-                c.r = b.radius
-            }
-        }
-        return c
-    },
-    generateGradient: function(n, m) {
-        var a = this.getStart(),
-            b = this.getEnd(),
-            k = m.width * 0.5,
-            d = m.height * 0.5,
-            j = m.x + k,
-            f = m.y + d,
-            g = n.createRadialGradient(j + a.x * k, f + a.y * d, a.r * Math.max(k, d), j + b.x * k, f + b.y * d, b.r * Math.max(k, d)),
-            l = this.getStops(),
-            e = l.length,
-            c;
-        for (c = 0; c < e; c++) {
-            g.addColorStop(l[c].offset, l[c].color)
-        }
-        return g
-    }
-});
-Ext.define("Ext.draw.Surface", {
-    extend: "Ext.draw.SurfaceBase",
-    xtype: "surface",
-    requires: ["Ext.draw.sprite.*", "Ext.draw.gradient.*", "Ext.draw.sprite.AttributeDefinition", "Ext.draw.Matrix", "Ext.draw.Draw"],
-    uses: ["Ext.draw.engine.Canvas"],
-    devicePixelRatio: window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI,
-    deprecated: {
-        "5.1.0": {
-            statics: {
-                methods: {
-                    stableSort: function(a) {
-                        return Ext.Array.sort(a, function(d, c) {
-                            return d.attr.zIndex - c.attr.zIndex
-                        })
-                    }
-                }
-            }
-        }
-    },
-    config: {
-        cls: Ext.baseCSSPrefix + "surface",
-        rect: null,
-        background: null,
-        items: [],
-        dirty: false,
-        flipRtlText: false
-    },
-    isSurface: true,
-    isPendingRenderFrame: false,
-    dirtyPredecessorCount: 0,
-    constructor: function(a) {
-        var b = this;
-        b.predecessors = [];
-        b.successors = [];
-        b.map = {};
-        b.callParent([a]);
-        b.matrix = new Ext.draw.Matrix();
-        b.inverseMatrix = b.matrix.inverse()
-    },
-    roundPixel: function(a) {
-        return Math.round(this.devicePixelRatio * a) / this.devicePixelRatio
-    },
-    waitFor: function(a) {
-        var b = this,
-            c = b.predecessors;
-        if (!Ext.Array.contains(c, a)) {
-            c.push(a);
-            a.successors.push(b);
-            if (a.getDirty()) {
-                b.dirtyPredecessorCount++
-            }
-        }
-    },
-    updateDirty: function(d) {
-        var c = this.successors,
-            e = c.length,
-            b = 0,
-            a;
-        for (; b < e; b++) {
-            a = c[b];
-            if (d) {
-                a.dirtyPredecessorCount++;
-                a.setDirty(true)
-            } else {
-                a.dirtyPredecessorCount--;
-                if (a.dirtyPredecessorCount === 0 && a.isPendingRenderFrame) {
-                    a.renderFrame()
-                }
-            }
-        }
-    },
-    applyBackground: function(a, b) {
-        this.setDirty(true);
-        if (Ext.isString(a)) {
-            a = {
-                fillStyle: a
-            }
-        }
-        return Ext.factory(a, Ext.draw.sprite.Rect, b)
-    },
-    applyRect: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return
-        }
-        if (Ext.isArray(a)) {
-            return [a[0], a[1], a[2], a[3]]
-        } else {
-            if (Ext.isObject(a)) {
-                return [a.x || a.left, a.y || a.top, a.width || (a.right - a.left), a.height || (a.bottom - a.top)]
-            }
-        }
-    },
-    updateRect: function(i) {
-        var h = this,
-            c = i[0],
-            f = i[1],
-            g = c + i[2],
-            a = f + i[3],
-            e = h.getBackground(),
-            d = h.element;
-        d.setLocalXY(Math.floor(c), Math.floor(f));
-        d.setSize(Math.ceil(g - Math.floor(c)), Math.ceil(a - Math.floor(f)));
-        if (e) {
-            e.setAttributes({
-                x: 0,
-                y: 0,
-                width: Math.ceil(g - Math.floor(c)),
-                height: Math.ceil(a - Math.floor(f))
-            })
-        }
-        h.setDirty(true)
-    },
-    resetTransform: function() {
-        this.matrix.set(1, 0, 0, 1, 0, 0);
-        this.inverseMatrix.set(1, 0, 0, 1, 0, 0);
-        this.setDirty(true)
-    },
-    get: function(a) {
-        return this.map[a] || this.getItems()[a]
-    },
-    add: function() {
-        var g = this,
-            e = Array.prototype.slice.call(arguments),
-            j = Ext.isArray(e[0]),
-            a = g.map,
-            c = [],
-            f, k, h, b, d;
-        f = Ext.Array.clean(j ? e[0] : e);
-        if (!f.length) {
-            return c
-        }
-        for (b = 0, d = f.length; b < d; b++) {
-            k = f[b];
-            h = null;
-            if (k.isSprite && !a[k.getId()]) {
-                h = k
-            } else {
-                if (!a[k.id]) {
-                    h = this.createItem(k)
-                }
-            }
-            if (h) {
-                a[h.getId()] = h;
-                c.push(h);
-                h.setParent(g);
-                h.setSurface(g);
-                g.onAdd(h)
-            }
-        }
-        f = g.getItems();
-        if (f) {
-            f.push.apply(f, c)
-        }
-        g.dirtyZIndex = true;
-        g.setDirty(true);
-        if (!j && c.length === 1) {
-            return c[0]
-        } else {
-            return c
-        }
-    },
-    onAdd: Ext.emptyFn,
-    remove: function(a, c) {
-        var b = this,
-            e, d;
-        if (a) {
-            if (a.charAt) {
-                a = b.map[a]
-            }
-            if (!a || !a.isSprite) {
-                return null
-            }
-            if (a.isDestroyed || a.isDestroying) {
-                return a
-            }
-            e = a.getId();
-            d = b.map[e];
-            delete b.map[e];
-            if (c) {
-                a.destroy()
-            }
-            if (!d) {
-                return a
-            }
-            a.setParent(null);
-            a.setSurface(null);
-            Ext.Array.remove(b.getItems(), a);
-            b.dirtyZIndex = true;
-            b.setDirty(true)
-        }
-        return a || null
-    },
-    removeAll: function(d) {
-        var a = this.getItems(),
-            b = a.length - 1,
-            c;
-        if (d) {
-            for (; b >= 0; b--) {
-                a[b].destroy()
-            }
-        } else {
-            for (; b >= 0; b--) {
-                c = a[b];
-                c.setParent(null);
-                c.setSurface(null)
-            }
-        }
-        a.length = 0;
-        this.map = {};
-        this.dirtyZIndex = true
-    },
-    applyItems: function(a) {
-        if (this.getItems()) {
-            this.removeAll(true)
-        }
-        return Ext.Array.from(this.add(a))
-    },
-    createItem: function(a) {
-        return Ext.create(a.xclass || "sprite." + a.type, a)
-    },
-    getBBox: function(f, b) {
-        var f = Ext.Array.from(f),
-            c = Infinity,
-            h = -Infinity,
-            g = Infinity,
-            a = -Infinity,
-            j, k, d, e;
-        for (d = 0, e = f.length; d < e; d++) {
-            j = f[d];
-            k = j.getBBox(b);
-            if (c > k.x) {
-                c = k.x
-            }
-            if (h < k.x + k.width) {
-                h = k.x + k.width
-            }
-            if (g > k.y) {
-                g = k.y
-            }
-            if (a < k.y + k.height) {
-                a = k.y + k.height
-            }
-        }
-        return {
-            x: c,
-            y: g,
-            width: h - c,
-            height: a - g
-        }
-    },
-    emptyRect: [0, 0, 0, 0],
-    getEventXY: function(d) {
-        var g = this,
-            f = g.getInherited().rtl,
-            c = d.getXY(),
-            a = g.getOwnerBody(),
-            i = a.getXY(),
-            h = g.getRect() || g.emptyRect,
-            j = [],
-            b;
-        if (f) {
-            b = a.getWidth();
-            j[0] = i[0] - c[0] - h[0] + b
-        } else {
-            j[0] = c[0] - i[0] - h[0]
-        }
-        j[1] = c[1] - i[1] - h[1];
-        return j
-    },
-    clear: Ext.emptyFn,
-    orderByZIndex: function() {
-        var d = this,
-            a = d.getItems(),
-            e = false,
-            b, c;
-        if (d.getDirty()) {
-            for (b = 0, c = a.length; b < c; b++) {
-                if (a[b].attr.dirtyZIndex) {
-                    e = true;
-                    break
-                }
-            }
-            if (e) {
-                Ext.Array.sort(a, function(g, f) {
-                    return g.attr.zIndex - f.attr.zIndex
-                });
-                this.setDirty(true)
-            }
-            for (b = 0, c = a.length; b < c; b++) {
-                a[b].attr.dirtyZIndex = false
-            }
-        }
-    },
-    repaint: function() {
-        var a = this;
-        a.repaint = Ext.emptyFn;
-        Ext.defer(function() {
-            delete a.repaint;
-            a.element.repaint()
-        }, 1)
-    },
-    renderFrame: function() {
-        var g = this;
-        if (!g.element) {
-            return
-        }
-        if (g.dirtyPredecessorCount > 0) {
-            g.isPendingRenderFrame = true;
-            return
-        }
-        var f = g.getRect(),
-            c = g.getBackground(),
-            a = g.getItems(),
-            e, b, d;
-        if (!f) {
-            return
-        }
-        g.orderByZIndex();
-        if (g.getDirty()) {
-            g.clear();
-            g.clearTransform();
-            if (c) {
-                g.renderSprite(c)
-            }
-            for (b = 0, d = a.length; b < d; b++) {
-                e = a[b];
-                if (g.renderSprite(e) === false) {
-                    return
-                }
-                e.attr.textPositionCount = g.textPosition
-            }
-            g.setDirty(false)
-        }
-    },
-    renderSprite: Ext.emptyFn,
-    clearTransform: Ext.emptyFn,
-    destroy: function() {
-        var a = this;
-        a.removeAll(true);
-        a.predecessors = null;
-        a.successors = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.draw.overrides.Surface", {
-    override: "Ext.draw.Surface",
-    hitTest: function(b, c) {
-        var f = this,
-            g = f.getItems(),
-            e, d, a;
-        c = c || Ext.draw.sprite.Sprite.defaultHitTestOptions;
-        for (e = g.length - 1; e >= 0; e--) {
-            d = g[e];
-            if (d.hitTest) {
-                a = d.hitTest(b, c);
-                if (a) {
-                    return a
-                }
-            }
-        }
-        return null
-    },
-    hitTestEvent: function(b, a) {
-        var c = this.getEventXY(b);
-        return this.hitTest(c, a)
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext", {
-    requires: ["Ext.draw.Color"],
-    toSave: ["strokeOpacity", "strokeStyle", "fillOpacity", "fillStyle", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "lineDash", "lineDashOffset", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "globalCompositeOperation", "position", "fillGradient", "strokeGradient"],
-    strokeOpacity: 1,
-    strokeStyle: "none",
-    fillOpacity: 1,
-    fillStyle: "none",
-    lineDash: [],
-    lineDashOffset: 0,
-    globalAlpha: 1,
-    lineWidth: 1,
-    lineCap: "butt",
-    lineJoin: "miter",
-    miterLimit: 10,
-    shadowOffsetX: 0,
-    shadowOffsetY: 0,
-    shadowBlur: 0,
-    shadowColor: "none",
-    globalCompositeOperation: "src",
-    urlStringRe: /^url\(#([\w\-]+)\)$/,
-    constructor: function(a) {
-        this.surface = a;
-        this.state = [];
-        this.matrix = new Ext.draw.Matrix();
-        this.path = null;
-        this.clear()
-    },
-    clear: function() {
-        this.group = this.surface.mainGroup;
-        this.position = 0;
-        this.path = null
-    },
-    getElement: function(a) {
-        return this.surface.getSvgElement(this.group, a, this.position++)
-    },
-    removeElement: function(d) {
-        var d = Ext.fly(d),
-            h, g, b, f, a, e, c;
-        if (!d) {
-            return
-        }
-        if (d.dom.tagName === "g") {
-            a = d.dom.gradients;
-            for (c in a) {
-                a[c].destroy()
-            }
-        } else {
-            h = d.getAttribute("fill");
-            g = d.getAttribute("stroke");
-            b = h && h.match(this.urlStringRe);
-            f = g && g.match(this.urlStringRe);
-            if (b && b[1]) {
-                e = Ext.fly(b[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-            if (f && f[1]) {
-                e = Ext.fly(f[1]);
-                if (e) {
-                    e.destroy()
-                }
-            }
-        }
-        d.destroy()
-    },
-    save: function() {
-        var c = this.toSave,
-            e = {},
-            d = this.getElement("g"),
-            b, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            if (b in this) {
-                e[b] = this[b]
-            }
-        }
-        this.position = 0;
-        e.matrix = this.matrix.clone();
-        this.state.push(e);
-        this.group = d;
-        return d
-    },
-    restore: function() {
-        var d = this.toSave,
-            e = this.state.pop(),
-            c = this.group.dom.childNodes,
-            b, a;
-        while (c.length > this.position) {
-            this.removeElement(c[c.length - 1])
-        }
-        for (a = 0; a < d.length; a++) {
-            b = d[a];
-            if (b in e) {
-                this[b] = e[b]
-            } else {
-                delete this[b]
-            }
-        }
-        this.setTransform.apply(this, e.matrix.elements);
-        this.group = this.group.getParent()
-    },
-    transform: function(f, b, e, g, d, c) {
-        if (this.path) {
-            var a = Ext.draw.Matrix.fly([f, b, e, g, d, c]).inverse();
-            this.path.transform(a)
-        }
-        this.matrix.append(f, b, e, g, d, c)
-    },
-    setTransform: function(e, a, d, f, c, b) {
-        if (this.path) {
-            this.path.transform(this.matrix)
-        }
-        this.matrix.reset();
-        this.transform(e, a, d, f, c, b)
-    },
-    scale: function(a, b) {
-        this.transform(a, 0, 0, b, 0, 0)
-    },
-    rotate: function(d) {
-        var c = Math.cos(d),
-            a = Math.sin(d),
-            b = -Math.sin(d),
-            e = Math.cos(d);
-        this.transform(c, a, b, e, 0, 0)
-    },
-    translate: function(a, b) {
-        this.transform(1, 0, 0, 1, a, b)
-    },
-    setGradientBBox: function(a) {
-        this.bbox = a
-    },
-    beginPath: function() {
-        this.path = new Ext.draw.Path()
-    },
-    moveTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.moveTo(a, b);
-        this.path.element = null
-    },
-    lineTo: function(a, b) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.lineTo(a, b);
-        this.path.element = null
-    },
-    rect: function(b, d, c, a) {
-        this.moveTo(b, d);
-        this.lineTo(b + c, d);
-        this.lineTo(b + c, d + a);
-        this.lineTo(b, d + a);
-        this.closePath()
-    },
-    strokeRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.stroke()
-    },
-    fillRect: function(b, d, c, a) {
-        this.beginPath();
-        this.rect(b, d, c, a);
-        this.fill()
-    },
-    closePath: function() {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.closePath();
-        this.path.element = null
-    },
-    arcSvg: function(d, a, f, g, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcSvg(d, a, f, g, c, b, e);
-        this.path.element = null
-    },
-    arc: function(b, f, a, d, c, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arc(b, f, a, d, c, e);
-        this.path.element = null
-    },
-    ellipse: function(a, h, g, f, d, c, b, e) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.ellipse(a, h, g, f, d, c, b, e);
-        this.path.element = null
-    },
-    arcTo: function(b, e, a, d, g, f, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.arcTo(b, e, a, d, g, f, c);
-        this.path.element = null
-    },
-    bezierCurveTo: function(d, f, b, e, a, c) {
-        if (!this.path) {
-            this.beginPath()
-        }
-        this.path.bezierCurveTo(d, f, b, e, a, c);
-        this.path.element = null
-    },
-    strokeText: function(d, a, e) {
-        d = String(d);
-        if (this.strokeStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                stroke: this.strokeStyle,
-                fill: "none",
-                opacity: this.globalAlpha,
-                "stroke-opacity": this.strokeOpacity,
-                style: "font: " + this.font,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(b, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    fillText: function(d, a, e) {
-        d = String(d);
-        if (this.fillStyle) {
-            var b = this.getElement("text"),
-                c = this.surface.getSvgElement(b, "tspan", 0);
-            this.surface.setElementAttributes(b, {
-                x: a,
-                y: e,
-                transform: this.matrix.toSvg(),
-                fill: this.fillStyle,
-                opacity: this.globalAlpha,
-                "fill-opacity": this.fillOpacity,
-                style: "font: " + this.font
-            });
-            if (c.dom.firstChild) {
-                c.dom.removeChild(c.dom.firstChild)
-            }
-            this.surface.setElementAttributes(c, {
-                "alignment-baseline": "alphabetic"
-            });
-            c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))
-        }
-    },
-    drawImage: function(c, k, i, l, e, p, n, a, g) {
-        var f = this,
-            d = f.getElement("image"),
-            j = k,
-            h = i,
-            b = typeof l === "undefined" ? c.width : l,
-            m = typeof e === "undefined" ? c.height : e,
-            o = null;
-        if (typeof g !== "undefined") {
-            o = k + " " + i + " " + l + " " + e;
-            j = p;
-            h = n;
-            b = a;
-            m = g
-        }
-        d.dom.setAttributeNS("http://www.w3.org/1999/xlink", "href", c.src);
-        f.surface.setElementAttributes(d, {
-            viewBox: o,
-            x: j,
-            y: h,
-            width: b,
-            height: m,
-            opacity: f.globalAlpha,
-            transform: f.matrix.toSvg()
-        })
-    },
-    fill: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.fillStyle) {
-            var c, a = this.fillGradient,
-                d = this.bbox,
-                b = this.path.element;
-            if (!b) {
-                c = this.path.toString();
-                b = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(b, {
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(b, {
-                fill: a && d ? a.generateGradient(this, d) : this.fillStyle,
-                "fill-opacity": this.fillOpacity * this.globalAlpha
-            })
-        }
-    },
-    stroke: function() {
-        if (!this.path) {
-            return
-        }
-        if (this.strokeStyle) {
-            var c, b = this.strokeGradient,
-                d = this.bbox,
-                a = this.path.element;
-            if (!a || !this.path.svgString) {
-                c = this.path.toString();
-                if (!c) {
-                    return
-                }
-                a = this.path.element = this.getElement("path");
-                this.surface.setElementAttributes(a, {
-                    fill: "none",
-                    d: c,
-                    transform: this.matrix.toSvg()
-                })
-            }
-            this.surface.setElementAttributes(a, {
-                stroke: b && d ? b.generateGradient(this, d) : this.strokeStyle,
-                "stroke-linecap": this.lineCap,
-                "stroke-linejoin": this.lineJoin,
-                "stroke-width": this.lineWidth,
-                "stroke-opacity": this.strokeOpacity * this.globalAlpha,
-                "stroke-dasharray": this.lineDash.join(","),
-                "stroke-dashoffset": this.lineDashOffset
-            });
-            if (this.lineDash.length) {
-                this.surface.setElementAttributes(a, {
-                    "stroke-dasharray": this.lineDash.join(","),
-                    "stroke-dashoffset": this.lineDashOffset
-                })
-            }
-        }
-    },
-    fillStroke: function(a, e) {
-        var b = this,
-            d = b.fillStyle,
-            g = b.strokeStyle,
-            c = b.fillOpacity,
-            f = b.strokeOpacity;
-        if (e === undefined) {
-            e = a.transformFillStroke
-        }
-        if (!e) {
-            a.inverseMatrix.toContext(b)
-        }
-        if (d && c !== 0) {
-            b.fill()
-        }
-        if (g && f !== 0) {
-            b.stroke()
-        }
-    },
-    appendPath: function(a) {
-        this.path = a.clone()
-    },
-    setLineDash: function(a) {
-        this.lineDash = a
-    },
-    getLineDash: function() {
-        return this.lineDash
-    },
-    createLinearGradient: function(d, g, b, e) {
-        var f = this,
-            c = f.surface.getNextDef("linearGradient"),
-            a = f.group.dom.gradients || (f.group.dom.gradients = {}),
-            h;
-        f.surface.setElementAttributes(c, {
-            x1: d,
-            y1: g,
-            x2: b,
-            y2: e,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(f, f.surface, c);
-        a[c.dom.id] = h;
-        return h
-    },
-    createRadialGradient: function(b, j, d, a, i, c) {
-        var g = this,
-            e = g.surface.getNextDef("radialGradient"),
-            f = g.group.dom.gradients || (g.group.dom.gradients = {}),
-            h;
-        g.surface.setElementAttributes(e, {
-            fx: b,
-            fy: j,
-            cx: a,
-            cy: i,
-            r: c,
-            gradientUnits: "userSpaceOnUse"
-        });
-        h = new Ext.draw.engine.SvgContext.Gradient(g, g.surface, e, d / c);
-        f[e.dom.id] = h;
-        return h
-    }
-});
-Ext.define("Ext.draw.engine.SvgContext.Gradient", {
-    statics: {
-        map: {}
-    },
-    constructor: function(c, a, d, b) {
-        var f = this.statics().map,
-            e;
-        e = f[d.dom.id];
-        if (e) {
-            e.element = null
-        }
-        f[d.dom.id] = this;
-        this.ctx = c;
-        this.surface = a;
-        this.element = d;
-        this.position = 0;
-        this.compression = b || 0
-    },
-    addColorStop: function(d, b) {
-        var c = this.surface.getSvgElement(this.element, "stop", this.position++),
-            a = this.compression;
-        this.surface.setElementAttributes(c, {
-            offset: (((1 - a) * d + a) * 100).toFixed(2) + "%",
-            "stop-color": b,
-            "stop-opacity": Ext.draw.Color.fly(b).a.toFixed(15)
-        })
-    },
-    toString: function() {
-        var a = this.element.dom.childNodes;
-        while (a.length > this.position) {
-            Ext.fly(a[a.length - 1]).destroy()
-        }
-        return "url(#" + this.element.getId() + ")"
-    },
-    destroy: function() {
-        var b = this.statics().map,
-            a = this.element;
-        if (a && a.dom) {
-            delete b[a.dom.id];
-            a.destroy()
-        }
-        this.callParent()
-    }
-});
-Ext.define("Ext.draw.engine.Svg", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.SvgContext"],
-    statics: {
-        BBoxTextCache: {}
-    },
-    config: {
-        highPrecision: false
-    },
-    getElementConfig: function() {
-        return {
-            reference: "element",
-            style: {
-                position: "absolute"
-            },
-            children: [{
-                reference: "innerElement",
-                style: {
-                    width: "100%",
-                    height: "100%",
-                    position: "relative"
-                },
-                children: [{
-                    tag: "svg",
-                    reference: "svgElement",
-                    namespace: "http://www.w3.org/2000/svg",
-                    width: "100%",
-                    height: "100%",
-                    version: 1.1
-                }]
-            }]
-        }
-    },
-    constructor: function(a) {
-        var b = this;
-        b.callParent([a]);
-        b.mainGroup = b.createSvgNode("g");
-        b.defElement = b.createSvgNode("defs");
-        b.svgElement.appendChild(b.mainGroup);
-        b.svgElement.appendChild(b.defElement);
-        b.ctx = new Ext.draw.engine.SvgContext(b)
-    },
-    createSvgNode: function(a) {
-        var b = document.createElementNS("http://www.w3.org/2000/svg", a);
-        return Ext.get(b)
-    },
-    getSvgElement: function(d, b, a) {
-        var c;
-        if (d.dom.childNodes.length > a) {
-            c = d.dom.childNodes[a];
-            if (c.tagName === b) {
-                return Ext.get(c)
-            } else {
-                Ext.destroy(c)
-            }
-        }
-        c = Ext.get(this.createSvgNode(b));
-        if (a === 0) {
-            d.insertFirst(c)
-        } else {
-            c.insertAfter(Ext.fly(d.dom.childNodes[a - 1]))
-        }
-        c.cache = {};
-        return c
-    },
-    setElementAttributes: function(d, b) {
-        var f = d.dom,
-            a = d.cache,
-            c, e;
-        for (c in b) {
-            e = b[c];
-            if (a[c] !== e) {
-                a[c] = e;
-                f.setAttribute(c, e)
-            }
-        }
-    },
-    getNextDef: function(a) {
-        return this.getSvgElement(this.defElement, a, this.defPosition++)
-    },
-    clearTransform: function() {
-        var a = this;
-        a.mainGroup.set({
-            transform: a.matrix.toSvg()
-        })
-    },
-    clear: function() {
-        this.ctx.clear();
-        this.defPosition = 0
-    },
-    renderSprite: function(b) {
-        var d = this,
-            c = d.getRect(),
-            a = d.ctx;
-        if (b.attr.hidden || b.attr.globalAlpha === 0) {
-            a.save();
-            a.restore();
-            return
-        }
-        b.element = a.save();
-        b.preRender(this);
-        b.useAttributes(a, c);
-        if (false === b.render(this, a, [0, 0, c[2], c[3]])) {
-            return false
-        }
-        b.setDirty(false);
-        a.restore()
-    },
-    flatten: function(e, b) {
-        var c = '<?xml version="1.0" standalone="yes"?>',
-            f = Ext.getClassName(this),
-            a, g, d;
-        c += '<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="' + e.width + '" height="' + e.height + '">';
-        for (d = 0; d < b.length; d++) {
-            a = b[d];
-            if (Ext.getClassName(a) !== f) {
-                continue
-            }
-            g = a.getRect();
-            c += '<g transform="translate(' + g[0] + "," + g[1] + ')">';
-            c += this.serializeNode(a.svgElement.dom);
-            c += "</g>"
-        }
-        c += "</svg>";
-        return {
-            data: "data:image/svg+xml;utf8," + encodeURIComponent(c),
-            type: "svg"
-        }
-    },
-    serializeNode: function(d) {
-        var b = "",
-            c, f, a, e;
-        if (d.nodeType === document.TEXT_NODE) {
-            return d.nodeValue
-        }
-        b += "<" + d.nodeName;
-        if (d.attributes.length) {
-            for (c = 0, f = d.attributes.length; c < f; c++) {
-                a = d.attributes[c];
-                b += " " + a.name + '="' + a.value + '"'
-            }
-        }
-        b += ">";
-        if (d.childNodes && d.childNodes.length) {
-            for (c = 0, f = d.childNodes.length; c < f; c++) {
-                e = d.childNodes[c];
-                b += this.serializeNode(e)
-            }
-        }
-        b += "</" + d.nodeName + ">";
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.ctx.destroy();
-        a.mainGroup.destroy();
-        delete a.mainGroup;
-        delete a.ctx;
-        a.callParent()
-    },
-    remove: function(a, b) {
-        if (a && a.element) {
-            if (this.ctx) {
-                this.ctx.removeElement(a.element)
-            } else {
-                a.element.destroy()
-            }
-            a.element = null
-        }
-        this.callParent(arguments)
-    }
-});
-Ext.draw || (Ext.draw = {});
-Ext.draw.engine || (Ext.draw.engine = {});
-Ext.draw.engine.excanvas = true;
-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) {
-            Ext.onReady(function() {
-                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.lineDash = j.lineDash;
-            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.lineDash = [];
-            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(an, j) {
-            var ah, Z, aj, ar, al, ak, ao, av;
-            var ai = an.runtimeStyle.width;
-            var am = an.runtimeStyle.height;
-            an.runtimeStyle.width = "auto";
-            an.runtimeStyle.height = "auto";
-            var ag = an.width;
-            var aq = an.height;
-            an.runtimeStyle.width = ai;
-            an.runtimeStyle.height = am;
-            if (arguments.length == 3) {
-                ah = arguments[1];
-                Z = arguments[2];
-                al = ak = 0;
-                ao = aj = ag;
-                av = ar = aq
-            } else {
-                if (arguments.length == 5) {
-                    ah = arguments[1];
-                    Z = arguments[2];
-                    aj = arguments[3];
-                    ar = arguments[4];
-                    al = ak = 0;
-                    ao = ag;
-                    av = aq
-                } else {
-                    if (arguments.length == 9) {
-                        al = arguments[1];
-                        ak = arguments[2];
-                        ao = arguments[3];
-                        av = arguments[4];
-                        ah = arguments[5];
-                        Z = arguments[6];
-                        aj = arguments[7];
-                        ar = arguments[8]
-                    } else {
-                        throw Error("Invalid number of arguments")
-                    }
-                }
-            }
-            var au = V(this, ah, Z);
-            var at = [];
-            var i = 10;
-            var p = 10;
-            var ap = this.m_;
-            at.push(" <g_vml_:group", ' coordsize="', d * i, ",", d * p, '"', ' coordorigin="0,0"', ' style="width:', n(i * ap[0][0]), "px;height:", n(p * ap[1][1]), "px;position:absolute;", "top:", n(au.y / d), "px;left:", n(au.x / d), "px; rotation:", n(Math.atan(ap[0][1] / ap[1][1]) * 180 / Math.PI), ";");
-            at.push('" >', '<g_vml_:image src="', an.src, '"', ' style="width:', d * aj, "px;", " height:", d * ar, 'px"', ' cropleft="', al / ag, '"', ' croptop="', ak / aq, '"', ' cropright="', (ag - al - ao) / ag, '"', ' cropbottom="', (aq - ak - av) / aq, '"', " />", "</g_vml_:group>");
-            this.element_.insertAdjacentHTML("BeforeEnd", at.join(""))
-        };
-        q.setLineDash = function(i) {
-            if (i.length === 1) {
-                i = i.slice();
-                i[1] = i[0]
-            }
-            this.lineDash = i
-        };
-        q.getLineDash = function() {
-            return this.lineDash
-        };
-        q.stroke = function(ak) {
-            var ai = [];
-            var m = 10;
-            var al = 10;
-            ai.push("<g_vml_:shape", ' filled="', !!ak, '"', ' style="position:absolute;width:', m, "px;height:", al, 'px;left:0px;top:0px;"', ' coordorigin="0,0"', ' coordsize="', d * m, ",", d * al, '"', ' stroked="', !ak, '"', ' path="');
-            var Z = {
-                x: null,
-                y: null
-            };
-            var aj = {
-                x: null,
-                y: null
-            };
-            for (var ag = 0; ag < this.currentPath_.length; ag++) {
-                var j = this.currentPath_[ag];
-                var ah;
-                switch (j.type) {
-                    case "moveTo":
-                        ah = j;
-                        ai.push(" m ", n(j.x), ",", n(j.y));
-                        break;
-                    case "lineTo":
-                        ai.push(" l ", n(j.x), ",", n(j.y));
-                        break;
-                    case "close":
-                        ai.push(" x ");
-                        j = null;
-                        break;
-                    case "bezierCurveTo":
-                        ai.push(" c ", n(j.cp1x), ",", n(j.cp1y), ",", n(j.cp2x), ",", n(j.cp2y), ",", n(j.x), ",", n(j.y));
-                        break;
-                    case "at":
-                    case "wa":
-                        ai.push(" ", j.type, " ", n(j.x - this.arcScaleX_ * j.radius), ",", n(j.y - this.arcScaleY_ * j.radius), " ", n(j.x + this.arcScaleX_ * j.radius), ",", n(j.y + this.arcScaleY_ * j.radius), " ", n(j.xStart), ",", n(j.yStart), " ", n(j.xEnd), ",", n(j.yEnd));
-                        break
-                }
-                if (j) {
-                    if (Z.x == null || j.x < Z.x) {
-                        Z.x = j.x
-                    }
-                    if (aj.x == null || j.x > aj.x) {
-                        aj.x = j.x
-                    }
-                    if (Z.y == null || j.y < Z.y) {
-                        Z.y = j.y
-                    }
-                    if (aj.y == null || j.y > aj.y) {
-                        aj.y = j.y
-                    }
-                }
-            }
-            ai.push(' ">');
-            if (!ak) {
-                w(this, ai)
-            } else {
-                G(this, ai, Z, aj)
-            }
-            ai.push("</g_vml_:shape>");
-            this.element_.insertAdjacentHTML("beforeEnd", ai.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, '"', ' dashstyle="', m.lineDash.join(" "), '"', ' 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 / 3;
-                    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;left:0px;top:0px;">');
-            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
-    })()
-}
-Ext.define("Ext.draw.engine.Canvas", {
-    extend: "Ext.draw.Surface",
-    requires: ["Ext.draw.engine.excanvas", "Ext.draw.Animator", "Ext.draw.Color"],
-    config: {
-        highPrecision: false
-    },
-    statics: {
-        contextOverrides: {
-            setGradientBBox: function(a) {
-                this.bbox = a
-            },
-            fill: function() {
-                var c = this.fillStyle,
-                    a = this.fillGradient,
-                    b = this.fillOpacity,
-                    d = this.globalAlpha,
-                    e = this.bbox;
-                if (c !== Ext.draw.Color.RGBA_NONE && b !== 0) {
-                    if (a && e) {
-                        this.fillStyle = a.generateGradient(this, e)
-                    }
-                    if (b !== 1) {
-                        this.globalAlpha = d * b
-                    }
-                    this.$fill();
-                    if (b !== 1) {
-                        this.globalAlpha = d
-                    }
-                    if (a && e) {
-                        this.fillStyle = c
-                    }
-                }
-            },
-            stroke: function() {
-                var e = this.strokeStyle,
-                    c = this.strokeGradient,
-                    a = this.strokeOpacity,
-                    b = this.globalAlpha,
-                    d = this.bbox;
-                if (e !== Ext.draw.Color.RGBA_NONE && a !== 0) {
-                    if (c && d) {
-                        this.strokeStyle = c.generateGradient(this, d)
-                    }
-                    if (a !== 1) {
-                        this.globalAlpha = b * a
-                    }
-                    this.$stroke();
-                    if (a !== 1) {
-                        this.globalAlpha = b
-                    }
-                    if (c && d) {
-                        this.strokeStyle = e
-                    }
-                }
-            },
-            fillStroke: function(d, e) {
-                var j = this,
-                    i = this.fillStyle,
-                    h = this.fillOpacity,
-                    f = this.strokeStyle,
-                    c = this.strokeOpacity,
-                    b = j.shadowColor,
-                    a = j.shadowBlur,
-                    g = Ext.draw.Color.RGBA_NONE;
-                if (e === undefined) {
-                    e = d.transformFillStroke
-                }
-                if (!e) {
-                    d.inverseMatrix.toContext(j)
-                }
-                if (i !== g && h !== 0) {
-                    j.fill();
-                    j.shadowColor = g;
-                    j.shadowBlur = 0
-                }
-                if (f !== g && c !== 0) {
-                    j.stroke()
-                }
-                j.shadowColor = b;
-                j.shadowBlur = a
-            },
-            setLineDash: function(a) {
-                if (this.$setLineDash) {
-                    this.$setLineDash(a)
-                }
-            },
-            getLineDash: function() {
-                if (this.$getLineDash) {
-                    return this.$getLineDash()
-                }
-            },
-            ellipse: function(g, e, c, a, j, b, f, d) {
-                var i = Math.cos(j),
-                    h = Math.sin(j);
-                this.transform(i * c, h * c, -h * a, i * a, g, e);
-                this.arc(0, 0, 1, b, f, d);
-                this.transform(i / c, -h / a, h / c, i / a, -(i * g + h * e) / c, (h * g - i * e) / a)
-            },
-            appendPath: function(f) {
-                var e = this,
-                    c = 0,
-                    b = 0,
-                    a = f.commands,
-                    g = f.params,
-                    d = a.length;
-                e.beginPath();
-                for (; c < d; c++) {
-                    switch (a[c]) {
-                        case "M":
-                            e.moveTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "L":
-                            e.lineTo(g[b], g[b + 1]);
-                            b += 2;
-                            break;
-                        case "C":
-                            e.bezierCurveTo(g[b], g[b + 1], g[b + 2], g[b + 3], g[b + 4], g[b + 5]);
-                            b += 6;
-                            break;
-                        case "Z":
-                            e.closePath();
-                            break
-                    }
-                }
-            },
-            save: function() {
-                var c = this.toSave,
-                    d = c.length,
-                    e = d && {},
-                    b = 0,
-                    a;
-                for (; b < d; b++) {
-                    a = c[b];
-                    if (a in this) {
-                        e[a] = this[a]
-                    }
-                }
-                this.state.push(e);
-                this.$save()
-            },
-            restore: function() {
-                var b = this.state.pop(),
-                    a;
-                if (b) {
-                    for (a in b) {
-                        this[a] = b[a]
-                    }
-                }
-                this.$restore()
-            }
-        }
-    },
-    splitThreshold: 3000,
-    toSave: ["fillGradient", "strokeGradient"],
-    element: {
-        reference: "element",
-        style: {
-            position: "absolute"
-        },
-        children: [{
-            reference: "innerElement",
-            style: {
-                width: "100%",
-                height: "100%",
-                position: "relative"
-            }
-        }]
-    },
-    createCanvas: function() {
-        var c = Ext.Element.create({
-            tag: "canvas",
-            cls: Ext.baseCSSPrefix + "surface-canvas"
-        });
-        window.G_vmlCanvasManager && G_vmlCanvasManager.initElement(c.dom);
-        var d = Ext.draw.engine.Canvas.contextOverrides,
-            a = c.dom.getContext("2d"),
-            b;
-        if (a.ellipse) {
-            delete d.ellipse
-        }
-        a.state = [];
-        a.toSave = this.toSave;
-        for (b in d) {
-            a["$" + b] = a[b]
-        }
-        Ext.apply(a, d);
-        if (this.getHighPrecision()) {
-            this.enablePrecisionCompensation(a)
-        } else {
-            this.disablePrecisionCompensation(a)
-        }
-        this.innerElement.appendChild(c);
-        this.canvases.push(c);
-        this.contexts.push(a)
-    },
-    updateHighPrecision: function(d) {
-        var e = this.contexts,
-            c = e.length,
-            b, a;
-        for (b = 0; b < c; b++) {
-            a = e[b];
-            if (d) {
-                this.enablePrecisionCompensation(a)
-            } else {
-                this.disablePrecisionCompensation(a)
-            }
-        }
-    },
-    precisionNames: ["rect", "fillRect", "strokeRect", "clearRect", "moveTo", "lineTo", "arc", "arcTo", "save", "restore", "updatePrecisionCompensate", "setTransform", "transform", "scale", "translate", "rotate", "quadraticCurveTo", "bezierCurveTo", "createLinearGradient", "createRadialGradient", "fillText", "strokeText", "drawImage"],
-    disablePrecisionCompensation: function(b) {
-        var a = Ext.draw.engine.Canvas.contextOverrides,
-            f = this.precisionNames,
-            e = f.length,
-            d, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            if (!(c in a)) {
-                delete b[c]
-            }
-        }
-        this.setDirty(true)
-    },
-    enablePrecisionCompensation: function(j) {
-        var c = this,
-            a = 1,
-            g = 1,
-            l = 0,
-            k = 0,
-            i = new Ext.draw.Matrix(),
-            b = [],
-            e = {},
-            d = Ext.draw.engine.Canvas.contextOverrides,
-            h = j.constructor.prototype;
-        var f = {
-            toSave: c.toSave,
-            rect: function(m, p, n, o) {
-                return h.rect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            fillRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.fillRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            strokeRect: function(m, p, n, o) {
-                this.updatePrecisionCompensateRect();
-                h.strokeRect.call(this, m * a + l, p * g + k, n * a, o * g);
-                this.updatePrecisionCompensate()
-            },
-            clearRect: function(m, p, n, o) {
-                return h.clearRect.call(this, m * a + l, p * g + k, n * a, o * g)
-            },
-            moveTo: function(m, n) {
-                return h.moveTo.call(this, m * a + l, n * g + k)
-            },
-            lineTo: function(m, n) {
-                return h.lineTo.call(this, m * a + l, n * g + k)
-            },
-            arc: function(n, r, m, p, o, q) {
-                this.updatePrecisionCompensateRect();
-                h.arc.call(this, n * a + l, r * a + k, m * a, p, o, q);
-                this.updatePrecisionCompensate()
-            },
-            arcTo: function(o, q, n, p, m) {
-                this.updatePrecisionCompensateRect();
-                h.arcTo.call(this, o * a + l, q * g + k, n * a + l, p * g + k, m * a);
-                this.updatePrecisionCompensate()
-            },
-            save: function() {
-                b.push(i);
-                i = i.clone();
-                d.save.call(this);
-                h.save.call(this)
-            },
-            restore: function() {
-                i = b.pop();
-                d.restore.call(this);
-                h.restore.call(this);
-                this.updatePrecisionCompensate()
-            },
-            updatePrecisionCompensate: function() {
-                i.precisionCompensate(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            updatePrecisionCompensateRect: function() {
-                i.precisionCompensateRect(c.devicePixelRatio, e);
-                a = e.xx;
-                g = e.yy;
-                l = e.dx;
-                k = e.dy;
-                h.setTransform.call(this, c.devicePixelRatio, e.b, e.c, e.d, 0, 0)
-            },
-            setTransform: function(q, o, n, m, r, p) {
-                i.set(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            transform: function(q, o, n, m, r, p) {
-                i.append(q, o, n, m, r, p);
-                this.updatePrecisionCompensate()
-            },
-            scale: function(n, m) {
-                this.transform(n, 0, 0, m, 0, 0)
-            },
-            translate: function(n, m) {
-                this.transform(1, 0, 0, 1, n, m)
-            },
-            rotate: function(o) {
-                var n = Math.cos(o),
-                    m = Math.sin(o);
-                this.transform(n, m, -m, n, 0, 0)
-            },
-            quadraticCurveTo: function(n, p, m, o) {
-                h.quadraticCurveTo.call(this, n * a + l, p * g + k, m * a + l, o * g + k)
-            },
-            bezierCurveTo: function(r, p, o, n, m, q) {
-                h.bezierCurveTo.call(this, r * a + l, p * g + k, o * a + l, n * g + k, m * a + l, q * g + k)
-            },
-            createLinearGradient: function(n, p, m, o) {
-                this.updatePrecisionCompensateRect();
-                var q = h.createLinearGradient.call(this, n * a + l, p * g + k, m * a + l, o * g + k);
-                this.updatePrecisionCompensate();
-                return q
-            },
-            createRadialGradient: function(p, r, o, n, q, m) {
-                this.updatePrecisionCompensateRect();
-                var s = h.createLinearGradient.call(this, p * a + l, r * a + k, o * a, n * a + l, q * a + k, m * a);
-                this.updatePrecisionCompensate();
-                return s
-            },
-            fillText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.fillText.call(this, o, m, p)
-                } else {
-                    h.fillText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            strokeText: function(o, m, p, n) {
-                h.setTransform.apply(this, i.elements);
-                if (typeof n === "undefined") {
-                    h.strokeText.call(this, o, m, p)
-                } else {
-                    h.strokeText.call(this, o, m, p, n)
-                }
-                this.updatePrecisionCompensate()
-            },
-            fill: function() {
-                var m = this.fillGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.fillStyle = m.generateGradient(this, n)
-                }
-                h.fill.call(this);
-                this.updatePrecisionCompensate()
-            },
-            stroke: function() {
-                var m = this.strokeGradient,
-                    n = this.bbox;
-                this.updatePrecisionCompensateRect();
-                if (m && n) {
-                    this.strokeStyle = m.generateGradient(this, n)
-                }
-                h.stroke.call(this);
-                this.updatePrecisionCompensate()
-            },
-            drawImage: function(u, s, r, q, p, o, n, m, t) {
-                switch (arguments.length) {
-                    case 3:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k);
-                    case 5:
-                        return h.drawImage.call(this, u, s * a + l, r * g + k, q * a, p * g);
-                    case 9:
-                        return h.drawImage.call(this, u, s, r, q, p, o * a + l, n * g * k, m * a, t * g)
-                }
-            }
-        };
-        Ext.apply(j, f);
-        this.setDirty(true)
-    },
-    updateRect: function(a) {
-        this.callParent([a]);
-        var C = this,
-            p = Math.floor(a[0]),
-            e = Math.floor(a[1]),
-            g = Math.ceil(a[0] + a[2]),
-            B = Math.ceil(a[1] + a[3]),
-            u = C.devicePixelRatio,
-            D = C.canvases,
-            d = g - p,
-            y = B - e,
-            n = Math.round(C.splitThreshold / u),
-            c = C.xSplits = Math.ceil(d / n),
-            f = C.ySplits = Math.ceil(y / n),
-            v, s, q, A, z, x, o, m;
-        for (s = 0, z = 0; s < f; s++, z += n) {
-            for (v = 0, A = 0; v < c; v++, A += n) {
-                q = s * c + v;
-                if (q >= D.length) {
-                    C.createCanvas()
-                }
-                x = D[q].dom;
-                x.style.left = A + "px";
-                x.style.top = z + "px";
-                m = Math.min(n, y - z);
-                if (m * u !== x.height) {
-                    x.height = m * u;
-                    x.style.height = m + "px"
-                }
-                o = Math.min(n, d - A);
-                if (o * u !== x.width) {
-                    x.width = o * u;
-                    x.style.width = o + "px"
-                }
-                C.applyDefaults(C.contexts[q])
-            }
-        }
-        for (q += 1; q < D.length; q++) {
-            D[q].destroy()
-        }
-        C.activeCanvases = c * f;
-        D.length = C.activeCanvases;
-        C.clear()
-    },
-    clearTransform: function() {
-        var f = this,
-            a = f.xSplits,
-            g = f.ySplits,
-            d = f.contexts,
-            h = f.splitThreshold,
-            l = f.devicePixelRatio,
-            e, c, b, m;
-        for (e = 0; e < a; e++) {
-            for (c = 0; c < g; c++) {
-                b = c * a + e;
-                m = d[b];
-                m.translate(-h * e, -h * c);
-                m.scale(l, l);
-                f.matrix.toContext(m)
-            }
-        }
-    },
-    renderSprite: function(q) {
-        var C = this,
-            b = C.getRect(),
-            e = C.matrix,
-            g = q.getParent(),
-            v = Ext.draw.Matrix.fly([1, 0, 0, 1, 0, 0]),
-            p = C.splitThreshold / C.devicePixelRatio,
-            c = C.xSplits,
-            m = C.ySplits,
-            A, z, s, a, r, o, d = 0,
-            B, n = 0,
-            f, l = b[2],
-            y = b[3],
-            x, u, t;
-        while (g && (g !== C)) {
-            v.prependMatrix(g.matrix || g.attr && g.attr.matrix);
-            g = g.getParent()
-        }
-        v.prependMatrix(e);
-        a = q.getBBox();
-        if (a) {
-            a = v.transformBBox(a)
-        }
-        q.preRender(C);
-        if (q.attr.hidden || q.attr.globalAlpha === 0) {
-            q.setDirty(false);
-            return
-        }
-        for (u = 0, z = 0; u < m; u++, z += p) {
-            for (x = 0, A = 0; x < c; x++, A += p) {
-                t = u * c + x;
-                s = C.contexts[t];
-                r = Math.min(p, l - A);
-                o = Math.min(p, y - z);
-                d = A;
-                B = d + r;
-                n = z;
-                f = n + o;
-                if (a) {
-                    if (a.x > B || a.x + a.width < d || a.y > f || a.y + a.height < n) {
-                        continue
-                    }
-                }
-                s.save();
-                q.useAttributes(s, b);
-                if (false === q.render(C, s, [d, n, r, o], b)) {
-                    return false
-                }
-                s.restore()
-            }
-        }
-        q.setDirty(false)
-    },
-    flatten: function(n, a) {
-        var k = document.createElement("canvas"),
-            f = Ext.getClassName(this),
-            g = this.devicePixelRatio,
-            l = k.getContext("2d"),
-            b, c, h, e, d, m;
-        k.width = Math.ceil(n.width * g);
-        k.height = Math.ceil(n.height * g);
-        for (e = 0; e < a.length; e++) {
-            b = a[e];
-            if (Ext.getClassName(b) !== f) {
-                continue
-            }
-            h = b.getRect();
-            for (d = 0; d < b.canvases.length; d++) {
-                c = b.canvases[d];
-                m = c.getOffsetsTo(c.getParent());
-                l.drawImage(c.dom, (h[0] + m[0]) * g, (h[1] + m[1]) * g)
-            }
-        }
-        return {
-            data: k.toDataURL(),
-            type: "png"
-        }
-    },
-    applyDefaults: function(a) {
-        var b = Ext.draw.Color.RGBA_NONE;
-        a.strokeStyle = b;
-        a.fillStyle = b;
-        a.textAlign = "start";
-        a.textBaseline = "alphabetic";
-        a.miterLimit = 1
-    },
-    clear: function() {
-        var d = this,
-            e = d.activeCanvases,
-            c, b, a;
-        for (c = 0; c < e; c++) {
-            b = d.canvases[c].dom;
-            a = d.contexts[c];
-            a.setTransform(1, 0, 0, 1, 0, 0);
-            a.clearRect(0, 0, b.width, b.height)
-        }
-        d.setDirty(true)
-    },
-    destroy: function() {
-        var c = this,
-            a, b = c.canvases.length;
-        for (a = 0; a < b; a++) {
-            c.contexts[a] = null;
-            c.canvases[a].destroy();
-            c.canvases[a] = null
-        }
-        delete c.contexts;
-        delete c.canvases;
-        c.callParent()
-    },
-    privates: {
-        initElement: function() {
-            var a = this;
-            a.callParent();
-            a.canvases = [];
-            a.contexts = [];
-            a.activeCanvases = (a.xSplits = 0) * (a.ySplits = 0)
-        }
-    }
-}, function() {
-    var c = this,
-        b = c.prototype,
-        a = 10000000000;
-    if (Ext.os.is.Android4 && Ext.browser.is.Chrome) {
-        a = 3000
-    } else {
-        if (Ext.is.iOS) {
-            a = 2200
-        }
-    }
-    b.splitThreshold = a
-});
-Ext.define("Ext.draw.Container", {
-    extend: "Ext.draw.ContainerBase",
-    alternateClassName: "Ext.draw.Component",
-    xtype: "draw",
-    defaultType: "surface",
-    isDrawContainer: true,
-    requires: ["Ext.draw.Surface", "Ext.draw.engine.Svg", "Ext.draw.engine.Canvas", "Ext.draw.gradient.GradientDefinition"],
-    engine: "Ext.draw.engine.Canvas",
-    config: {
-        cls: Ext.baseCSSPrefix + "draw-container",
-        resizeHandler: null,
-        sprites: null,
-        gradients: []
-    },
-    defaultDownloadServerUrl: "http://svg.sencha.io",
-    supportedFormats: ["png", "pdf", "jpeg", "gif"],
-    supportedOptions: {
-        version: Ext.isNumber,
-        data: Ext.isString,
-        format: function(a) {
-            return Ext.Array.indexOf(this.supportedFormats, a) >= 0
-        },
-        filename: Ext.isString,
-        width: Ext.isNumber,
-        height: Ext.isNumber,
-        scale: Ext.isNumber,
-        pdf: Ext.isObject,
-        jpeg: Ext.isObject
-    },
-    initAnimator: function() {
-        this.frameCallbackId = Ext.draw.Animator.addFrameCallback("renderFrame", this)
-    },
-    applyGradients: function(b) {
-        var a = [],
-            c, f, d, e;
-        if (!Ext.isArray(b)) {
-            return a
-        }
-        for (c = 0, f = b.length; c < f; c++) {
-            d = b[c];
-            if (!Ext.isObject(d)) {
-                continue
-            }
-            if (typeof d.type !== "string") {
-                d.type = "linear"
-            }
-            if (d.angle) {
-                d.degrees = d.angle;
-                delete d.angle
-            }
-            if (Ext.isObject(d.stops)) {
-                d.stops = (function(i) {
-                    var g = [],
-                        h;
-                    for (e in i) {
-                        h = i[e];
-                        h.offset = e / 100;
-                        g.push(h)
-                    }
-                    return g
-                })(d.stops)
-            }
-            a.push(d)
-        }
-        Ext.draw.gradient.GradientDefinition.add(a);
-        return a
-    },
-    applySprites: function(f) {
-        if (!f) {
-            return
-        }
-        f = Ext.Array.from(f);
-        var e = f.length,
-            b = [],
-            d, a, c;
-        for (d = 0; d < e; d++) {
-            c = f[d];
-            a = c.surface;
-            if (!(a && a.isSurface)) {
-                if (Ext.isString(a)) {
-                    a = this.getSurface(a)
-                } else {
-                    a = this.getSurface("main")
-                }
-            }
-            c = a.add(c);
-            b.push(c)
-        }
-        return b
-    },
-    onBodyResize: function() {
-        var b = this.element,
-            a;
-        if (!b) {
-            return
-        }
-        a = b.getSize();
-        if (a.width && a.height) {
-            this.setBodySize(a)
-        }
-    },
-    setBodySize: function(c) {
-        var d = this,
-            b = d.getResizeHandler() || d.defaultResizeHandler,
-            a;
-        d.fireEvent("bodyresize", d, c);
-        a = b.call(d, c);
-        if (a !== false) {
-            d.renderFrame()
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.getItems().each(function(b) {
-            b.setRect([0, 0, a.width, a.height])
-        })
-    },
-    getSurface: function(d) {
-        d = this.getId() + "-" + (d || "main");
-        var c = this,
-            b = c.getItems(),
-            a = b.get(d);
-        if (!a) {
-            a = c.add({
-                xclass: c.engine,
-                id: d
-            });
-            c.onBodyResize()
-        }
-        return a
-    },
-    renderFrame: function() {
-        var e = this,
-            a = e.getItems(),
-            b, d, c;
-        for (b = 0, d = a.length; b < d; b++) {
-            c = a.items[b];
-            if (c.isSurface) {
-                c.renderFrame()
-            }
-        }
-    },
-    getImage: function(k) {
-        var l = this.innerElement.getSize(),
-            a = Array.prototype.slice.call(this.items.items),
-            d, g, c = this.surfaceZIndexes,
-            f, e, b, h;
-        for (e = 1; e < a.length; e++) {
-            b = a[e];
-            h = c[b.type];
-            f = e - 1;
-            while (f >= 0 && c[a[f].type] > h) {
-                a[f + 1] = a[f];
-                f--
-            }
-            a[f + 1] = b
-        }
-        d = a[0].flatten(l, a);
-        if (k === "image") {
-            g = new Image();
-            g.src = d.data;
-            d.data = g;
-            return d
-        }
-        if (k === "stream") {
-            d.data = d.data.replace(/^data:image\/[^;]+/, "data:application/octet-stream");
-            return d
-        }
-        return d
-    },
-    download: function(d) {
-        var e = this,
-            a = [],
-            b, c, f;
-        d = Ext.apply({
-            version: 2,
-            data: e.getImage().data
-        }, d);
-        for (c in d) {
-            if (d.hasOwnProperty(c)) {
-                f = d[c];
-                if (c in e.supportedOptions) {
-                    if (e.supportedOptions[c].call(e, f)) {
-                        a.push({
-                            tag: "input",
-                            type: "hidden",
-                            name: c,
-                            value: Ext.String.htmlEncode(Ext.isObject(f) ? Ext.JSON.encode(f) : f)
-                        })
-                    }
-                }
-            }
-        }
-        b = Ext.dom.Helper.markup({
-            tag: "html",
-            children: [{
-                tag: "head"
-            }, {
-                tag: "body",
-                children: [{
-                    tag: "form",
-                    method: "POST",
-                    action: d.url || e.defaultDownloadServerUrl,
-                    children: a
-                }, {
-                    tag: "script",
-                    type: "text/javascript",
-                    children: 'document.getElementsByTagName("form")[0].submit();'
-                }]
-            }]
-        });
-        window.open("", "ImageDownload_" + Date.now()).document.write(b)
-    },
-    destroy: function() {
-        var a = this.frameCallbackId;
-        if (a) {
-            Ext.draw.Animator.removeFrameCallback(a)
-        }
-        this.callParent()
-    }
-}, function() {
-    if (location.search.match("svg")) {
-        Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-    } else {
-        if ((Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) || (Ext.browser.is.AndroidStock4 && (Ext.os.version.getMinor() === 1 || Ext.os.version.getMinor() === 2 || Ext.os.version.getMinor() === 3))) {
-            Ext.draw.Container.prototype.engine = "Ext.draw.engine.Svg"
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Base", {
-    mixins: {
-        factoryable: "Ext.mixin.Factoryable"
-    },
-    requires: ["Ext.draw.Color"],
-    factoryConfig: {
-        type: "chart.theme"
-    },
-    isTheme: true,
-    config: {
-        baseColor: null,
-        colors: undefined,
-        gradients: null,
-        chart: {
-            defaults: {
-                background: "#23272a"
-            }
-        },
-        axis: {
-            defaults: {
-                label: {
-                    x: 0,
-                    y: 0,
-                    textBaseline: "middle",
-                    textAlign: "center",
-                    fontSize: "default",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fillStyle: "black",
-                    color: "white"
-                },
-                title: {
-                    fillStyle: "black",
-                    fontSize: "default*1.23",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    color: "white"
-                },
-                style: {
-                    strokeStyle: "black"
-                },
-                grid: {
-                    strokeStyle: "rgba(44, 47, 51, 1)"
-                }
-            },
-            top: {
-                style: {
-                    textPadding: 5
-                }
-            },
-            bottom: {
-                style: {
-                    textPadding: 5
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "black",
-                    strokeStyle: "none",
-                    fontFamily: "default",
-                    fontWeight: "default",
-                    fontSize: "default*1.077",
-                    textBaseline: "middle",
-                    textAlign: "center"
-                },
-                labelOverflowPadding: 5
-            }
-        },
-        sprites: {
-            text: {
-                fontSize: "default",
-                fontWeight: "default",
-                fontFamily: "default",
-                fillStyle: "black",
-                color: "white"
-            }
-        },
-        seriesThemes: undefined,
-        markerThemes: {
-            type: ["circle", "cross", "plus", "square", "triangle", "diamond"]
-        },
-        useGradients: false,
-        background: null
-    },
-    colorDefaults: ["#94ae0a", "#115fa6", "#a61120", "#ff8809", "#ffd13e", "#a61187", "#24ad9a", "#7c7474", "#a66111"],
-    constructor: function(a) {
-        this.initConfig(a);
-        this.resolveDefaults()
-    },
-    defaultRegEx: /^default([+\-/\*]\d+(?:\.\d+)?)?$/,
-    defaultOperators: {
-        "*": function(b, a) {
-            return b * a
-        },
-        "+": function(b, a) {
-            return b + a
-        },
-        "-": function(b, a) {
-            return b - a
-        }
-    },
-    resolveDefaults: function() {
-        var a = this;
-        Ext.onReady(function() {
-            var f = Ext.clone(a.getSprites()),
-                e = Ext.clone(a.getAxis()),
-                d = Ext.clone(a.getSeries()),
-                g, c, b;
-            if (!a.superclass.defaults) {
-                g = Ext.getBody().createChild({
-                    tag: "div",
-                    cls: "x-component"
-                });
-                a.superclass.defaults = {
-                    fontFamily: g.getStyle("fontFamily"),
-                    fontWeight: g.getStyle("fontWeight"),
-                    fontSize: parseFloat(g.getStyle("fontSize")),
-                    fontVariant: g.getStyle("fontVariant"),
-                    fontStyle: g.getStyle("fontStyle")
-                };
-                g.destroy()
-            }
-            a.replaceDefaults(f.text);
-            a.setSprites(f);
-            for (c in e) {
-                b = e[c];
-                a.replaceDefaults(b.label);
-                a.replaceDefaults(b.title)
-            }
-            a.setAxis(e);
-            for (c in d) {
-                b = d[c];
-                a.replaceDefaults(b.label)
-            }
-            a.setSeries(d)
-        })
-    },
-    replaceDefaults: function(h) {
-        var e = this,
-            g = e.superclass.defaults,
-            a = e.defaultRegEx,
-            d, f, c, b;
-        if (Ext.isObject(h)) {
-            for (d in g) {
-                c = a.exec(h[d]);
-                if (c) {
-                    f = g[d];
-                    c = c[1];
-                    if (c) {
-                        b = e.defaultOperators[c.charAt(0)];
-                        f = Math.round(b(f, parseFloat(c.substr(1))))
-                    }
-                    h[d] = f
-                }
-            }
-        }
-    },
-    applyBaseColor: function(c) {
-        var a, b;
-        if (c) {
-            a = c.isColor ? c : Ext.draw.Color.fromString(c);
-            b = a.getHSL()[2];
-            if (b < 0.15) {
-                a = a.createLighter(0.3)
-            } else {
-                if (b < 0.3) {
-                    a = a.createLighter(0.15)
-                } else {
-                    if (b > 0.85) {
-                        a = a.createDarker(0.3)
-                    } else {
-                        if (b > 0.7) {
-                            a = a.createDarker(0.15)
-                        }
-                    }
-                }
-            }
-            this.setColors([a.createDarker(0.3).toString(), a.createDarker(0.15).toString(), a.toString(), a.createLighter(0.12).toString(), a.createLighter(0.24).toString(), a.createLighter(0.31).toString()])
-        }
-        return c
-    },
-    applyColors: function(a) {
-        return a || this.colorDefaults
-    },
-    updateUseGradients: function(a) {
-        if (a) {
-            this.updateGradients({
-                type: "linear",
-                degrees: 90
-            })
-        }
-    },
-    updateBackground: function(a) {
-        if (a) {
-            var b = this.getChart();
-            b.defaults.background = a;
-            this.setChart(b)
-        }
-    },
-    updateGradients: function(a) {
-        var c = this.getColors(),
-            e = [],
-            h, b, d, f, g;
-        if (Ext.isObject(a)) {
-            for (f = 0, g = c && c.length || 0; f < g; f++) {
-                b = Ext.draw.Color.fromString(c[f]);
-                if (b) {
-                    d = b.createLighter(0.15).toString();
-                    h = Ext.apply(Ext.Object.chain(a), {
-                        stops: [{
-                            offset: 1,
-                            color: b.toString()
-                        }, {
-                            offset: 0,
-                            color: d.toString()
-                        }]
-                    });
-                    e.push(h)
-                }
-            }
-            this.setColors(e)
-        }
-    },
-    applySeriesThemes: function(a) {
-        this.getBaseColor();
-        this.getUseGradients();
-        this.getGradients();
-        var b = this.getColors();
-        if (!a) {
-            a = {
-                fillStyle: Ext.Array.clone(b),
-                strokeStyle: Ext.Array.map(b, function(d) {
-                    var c = Ext.draw.Color.fromString(d.stops ? d.stops[0].color : d);
-                    return c.createDarker(0.15).toString()
-                })
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.theme.Default", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default", "chart.theme.Base"]
-});
-Ext.define("Ext.chart.Markers", {
-    extend: "Ext.draw.sprite.Instancing",
-    isMarkers: true,
-    defaultCategory: "default",
-    constructor: function() {
-        this.callParent(arguments);
-        this.categories = {};
-        this.revisions = {}
-    },
-    destroy: function() {
-        this.categories = null;
-        this.revisions = null;
-        this.callParent()
-    },
-    getMarkerFor: function(b, a) {
-        if (b in this.categories) {
-            var c = this.categories[b];
-            if (a in c) {
-                return this.get(c[a])
-            }
-        }
-    },
-    clear: function(a) {
-        a = a || this.defaultCategory;
-        if (!(a in this.revisions)) {
-            this.revisions[a] = 1
-        } else {
-            this.revisions[a]++
-        }
-    },
-    putMarkerFor: function(e, b, c, h, f) {
-        e = e || this.defaultCategory;
-        var d = this,
-            g = d.categories[e] || (d.categories[e] = {}),
-            a;
-        if (c in g) {
-            d.setAttributesFor(g[c], b, h)
-        } else {
-            g[c] = d.getCount();
-            d.createInstance(b, h)
-        }
-        a = d.get(g[c]);
-        if (a) {
-            a.category = e;
-            if (!f) {
-                a.revision = d.revisions[e] || (d.revisions[e] = 1)
-            }
-        }
-    },
-    getMarkerBBoxFor: function(c, a, b) {
-        if (c in this.categories) {
-            var d = this.categories[c];
-            if (a in d) {
-                return this.getBBoxFor(d[a], b)
-            }
-        }
-    },
-    getBBox: function() {
-        return null
-    },
-    render: function(a, l, b) {
-        var f = this,
-            k = f.revisions,
-            j = f.attr.matrix,
-            h = f.getTemplate(),
-            d = h.attr,
-            g, c, e;
-        j.toContext(l);
-        h.preRender(a, l, b);
-        h.useAttributes(l, b);
-        for (c = 0, e = f.instances.length; c < e; c++) {
-            g = f.get(c);
-            if (g.hidden || g.revision !== k[g.category]) {
-                continue
-            }
-            l.save();
-            h.attr = g;
-            h.useAttributes(l, b);
-            h.render(a, l, b);
-            l.restore()
-        }
-        h.attr = d
-    }
-});
-Ext.define("Ext.chart.label.Callout", {
-    extend: "Ext.draw.modifier.Modifier",
-    prepareAttributes: function(a) {
-        if (!a.hasOwnProperty("calloutOriginal")) {
-            a.calloutOriginal = Ext.Object.chain(a);
-            a.calloutOriginal.prototype = a
-        }
-        if (this._previous) {
-            this._previous.prepareAttributes(a.calloutOriginal)
-        }
-    },
-    setAttrs: function(e, h) {
-        var d = e.callout,
-            i = e.calloutOriginal,
-            l = e.bbox.plain,
-            c = (l.width || 0) + e.labelOverflowPadding,
-            m = (l.height || 0) + e.labelOverflowPadding,
-            p, o;
-        if ("callout" in h) {
-            d = h.callout
-        }
-        if ("callout" in h || "calloutPlaceX" in h || "calloutPlaceY" in h || "x" in h || "y" in h) {
-            var n = "rotationRads" in h ? i.rotationRads = h.rotationRads : i.rotationRads,
-                g = "x" in h ? (i.x = h.x) : i.x,
-                f = "y" in h ? (i.y = h.y) : i.y,
-                b = "calloutPlaceX" in h ? h.calloutPlaceX : e.calloutPlaceX,
-                a = "calloutPlaceY" in h ? h.calloutPlaceY : e.calloutPlaceY,
-                k = "calloutVertical" in h ? h.calloutVertical : e.calloutVertical,
-                j;
-            n %= Math.PI * 2;
-            if (Math.cos(n) < 0) {
-                n = (n + Math.PI) % (Math.PI * 2)
-            }
-            if (n > Math.PI) {
-                n -= Math.PI * 2
-            }
-            if (k) {
-                n = n * (1 - d) - Math.PI / 2 * d;
-                j = c;
-                c = m;
-                m = j
-            } else {
-                n = n * (1 - d)
-            }
-            h.rotationRads = n;
-            h.x = g * (1 - d) + b * d;
-            h.y = f * (1 - d) + a * d;
-            p = b - g;
-            o = a - f;
-            if (Math.abs(o * c) > Math.abs(p * m)) {
-                if (o > 0) {
-                    h.calloutEndX = h.x - (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y - (m / 2) * d
-                } else {
-                    h.calloutEndX = h.x + (m / 2) * (p / o) * d;
-                    h.calloutEndY = h.y + (m / 2) * d
-                }
-            } else {
-                if (p > 0) {
-                    h.calloutEndX = h.x - c / 2;
-                    h.calloutEndY = h.y - (c / 2) * (o / p) * d
-                } else {
-                    h.calloutEndX = h.x + c / 2;
-                    h.calloutEndY = h.y + (c / 2) * (o / p) * d
-                }
-            }
-            if (h.calloutStartX && h.calloutStartY) {
-                h.calloutHasLine = (p > 0 && h.calloutStartX < h.calloutEndX) || (p <= 0 && h.calloutStartX > h.calloutEndX) || (o > 0 && h.calloutStartY < h.calloutEndY) || (o <= 0 && h.calloutStartY > h.calloutEndY)
-            } else {
-                h.calloutHasLine = true
-            }
-        }
-        return h
-    },
-    pushDown: function(a, b) {
-        b = this.callParent([a.calloutOriginal, b]);
-        return this.setAttrs(a, b)
-    },
-    popUp: function(a, b) {
-        a = a.prototype;
-        b = this.setAttrs(a, b);
-        if (this._next) {
-            return this._next.popUp(a, b)
-        } else {
-            return Ext.apply(a, b)
-        }
-    }
-});
-Ext.define("Ext.chart.label.Label", {
-    extend: "Ext.draw.sprite.Text",
-    requires: ["Ext.chart.label.Callout"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                callout: "limited01",
-                calloutHasLine: "bool",
-                calloutPlaceX: "number",
-                calloutPlaceY: "number",
-                calloutStartX: "number",
-                calloutStartY: "number",
-                calloutEndX: "number",
-                calloutEndY: "number",
-                calloutColor: "color",
-                calloutWidth: "number",
-                calloutVertical: "bool",
-                labelOverflowPadding: "number",
-                display: "enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",
-                orientation: "enums(horizontal,vertical)",
-                renderer: "default"
-            },
-            defaults: {
-                callout: 0,
-                calloutHasLine: true,
-                calloutPlaceX: 0,
-                calloutPlaceY: 0,
-                calloutStartX: 0,
-                calloutStartY: 0,
-                calloutEndX: 0,
-                calloutEndY: 0,
-                calloutWidth: 1,
-                calloutVertical: false,
-                calloutColor: "black",
-                labelOverflowPadding: 5,
-                display: "none",
-                orientation: "",
-                renderer: null
-            },
-            triggers: {
-                callout: "transform",
-                calloutPlaceX: "transform",
-                calloutPlaceY: "transform",
-                labelOverflowPadding: "transform",
-                calloutRotation: "transform",
-                display: "hidden"
-            },
-            updaters: {
-                hidden: function(a) {
-                    a.hidden = a.display === "none"
-                }
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                callout: 200
-            }
-        },
-        field: null,
-        calloutLine: true
-    },
-    applyCalloutLine: function(a) {
-        if (a) {
-            return Ext.apply({}, a)
-        }
-    },
-    prepareModifiers: function() {
-        this.callParent(arguments);
-        this.calloutModifier = new Ext.chart.label.Callout({
-            sprite: this
-        });
-        this.fx.setNext(this.calloutModifier);
-        this.calloutModifier.setNext(this.topModifier)
-    },
-    render: function(b, c) {
-        var e = this,
-            a = e.attr,
-            d = a.calloutColor;
-        c.save();
-        c.globalAlpha *= a.callout;
-        if (c.globalAlpha > 0 && a.calloutHasLine) {
-            if (d && d.isGradient) {
-                d = d.getStops()[0].color
-            }
-            c.strokeStyle = d;
-            c.fillStyle = d;
-            c.lineWidth = a.calloutWidth;
-            c.beginPath();
-            c.moveTo(e.attr.calloutStartX, e.attr.calloutStartY);
-            c.lineTo(e.attr.calloutEndX, e.attr.calloutEndY);
-            c.stroke();
-            c.beginPath();
-            c.arc(e.attr.calloutStartX, e.attr.calloutStartY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill();
-            c.beginPath();
-            c.arc(e.attr.calloutEndX, e.attr.calloutEndY, 1 * a.calloutWidth, 0, 2 * Math.PI, true);
-            c.fill()
-        }
-        c.restore();
-        Ext.draw.sprite.Text.prototype.render.apply(e, arguments)
-    }
-});
-Ext.define("Ext.chart.series.Series", {
-    requires: ["Ext.chart.Markers", "Ext.chart.label.Label", "Ext.tip.ToolTip"],
-    mixins: ["Ext.mixin.Observable", "Ext.mixin.Bindable"],
-    isSeries: true,
-    defaultBindProperty: "store",
-    type: null,
-    seriesType: "sprite",
-    identifiablePrefix: "ext-line-",
-    observableType: "series",
-    darkerStrokeRatio: 0.15,
-    config: {
-        chart: null,
-        title: null,
-        renderer: null,
-        showInLegend: true,
-        triggerAfterDraw: false,
-        style: {},
-        subStyle: {},
-        themeStyle: {},
-        colors: null,
-        useDarkerStrokeColor: true,
-        store: null,
-        label: {},
-        labelOverflowPadding: null,
-        showMarkers: true,
-        marker: null,
-        markerSubStyle: null,
-        itemInstancing: null,
-        background: null,
-        highlightItem: null,
-        surface: null,
-        overlaySurface: null,
-        hidden: false,
-        highlight: false,
-        highlightCfg: {
-            merge: function(a) {
-                return a
-            },
-            $value: {
-                fillStyle: "yellow",
-                strokeStyle: "red"
-            }
-        },
-        animation: null,
-        tooltip: null
-    },
-    directions: [],
-    sprites: null,
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 0
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        var a = this.getChart();
-        if (a && a.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    updateTitle: function(a) {
-        var j = this,
-            g = j.getChart();
-        if (!g || g.isInitializing) {
-            return
-        }
-        a = Ext.Array.from(a);
-        var c = g.getSeries(),
-            b = Ext.Array.indexOf(c, j),
-            e = g.getLegendStore(),
-            h = j.getYField(),
-            d, l, k, f;
-        if (e.getCount() && b !== -1) {
-            f = h ? Math.min(a.length, h.length) : a.length;
-            for (d = 0; d < f; d++) {
-                k = a[d];
-                l = e.getAt(b + d);
-                if (k && l) {
-                    l.set("name", k)
-                }
-            }
-        }
-    },
-    applyHighlight: function(a, b) {
-        if (Ext.isObject(a)) {
-            a = Ext.merge({}, this.config.highlightCfg, a)
-        } else {
-            if (a === true) {
-                a = this.config.highlightCfg
-            }
-        }
-        return Ext.apply(b || {}, a)
-    },
-    updateHighlight: function(a) {
-        this.getStyle();
-        if (!Ext.Object.isEmpty(a)) {
-            this.addItemHighlight()
-        }
-    },
-    updateHighlightCfg: function(a) {
-        if (!Ext.Object.equals(a, this.defaultConfig.highlightCfg)) {
-            this.addItemHighlight()
-        }
-    },
-    applyItemInstancing: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    setAttributesForItem: function(c, d) {
-        var b = c && c.sprite,
-            a;
-        if (b) {
-            if (b.itemsMarker && c.category === "items") {
-                b.putMarker(c.category, d, c.index, false, true)
-            }
-            if (b.isMarkerHolder && c.category === "markers") {
-                b.putMarker(c.category, d, c.index, false, true)
-            } else {
-                if (b.isInstancing) {
-                    b.setAttributesFor(c.index, d)
-                } else {
-                    if (Ext.isArray(b)) {
-                        for (a = 0; a < b.length; a++) {
-                            b[a].setAttributes(d)
-                        }
-                    } else {
-                        b.setAttributes(d)
-                    }
-                }
-            }
-        }
-    },
-    getBBoxForItem: function(a) {
-        if (a && a.sprite) {
-            if (a.sprite.itemsMarker && a.category === "items") {
-                return a.sprite.getMarkerBBox(a.category, a.index)
-            } else {
-                if (a.sprite instanceof Ext.draw.sprite.Instancing) {
-                    return a.sprite.getBBoxFor(a.index)
-                } else {
-                    return a.sprite.getBBox()
-                }
-            }
-        }
-        return null
-    },
-    applyHighlightItem: function(d, a) {
-        if (d === a) {
-            return
-        }
-        if (Ext.isObject(d) && Ext.isObject(a)) {
-            var c = d.sprite === a.sprite,
-                b = d.index === a.index;
-            if (c && b) {
-                return
-            }
-        }
-        return d
-    },
-    updateHighlightItem: function(b, a) {
-        this.setAttributesForItem(a, {
-            highlighted: false
-        });
-        this.setAttributesForItem(b, {
-            highlighted: true
-        })
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if (a.tips) {
-            a = Ext.apply({
-                tooltip: a.tips
-            }, a)
-        }
-        if (a.highlightCfg) {
-            a = Ext.apply({
-                highlight: a.highlightCfg
-            }, a)
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.sprites = [];
-        b.dataRange = [];
-        b.mixins.observable.constructor.call(b, a);
-        b.initBindable()
-    },
-    lookupViewModel: function(a) {
-        var b = this.getChart();
-        return b ? b.lookupViewModel(a) : null
-    },
-    applyTooltip: function(c, b) {
-        var a = Ext.apply({
-            xtype: "tooltip",
-            renderer: Ext.emptyFn,
-            constrainPosition: true,
-            shrinkWrapDock: true,
-            autoHide: true,
-            offsetX: 10,
-            offsetY: 10
-        }, c);
-        return Ext.create(a)
-    },
-    updateTooltip: function() {
-        this.addItemHighlight()
-    },
-    addItemHighlight: function() {
-        var d = this.getChart();
-        if (!d) {
-            return
-        }
-        var e = d.getInteractions(),
-            c, a, b;
-        for (c = 0; c < e.length; c++) {
-            a = e[c];
-            if (a.isItemHighlight || a.isItemEdit) {
-                b = true;
-                break
-            }
-        }
-        if (!b) {
-            e.push("itemhighlight");
-            d.setInteractions(e)
-        }
-    },
-    showTooltip: function(l, m) {
-        var d = this,
-            n = d.getTooltip(),
-            j, a, i, f, h, k, g, e, b, c;
-        if (!n) {
-            return
-        }
-        clearTimeout(d.tooltipTimeout);
-        b = n.config;
-        if (n.trackMouse) {
-            m[0] += b.offsetX;
-            m[1] += b.offsetY
-        } else {
-            j = l.sprite;
-            a = j.getSurface();
-            i = Ext.get(a.getId());
-            if (i) {
-                k = l.series.getBBoxForItem(l);
-                g = k.x + k.width / 2;
-                e = k.y + k.height / 2;
-                h = a.matrix.transformPoint([g, e]);
-                f = i.getXY();
-                c = a.getInherited().rtl;
-                g = c ? f[0] + i.getWidth() - h[0] : f[0] + h[0];
-                e = f[1] + h[1];
-                m = [g, e]
-            }
-        }
-        Ext.callback(n.renderer, n.scope, [n, l.record, l], 0, d);
-        n.show(m)
-    },
-    hideTooltip: function(b) {
-        var a = this,
-            c = a.getTooltip();
-        if (!c) {
-            return
-        }
-        clearTimeout(a.tooltipTimeout);
-        a.tooltipTimeout = Ext.defer(function() {
-            c.hide()
-        }, 1)
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    getStore: function() {
-        return this._store || this.getChart() && this.getChart().getStore()
-    },
-    updateStore: function(b, a) {
-        var h = this,
-            g = h.getChart(),
-            c = g && g.getStore(),
-            f, j, e, d;
-        a = a || c;
-        if (a && a !== b) {
-            a.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            })
-        }
-        if (b) {
-            b.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: h
-            });
-            f = h.getSprites();
-            for (d = 0, e = f.length; d < e; d++) {
-                j = f[d];
-                if (j.setStore) {
-                    j.setStore(b)
-                }
-            }
-            h.onDataChanged()
-        }
-        h.fireEvent("storechange", h, b, a)
-    },
-    onStoreChange: function(b, a, c) {
-        if (!this._store) {
-            this.updateStore(a, c)
-        }
-    },
-    coordinate: function(o, m, e) {
-        var l = this,
-            p = l.getStore(),
-            h = l.getHidden(),
-            k = p.getData().items,
-            b = l["get" + o + "Axis"](),
-            f = {
-                min: Infinity,
-                max: -Infinity
-            },
-            q = l["fieldCategory" + o] || [o],
-            g = l.getFields(q),
-            d, n, c, a = {},
-            j = l.getSprites();
-        if (j.length > 0) {
-            if (!Ext.isBoolean(h) || !h) {
-                for (d = 0; d < q.length; d++) {
-                    n = g[d];
-                    c = l.coordinateData(k, n, b);
-                    l.getRangeOfData(c, f);
-                    a["data" + q[d]] = c
-                }
-            }
-            l.dataRange[m] = f.min;
-            l.dataRange[m + e] = f.max;
-            a["dataMin" + o] = f.min;
-            a["dataMax" + o] = f.max;
-            if (b) {
-                b.range = null;
-                a["range" + o] = b.getRange()
-            }
-            for (d = 0; d < j.length; d++) {
-                j[d].setAttributes(a)
-            }
-        }
-    },
-    coordinateData: function(b, h, d) {
-        var g = [],
-            f = b.length,
-            e = d && d.getLayout(),
-            c, a;
-        for (c = 0; c < f; c++) {
-            a = b[c].data[h];
-            if (!Ext.isEmpty(a, true)) {
-                if (e) {
-                    g[c] = e.getCoordFor(a, h, c, b)
-                } else {
-                    g[c] = +a
-                }
-            } else {
-                g[c] = a
-            }
-        }
-        return g
-    },
-    getRangeOfData: function(g, b) {
-        var e = g.length,
-            d = b.min,
-            a = b.max,
-            c, f;
-        for (c = 0; c < e; c++) {
-            f = g[c];
-            if (f < d) {
-                d = f
-            }
-            if (f > a) {
-                a = f
-            }
-        }
-        b.min = d;
-        b.max = a
-    },
-    updateLabelData: function() {
-        var h = this,
-            l = h.getStore(),
-            g = l.getData().items,
-            f = h.getSprites(),
-            a = h.getLabel().getTemplate(),
-            n = Ext.Array.from(a.getField()),
-            c, b, e, d, m, k;
-        if (!f.length || !n.length) {
-            return
-        }
-        for (c = 0; c < f.length; c++) {
-            d = [];
-            m = f[c];
-            k = m.getField();
-            if (Ext.Array.indexOf(n, k) < 0) {
-                k = n[c]
-            }
-            for (b = 0, e = g.length; b < e; b++) {
-                d.push(g[b].get(k))
-            }
-            m.setAttributes({
-                labels: d
-            })
-        }
-    },
-    processData: function() {
-        if (!this.getStore()) {
-            return
-        }
-        var d = this,
-            f = this.directions,
-            a, c = f.length,
-            e, b;
-        for (a = 0; a < c; a++) {
-            e = f[a];
-            b = d["get" + e + "Axis"]();
-            if (b) {
-                b.processData(d);
-                continue
-            }
-            if (d["coordinate" + e]) {
-                d["coordinate" + e]()
-            }
-        }
-        d.updateLabelData()
-    },
-    applyBackground: function(a) {
-        if (this.getChart()) {
-            this.getSurface().setBackground(a);
-            return this.getSurface().getBackground()
-        } else {
-            return a
-        }
-    },
-    updateChart: function(d, a) {
-        var c = this,
-            b = c._store;
-        if (a) {
-            a.un("axeschange", "onAxesChange", c);
-            c.clearSprites();
-            c.setSurface(null);
-            c.setOverlaySurface(null);
-            a.unregister(c);
-            c.onChartDetached(a);
-            if (!b) {
-                c.updateStore(null)
-            }
-        }
-        if (d) {
-            c.setSurface(d.getSurface("series"));
-            c.setOverlaySurface(d.getSurface("overlay"));
-            d.on("axeschange", "onAxesChange", c);
-            if (d.getAxes()) {
-                c.onAxesChange(d)
-            }
-            c.onChartAttached(d);
-            d.register(c);
-            if (!b) {
-                c.updateStore(d.getStore())
-            }
-        }
-    },
-    onAxesChange: function(h) {
-        var k = this,
-            g = h.getAxes(),
-            c, a = {},
-            b = {},
-            e = false,
-            j = this.directions,
-            l, d, f;
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            b[l] = k.getFields(k["fieldCategory" + l])
-        }
-        for (d = 0, f = g.length; d < f; d++) {
-            c = g[d];
-            if (!a[c.getDirection()]) {
-                a[c.getDirection()] = [c]
-            } else {
-                a[c.getDirection()].push(c)
-            }
-        }
-        for (d = 0, f = j.length; d < f; d++) {
-            l = j[d];
-            if (k["get" + l + "Axis"]()) {
-                continue
-            }
-            if (a[l]) {
-                c = k.findMatchingAxis(a[l], b[l]);
-                if (c) {
-                    k["set" + l + "Axis"](c);
-                    if (c.getNeedHighPrecision()) {
-                        e = true
-                    }
-                }
-            }
-        }
-        this.getSurface().setHighPrecision(e)
-    },
-    findMatchingAxis: function(f, e) {
-        var d, c, b, a;
-        for (b = 0; b < f.length; b++) {
-            d = f[b];
-            c = d.getFields();
-            if (!c.length) {
-                return d
-            } else {
-                if (e) {
-                    for (a = 0; a < e.length; a++) {
-                        if (Ext.Array.indexOf(c, e[a]) >= 0) {
-                            return d
-                        }
-                    }
-                }
-            }
-        }
-    },
-    onChartDetached: function(a) {
-        var b = this;
-        b.fireEvent("chartdetached", a, b);
-        a.un("storechange", "onStoreChange", b)
-    },
-    onChartAttached: function(a) {
-        var b = this;
-        b.setBackground(b.getBackground());
-        b.fireEvent("chartattached", a, b);
-        a.on("storechange", "onStoreChange", b);
-        b.processData()
-    },
-    updateOverlaySurface: function(a) {
-        var b = this;
-        if (a) {
-            if (b.getLabel()) {
-                b.getOverlaySurface().add(b.getLabel())
-            }
-        }
-    },
-    applyLabel: function(a, b) {
-        if (!b) {
-            b = new Ext.chart.Markers({
-                zIndex: 10
-            });
-            b.setTemplate(new Ext.chart.label.Label(a))
-        } else {
-            b.getTemplate().setAttributes(a)
-        }
-        return b
-    },
-    createItemInstancingSprite: function(c, b) {
-        var e = this,
-            f = new Ext.chart.Markers(),
-            a, d;
-        f.setAttributes({
-            zIndex: Number.MAX_VALUE
-        });
-        a = Ext.apply({}, b);
-        if (e.getHighlight()) {
-            a.highlight = e.getHighlight();
-            a.modifiers = ["highlight"]
-        }
-        f.setTemplate(a);
-        d = f.getTemplate();
-        d.setAttributes(e.getStyle());
-        d.fx.on("animationstart", "onSpriteAnimationStart", this);
-        d.fx.on("animationend", "onSpriteAnimationEnd", this);
-        c.bindMarker("items", f);
-        e.getSurface().add(f);
-        return f
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer()
-        }
-    },
-    updateRenderer: function(c) {
-        var b = this,
-            a = b.getChart(),
-            d;
-        if (a && a.isInitializing) {
-            return
-        }
-        d = b.getSprites();
-        if (d.length) {
-            d[0].setAttributes({
-                renderer: c || null
-            });
-            if (a && !a.isInitializing) {
-                a.redraw()
-            }
-        }
-    },
-    updateShowMarkers: function(a) {
-        var d = this.getSprites(),
-            b = d && d[0],
-            c = b && b.getMarker("markers");
-        if (c) {
-            c.getTemplate().setAttributes({
-                hidden: !a
-            })
-        }
-    },
-    createSprite: function() {
-        var f = this,
-            a = f.getSurface(),
-            e = f.getItemInstancing(),
-            d = a.add(f.getDefaultSpriteConfig()),
-            b = f.getMarker(),
-            g, c;
-        d.setAttributes(f.getStyle());
-        d.setSeries(f);
-        if (e) {
-            d.itemsMarker = f.createItemInstancingSprite(d, e)
-        }
-        if (d.bindMarker) {
-            if (b) {
-                g = new Ext.chart.Markers();
-                c = Ext.Object.merge({}, b);
-                if (f.getHighlight()) {
-                    c.highlight = f.getHighlight();
-                    c.modifiers = ["highlight"]
-                }
-                g.setTemplate(c);
-                g.getTemplate().fx.setCustomDurations({
-                    translationX: 0,
-                    translationY: 0
-                });
-                d.dataMarker = g;
-                d.bindMarker("markers", g);
-                f.getOverlaySurface().add(g)
-            }
-            if (f.getLabel().getTemplate().getField()) {
-                d.bindMarker("labels", f.getLabel())
-            }
-        }
-        if (d.setStore) {
-            d.setStore(f.getStore())
-        }
-        d.fx.on("animationstart", "onSpriteAnimationStart", f);
-        d.fx.on("animationend", "onSpriteAnimationEnd", f);
-        f.sprites.push(d);
-        return d
-    },
-    getSprites: Ext.emptyFn,
-    onDataChanged: function() {
-        var d = this,
-            c = d.getChart(),
-            b = c && c.getStore(),
-            a = d.getStore();
-        if (a !== b) {
-            d.processData()
-        }
-    },
-    isXType: function(a) {
-        return a === "series"
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    applyThemeStyle: function(e, a) {
-        var b = this,
-            d, c;
-        d = e && e.subStyle && e.subStyle.fillStyle;
-        c = d && e.subStyle.strokeStyle;
-        if (d && !c) {
-            e.subStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        d = e && e.markerSubStyle && e.markerSubStyle.fillStyle;
-        c = d && e.markerSubStyle.strokeStyle;
-        if (d && !c) {
-            e.markerSubStyle.strokeStyle = b.getStrokeColorsFromFillColors(d)
-        }
-        return Ext.apply(a || {}, e)
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        return Ext.apply({}, c, b)
-    },
-    applySubStyle: function(b, c) {
-        var a = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + this.seriesType));
-        if (a && a.def) {
-            b = a.def.batchedNormalize(b, true)
-        }
-        return Ext.merge({}, c, b)
-    },
-    applyMarker: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.normalize(Ext.isObject(c) ? c : {}, true);
-            c.type = d
-        }
-        return Ext.merge(a || {}, c)
-    },
-    applyMarkerSubStyle: function(c, a) {
-        var d = (c && c.type) || (a && a.type) || "circle",
-            b = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite." + d));
-        if (b && b.def) {
-            c = b.def.batchedNormalize(c, true)
-        }
-        return Ext.merge(a || {}, c)
-    },
-    updateHidden: function(b) {
-        var a = this;
-        a.getColors();
-        a.getSubStyle();
-        a.setSubStyle({
-            hidden: b
-        });
-        a.processData();
-        a.doUpdateStyles();
-        if (!Ext.isArray(b)) {
-            a.updateLegendStore(b)
-        }
-    },
-    updateLegendStore: function(f, b) {
-        var e = this,
-            d = e.getChart(),
-            c = d.getLegendStore(),
-            g = e.getId(),
-            a;
-        if (c) {
-            if (arguments.length > 1) {
-                a = c.findBy(function(h) {
-                    return h.get("series") === g && h.get("index") === b
-                });
-                if (a !== -1) {
-                    a = c.getAt(a)
-                }
-            } else {
-                a = c.findRecord("series", g)
-            }
-            if (a && a.get("disabled") !== f) {
-                a.set("disabled", f)
-            }
-        }
-    },
-    setHiddenByIndex: function(a, c) {
-        var b = this;
-        if (Ext.isArray(b.getHidden())) {
-            b.getHidden()[a] = c;
-            b.updateHidden(b.getHidden());
-            b.updateLegendStore(c, a)
-        } else {
-            b.setHidden(c)
-        }
-    },
-    getStrokeColorsFromFillColors: function(a) {
-        var c = this,
-            e = c.getUseDarkerStrokeColor(),
-            b = (Ext.isNumber(e) ? e : c.darkerStrokeRatio),
-            d;
-        if (e) {
-            d = Ext.Array.map(a, function(f) {
-                f = Ext.isString(f) ? f : f.stops[0].color;
-                f = Ext.draw.Color.fromString(f);
-                return f.createDarker(b).toString()
-            })
-        } else {
-            d = Ext.Array.clone(a)
-        }
-        return d
-    },
-    updateThemeColors: function(b) {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = Ext.Array.clone(b),
-            f = c.getStrokeColorsFromFillColors(b),
-            e = {
-                fillStyle: a,
-                strokeStyle: f
-            };
-        d.subStyle = Ext.apply(d.subStyle || {}, e);
-        d.markerSubStyle = Ext.apply(d.markerSubStyle || {}, e);
-        c.doUpdateStyles()
-    },
-    themeOnlyIfConfigured: {},
-    updateTheme: function(d) {
-        var h = this,
-            a = d.getSeries(),
-            n = h.getInitialConfig(),
-            c = h.defaultConfig,
-            f = h.getConfigurator().configs,
-            j = a.defaults,
-            k = a[h.type],
-            g = h.themeOnlyIfConfigured,
-            l, i, o, b, m, e;
-        a = Ext.merge({}, j, k);
-        for (l in a) {
-            i = a[l];
-            e = f[l];
-            if (i !== null && i !== undefined && e) {
-                m = n[l];
-                o = Ext.isObject(i);
-                b = m === c[l];
-                if (o) {
-                    if (b && g[l]) {
-                        continue
-                    }
-                    i = Ext.merge({}, i, m)
-                }
-                if (b || o) {
-                    h[e.names.set](i)
-                }
-            }
-        }
-    },
-    updateChartColors: function(a) {
-        var b = this;
-        if (!b.getColors()) {
-            b.updateThemeColors(a)
-        }
-    },
-    updateColors: function(a) {
-        this.updateThemeColors(a)
-    },
-    updateStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateSubStyle: function() {
-        this.doUpdateStyles()
-    },
-    updateThemeStyle: function() {
-        this.doUpdateStyles()
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.sprites,
-            d = g.getItemInstancing(),
-            c = 0,
-            f = h && h.length,
-            a = g.getConfig("showMarkers", true),
-            b = g.getMarker(),
-            e;
-        for (; c < f; c++) {
-            e = g.getStyleByIndex(c);
-            if (d) {
-                h[c].itemsMarker.getTemplate().setAttributes(e)
-            }
-            h[c].setAttributes(e);
-            if (b && h[c].dataMarker) {
-                h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))
-            }
-        }
-    },
-    getStyleWithTheme: function() {
-        var b = this,
-            c = b.getThemeStyle(),
-            d = (c && c.style) || {},
-            a = Ext.applyIf(Ext.apply({}, b.getStyle()), d);
-        return a
-    },
-    getSubStyleWithTheme: function() {
-        var c = this,
-            d = c.getThemeStyle(),
-            a = (d && d.subStyle) || {},
-            b = Ext.applyIf(Ext.apply({}, c.getSubStyle()), a);
-        return b
-    },
-    getStyleByIndex: function(b) {
-        var e = this,
-            h = e.getThemeStyle(),
-            d, g, c, f, a = {};
-        d = e.getStyle();
-        g = (h && h.style) || {};
-        c = e.styleDataForIndex(e.getSubStyle(), b);
-        f = e.styleDataForIndex((h && h.subStyle), b);
-        Ext.apply(a, g);
-        Ext.apply(a, f);
-        Ext.apply(a, d);
-        Ext.apply(a, c);
-        return a
-    },
-    getMarkerStyleByIndex: function(d) {
-        var g = this,
-            c = g.getThemeStyle(),
-            a, e, k, j, b, l, h, f, m = {};
-        a = g.getStyle();
-        e = (c && c.style) || {};
-        k = g.styleDataForIndex(g.getSubStyle(), d);
-        if (k.hasOwnProperty("hidden")) {
-            k.hidden = k.hidden || !this.getConfig("showMarkers", true)
-        }
-        j = g.styleDataForIndex((c && c.subStyle), d);
-        b = g.getMarker();
-        l = (c && c.marker) || {};
-        h = g.getMarkerSubStyle();
-        f = g.styleDataForIndex((c && c.markerSubStyle), d);
-        Ext.apply(m, e);
-        Ext.apply(m, j);
-        Ext.apply(m, l);
-        Ext.apply(m, f);
-        Ext.apply(m, a);
-        Ext.apply(m, k);
-        Ext.apply(m, b);
-        Ext.apply(m, h);
-        return m
-    },
-    styleDataForIndex: function(d, c) {
-        var e, b, a = {};
-        if (d) {
-            for (b in d) {
-                e = d[b];
-                if (Ext.isArray(e)) {
-                    a[b] = e[c % e.length]
-                } else {
-                    a[b] = e
-                }
-            }
-        }
-        return a
-    },
-    getItemForPoint: Ext.emptyFn,
-    getItemByIndex: function(a, e) {
-        var d = this,
-            f = d.getSprites(),
-            b = f && f[0],
-            c;
-        if (!b) {
-            return
-        }
-        if (e === undefined && b.isMarkerHolder) {
-            e = d.getItemInstancing() ? "items" : "markers"
-        } else {
-            if (!e || e === "" || e === "sprites") {
-                b = f[a]
-            }
-        }
-        if (b) {
-            c = {
-                series: d,
-                category: e,
-                index: a,
-                record: d.getStore().getData().items[a],
-                field: d.getYField(),
-                sprite: b
-            };
-            return c
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.fireEvent("animationstart", this, a)
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.fireEvent("animationend", this, a)
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    provideLegendInfo: function(a) {
-        a.push({
-            name: this.getTitle() || this.getId(),
-            mark: "black",
-            disabled: this.getHidden(),
-            series: this.getId(),
-            index: 0
-        })
-    },
-    clearSprites: function() {
-        var d = this.sprites,
-            b, a, c;
-        for (a = 0, c = d.length; a < c; a++) {
-            b = d[a];
-            if (b && b.isSprite) {
-                b.destroy()
-            }
-        }
-        this.sprites = []
-    },
-    destroy: function() {
-        var b = this,
-            a = b._store,
-            c = b.getConfig("tooltip", true);
-        if (a && a.getAutoDestroy()) {
-            Ext.destroy(a)
-        }
-        b.setChart(null);
-        b.clearListeners();
-        if (c) {
-            Ext.destroy(c);
-            clearTimeout(b.tooltipTimeout)
-        }
-        b.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Abstract", {
-    xtype: "interaction",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        gestures: {
-            tap: "onGesture"
-        },
-        chart: null,
-        enabled: true
-    },
-    throttleGap: 0,
-    stopAnimationBeforeSync: false,
-    constructor: function(a) {
-        var b = this,
-            c;
-        a = a || {};
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.call(b, a)
-    },
-    initialize: Ext.emptyFn,
-    updateChart: function(c, a) {
-        var b = this;
-        if (a === c) {
-            return
-        }
-        if (a) {
-            a.unregister(b);
-            b.removeChartListener(a)
-        }
-        if (c) {
-            c.register(b);
-            b.addChartListener()
-        }
-    },
-    updateEnabled: function(a) {
-        var c = this,
-            b = c.getChart();
-        if (b) {
-            if (a) {
-                c.addChartListener()
-            } else {
-                c.removeChartListener(b)
-            }
-        }
-    },
-    onGesture: Ext.emptyFn,
-    getItemForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemForPoint(c[0], c[1])
-    },
-    getItemsForEvent: function(d) {
-        var b = this,
-            a = b.getChart(),
-            c = a.getEventXY(d);
-        return a.getItemsForPoint(c[0], c[1])
-    },
-    addChartListener: function() {
-        var c = this,
-            b = c.getChart(),
-            e = c.getGestures(),
-            a;
-        if (!c.getEnabled()) {
-            return
-        }
-
-        function d(f, g) {
-            b.addElementListener(f, c.listeners[f] = function(j) {
-                var i = c.getLocks(),
-                    h;
-                if (c.getEnabled() && (!(f in i) || i[f] === c)) {
-                    h = (Ext.isFunction(g) ? g : c[g]).apply(this, arguments);
-                    if (h === false && j && j.stopPropagation) {
-                        j.stopPropagation()
-                    }
-                    return h
-                }
-            }, c)
-        }
-        c.listeners = c.listeners || {};
-        for (a in e) {
-            d(a, e[a])
-        }
-    },
-    removeChartListener: function(c) {
-        var d = this,
-            e = d.getGestures(),
-            b;
-
-        function a(f) {
-            var g = d.listeners[f];
-            if (g) {
-                c.removeElementListener(f, g);
-                delete d.listeners[f]
-            }
-        }
-        if (d.listeners) {
-            for (b in e) {
-                a(b)
-            }
-        }
-    },
-    lockEvents: function() {
-        var d = this,
-            c = d.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            c[a[b]] = d
-        }
-    },
-    unlockEvents: function() {
-        var c = this.getLocks(),
-            a = Array.prototype.slice.call(arguments),
-            b = a.length;
-        while (b--) {
-            delete c[a[b]]
-        }
-    },
-    getLocks: function() {
-        var a = this.getChart();
-        return a.lockedEvents || (a.lockedEvents = {})
-    },
-    isMultiTouch: function() {
-        if (Ext.browser.is.IE10) {
-            return true
-        }
-        return !Ext.os.is.Desktop
-    },
-    initializeDefaults: Ext.emptyFn,
-    doSync: function() {
-        var b = this,
-            a = b.getChart();
-        if (b.syncTimer) {
-            clearTimeout(b.syncTimer);
-            b.syncTimer = null
-        }
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount++
-        }
-        a.redraw();
-        if (b.stopAnimationBeforeSync) {
-            a.animationSuspendCount--
-        }
-        b.syncThrottle = Date.now() + b.throttleGap
-    },
-    sync: function() {
-        var a = this;
-        if (a.throttleGap && Ext.frameStartTime < a.syncThrottle) {
-            if (a.syncTimer) {
-                return
-            }
-            a.syncTimer = Ext.defer(function() {
-                a.doSync()
-            }, a.throttleGap)
-        } else {
-            a.doSync()
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    isXType: function(a) {
-        return a === "interaction"
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        delete a.listeners;
-        a.callParent()
-    }
-}, function() {
-    if (Ext.os.is.Android4) {
-        this.prototype.throttleGap = 40
-    }
-});
-Ext.define("Ext.chart.MarkerHolder", {
-    extend: "Ext.Mixin",
-    mixinConfig: {
-        id: "markerHolder",
-        after: {
-            constructor: "constructor",
-            preRender: "preRender"
-        },
-        before: {
-            destroy: "destroy"
-        }
-    },
-    isMarkerHolder: true,
-    surfaceMatrix: null,
-    inverseSurfaceMatrix: null,
-    deprecated: {
-        6: {
-            methods: {
-                getBoundMarker: {
-                    message: "Please use the 'getMarker' method instead.",
-                    fn: function(b) {
-                        var a = this.boundMarkers[b];
-                        return a ? [a] : a
-                    }
-                }
-            }
-        }
-    },
-    constructor: function() {
-        this.boundMarkers = {};
-        this.cleanRedraw = false
-    },
-    bindMarker: function(b, a) {
-        var c = this,
-            d = c.boundMarkers;
-        if (a && a.isMarkers) {
-            c.releaseMarker(b);
-            d[b] = a;
-            a.on("destroy", c.onMarkerDestroy, c)
-        }
-    },
-    onMarkerDestroy: function(a) {
-        this.releaseMarker(a)
-    },
-    releaseMarker: function(a) {
-        var c = this.boundMarkers,
-            b;
-        if (a && a.isMarkers) {
-            for (b in c) {
-                if (c[b] === a) {
-                    delete c[b];
-                    break
-                }
-            }
-        } else {
-            b = a;
-            a = c[b];
-            delete c[b]
-        }
-        return a || null
-    },
-    getMarker: function(a) {
-        return this.boundMarkers[a] || null
-    },
-    preRender: function() {
-        var f = this,
-            g = f.getId(),
-            d = f.boundMarkers,
-            e = f.getParent(),
-            c, a, b;
-        if (f.surfaceMatrix) {
-            b = f.surfaceMatrix.set(1, 0, 0, 1, 0, 0)
-        } else {
-            b = f.surfaceMatrix = new Ext.draw.Matrix()
-        }
-        f.cleanRedraw = !f.attr.dirty;
-        if (!f.cleanRedraw) {
-            for (c in d) {
-                a = d[c];
-                if (a) {
-                    a.clear(g)
-                }
-            }
-        }
-        while (e && e.attr && e.attr.matrix) {
-            b.prependMatrix(e.attr.matrix);
-            e = e.getParent()
-        }
-        b.prependMatrix(e.matrix);
-        f.surfaceMatrix = b;
-        f.inverseSurfaceMatrix = b.inverse(f.inverseSurfaceMatrix)
-    },
-    putMarker: function(d, a, c, g, e) {
-        var b = this.boundMarkers[d],
-            f = this.getId();
-        if (b) {
-            b.putMarkerFor(f, a, c, g, e)
-        }
-    },
-    getMarkerBBox: function(c, b, d) {
-        var a = this.boundMarkers[c],
-            e = this.getId();
-        if (a) {
-            return a.getMarkerBBoxFor(e, b, d)
-        }
-    },
-    destroy: function() {
-        var c = this.boundMarkers,
-            b, a;
-        for (b in c) {
-            a = c[b];
-            a.destroy()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.axis",
-    type: "axis",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    requires: ["Ext.draw.sprite.Text"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                grid: "bool",
-                axisLine: "bool",
-                minorTicks: "bool",
-                minorTickSize: "number",
-                majorTicks: "bool",
-                majorTickSize: "number",
-                length: "number",
-                startGap: "number",
-                endGap: "number",
-                dataMin: "number",
-                dataMax: "number",
-                visibleMin: "number",
-                visibleMax: "number",
-                position: "enums(left,right,top,bottom,angular,radial,gauge)",
-                minStepSize: "number",
-                estStepSize: "number",
-                titleOffset: "number",
-                textPadding: "number",
-                min: "number",
-                max: "number",
-                centerX: "number",
-                centerY: "number",
-                radius: "number",
-                totalAngle: "number",
-                baseRotation: "number",
-                data: "default",
-                enlargeEstStepSizeByText: "bool"
-            },
-            defaults: {
-                grid: false,
-                axisLine: true,
-                minorTicks: false,
-                minorTickSize: 3,
-                majorTicks: true,
-                majorTickSize: 5,
-                length: 0,
-                startGap: 0,
-                endGap: 0,
-                visibleMin: 0,
-                visibleMax: 1,
-                dataMin: 0,
-                dataMax: 1,
-                position: "",
-                minStepSize: 0,
-                estStepSize: 20,
-                min: 0,
-                max: 1,
-                centerX: 0,
-                centerY: 0,
-                radius: 1,
-                baseRotation: 0,
-                data: null,
-                titleOffset: 0,
-                textPadding: 0,
-                scalingCenterY: 0,
-                scalingCenterX: 0,
-                strokeStyle: "black",
-                enlargeEstStepSizeByText: false
-            },
-            triggers: {
-                minorTickSize: "bbox",
-                majorTickSize: "bbox",
-                position: "bbox,layout",
-                axisLine: "bbox,layout",
-                min: "layout",
-                max: "layout",
-                length: "layout",
-                minStepSize: "layout",
-                estStepSize: "layout",
-                data: "layout",
-                dataMin: "layout",
-                dataMax: "layout",
-                visibleMin: "layout",
-                visibleMax: "layout",
-                enlargeEstStepSizeByText: "layout"
-            },
-            updaters: {
-                layout: "layoutUpdater"
-            }
-        }
-    },
-    config: {
-        label: null,
-        layout: null,
-        segmenter: null,
-        renderer: null,
-        layoutContext: null,
-        axis: null
-    },
-    thickness: 0,
-    stepSize: 0,
-    getBBox: function() {
-        return null
-    },
-    defaultRenderer: function(a) {
-        return this.segmenter.renderer(a, this)
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            c = e.position,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (c === "left" || c === "right") {
-            e.translationX = 0;
-            e.translationY = i * e.length / (i - b);
-            e.scalingX = 1;
-            e.scalingY = -e.length / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (c === "top" || c === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * e.length / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    iterate: function(e, j) {
-        var c, g, a, b, h, d, k = Ext.Array.some,
-            m = Math.abs,
-            f;
-        if (e.getLabel) {
-            if (e.min < e.from) {
-                j.call(this, e.min, e.getLabel(e.min), -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                j.call(this, e.get(c), e.getLabel(c), c, e)
-            }
-            if (e.max > e.to) {
-                j.call(this, e.max, e.getLabel(e.max), e.steps + 1, e)
-            }
-        } else {
-            b = this.getAxis();
-            h = b.floatingAxes;
-            d = [];
-            f = (e.to - e.from) / (e.steps + 1);
-            if (b.getFloating()) {
-                for (a in h) {
-                    d.push(h[a])
-                }
-            }
-
-            function l(i) {
-                return !d.length || k(d, function(n) {
-                    return m(n - i) > f
-                })
-            }
-            if (e.min < e.from && l(e.min)) {
-                j.call(this, e.min, e.min, -1, e)
-            }
-            for (c = 0; c <= e.steps; c++) {
-                g = e.get(c);
-                if (l(g)) {
-                    j.call(this, g, g, c, e)
-                }
-            }
-            if (e.max > e.to && l(e.max)) {
-                j.call(this, e.max, e.max, e.steps + 1, e)
-            }
-        }
-    },
-    renderTicks: function(l, m, s, p) {
-        var v = this,
-            k = v.attr,
-            u = k.position,
-            n = k.matrix,
-            e = 0.5 * k.lineWidth,
-            f = n.getXX(),
-            i = n.getDX(),
-            j = n.getYY(),
-            h = n.getDY(),
-            o = s.majorTicks,
-            d = k.majorTickSize,
-            a = s.minorTicks,
-            r = k.minorTickSize;
-        if (o) {
-            switch (u) {
-                case "right":
-                    function q(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(0, x);
-                            m.lineTo(w, x)
-                        }
-                    }
-                    v.iterate(o, q(d));
-                    a && v.iterate(a, q(r));
-                    break;
-                case "left":
-                    function t(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * j + h) + e;
-                            m.moveTo(p[2] - w, x);
-                            m.lineTo(p[2], x)
-                        }
-                    }
-                    v.iterate(o, t(d));
-                    a && v.iterate(a, t(r));
-                    break;
-                case "bottom":
-                    function c(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, 0);
-                            m.lineTo(x, w)
-                        }
-                    }
-                    v.iterate(o, c(d));
-                    a && v.iterate(a, c(r));
-                    break;
-                case "top":
-                    function b(w) {
-                        return function(x, z, y) {
-                            x = l.roundPixel(x * f + i) - e;
-                            m.moveTo(x, p[3]);
-                            m.lineTo(x, p[3] - w)
-                        }
-                    }
-                    v.iterate(o, b(d));
-                    a && v.iterate(a, b(r));
-                    break;
-                case "angular":
-                    v.iterate(o, function(w, y, x) {
-                        w = w / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break;
-                case "gauge":
-                    var g = v.getGaugeAngles();
-                    v.iterate(o, function(w, y, x) {
-                        w = (w - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + g.start;
-                        m.moveTo(k.centerX + (k.length) * Math.cos(w), k.centerY + (k.length) * Math.sin(w));
-                        m.lineTo(k.centerX + (k.length + d) * Math.cos(w), k.centerY + (k.length + d) * Math.sin(w))
-                    });
-                    break
-            }
-        }
-    },
-    renderLabels: function(E, q, D, K) {
-        var o = this,
-            k = o.attr,
-            i = 0.5 * k.lineWidth,
-            u = k.position,
-            y = k.matrix,
-            A = k.textPadding,
-            x = y.getXX(),
-            d = y.getDX(),
-            g = y.getYY(),
-            c = y.getDY(),
-            n = 0,
-            I = D.majorTicks,
-            G = Math.max(k.majorTickSize, k.minorTickSize) + k.lineWidth,
-            f = Ext.draw.Draw.isBBoxIntersect,
-            F = o.getLabel(),
-            J, s, r = null,
-            w = 0,
-            b = 0,
-            m = D.segmenter,
-            B = o.getRenderer(),
-            t = o.getAxis(),
-            z = t.getTitle(),
-            a = z && z.attr.text !== "" && z.getBBox(),
-            l, h = null,
-            p, C, v, e, H;
-        if (I && F && !F.attr.hidden) {
-            J = F.attr.font;
-            if (q.font !== J) {
-                q.font = J
-            }
-            F.setAttributes({
-                translationX: 0,
-                translationY: 0
-            }, true);
-            F.applyTransformations();
-            l = F.attr.inverseMatrix.elements.slice(0);
-            switch (u) {
-                case "left":
-                    e = a ? a.x + a.width : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(e + d) - i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - G + d) - i;
-                            break;
-                        default:
-                            H = E.roundPixel(e + (K[2] - e - G) / 2 + d) - i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "right":
-                    e = a ? K[2] - a.x : 0;
-                    switch (F.attr.textAlign) {
-                        case "start":
-                            H = E.roundPixel(G + d) + i;
-                            break;
-                        case "end":
-                            H = E.roundPixel(K[2] - e + d) + i;
-                            break;
-                        default:
-                            H = E.roundPixel(G + (K[2] - G - e) / 2 + d) + i
-                    }
-                    F.setAttributes({
-                        translationX: H
-                    }, true);
-                    break;
-                case "top":
-                    e = a ? a.y + a.height : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(e + (K[3] - e - G) / 2) - i
-                    }, true);
-                    break;
-                case "bottom":
-                    e = a ? K[3] - a.y : 0;
-                    F.setAttributes({
-                        translationY: E.roundPixel(G + (K[3] - G - e) / 2) + i
-                    }, true);
-                    break;
-                case "radial":
-                    F.setAttributes({
-                        translationX: k.centerX
-                    }, true);
-                    break;
-                case "angular":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break;
-                case "gauge":
-                    F.setAttributes({
-                        translationY: k.centerY
-                    }, true);
-                    break
-            }
-            if (u === "left" || u === "right") {
-                o.iterate(I, function(L, N, M) {
-                    if (N === undefined) {
-                        return
-                    }
-                    if (B) {
-                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                    } else {
-                        v = m.renderer(N, D, r)
-                    }
-                    r = N;
-                    F.setAttributes({
-                        text: String(v),
-                        translationY: E.roundPixel(L * g + c)
-                    }, true);
-                    F.applyTransformations();
-                    n = Math.max(n, F.getBBox().width + G);
-                    if (n <= o.thickness) {
-                        C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                        p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                        if (h && !f(p, h, A)) {
-                            return
-                        }
-                        E.renderSprite(F);
-                        h = p;
-                        w += p.height;
-                        b++
-                    }
-                })
-            } else {
-                if (u === "top" || u === "bottom") {
-                    o.iterate(I, function(L, N, M) {
-                        if (N === undefined) {
-                            return
-                        }
-                        if (B) {
-                            v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                        } else {
-                            v = m.renderer(N, D, r)
-                        }
-                        r = N;
-                        F.setAttributes({
-                            text: String(v),
-                            translationX: E.roundPixel(L * x + d)
-                        }, true);
-                        F.applyTransformations();
-                        n = Math.max(n, F.getBBox().height + G);
-                        if (n <= o.thickness) {
-                            C = Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));
-                            p = C.prepend.apply(C, l).transformBBox(F.getBBox(true));
-                            if (h && !f(p, h, A)) {
-                                return
-                            }
-                            E.renderSprite(F);
-                            h = p;
-                            w += p.width;
-                            b++
-                        }
-                    })
-                } else {
-                    if (u === "radial") {
-                        o.iterate(I, function(L, N, M) {
-                            if (N === undefined) {
-                                return
-                            }
-                            if (B) {
-                                v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                            } else {
-                                v = m.renderer(N, D, r)
-                            }
-                            r = N;
-                            if (typeof v !== "undefined") {
-                                F.setAttributes({
-                                    text: String(v),
-                                    translationX: k.centerX - E.roundPixel(L) / k.max * k.length * Math.cos(k.baseRotation + Math.PI / 2),
-                                    translationY: k.centerY - E.roundPixel(L) / k.max * k.length * Math.sin(k.baseRotation + Math.PI / 2)
-                                }, true);
-                                F.applyTransformations();
-                                p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                if (h && !f(p, h)) {
-                                    return
-                                }
-                                E.renderSprite(F);
-                                h = p;
-                                w += p.width;
-                                b++
-                            }
-                        })
-                    } else {
-                        if (u === "angular") {
-                            s = k.majorTickSize + k.lineWidth * 0.5 + (parseInt(F.attr.fontSize, 10) || 10) / 2;
-                            o.iterate(I, function(L, N, M) {
-                                if (N === undefined) {
-                                    return
-                                }
-                                if (B) {
-                                    v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                } else {
-                                    v = m.renderer(N, D, r)
-                                }
-                                r = N;
-                                n = Math.max(n, Math.max(k.majorTickSize, k.minorTickSize) + (k.lineCap !== "butt" ? k.lineWidth * 0.5 : 0));
-                                if (typeof v !== "undefined") {
-                                    var O = L / (k.max + 1) * Math.PI * 2 + k.baseRotation;
-                                    F.setAttributes({
-                                        text: String(v),
-                                        translationX: k.centerX + (k.length + s) * Math.cos(O),
-                                        translationY: k.centerY + (k.length + s) * Math.sin(O)
-                                    }, true);
-                                    F.applyTransformations();
-                                    p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                    if (h && !f(p, h)) {
-                                        return
-                                    }
-                                    E.renderSprite(F);
-                                    h = p;
-                                    w += p.width;
-                                    b++
-                                }
-                            })
-                        } else {
-                            if (u === "gauge") {
-                                var j = o.getGaugeAngles();
-                                o.iterate(I, function(L, N, M) {
-                                    if (N === undefined) {
-                                        return
-                                    }
-                                    if (B) {
-                                        v = Ext.callback(B, null, [t, N, D, r], 0, t)
-                                    } else {
-                                        v = m.renderer(N, D, r)
-                                    }
-                                    r = N;
-                                    if (typeof v !== "undefined") {
-                                        var O = (L - k.min) / (k.max - k.min + 1) * k.totalAngle - k.totalAngle + j.start;
-                                        F.setAttributes({
-                                            text: String(v),
-                                            translationX: k.centerX + (k.length + 10) * Math.cos(O),
-                                            translationY: k.centerY + (k.length + 10) * Math.sin(O)
-                                        }, true);
-                                        F.applyTransformations();
-                                        p = F.attr.matrix.transformBBox(F.getBBox(true));
-                                        if (h && !f(p, h)) {
-                                            return
-                                        }
-                                        E.renderSprite(F);
-                                        h = p;
-                                        w += p.width;
-                                        b++
-                                    }
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-            if (k.enlargeEstStepSizeByText && b) {
-                w /= b;
-                w += G;
-                w *= 2;
-                if (k.estStepSize < w) {
-                    k.estStepSize = w
-                }
-            }
-            if (Math.abs(o.thickness - (n)) > 1) {
-                o.thickness = n;
-                k.bbox.plain.dirty = true;
-                k.bbox.transform.dirty = true;
-                o.doThicknessChanged();
-                return false
-            }
-        }
-    },
-    renderAxisLine: function(a, i, e, c) {
-        var h = this,
-            g = h.attr,
-            b = g.lineWidth * 0.5,
-            j = g.position,
-            d, f;
-        if (g.axisLine && g.length) {
-            switch (j) {
-                case "left":
-                    d = a.roundPixel(c[2]) - b;
-                    i.moveTo(d, -g.endGap);
-                    i.lineTo(d, g.length + g.startGap + 1);
-                    break;
-                case "right":
-                    i.moveTo(b, -g.endGap);
-                    i.lineTo(b, g.length + g.startGap + 1);
-                    break;
-                case "bottom":
-                    i.moveTo(-g.startGap, b);
-                    i.lineTo(g.length + g.endGap, b);
-                    break;
-                case "top":
-                    d = a.roundPixel(c[3]) - b;
-                    i.moveTo(-g.startGap, d);
-                    i.lineTo(g.length + g.endGap, d);
-                    break;
-                case "angular":
-                    i.moveTo(g.centerX + g.length, g.centerY);
-                    i.arc(g.centerX, g.centerY, g.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    f = h.getGaugeAngles();
-                    i.moveTo(g.centerX + Math.cos(f.start) * g.length, g.centerY + Math.sin(f.start) * g.length);
-                    i.arc(g.centerX, g.centerY, g.length, f.start, f.end, true);
-                    break
-            }
-        }
-    },
-    getGaugeAngles: function() {
-        var a = this,
-            c = a.attr.totalAngle,
-            b;
-        if (c <= Math.PI) {
-            b = (Math.PI - c) * 0.5
-        } else {
-            b = -(Math.PI * 2 - c) * 0.5
-        }
-        b = Math.PI * 2 - b;
-        return {
-            start: b,
-            end: b - c
-        }
-    },
-    renderGridLines: function(m, n, s, r) {
-        var t = this,
-            b = t.getAxis(),
-            l = t.attr,
-            p = l.matrix,
-            d = l.startGap,
-            a = l.endGap,
-            c = p.getXX(),
-            k = p.getYY(),
-            h = p.getDX(),
-            g = p.getDY(),
-            u = l.position,
-            f = b.getGridAlignment(),
-            q = s.majorTicks,
-            e, o, i;
-        if (l.grid) {
-            if (q) {
-                if (u === "left" || u === "right") {
-                    i = l.min * k + g + a + d;
-                    t.iterate(q, function(j, w, v) {
-                        e = j * k + g + a;
-                        t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                            y: e,
-                            height: i - e
-                        }, o = v, true);
-                        i = e
-                    });
-                    o++;
-                    e = 0;
-                    t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                        y: e,
-                        height: i - e
-                    }, o, true)
-                } else {
-                    if (u === "top" || u === "bottom") {
-                        i = l.min * c + h + d;
-                        if (d) {
-                            t.putMarker(f + "-even", {
-                                x: 0,
-                                width: i
-                            }, -1, true)
-                        }
-                        t.iterate(q, function(j, w, v) {
-                            e = j * c + h + d;
-                            t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                x: e,
-                                width: i - e
-                            }, o = v, true);
-                            i = e
-                        });
-                        o++;
-                        e = l.length + l.startGap + l.endGap;
-                        t.putMarker(f + "-" + (o % 2 ? "odd" : "even"), {
-                            x: e,
-                            width: i - e
-                        }, o, true)
-                    } else {
-                        if (u === "radial") {
-                            t.iterate(q, function(j, w, v) {
-                                if (!j) {
-                                    return
-                                }
-                                e = j / l.max * l.length;
-                                t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                    scalingX: e,
-                                    scalingY: e
-                                }, v, true);
-                                i = e
-                            })
-                        } else {
-                            if (u === "angular") {
-                                t.iterate(q, function(j, w, v) {
-                                    if (!l.length) {
-                                        return
-                                    }
-                                    e = j / (l.max + 1) * Math.PI * 2 + l.baseRotation;
-                                    t.putMarker(f + "-" + (v % 2 ? "odd" : "even"), {
-                                        rotationRads: e,
-                                        rotationCenterX: 0,
-                                        rotationCenterY: 0,
-                                        scalingX: l.length,
-                                        scalingY: l.length
-                                    }, v, true);
-                                    i = e
-                                })
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    renderLimits: function(o) {
-        var t = this,
-            a = t.getAxis(),
-            h = a.getChart(),
-            p = h.getInnerPadding(),
-            d = Ext.Array.from(a.getLimits());
-        if (!d.length) {
-            return
-        }
-        var r = a.limits.surface.getRect(),
-            m = t.attr,
-            n = m.matrix,
-            u = m.position,
-            k = Ext.Object.chain,
-            v = a.limits.titles,
-            c, j, b, s, l, q, f, g, e;
-        v.instances = [];
-        v.position = 0;
-        if (u === "left" || u === "right") {
-            for (q = 0, f = d.length; q < f; q++) {
-                s = k(d[q]);
-                !s.line && (s.line = {});
-                l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                l = l * n.getYY() + n.getDY();
-                s.line.y = l + p.top;
-                s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                t.putMarker("horizontal-limit-lines", s.line, q, true);
-                if (s.line.title) {
-                    v.createInstance(s.line.title);
-                    c = v.getBBoxFor(v.position - 1);
-                    j = s.line.title.position || (u === "left" ? "start" : "end");
-                    switch (j) {
-                        case "start":
-                            g = 10;
-                            break;
-                        case "end":
-                            g = r[2] - 10;
-                            break;
-                        case "middle":
-                            g = r[2] / 2;
-                            break
-                    }
-                    v.setAttributesFor(v.position - 1, {
-                        x: g,
-                        y: s.line.y - c.height / 2,
-                        textAlign: j,
-                        fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                    })
-                }
-            }
-        } else {
-            if (u === "top" || u === "bottom") {
-                for (q = 0, f = d.length; q < f; q++) {
-                    s = k(d[q]);
-                    !s.line && (s.line = {});
-                    l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                    l = l * n.getXX() + n.getDX();
-                    s.line.x = l + p.left;
-                    s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                    t.putMarker("vertical-limit-lines", s.line, q, true);
-                    if (s.line.title) {
-                        v.createInstance(s.line.title);
-                        c = v.getBBoxFor(v.position - 1);
-                        j = s.line.title.position || (u === "top" ? "end" : "start");
-                        switch (j) {
-                            case "start":
-                                e = r[3] - c.width / 2 - 10;
-                                break;
-                            case "end":
-                                e = c.width / 2 + 10;
-                                break;
-                            case "middle":
-                                e = r[3] / 2;
-                                break
-                        }
-                        v.setAttributesFor(v.position - 1, {
-                            x: s.line.x + c.height / 2,
-                            y: e,
-                            fillStyle: s.line.title.fillStyle || s.line.strokeStyle,
-                            rotationRads: Math.PI / 2
-                        })
-                    }
-                }
-            } else {
-                if (u === "radial") {
-                    for (q = 0, f = d.length; q < f; q++) {
-                        s = k(d[q]);
-                        !s.line && (s.line = {});
-                        l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                        if (l > m.max) {
-                            continue
-                        }
-                        l = l / m.max * m.length;
-                        s.line.cx = m.centerX;
-                        s.line.cy = m.centerY;
-                        s.line.scalingX = l;
-                        s.line.scalingY = l;
-                        s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                        t.putMarker("circular-limit-lines", s.line, q, true);
-                        if (s.line.title) {
-                            v.createInstance(s.line.title);
-                            c = v.getBBoxFor(v.position - 1);
-                            v.setAttributesFor(v.position - 1, {
-                                x: m.centerX,
-                                y: m.centerY - l - c.height / 2,
-                                fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                            })
-                        }
-                    }
-                } else {
-                    if (u === "angular") {
-                        for (q = 0, f = d.length; q < f; q++) {
-                            s = k(d[q]);
-                            !s.line && (s.line = {});
-                            l = Ext.isString(s.value) ? a.getCoordFor(s.value) : s.value;
-                            l = l / (m.max + 1) * Math.PI * 2 + m.baseRotation;
-                            s.line.translationX = m.centerX;
-                            s.line.translationY = m.centerY;
-                            s.line.rotationRads = l;
-                            s.line.rotationCenterX = 0;
-                            s.line.rotationCenterY = 0;
-                            s.line.scalingX = m.length;
-                            s.line.scalingY = m.length;
-                            s.line.strokeStyle = s.line.strokeStyle || m.strokeStyle;
-                            t.putMarker("radial-limit-lines", s.line, q, true);
-                            if (s.line.title) {
-                                v.createInstance(s.line.title);
-                                c = v.getBBoxFor(v.position - 1);
-                                b = ((l > -0.5 * Math.PI && l < 0.5 * Math.PI) || (l > 1.5 * Math.PI && l < 2 * Math.PI)) ? 1 : -1;
-                                v.setAttributesFor(v.position - 1, {
-                                    x: m.centerX + 0.5 * m.length * Math.cos(l) + b * c.height / 2 * Math.sin(l),
-                                    y: m.centerY + 0.5 * m.length * Math.sin(l) - b * c.height / 2 * Math.cos(l),
-                                    rotationRads: b === 1 ? l : l - Math.PI,
-                                    fillStyle: s.line.title.fillStyle || s.line.strokeStyle
-                                })
-                            }
-                        }
-                    } else {
-                        if (u === "gauge") {}
-                    }
-                }
-            }
-        }
-    },
-    doThicknessChanged: function() {
-        var a = this.getAxis();
-        if (a) {
-            a.onThicknessChanged()
-        }
-    },
-    render: function(a, c, d) {
-        var e = this,
-            b = e.getLayoutContext();
-        if (b) {
-            if (false === e.renderLabels(a, c, b, d)) {
-                return false
-            }
-            c.beginPath();
-            e.renderTicks(a, c, b, d);
-            e.renderAxisLine(a, c, b, d);
-            e.renderGridLines(a, c, b, d);
-            e.renderLimits(d);
-            c.stroke()
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Segmenter", {
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    renderer: function(b, a) {
-        return String(b)
-    },
-    from: function(a) {
-        return a
-    },
-    diff: Ext.emptyFn,
-    align: Ext.emptyFn,
-    add: Ext.emptyFn,
-    preferredStep: Ext.emptyFn
-});
-Ext.define("Ext.chart.axis.segmenter.Names", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.names",
-    renderer: function(b, a) {
-        return b
-    },
-    diff: function(b, a, c) {
-        return Math.floor(a - b)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c)
-    },
-    add: function(c, b, a) {
-        return c + b
-    },
-    preferredStep: function(c, a, b, d) {
-        return {
-            unit: 1,
-            step: 1
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Numeric", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.numeric",
-    isNumeric: true,
-    renderer: function(b, a) {
-        return b.toFixed(Math.max(0, a.majorTicks.unit.fixes))
-    },
-    diff: function(b, a, c) {
-        return Math.floor((a - b) / c.scale)
-    },
-    align: function(c, b, a) {
-        return Math.floor(c / (a.scale * b)) * a.scale * b
-    },
-    add: function(c, b, a) {
-        return c + b * a.scale
-    },
-    preferredStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        b /= d;
-        if (b < 2) {
-            b = 2
-        } else {
-            if (b < 5) {
-                b = 5
-            } else {
-                if (b < 10) {
-                    b = 10;
-                    a++
-                }
-            }
-        }
-        return {
-            unit: {
-                fixes: -a,
-                scale: d
-            },
-            step: b
-        }
-    },
-    exactStep: function(c, b) {
-        var a = Math.floor(Math.log(b) * Math.LOG10E),
-            d = Math.pow(10, a);
-        return {
-            unit: {
-                fixes: -a + (b % d === 0 ? 0 : 1),
-                scale: 1
-            },
-            step: b
-        }
-    },
-    adjustByMajorUnit: function(e, g, c) {
-        var d = c[0],
-            b = c[1],
-            a = e * g,
-            f = d % a;
-        if (f !== 0) {
-            c[0] = d - f + (d < 0 ? -a : 0)
-        }
-        f = b % a;
-        if (f !== 0) {
-            c[1] = b - f + (b > 0 ? a : 0)
-        }
-    }
-});
-Ext.define("Ext.chart.axis.segmenter.Time", {
-    extend: "Ext.chart.axis.segmenter.Segmenter",
-    alias: "segmenter.time",
-    config: {
-        step: null
-    },
-    renderer: function(c, b) {
-        var a = Ext.Date;
-        switch (b.majorTicks.unit) {
-            case "y":
-                return a.format(c, "Y");
-            case "mo":
-                return a.format(c, "Y-m");
-            case "d":
-                return a.format(c, "Y-m-d")
-        }
-        return a.format(c, "Y-m-d\nH:i:s")
-    },
-    from: function(a) {
-        return new Date(a)
-    },
-    diff: function(b, a, c) {
-        if (isFinite(b)) {
-            b = new Date(b)
-        }
-        if (isFinite(a)) {
-            a = new Date(a)
-        }
-        return Ext.Date.diff(b, a, c)
-    },
-    align: function(a, c, b) {
-        if (b === "d" && c >= 7) {
-            a = Ext.Date.align(a, "d", c);
-            a.setDate(a.getDate() - a.getDay() + 1);
-            return a
-        } else {
-            return Ext.Date.align(a, b, c)
-        }
-    },
-    add: function(c, b, a) {
-        return Ext.Date.add(new Date(c), a, b)
-    },
-    stepUnits: [
-        [Ext.Date.YEAR, 1, 2, 5, 10, 20, 50, 100, 200, 500],
-        [Ext.Date.MONTH, 1, 3, 6],
-        [Ext.Date.DAY, 1, 7, 14],
-        [Ext.Date.HOUR, 1, 6, 12],
-        [Ext.Date.MINUTE, 1, 5, 15, 30],
-        [Ext.Date.SECOND, 1, 5, 15, 30],
-        [Ext.Date.MILLI, 1, 2, 5, 10, 20, 50, 100, 200, 500]
-    ],
-    preferredStep: function(b, e) {
-        if (this.getStep()) {
-            return this.getStep()
-        }
-        var f = new Date(+b),
-            g = new Date(+b + Math.ceil(e)),
-            d = this.stepUnits,
-            l, k, h, c, a;
-        for (c = 0; c < d.length; c++) {
-            k = d[c][0];
-            h = this.diff(f, g, k);
-            if (h > 0) {
-                for (a = 1; a < d[c].length; a++) {
-                    if (h <= d[c][a]) {
-                        l = {
-                            unit: k,
-                            step: d[c][a]
-                        };
-                        break
-                    }
-                }
-                if (!l) {
-                    c--;
-                    l = {
-                        unit: d[c][0],
-                        step: 1
-                    }
-                }
-                break
-            }
-        }
-        if (!l) {
-            l = {
-                unit: Ext.Date.DAY,
-                step: 1
-            }
-        }
-        return l
-    }
-});
-Ext.define("Ext.chart.axis.layout.Layout", {
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    config: {
-        axis: null
-    },
-    constructor: function(a) {
-        this.mixins.observable.constructor.call(this, a)
-    },
-    processData: function(b) {
-        var e = this,
-            c = e.getAxis(),
-            f = c.getDirection(),
-            g = c.boundSeries,
-            a, d;
-        if (b) {
-            b["coordinate" + f]()
-        } else {
-            for (a = 0, d = g.length; a < d; a++) {
-                g[a]["coordinate" + f]()
-            }
-        }
-    },
-    calculateMajorTicks: function(a) {
-        var f = this,
-            e = a.attr,
-            d = e.max - e.min,
-            i = d / Math.max(1, e.length) * (e.visibleMax - e.visibleMin),
-            h = e.min + d * e.visibleMin,
-            b = e.min + d * e.visibleMax,
-            g = e.estStepSize * i,
-            c = f.snapEnds(a, e.min, e.max, g);
-        if (c) {
-            f.trimByRange(a, c, h, b);
-            a.majorTicks = c
-        }
-    },
-    calculateMinorTicks: function(a) {
-        if (this.snapMinorEnds) {
-            a.minorTicks = this.snapMinorEnds(a)
-        }
-    },
-    calculateLayout: function(b) {
-        var c = this,
-            a = b.attr;
-        if (a.length === 0) {
-            return null
-        }
-        if (a.majorTicks) {
-            c.calculateMajorTicks(b);
-            if (a.minorTicks) {
-                c.calculateMinorTicks(b)
-            }
-        }
-    },
-    snapEnds: Ext.emptyFn,
-    trimByRange: function(b, f, i, a) {
-        var g = b.segmenter,
-            j = f.unit,
-            h = g.diff(f.from, i, j),
-            d = g.diff(f.from, a, j),
-            c = Math.max(0, Math.ceil(h / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = g.add(f.from, e * f.step, j)
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < i) {
-            f.from = g.add(f.from, c * f.step, j);
-            while (f.from < i) {
-                c++;
-                f.from = g.add(f.from, f.step, j)
-            }
-        }
-        if (f.min < i) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    }
-});
-Ext.define("Ext.chart.axis.layout.Discrete", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.discrete",
-    isDiscrete: true,
-    processData: function() {
-        var f = this,
-            d = f.getAxis(),
-            c = d.boundSeries,
-            g = d.getDirection(),
-            b, e, a;
-        f.labels = [];
-        f.labelMap = {};
-        for (b = 0, e = c.length; b < e; b++) {
-            a = c[b];
-            if (a["get" + g + "Axis"]() === d) {
-                a["coordinate" + g]()
-            }
-        }
-        d.getSprites()[0].setAttributes({
-            data: f.labels
-        });
-        f.fireEvent("datachange", f.labels)
-    },
-    calculateLayout: function(a) {
-        a.data = this.labels;
-        this.callParent([a])
-    },
-    calculateMajorTicks: function(a) {
-        var g = this,
-            f = a.attr,
-            d = a.data,
-            e = f.max - f.min,
-            j = e / Math.max(1, f.length) * (f.visibleMax - f.visibleMin),
-            i = f.min + e * f.visibleMin,
-            b = f.min + e * f.visibleMax,
-            h = f.estStepSize * j;
-        var c = g.snapEnds(a, Math.max(0, f.min), Math.min(f.max, d.length - 1), h);
-        if (c) {
-            g.trimByRange(a, c, i, b);
-            a.majorTicks = c
-        }
-    },
-    snapEnds: function(e, d, a, b) {
-        b = Math.ceil(b);
-        var c = Math.floor((a - d) / b),
-            f = e.data;
-        return {
-            min: d,
-            max: a,
-            from: d,
-            to: c * b + d,
-            step: b,
-            steps: c,
-            unit: 1,
-            getLabel: function(g) {
-                return f[this.from + this.step * g]
-            },
-            get: function(g) {
-                return this.from + this.step * g
-            }
-        }
-    },
-    trimByRange: function(b, f, h, a) {
-        var i = f.unit,
-            g = Math.ceil((h - f.from) / i) * i,
-            d = Math.floor((a - f.from) / i) * i,
-            c = Math.max(0, Math.ceil(g / f.step)),
-            e = Math.min(f.steps, Math.floor(d / f.step));
-        if (e < f.steps) {
-            f.to = e
-        }
-        if (f.max > a) {
-            f.max = f.to
-        }
-        if (f.from < h && f.step > 0) {
-            f.from = f.from + c * f.step * i;
-            while (f.from < h) {
-                c++;
-                f.from += f.step * i
-            }
-        }
-        if (f.min < h) {
-            f.min = f.from
-        }
-        f.steps = e - c
-    },
-    getCoordFor: function(c, d, a, b) {
-        this.labels.push(c);
-        return this.labels.length - 1
-    }
-});
-Ext.define("Ext.chart.axis.layout.CombineDuplicate", {
-    extend: "Ext.chart.axis.layout.Discrete",
-    alias: "axisLayout.combineDuplicate",
-    getCoordFor: function(d, e, b, c) {
-        if (!(d in this.labelMap)) {
-            var a = this.labelMap[d] = this.labels.length;
-            this.labels.push(d);
-            return a
-        }
-        return this.labelMap[d]
-    }
-});
-Ext.define("Ext.chart.axis.layout.Continuous", {
-    extend: "Ext.chart.axis.layout.Layout",
-    alias: "axisLayout.continuous",
-    isContinuous: true,
-    config: {
-        adjustMinimumByMajorUnit: false,
-        adjustMaximumByMajorUnit: false
-    },
-    getCoordFor: function(c, d, a, b) {
-        return +c
-    },
-    snapEnds: function(a, d, i, h) {
-        var f = a.segmenter,
-            c = this.getAxis(),
-            l = c.getMajorTickSteps(),
-            e = l && f.exactStep ? f.exactStep(d, (i - d) / l) : f.preferredStep(d, h),
-            k = e.unit,
-            b = e.step,
-            j = f.align(d, b, k),
-            g = (l || f.diff(d, i, k)) + 1;
-        return {
-            min: f.from(d),
-            max: f.from(i),
-            from: j,
-            to: f.add(j, g * b, k),
-            step: b,
-            steps: g,
-            unit: k,
-            get: function(m) {
-                return f.add(this.from, this.step * m, k)
-            }
-        }
-    },
-    snapMinorEnds: function(a) {
-        var e = a.majorTicks,
-            m = this.getAxis().getMinorTickSteps(),
-            f = a.segmenter,
-            d = e.min,
-            i = e.max,
-            k = e.from,
-            l = e.unit,
-            b = e.step / m,
-            n = b * l.scale,
-            j = k - d,
-            c = Math.floor(j / n),
-            h = c + Math.floor((i - e.to) / n) + 1,
-            g = e.steps * m + h;
-        return {
-            min: d,
-            max: i,
-            from: d + j % n,
-            to: f.add(k, g * b, l),
-            step: b,
-            steps: g,
-            unit: l,
-            get: function(o) {
-                return (o % m + c + 1 !== 0) ? f.add(this.from, this.step * o, l) : null
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis", {
-    xtype: "axis",
-    mixins: {
-        observable: "Ext.mixin.Observable"
-    },
-    requires: ["Ext.chart.axis.sprite.Axis", "Ext.chart.axis.segmenter.*", "Ext.chart.axis.layout.*"],
-    isAxis: true,
-    config: {
-        position: "bottom",
-        fields: [],
-        label: undefined,
-        grid: false,
-        limits: null,
-        renderer: null,
-        chart: null,
-        style: null,
-        margin: 0,
-        titleMargin: 4,
-        background: null,
-        minimum: NaN,
-        maximum: NaN,
-        reconcileRange: false,
-        minZoom: 1,
-        maxZoom: 10000,
-        layout: "continuous",
-        segmenter: "numeric",
-        hidden: false,
-        majorTickSteps: 0,
-        minorTickSteps: 0,
-        adjustByMajorUnit: true,
-        title: null,
-        increment: 0.5,
-        length: 0,
-        center: null,
-        radius: null,
-        totalAngle: Math.PI,
-        rotation: null,
-        labelInSpan: null,
-        visibleRange: [0, 1],
-        needHighPrecision: false,
-        linkedTo: null,
-        floating: null
-    },
-    titleOffset: 0,
-    spriteAnimationCount: 0,
-    prevMin: 0,
-    prevMax: 1,
-    boundSeries: [],
-    sprites: null,
-    surface: null,
-    range: null,
-    xValues: [],
-    yValues: [],
-    masterAxis: null,
-    applyRotation: function(b) {
-        var a = Math.PI * 2;
-        return (b % a + Math.PI) % a - Math.PI
-    },
-    updateRotation: function(b) {
-        var c = this.getSprites(),
-            a = this.getPosition();
-        if (!this.getHidden() && a === "angular" && c[0]) {
-            c[0].setAttributes({
-                baseRotation: b
-            })
-        }
-    },
-    applyTitle: function(c, b) {
-        var a;
-        if (Ext.isString(c)) {
-            c = {
-                text: c
-            }
-        }
-        if (!b) {
-            b = Ext.create("sprite.text", c);
-            if ((a = this.getSurface())) {
-                a.add(b)
-            }
-        } else {
-            b.setAttributes(c)
-        }
-        return b
-    },
-    applyFloating: function(b, a) {
-        if (b === null) {
-            b = {
-                value: null,
-                alongAxis: null
-            }
-        } else {
-            if (Ext.isNumber(b)) {
-                b = {
-                    value: b,
-                    alongAxis: null
-                }
-            }
-        }
-        if (Ext.isObject(b)) {
-            if (a && a.alongAxis) {
-                delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]
-            }
-            return b
-        }
-        return a
-    },
-    constructor: function(a) {
-        var b = this,
-            c;
-        b.sprites = [];
-        b.labels = [];
-        b.floatingAxes = {};
-        a = a || {};
-        if (a.position === "angular") {
-            a.style = a.style || {};
-            a.style.estStepSize = 1
-        }
-        if ("id" in a) {
-            c = a.id
-        } else {
-            if ("id" in b.config) {
-                c = b.config.id
-            } else {
-                c = b.getId()
-            }
-        }
-        b.setId(c);
-        b.mixins.observable.constructor.apply(b, arguments)
-    },
-    getAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "vertical";
-            case "top":
-            case "bottom":
-                return "horizontal";
-            case "radial":
-                return "radial";
-            case "angular":
-                return "angular"
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal";
-            case "top":
-            case "bottom":
-                return "vertical";
-            case "radial":
-                return "circular";
-            case "angular":
-                return "radial"
-        }
-    },
-    getSurface: function() {
-        var e = this,
-            d = e.getChart();
-        if (d && !e.surface) {
-            var b = e.surface = d.getSurface(e.getId(), "axis"),
-                c = e.gridSurface = d.getSurface("main"),
-                a = e.getSprites()[0],
-                f = e.getGridAlignment();
-            c.waitFor(b);
-            e.getGrid();
-            if (e.getLimits() && f) {
-                f = f.replace("3d", "");
-                e.limits = {
-                    surface: d.getSurface("overlay"),
-                    lines: new Ext.chart.Markers(),
-                    titles: new Ext.draw.sprite.Instancing()
-                };
-                e.limits.lines.setTemplate({
-                    xclass: "grid." + f
-                });
-                e.limits.lines.getTemplate().setAttributes({
-                    strokeStyle: "black"
-                }, true);
-                e.limits.surface.add(e.limits.lines);
-                a.bindMarker(f + "-limit-lines", e.limits.lines);
-                e.limitTitleTpl = new Ext.draw.sprite.Text();
-                e.limits.titles.setTemplate(e.limitTitleTpl);
-                e.limits.surface.add(e.limits.titles);
-                d.on("redraw", e.renderLimits, e)
-            }
-        }
-        return e.surface
-    },
-    applyGrid: function(a) {
-        if (a === true) {
-            return {}
-        }
-        return a
-    },
-    updateGrid: function(b) {
-        var e = this,
-            d = e.getChart();
-        if (!d) {
-            e.on({
-                chartattached: Ext.bind(e.updateGrid, e, [b]),
-                single: true
-            });
-            return
-        }
-        var c = e.gridSurface,
-            a = e.getSprites()[0],
-            f = e.getGridAlignment(),
-            g;
-        if (b) {
-            g = e.gridSpriteEven;
-            if (!g) {
-                g = e.gridSpriteEven = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-even", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.even)) {
-                    g.getTemplate().setAttributes(b.even)
-                }
-            }
-            g = e.gridSpriteOdd;
-            if (!g) {
-                g = e.gridSpriteOdd = new Ext.chart.Markers();
-                g.setTemplate({
-                    xclass: "grid." + f
-                });
-                c.add(g);
-                a.bindMarker(f + "-odd", g)
-            }
-            if (Ext.isObject(b)) {
-                g.getTemplate().setAttributes(b);
-                if (Ext.isObject(b.odd)) {
-                    g.getTemplate().setAttributes(b.odd)
-                }
-            }
-        }
-    },
-    renderLimits: function() {
-        this.getSprites()[0].renderLimits()
-    },
-    getCoordFor: function(c, d, a, b) {
-        return this.getLayout().getCoordFor(c, d, a, b)
-    },
-    applyPosition: function(a) {
-        return a.toLowerCase()
-    },
-    applyLength: function(b, a) {
-        return b > 0 ? b : a
-    },
-    applyLabel: function(b, a) {
-        if (!a) {
-            a = new Ext.draw.sprite.Text({})
-        }
-        if (this.limitTitleTpl) {
-            this.limitTitleTpl.setAttributes(b)
-        }
-        a.setAttributes(b);
-        return a
-    },
-    applyLayout: function(b, a) {
-        b = Ext.factory(b, null, a, "axisLayout");
-        b.setAxis(this);
-        return b
-    },
-    applySegmenter: function(a, b) {
-        a = Ext.factory(a, null, b, "segmenter");
-        a.setAxis(this);
-        return a
-    },
-    updateMinimum: function() {
-        this.range = null
-    },
-    updateMaximum: function() {
-        this.range = null
-    },
-    hideLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: true
-        })
-    },
-    showLabels: function() {
-        this.getSprites()[0].setDirty(true);
-        this.setLabel({
-            hidden: false
-        })
-    },
-    renderFrame: function() {
-        this.getSurface().renderFrame()
-    },
-    updateChart: function(d, b) {
-        var c = this,
-            a;
-        if (b) {
-            b.unregister(c);
-            b.un("serieschange", c.onSeriesChange, c);
-            b.un("redraw", c.renderLimits, c);
-            c.linkAxis();
-            c.fireEvent("chartdetached", b, c)
-        }
-        if (d) {
-            d.on("serieschange", c.onSeriesChange, c);
-            c.surface = null;
-            a = c.getSurface();
-            c.getLabel().setSurface(a);
-            a.add(c.getSprites());
-            a.add(c.getTitle());
-            d.register(c);
-            c.fireEvent("chartattached", d, c)
-        }
-    },
-    applyBackground: function(a) {
-        var b = Ext.ClassManager.getByAlias("sprite.rect");
-        return b.def.normalize(a)
-    },
-    processData: function() {
-        this.getLayout().processData();
-        this.range = null
-    },
-    getDirection: function() {
-        return this.getChart().getDirectionForAxis(this.getPosition())
-    },
-    isSide: function() {
-        var a = this.getPosition();
-        return a === "left" || a === "right"
-    },
-    applyFields: function(a) {
-        return Ext.Array.from(a)
-    },
-    applyVisibleRange: function(a, c) {
-        this.getChart();
-        if (a[0] > a[1]) {
-            var b = a[0];
-            a[0] = a[1];
-            a[0] = b
-        }
-        if (a[1] === a[0]) {
-            a[1] += 1 / this.getMaxZoom()
-        }
-        if (a[1] > a[0] + 1) {
-            a[0] = 0;
-            a[1] = 1
-        } else {
-            if (a[0] < 0) {
-                a[1] -= a[0];
-                a[0] = 0
-            } else {
-                if (a[1] > 1) {
-                    a[0] -= a[1] - 1;
-                    a[1] = 1
-                }
-            }
-        }
-        if (c && a[0] === c[0] && a[1] === c[1]) {
-            return undefined
-        }
-        return a
-    },
-    updateVisibleRange: function(a) {
-        this.fireEvent("visiblerangechange", this, a)
-    },
-    onSeriesChange: function(e) {
-        var f = this,
-            b = e.getSeries(),
-            j = "get" + f.getDirection() + "Axis",
-            g = [],
-            c, d = b.length,
-            a, h;
-        for (c = 0; c < d; c++) {
-            if (this === b[c][j]()) {
-                g.push(b[c])
-            }
-        }
-        f.boundSeries = g;
-        a = f.getLinkedTo();
-        h = !Ext.isEmpty(a) && e.getAxis(a);
-        if (h) {
-            f.linkAxis(h)
-        } else {
-            f.getLayout().processData()
-        }
-    },
-    linkAxis: function(a) {
-        var c = this;
-
-        function b(f, d, e) {
-            e.getLayout()[f]("datachange", "onDataChange", d);
-            e[f]("rangechange", "onMasterAxisRangeChange", d)
-        }
-        if (c.masterAxis) {
-            b("un", c, c.masterAxis);
-            c.masterAxis = null
-        }
-        if (a) {
-            if (a.type !== this.type) {
-                Ext.Error.raise("Linked axes must be of the same type.")
-            }
-            b("on", c, a);
-            c.onDataChange(a.getLayout().labels);
-            c.onMasterAxisRangeChange(a, a.range);
-            c.setStyle(Ext.apply({}, c.config.style, a.config.style));
-            c.setTitle(Ext.apply({}, c.config.title, a.config.title));
-            c.setLabel(Ext.apply({}, c.config.label, a.config.label));
-            c.masterAxis = a
-        }
-    },
-    onDataChange: function(a) {
-        this.getLayout().labels = a
-    },
-    onMasterAxisRangeChange: function(b, a) {
-        this.range = a
-    },
-    applyRange: function(a) {
-        if (!a) {
-            return this.dataRange.slice(0)
-        } else {
-            return [a[0] === null ? this.dataRange[0] : a[0], a[1] === null ? this.dataRange[1] : a[1]]
-        }
-    },
-    getRange: function() {
-        var m = this;
-        if (m.range) {
-            return m.range
-        } else {
-            if (m.masterAxis) {
-                return m.masterAxis.range
-            }
-        }
-        if (Ext.isNumber(m.getMinimum() + m.getMaximum())) {
-            return m.range = [m.getMinimum(), m.getMaximum()]
-        }
-        var d = Infinity,
-            n = -Infinity,
-            o = m.boundSeries,
-            h = m.getLayout(),
-            l = m.getSegmenter(),
-            p = m.getVisibleRange(),
-            b = "get" + m.getDirection() + "Range",
-            a, j, g, f, e, k;
-        for (e = 0, k = o.length; e < k; e++) {
-            f = o[e];
-            var c = f[b]();
-            if (c) {
-                if (c[0] < d) {
-                    d = c[0]
-                }
-                if (c[1] > n) {
-                    n = c[1]
-                }
-            }
-        }
-        if (!isFinite(n)) {
-            n = m.prevMax
-        }
-        if (!isFinite(d)) {
-            d = m.prevMin
-        }
-        if (m.getLabelInSpan() || d === n) {
-            n += m.getIncrement();
-            d -= m.getIncrement()
-        }
-        if (Ext.isNumber(m.getMinimum())) {
-            d = m.getMinimum()
-        } else {
-            m.prevMin = d
-        }
-        if (Ext.isNumber(m.getMaximum())) {
-            n = m.getMaximum()
-        } else {
-            m.prevMax = n
-        }
-        m.range = [Ext.Number.correctFloat(d), Ext.Number.correctFloat(n)];
-        if (m.getReconcileRange()) {
-            m.reconcileRange()
-        }
-        if (m.getAdjustByMajorUnit() && l.adjustByMajorUnit && !m.getMajorTickSteps()) {
-            j = Ext.Object.chain(m.getSprites()[0].attr);
-            j.min = m.range[0];
-            j.max = m.range[1];
-            j.visibleMin = p[0];
-            j.visibleMax = p[1];
-            a = {
-                attr: j,
-                segmenter: l
-            };
-            h.calculateLayout(a);
-            g = a.majorTicks;
-            if (g) {
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range);
-                j.min = m.range[0];
-                j.max = m.range[1];
-                delete a.majorTicks;
-                h.calculateLayout(a);
-                g = a.majorTicks;
-                l.adjustByMajorUnit(g.step, g.unit.scale, m.range)
-            } else {
-                if (!m.hasClearRangePending) {
-                    m.hasClearRangePending = true;
-                    m.getChart().on("layout", "clearRange", m)
-                }
-            }
-        }
-        if (!Ext.Array.equals(m.range, m.oldRange || [])) {
-            m.fireEvent("rangechange", m, m.range);
-            m.oldRange = m.range
-        }
-        return m.range
-    },
-    clearRange: function() {
-        delete this.hasClearRangePending;
-        this.range = null
-    },
-    reconcileRange: function() {
-        var e = this,
-            g = e.getChart().getAxes(),
-            f = e.getDirection(),
-            b, d, c, a;
-        if (!g) {
-            return
-        }
-        for (b = 0, d = g.length; b < d; b++) {
-            c = g[b];
-            a = c.getRange();
-            if (c === e || c.getDirection() !== f || !a || !c.getReconcileRange()) {
-                continue
-            }
-            if (a[0] < e.range[0]) {
-                e.range[0] = a[0]
-            }
-            if (a[1] > e.range[1]) {
-                e.range[1] = a[1]
-            }
-        }
-    },
-    applyStyle: function(c, b) {
-        var a = Ext.ClassManager.getByAlias("sprite." + this.seriesType);
-        if (a && a.def) {
-            c = a.def.normalize(c)
-        }
-        b = Ext.apply(b || {}, c);
-        return b
-    },
-    themeOnlyIfConfigured: {
-        grid: true
-    },
-    updateTheme: function(d) {
-        var i = this,
-            k = d.getAxis(),
-            e = i.getPosition(),
-            o = i.getInitialConfig(),
-            c = i.defaultConfig,
-            g = i.getConfigurator().configs,
-            a = k.defaults,
-            n = k[e],
-            h = i.themeOnlyIfConfigured,
-            l, j, p, b, m, f;
-        k = Ext.merge({}, a, n);
-        for (l in k) {
-            j = k[l];
-            f = g[l];
-            if (j !== null && j !== undefined && f) {
-                m = o[l];
-                p = Ext.isObject(j);
-                b = m === c[l];
-                if (p) {
-                    if (b && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (b || p) {
-                    i[f.names.set](j)
-                }
-            }
-        }
-    },
-    updateCenter: function(b) {
-        var e = this.getSprites(),
-            a = e[0],
-            d = b[0],
-            c = b[1];
-        if (a) {
-            a.setAttributes({
-                centerX: d,
-                centerY: c
-            })
-        }
-        if (this.gridSpriteEven) {
-            this.gridSpriteEven.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-        if (this.gridSpriteOdd) {
-            this.gridSpriteOdd.getTemplate().setAttributes({
-                translationX: d,
-                translationY: c,
-                rotationCenterX: d,
-                rotationCenterY: c
-            })
-        }
-    },
-    getSprites: function() {
-        if (!this.getChart()) {
-            return
-        }
-        var i = this,
-            e = i.getRange(),
-            f = i.getPosition(),
-            g = i.getChart(),
-            c = g.getAnimation(),
-            d, a, b = i.getLength(),
-            h = i.superclass;
-        if (c === false) {
-            c = {
-                duration: 0
-            }
-        }
-        if (e) {
-            a = Ext.applyIf({
-                position: f,
-                axis: i,
-                min: e[0],
-                max: e[1],
-                length: b,
-                grid: i.getGrid(),
-                hidden: i.getHidden(),
-                titleOffset: i.titleOffset,
-                layout: i.getLayout(),
-                segmenter: i.getSegmenter(),
-                totalAngle: i.getTotalAngle(),
-                label: i.getLabel()
-            }, i.getStyle());
-            if (!i.sprites.length) {
-                while (!h.xtype) {
-                    h = h.superclass
-                }
-                d = Ext.create("sprite." + h.xtype, a);
-                d.fx.setCustomDurations({
-                    baseRotation: 0
-                });
-                d.fx.on("animationstart", "onAnimationStart", i);
-                d.fx.on("animationend", "onAnimationEnd", i);
-                d.setLayout(i.getLayout());
-                d.setSegmenter(i.getSegmenter());
-                d.setLabel(i.getLabel());
-                i.sprites.push(d);
-                i.updateTitleSprite()
-            } else {
-                d = i.sprites[0];
-                d.setAnimation(c);
-                d.setAttributes(a)
-            }
-            if (i.getRenderer()) {
-                d.setRenderer(i.getRenderer())
-            }
-        }
-        return i.sprites
-    },
-    updateTitleSprite: function() {
-        var f = this,
-            b = f.getLength();
-        if (!f.sprites[0] || !Ext.isNumber(b)) {
-            return
-        }
-        var h = this.sprites[0].thickness,
-            a = f.getSurface(),
-            g = f.getTitle(),
-            e = f.getPosition(),
-            c = f.getMargin(),
-            i = f.getTitleMargin(),
-            d = a.roundPixel(b / 2);
-        if (g) {
-            switch (e) {
-                case "top":
-                    g.setAttributes({
-                        x: d,
-                        y: c + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "bottom":
-                    g.setAttributes({
-                        x: d,
-                        y: h + i / 2,
-                        textBaseline: "top",
-                        textAlign: "center"
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().height + i;
-                    break;
-                case "left":
-                    g.setAttributes({
-                        x: c + i / 2,
-                        y: d,
-                        textBaseline: "top",
-                        textAlign: "center",
-                        rotationCenterX: c + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: -Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break;
-                case "right":
-                    g.setAttributes({
-                        x: h - c + i / 2,
-                        y: d,
-                        textBaseline: "bottom",
-                        textAlign: "center",
-                        rotationCenterX: h + i / 2,
-                        rotationCenterY: d,
-                        rotationRads: Math.PI / 2
-                    }, true);
-                    g.applyTransformations();
-                    f.titleOffset = g.getBBox().width + i;
-                    break
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        this.getChart().onThicknessChanged()
-    },
-    getThickness: function() {
-        if (this.getHidden()) {
-            return 0
-        }
-        return (this.sprites[0] && this.sprites[0].thickness || 1) + this.titleOffset + this.getMargin()
-    },
-    onAnimationStart: function() {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart", this)
-        }
-    },
-    onAnimationEnd: function() {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend", this)
-        }
-    },
-    getItemId: function() {
-        return this.getId()
-    },
-    getAncestorIds: function() {
-        return [this.getChart().getId()]
-    },
-    isXType: function(a) {
-        return a === "axis"
-    },
-    resolveListenerScope: function(e) {
-        var d = this,
-            a = Ext._namedScopes[e],
-            c = d.getChart(),
-            b;
-        if (!a) {
-            b = c ? c.resolveListenerScope(e, false) : (e || d)
-        } else {
-            if (a.isThis) {
-                b = d
-            } else {
-                if (a.isController) {
-                    b = c ? c.resolveListenerScope(e, false) : d
-                } else {
-                    if (a.isSelf) {
-                        b = c ? c.resolveListenerScope(e, false) : d;
-                        if (b === c && !c.getInheritedConfig("defaultListenerScope")) {
-                            b = d
-                        }
-                    }
-                }
-            }
-        }
-        return b
-    },
-    destroy: function() {
-        var a = this;
-        a.setChart(null);
-        a.surface.destroy();
-        a.surface = null;
-        a.callParent()
-    }
-});
-Ext.define("Ext.chart.LegendBase", {
-    extend: "Ext.view.View",
-    config: {
-        tpl: ['<div class="', Ext.baseCSSPrefix, 'legend-container">', '<tpl for=".">', '<div class="', Ext.baseCSSPrefix, 'legend-item">', "<span ", 'class="', Ext.baseCSSPrefix, "legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ", 'style="background:{mark};">', "</span>{name}", "</div>", "</tpl>", "</div>"],
-        nodeContainerSelector: "div." + Ext.baseCSSPrefix + "legend-container",
-        itemSelector: "div." + Ext.baseCSSPrefix + "legend-item",
-        docked: "bottom"
-    },
-    setDocked: function(d) {
-        var c = this,
-            a = c.ownerCt,
-            b;
-        c.docked = d;
-        switch (d) {
-            case "top":
-            case "bottom":
-                c.addCls(Ext.baseCSSPrefix + "horizontal");
-                b = "hbox";
-                break;
-            case "left":
-            case "right":
-                c.removeCls(Ext.baseCSSPrefix + "horizontal");
-                b = "vbox";
-                break
-        }
-        if (a) {
-            a.setDocked(d)
-        }
-    },
-    setStore: function(a) {
-        this.bindStore(a)
-    },
-    clearViewEl: function() {
-        this.callParent(arguments);
-        Ext.removeNode(this.getNodeContainer())
-    },
-    onItemClick: function(a, c, b, d) {
-        this.callParent(arguments);
-        this.toggleItem(b)
-    }
-});
-Ext.define("Ext.chart.Legend", {
-    xtype: "legend",
-    extend: "Ext.chart.LegendBase",
-    config: {
-        baseCls: Ext.baseCSSPrefix + "legend",
-        padding: 5,
-        rect: null,
-        disableSelection: true,
-        toggleable: true
-    },
-    toggleItem: function(c) {
-        if (!this.getToggleable()) {
-            return
-        }
-        var b = this.getStore(),
-            h = 0,
-            e, g = true,
-            d, f, a;
-        if (b) {
-            f = b.getCount();
-            for (d = 0; d < f; d++) {
-                a = b.getAt(d);
-                if (a.get("disabled")) {
-                    h++
-                }
-            }
-            g = f - h > 1;
-            a = b.getAt(c);
-            if (a) {
-                e = a.get("disabled");
-                if (e || g) {
-                    a.set("disabled", !e)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.AbstractChart", {
-    extend: "Ext.draw.Container",
-    requires: ["Ext.chart.theme.Default", "Ext.chart.series.Series", "Ext.chart.interactions.Abstract", "Ext.chart.axis.Axis", "Ext.data.StoreManager", "Ext.chart.Legend", "Ext.data.Store"],
-    isChart: true,
-    defaultBindProperty: "store",
-    config: {
-        store: "ext-empty-store",
-        theme: "default",
-        style: null,
-        animation: !Ext.isIE8,
-        series: [],
-        axes: [],
-        legend: null,
-        colors: null,
-        insetPadding: {
-            top: 10,
-            left: 10,
-            right: 10,
-            bottom: 10
-        },
-        background: null,
-        interactions: [],
-        mainRect: null,
-        resizeHandler: null,
-        highlightItem: null
-    },
-    animationSuspendCount: 0,
-    chartLayoutSuspendCount: 0,
-    axisThicknessSuspendCount: 0,
-    isThicknessChanged: false,
-    surfaceZIndexes: {
-        background: 0,
-        main: 1,
-        grid: 2,
-        series: 3,
-        axis: 4,
-        chart: 5,
-        overlay: 6,
-        events: 7
-    },
-    constructor: function(a) {
-        var b = this;
-        b.itemListeners = {};
-        b.surfaceMap = {};
-        b.chartComponents = {};
-        b.isInitializing = true;
-        b.suspendChartLayout();
-        b.animationSuspendCount++;
-        b.callParent(arguments);
-        delete b.isInitializing;
-        b.getSurface("main");
-        b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);
-        b.getSurface("overlay").waitFor(b.getSurface("series"));
-        b.animationSuspendCount--;
-        b.resumeChartLayout()
-    },
-    applyAnimation: function(a, b) {
-        if (!a) {
-            a = {
-                duration: 0
-            }
-        } else {
-            if (a === true) {
-                a = {
-                    easing: "easeInOut",
-                    duration: 500
-                }
-            }
-        }
-        return b ? Ext.apply({}, a, b) : a
-    },
-    getAnimation: function() {
-        if (this.animationSuspendCount) {
-            return {
-                duration: 0
-            }
-        } else {
-            return this.callParent()
-        }
-    },
-    applyInsetPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    suspendAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            e = c.length,
-            b = -1,
-            a;
-        d.animationSuspendCount++;
-        if (d.animationSuspendCount === 1) {
-            while (++b < e) {
-                a = c[b];
-                a.setAnimation(a.getAnimation())
-            }
-        }
-    },
-    resumeAnimation: function() {
-        var d = this,
-            c = d.getSeries(),
-            f = c.length,
-            b = -1,
-            a, e;
-        d.animationSuspendCount--;
-        if (d.animationSuspendCount === 0) {
-            while (++b < f) {
-                a = c[b];
-                e = a.getAnimation();
-                a.setAnimation(e.duration && e || d.getAnimation())
-            }
-        }
-    },
-    suspendChartLayout: function() {
-        this.chartLayoutSuspendCount++;
-        if (this.chartLayoutSuspendCount === 1) {
-            if (this.scheduledLayoutId) {
-                this.layoutInSuspension = true;
-                this.cancelChartLayout()
-            } else {
-                this.layoutInSuspension = false
-            }
-        }
-    },
-    resumeChartLayout: function() {
-        this.chartLayoutSuspendCount--;
-        if (this.chartLayoutSuspendCount === 0) {
-            if (this.layoutInSuspension) {
-                this.scheduleLayout()
-            }
-        }
-    },
-    cancelChartLayout: function() {
-        if (this.scheduledLayoutId) {
-            Ext.draw.Animator.cancel(this.scheduledLayoutId);
-            this.scheduledLayoutId = null
-        }
-    },
-    scheduleLayout: function() {
-        var a = this;
-        if (a.allowSchedule() && !a.scheduledLayoutId) {
-            a.scheduledLayoutId = Ext.draw.Animator.schedule("doScheduleLayout", a)
-        }
-    },
-    allowSchedule: function() {
-        return true
-    },
-    doScheduleLayout: function() {
-        if (this.chartLayoutSuspendCount) {
-            this.layoutInSuspension = true
-        } else {
-            this.performLayout()
-        }
-    },
-    suspendThicknessChanged: function() {
-        this.axisThicknessSuspendCount++
-    },
-    resumeThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount > 0) {
-            this.axisThicknessSuspendCount--;
-            if (this.axisThicknessSuspendCount === 0 && this.isThicknessChanged) {
-                this.onThicknessChanged()
-            }
-        }
-    },
-    onThicknessChanged: function() {
-        if (this.axisThicknessSuspendCount === 0) {
-            this.isThicknessChanged = false;
-            this.performLayout()
-        } else {
-            this.isThicknessChanged = true
-        }
-    },
-    applySprites: function(b) {
-        var a = this.getSurface("chart");
-        b = Ext.Array.from(b);
-        a.removeAll(true);
-        a.add(b);
-        return b
-    },
-    initItems: function() {
-        var a = this.items,
-            b, d, c;
-        if (a && !a.isMixedCollection) {
-            this.items = [];
-            a = Ext.Array.from(a);
-            for (b = 0, d = a.length; b < d; b++) {
-                c = a[b];
-                if (c.type) {
-                    Ext.raise("To add custom sprites to the chart use the 'sprites' config.")
-                } else {
-                    this.items.push(c)
-                }
-            }
-        }
-        this.callParent()
-    },
-    applyBackground: function(c, e) {
-        var b = this.getSurface("background"),
-            d, a, f;
-        if (c) {
-            if (e) {
-                d = e.attr.width;
-                a = e.attr.height;
-                f = e.type === (c.type || "rect")
-            }
-            if (c.isSprite) {
-                e = c
-            } else {
-                if (c.type === "image" && Ext.isString(c.src)) {
-                    if (f) {
-                        e.setAttributes({
-                            src: c.src
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add(c)
-                    }
-                } else {
-                    if (f) {
-                        e.setAttributes({
-                            fillStyle: c
-                        })
-                    } else {
-                        b.remove(e, true);
-                        e = b.add({
-                            type: "rect",
-                            fillStyle: c,
-                            fx: {
-                                customDurations: {
-                                    x: 0,
-                                    y: 0,
-                                    width: 0,
-                                    height: 0
-                                }
-                            }
-                        })
-                    }
-                }
-            }
-        }
-        if (d && a) {
-            e.setAttributes({
-                width: d,
-                height: a
-            })
-        }
-        e.setAnimation(this.getAnimation());
-        return e
-    },
-    getLegendStore: function() {
-        return this.legendStore
-    },
-    refreshLegendStore: function() {
-        if (this.getLegendStore()) {
-            var d, e, c = this.getSeries(),
-                b, a = [];
-            if (c) {
-                for (d = 0, e = c.length; d < e; d++) {
-                    b = c[d];
-                    if (b.getShowInLegend()) {
-                        b.provideLegendInfo(a)
-                    }
-                }
-            }
-            this.getLegendStore().setData(a)
-        }
-    },
-    resetLegendStore: function() {
-        var c = this.getLegendStore(),
-            e, d, a, b;
-        if (c) {
-            e = this.getLegendStore().getData().items;
-            for (d = 0, a = e.length; d < a; d++) {
-                b = e[d];
-                b.beginEdit();
-                b.set("disabled", false);
-                b.commit()
-            }
-        }
-    },
-    onUpdateLegendStore: function(b, a) {
-        var d = this.getSeries(),
-            c;
-        if (a && d) {
-            c = d.map[a.get("series")];
-            if (c) {
-                c.setHiddenByIndex(a.get("index"), a.get("disabled"));
-                this.redraw()
-            }
-        }
-    },
-    defaultResizeHandler: function(a) {
-        this.scheduleLayout();
-        return false
-    },
-    applyMainRect: function(a, b) {
-        if (!b) {
-            return a
-        }
-        this.getSeries();
-        this.getAxes();
-        if (a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]) {
-            return b
-        } else {
-            return a
-        }
-    },
-    register: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        b[c] = a
-    },
-    unregister: function(a) {
-        var b = this.chartComponents,
-            c = a.getId();
-        delete b[c]
-    },
-    get: function(a) {
-        return this.chartComponents[a]
-    },
-    getAxis: function(a) {
-        if (a instanceof Ext.chart.axis.Axis) {
-            return a
-        } else {
-            if (Ext.isNumber(a)) {
-                return this.getAxes()[a]
-            } else {
-                if (Ext.isString(a)) {
-                    return this.get(a)
-                }
-            }
-        }
-    },
-    getSurface: function(b, c) {
-        b = b || "main";
-        c = c || b;
-        var d = this,
-            a = this.callParent([b]),
-            f = d.surfaceZIndexes,
-            e = d.surfaceMap;
-        if (c in f) {
-            a.element.setStyle("zIndex", f[c])
-        }
-        if (!e[c]) {
-            e[c] = []
-        }
-        if (Ext.Array.indexOf(e[c], a) < 0) {
-            a.type = c;
-            e[c].push(a);
-            a.on("destroy", d.forgetSurface, d)
-        }
-        return a
-    },
-    forgetSurface: function(a) {
-        var d = this.surfaceMap;
-        if (!d || this.isDestroying) {
-            return
-        }
-        var c = d[a.type],
-            b = c ? Ext.Array.indexOf(c, a) : -1;
-        if (b >= 0) {
-            c.splice(b, 1)
-        }
-    },
-    applyAxes: function(b, k) {
-        var l = this,
-            g = {
-                left: "right",
-                right: "left"
-            },
-            m = [],
-            c, d, e, a, f, h, j;
-        l.animationSuspendCount++;
-        l.getStore();
-        if (!k) {
-            k = [];
-            k.map = {}
-        }
-        j = k.map;
-        m.map = {};
-        b = Ext.Array.from(b, true);
-        for (f = 0, h = b.length; f < h; f++) {
-            c = b[f];
-            if (!c) {
-                continue
-            }
-            if (c instanceof Ext.chart.axis.Axis) {
-                d = j[c.getId()];
-                c.setChart(l)
-            } else {
-                c = Ext.Object.chain(c);
-                e = c.linkedTo;
-                a = c.id;
-                if (Ext.isNumber(e)) {
-                    c = Ext.merge({}, b[e], c)
-                } else {
-                    if (Ext.isString(e)) {
-                        Ext.Array.each(b, function(i) {
-                            if (i.id === c.linkedTo) {
-                                c = Ext.merge({}, i, c);
-                                return false
-                            }
-                        })
-                    }
-                }
-                c.id = a;
-                c.chart = l;
-                if (l.getInherited().rtl) {
-                    c.position = g[c.position] || c.position
-                }
-                a = c.getId && c.getId() || c.id;
-                c = Ext.factory(c, null, d = j[a], "axis")
-            }
-            if (c) {
-                m.push(c);
-                m.map[c.getId()] = c;
-                if (!d) {
-                    c.on("animationstart", "onAnimationStart", l);
-                    c.on("animationend", "onAnimationEnd", l)
-                }
-            }
-        }
-        for (f in j) {
-            if (!m.map[f]) {
-                j[f].destroy()
-            }
-        }
-        l.animationSuspendCount--;
-        return m
-    },
-    updateAxes: function() {
-        if (!this.isDestroying) {
-            this.scheduleLayout()
-        }
-    },
-    circularCopyArray: function(e, f, d) {
-        var c = [],
-            b, a = e && e.length;
-        if (a) {
-            for (b = 0; b < d; b++) {
-                c.push(e[(f + b) % a])
-            }
-        }
-        return c
-    },
-    circularCopyObject: function(f, g, d) {
-        var c = this,
-            b, e, a = {};
-        if (d) {
-            for (b in f) {
-                if (f.hasOwnProperty(b)) {
-                    e = f[b];
-                    if (Ext.isArray(e)) {
-                        a[b] = c.circularCopyArray(e, g, d)
-                    } else {
-                        a[b] = e
-                    }
-                }
-            }
-        }
-        return a
-    },
-    getColors: function() {
-        var b = this,
-            a = b.config.colors,
-            c = b.getTheme();
-        if (Ext.isArray(a) && a.length > 0) {
-            a = b.applyColors(a)
-        }
-        return a || (c && c.getColors())
-    },
-    applyColors: function(a) {
-        a = Ext.Array.map(a, function(b) {
-            if (Ext.isString(b)) {
-                return b
-            } else {
-                return b.toString()
-            }
-        });
-        return a
-    },
-    updateColors: function(c) {
-        var k = this,
-            e = k.getTheme(),
-            a = c || (e && e.getColors()),
-            l = 0,
-            f = k.getSeries(),
-            d = f && f.length,
-            g, j, b, h;
-        if (a.length) {
-            for (g = 0; g < d; g++) {
-                j = f[g];
-                h = j.themeColorCount();
-                b = k.circularCopyArray(a, l, h);
-                l += h;
-                j.updateChartColors(b)
-            }
-        }
-        k.refreshLegendStore()
-    },
-    applyTheme: function(a) {
-        if (a && a.isTheme) {
-            return a
-        }
-        return Ext.Factory.chartTheme(a)
-    },
-    updateTheme: function(g) {
-        var e = this,
-            f = e.getAxes(),
-            d = e.getSeries(),
-            a = e.getColors(),
-            c, b;
-        e.updateChartTheme(g);
-        for (b = 0; b < f.length; b++) {
-            f[b].updateTheme(g)
-        }
-        for (b = 0; b < d.length; b++) {
-            c = d[b];
-            c.updateTheme(g)
-        }
-        e.updateSpriteTheme(g);
-        e.updateColors(a);
-        e.redraw()
-    },
-    themeOnlyIfConfigured: {},
-    updateChartTheme: function(c) {
-        var i = this,
-            k = c.getChart(),
-            n = i.getInitialConfig(),
-            b = i.defaultConfig,
-            e = i.getConfigurator().configs,
-            f = k.defaults,
-            g = k[i.xtype],
-            h = i.themeOnlyIfConfigured,
-            l, j, o, a, m, d;
-        k = Ext.merge({}, f, g);
-        for (l in k) {
-            j = k[l];
-            d = e[l];
-            if (j !== null && j !== undefined && d) {
-                m = n[l];
-                o = Ext.isObject(j);
-                a = m === b[l];
-                if (o) {
-                    if (a && h[l]) {
-                        continue
-                    }
-                    j = Ext.merge({}, j, m)
-                }
-                if (a || o) {
-                    i[d.names.set](j)
-                }
-            }
-        }
-    },
-    updateSpriteTheme: function(c) {
-        this.getSprites();
-        var j = this,
-            e = j.getSurface("chart"),
-            h = e.getItems(),
-            m = c.getSprites(),
-            k, a, l, f, d, b, g;
-        for (b = 0, g = h.length; b < g; b++) {
-            k = h[b];
-            a = m[k.type];
-            if (a) {
-                f = {};
-                d = k.type === "text";
-                for (l in a) {
-                    if (!(l in k.config)) {
-                        if (!(d && l.indexOf("font") === 0 && k.config.font)) {
-                            f[l] = a[l]
-                        }
-                    }
-                }
-                k.setAttributes(f)
-            }
-        }
-    },
-    addSeries: function(b) {
-        var a = this.getSeries();
-        Ext.Array.push(a, b);
-        this.setSeries(a)
-    },
-    removeSeries: function(d) {
-        d = Ext.Array.from(d);
-        var b = this.getSeries(),
-            f = [],
-            a = d.length,
-            g = {},
-            c, e;
-        for (c = 0; c < a; c++) {
-            e = d[c];
-            if (typeof e !== "string") {
-                e = e.getId()
-            }
-            g[e] = true
-        }
-        for (c = 0, a = b.length; c < a; c++) {
-            if (!g[b[c].getId()]) {
-                f.push(b[c])
-            }
-        }
-        this.setSeries(f)
-    },
-    applySeries: function(e, d) {
-        var g = this,
-            j = [],
-            h, a, c, f, b;
-        g.animationSuspendCount++;
-        g.getAxes();
-        if (d) {
-            h = d.map
-        } else {
-            d = [];
-            h = d.map = {}
-        }
-        j.map = {};
-        e = Ext.Array.from(e, true);
-        for (c = 0, f = e.length; c < f; c++) {
-            b = e[c];
-            if (!b) {
-                continue
-            }
-            a = h[b.getId && b.getId() || b.id];
-            if (b instanceof Ext.chart.series.Series) {
-                if (a && a !== b) {
-                    a.destroy()
-                }
-                b.setChart(g)
-            } else {
-                if (Ext.isObject(b)) {
-                    if (a) {
-                        a.setConfig(b);
-                        b = a
-                    } else {
-                        if (Ext.isString(b)) {
-                            b = {
-                                type: b
-                            }
-                        }
-                        b.chart = g;
-                        b = Ext.create(b.xclass || ("series." + b.type), b);
-                        b.on("animationstart", "onAnimationStart", g);
-                        b.on("animationend", "onAnimationEnd", g)
-                    }
-                }
-            }
-            j.push(b);
-            j.map[b.getId()] = b
-        }
-        for (c in h) {
-            if (!j.map[h[c].getId()]) {
-                h[c].destroy()
-            }
-        }
-        g.animationSuspendCount--;
-        return j
-    },
-    applyLegend: function(b, a) {
-        return Ext.factory(b, Ext.chart.Legend, a)
-    },
-    updateLegend: function(b, a) {
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            this.getItems();
-            this.legendStore = new Ext.data.Store({
-                autoDestroy: true,
-                fields: ["id", "name", "mark", "disabled", "series", "index"]
-            });
-            b.setStore(this.legendStore);
-            this.refreshLegendStore();
-            this.legendStore.on("update", "onUpdateLegendStore", this)
-        }
-    },
-    updateSeries: function(b, a) {
-        var c = this;
-        if (c.isDestroying) {
-            return
-        }
-        c.animationSuspendCount++;
-        c.fireEvent("serieschange", c, b, a);
-        c.refreshLegendStore();
-        if (!Ext.isEmpty(b)) {
-            c.updateTheme(c.getTheme())
-        }
-        c.scheduleLayout();
-        c.animationSuspendCount--
-    },
-    applyInteractions: function(h, d) {
-        if (!d) {
-            d = [];
-            d.map = {}
-        }
-        var g = this,
-            a = [],
-            c = d.map,
-            e, f, b;
-        a.map = {};
-        h = Ext.Array.from(h, true);
-        for (e = 0, f = h.length; e < f; e++) {
-            b = h[e];
-            if (!b) {
-                continue
-            }
-            b = Ext.factory(b, null, c[b.getId && b.getId() || b.id], "interaction");
-            if (b) {
-                b.setChart(g);
-                a.push(b);
-                a.map[b.getId()] = b
-            }
-        }
-        for (e in c) {
-            if (!a.map[e]) {
-                c[e].destroy()
-            }
-        }
-        return a
-    },
-    getInteraction: function(e) {
-        var f = this.getInteractions(),
-            a = f && f.length,
-            c = null,
-            b, d;
-        if (a) {
-            for (d = 0; d < a; ++d) {
-                b = f[d];
-                if (b.type === e) {
-                    c = b;
-                    break
-                }
-            }
-        }
-        return c
-    },
-    applyStore: function(a) {
-        return a && Ext.StoreManager.lookup(a)
-    },
-    updateStore: function(a, c) {
-        var b = this;
-        if (c) {
-            c.un({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            });
-            if (c.autoDestroy) {
-                c.destroy()
-            }
-        }
-        if (a) {
-            a.on({
-                datachanged: "onDataChanged",
-                update: "onDataChanged",
-                scope: b,
-                order: "after"
-            })
-        }
-        b.fireEvent("storechange", b, a, c);
-        b.onDataChanged()
-    },
-    redraw: function() {
-        this.fireEvent("redraw", this)
-    },
-    performLayout: function() {
-        var d = this,
-            b = d.getChartSize(true),
-            c = [0, 0, b.width, b.height],
-            a = d.getBackground();
-        d.hasFirstLayout = true;
-        d.fireEvent("layout", d);
-        d.cancelChartLayout();
-        d.getSurface("background").setRect(c);
-        d.getSurface("chart").setRect(c);
-        a.setAttributes({
-            width: b.width,
-            height: b.height
-        })
-    },
-    getChartSize: function(b) {
-        var a = this;
-        if (b) {
-            a.chartSize = null
-        }
-        return a.chartSize || (a.chartSize = a.innerElement.getSize())
-    },
-    getEventXY: function(a) {
-        return this.getSurface().getEventXY(a)
-    },
-    getItemForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            e = f.getMainRect(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            c, j;
-        if (!(e && h >= 0 && h <= e[2] && g >= 0 && g <= e[3])) {
-            return null
-        }
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                return j
-            }
-        }
-        return null
-    },
-    getItemsForPoint: function(h, g) {
-        var f = this,
-            a = f.getSeries(),
-            d = a.length,
-            b = f.hasFirstLayout ? d - 1 : -1,
-            e = [],
-            c, j;
-        for (; b >= 0; b--) {
-            c = a[b];
-            j = c.getItemForPoint(h, g);
-            if (j) {
-                e.push(j)
-            }
-        }
-        return e
-    },
-    onAnimationStart: function() {
-        this.fireEvent("animationstart", this)
-    },
-    onAnimationEnd: function() {
-        this.fireEvent("animationend", this)
-    },
-    onDataChanged: function() {
-        var d = this;
-        if (d.isInitializing) {
-            return
-        }
-        var c = d.getMainRect(),
-            a = d.getStore(),
-            b = d.getSeries(),
-            e = d.getAxes();
-        if (!a || !e || !b) {
-            return
-        }
-        if (!c) {
-            d.on({
-                redraw: d.onDataChanged,
-                scope: d,
-                single: true
-            });
-            return
-        }
-        d.processData();
-        d.redraw()
-    },
-    recordCount: 0,
-    processData: function() {
-        var g = this,
-            e = g.getStore().getCount(),
-            c = g.getSeries(),
-            f = c.length,
-            d = false,
-            b = 0,
-            a;
-        for (; b < f; b++) {
-            a = c[b];
-            a.processData();
-            if (!d && a.isStoreDependantColorCount) {
-                d = true
-            }
-        }
-        if (d && e > g.recordCount) {
-            g.updateColors(g.getColors());
-            g.recordCount = e
-        }
-    },
-    bindStore: function(a) {
-        this.setStore(a)
-    },
-    applyHighlightItem: function(f, a) {
-        if (f === a) {
-            return
-        }
-        if (Ext.isObject(f) && Ext.isObject(a)) {
-            var e = f,
-                d = a,
-                c = e.sprite && (e.sprite[0] || e.sprite),
-                b = d.sprite && (d.sprite[0] || d.sprite);
-            if (c === b && e.index === d.index) {
-                return
-            }
-        }
-        return f
-    },
-    updateHighlightItem: function(b, a) {
-        if (a) {
-            a.series.setAttributesForItem(a, {
-                highlighted: false
-            })
-        }
-        if (b) {
-            b.series.setAttributesForItem(b, {
-                highlighted: true
-            });
-            this.fireEvent("itemhighlight", this, b, a)
-        }
-        this.fireEvent("itemhighlightchange", this, b, a)
-    },
-    destroyChart: function() {
-        var f = this,
-            d = f.getLegend(),
-            g = f.getAxes(),
-            c = f.getSeries(),
-            h = f.getInteractions(),
-            b = [],
-            a, e;
-        f.surfaceMap = null;
-        for (a = 0, e = h.length; a < e; a++) {
-            h[a].destroy()
-        }
-        for (a = 0, e = g.length; a < e; a++) {
-            g[a].destroy()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            c[a].destroy()
-        }
-        f.setInteractions(b);
-        f.setAxes(b);
-        f.setSeries(b);
-        if (d) {
-            d.destroy();
-            f.setLegend(null)
-        }
-        f.legendStore = null;
-        f.setStore(null);
-        f.cancelChartLayout()
-    },
-    getRefItems: function(b) {
-        var g = this,
-            e = g.getSeries(),
-            h = g.getAxes(),
-            a = g.getInteractions(),
-            c = [],
-            d, f;
-        for (d = 0, f = e.length; d < f; d++) {
-            c.push(e[d]);
-            if (e[d].getRefItems) {
-                c.push.apply(c, e[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = h.length; d < f; d++) {
-            c.push(h[d]);
-            if (h[d].getRefItems) {
-                c.push.apply(c, h[d].getRefItems(b))
-            }
-        }
-        for (d = 0, f = a.length; d < f; d++) {
-            c.push(a[d]);
-            if (a[d].getRefItems) {
-                c.push.apply(c, a[d].getRefItems(b))
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.overrides.AbstractChart", {
-    override: "Ext.chart.AbstractChart",
-    updateLegend: function(b, a) {
-        var c;
-        this.callParent([b, a]);
-        if (b) {
-            c = b.docked;
-            this.addDocked({
-                dock: c,
-                xtype: "panel",
-                shrinkWrap: true,
-                scrollable: true,
-                layout: {
-                    type: c === "top" || c === "bottom" ? "hbox" : "vbox",
-                    pack: "center"
-                },
-                items: b,
-                cls: Ext.baseCSSPrefix + "legend-panel"
-            })
-        }
-    },
-    performLayout: function() {
-        if (this.isVisible(true)) {
-            return this.callParent()
-        }
-        this.cancelChartLayout();
-        return false
-    },
-    afterComponentLayout: function(c, a, b, d) {
-        this.callParent([c, a, b, d]);
-        this.scheduleLayout()
-    },
-    allowSchedule: function() {
-        return this.rendered
-    },
-    onDestroy: function() {
-        this.destroyChart();
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.horizontal",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(b, c, e) {
-        var a = this.attr,
-            f = b.roundPixel(a.y),
-            d = c.lineWidth * 0.5;
-        c.beginPath();
-        c.rect(e[0] - b.matrix.getDX(), f + d, +e[2], a.height);
-        c.fill();
-        c.beginPath();
-        c.moveTo(e[0] - b.matrix.getDX(), f + d);
-        c.lineTo(e[0] + e[2] - b.matrix.getDX(), f + d);
-        c.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "grid.vertical",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 1,
-                height: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    },
-    render: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    }
-});
-Ext.define("Ext.chart.CartesianChart", {
-    extend: "Ext.chart.AbstractChart",
-    alternateClassName: "Ext.chart.Chart",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid"],
-    xtype: ["cartesian", "chart"],
-    isCartesian: true,
-    config: {
-        flipXY: false,
-        innerRect: [0, 0, 1, 1],
-        innerPadding: {
-            top: 0,
-            left: 0,
-            right: 0,
-            bottom: 0
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        if (!Ext.isObject(b)) {
-            return Ext.util.Format.parseBox(b)
-        } else {
-            if (!a) {
-                return b
-            } else {
-                return Ext.apply(a, b)
-            }
-        }
-    },
-    getDirectionForAxis: function(a) {
-        var b = this.getFlipXY();
-        if (a === "left" || a === "right") {
-            if (b) {
-                return "X"
-            } else {
-                return "Y"
-            }
-        } else {
-            if (b) {
-                return "Y"
-            } else {
-                return "X"
-            }
-        }
-    },
-    performLayout: function() {
-        var A = this;
-        A.animationSuspendCount++;
-        if (A.callParent() === false) {
-            --A.animationSuspendCount;
-            return
-        }
-        A.suspendThicknessChanged();
-        var d = A.getSurface("chart").getRect(),
-            o = d[2],
-            n = d[3],
-            z = A.getAxes(),
-            b, q = A.getSeries(),
-            h, l, a, f = A.getInsetPadding(),
-            v = A.getInnerPadding(),
-            r, c, e = Ext.apply({}, f),
-            u, p, s, k, m, y, t, x, g, j = A.getInherited().rtl,
-            w = A.getFlipXY();
-        if (o <= 0 || n <= 0) {
-            return
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            m = b.getFloating();
-            y = m ? m.value : null;
-            a = b.getThickness();
-            switch (b.getPosition()) {
-                case "top":
-                    l.setRect([0, e.top + 1, o, a]);
-                    break;
-                case "bottom":
-                    l.setRect([0, n - (e.bottom + a), o, a]);
-                    break;
-                case "left":
-                    l.setRect([e.left, 0, a, n]);
-                    break;
-                case "right":
-                    l.setRect([o - (e.right + a), 0, a, n]);
-                    break
-            }
-            if (y === null) {
-                e[b.getPosition()] += a
-            }
-        }
-        o -= e.left + e.right;
-        n -= e.top + e.bottom;
-        u = [e.left, e.top, o, n];
-        e.left += v.left;
-        e.top += v.top;
-        e.right += v.right;
-        e.bottom += v.bottom;
-        p = o - v.left - v.right;
-        s = n - v.top - v.bottom;
-        A.setInnerRect([e.left, e.top, p, s]);
-        if (p <= 0 || s <= 0) {
-            return
-        }
-        A.setMainRect(u);
-        A.getSurface().setRect(u);
-        for (x = 0, g = A.surfaceMap.grid && A.surfaceMap.grid.length; x < g; x++) {
-            c = A.surfaceMap.grid[x];
-            c.setRect(u);
-            c.matrix.set(1, 0, 0, 1, v.left, v.top);
-            c.matrix.inverse(c.inverseMatrix)
-        }
-        for (x = 0; x < z.length; x++) {
-            b = z[x];
-            l = b.getSurface();
-            t = l.matrix;
-            k = t.elements;
-            switch (b.getPosition()) {
-                case "top":
-                case "bottom":
-                    k[4] = e.left;
-                    b.setLength(p);
-                    break;
-                case "left":
-                case "right":
-                    k[5] = e.top;
-                    b.setLength(s);
-                    break
-            }
-            b.updateTitleSprite();
-            t.inverse(l.inverseMatrix)
-        }
-        for (x = 0, g = q.length; x < g; x++) {
-            h = q[x];
-            r = h.getSurface();
-            r.setRect(u);
-            if (w) {
-                if (j) {
-                    r.matrix.set(0, -1, -1, 0, v.left + p, v.top + s)
-                } else {
-                    r.matrix.set(0, -1, 1, 0, v.left, v.top + s)
-                }
-            } else {
-                r.matrix.set(1, 0, 0, -1, v.left, v.top + s)
-            }
-            r.matrix.inverse(r.inverseMatrix);
-            h.getOverlaySurface().setRect(u)
-        }
-        A.redraw();
-        A.animationSuspendCount--;
-        A.resumeThicknessChanged()
-    },
-    refloatAxes: function() {
-        var h = this,
-            g = h.getAxes(),
-            o = (g && g.length) || 0,
-            c, d, n, f, l, b, k, r = h.getChartSize(),
-            q = h.getInsetPadding(),
-            p = h.getInnerPadding(),
-            a = r.width - q.left - q.right,
-            m = r.height - q.top - q.bottom,
-            j, e;
-        for (e = 0; e < o; e++) {
-            c = g[e];
-            f = c.getFloating();
-            l = f ? f.value : null;
-            if (l === null) {
-                delete c.floatingAtCoord;
-                continue
-            }
-            d = c.getSurface();
-            n = d.getRect();
-            if (!n) {
-                continue
-            }
-            n = n.slice();
-            b = h.getAxis(f.alongAxis);
-            if (b) {
-                j = b.getAlignment() === "horizontal";
-                if (Ext.isString(l)) {
-                    l = b.getCoordFor(l)
-                }
-                b.floatingAxes[c.getId()] = l;
-                k = b.getSprites()[0].attr.matrix;
-                if (j) {
-                    l = l * k.getXX() + k.getDX();
-                    c.floatingAtCoord = l + p.left + p.right
-                } else {
-                    l = l * k.getYY() + k.getDY();
-                    c.floatingAtCoord = l + p.top + p.bottom
-                }
-            } else {
-                j = c.getAlignment() === "horizontal";
-                if (j) {
-                    c.floatingAtCoord = l + p.top + p.bottom
-                } else {
-                    c.floatingAtCoord = l + p.left + p.right
-                }
-                l = d.roundPixel(0.01 * l * (j ? m : a))
-            }
-            switch (c.getPosition()) {
-                case "top":
-                    n[1] = q.top + p.top + l - n[3] + 1;
-                    break;
-                case "bottom":
-                    n[1] = q.top + p.top + (b ? l : m - l);
-                    break;
-                case "left":
-                    n[0] = q.left + p.left + l - n[2];
-                    break;
-                case "right":
-                    n[0] = q.left + p.left + (b ? l : a - l) - 1;
-                    break
-            }
-            d.setRect(n)
-        }
-    },
-    redraw: function() {
-        var C = this,
-            r = C.getSeries(),
-            z = C.getAxes(),
-            b = C.getMainRect(),
-            p, t, w = C.getInnerPadding(),
-            f, l, s, e, q, A, v, g, d, c, a, k, n, y = C.getFlipXY(),
-            x = 1000,
-            m, u, h, o, B;
-        if (!b) {
-            return
-        }
-        p = b[2] - w.left - w.right;
-        t = b[3] - w.top - w.bottom;
-        for (A = 0; A < r.length; A++) {
-            h = r[A];
-            if ((c = h.getXAxis())) {
-                n = c.getVisibleRange();
-                l = c.getRange();
-                l = [l[0] + (l[1] - l[0]) * n[0], l[0] + (l[1] - l[0]) * n[1]]
-            } else {
-                l = h.getXRange()
-            }
-            if ((a = h.getYAxis())) {
-                n = a.getVisibleRange();
-                s = a.getRange();
-                s = [s[0] + (s[1] - s[0]) * n[0], s[0] + (s[1] - s[0]) * n[1]]
-            } else {
-                s = h.getYRange()
-            }
-            q = {
-                visibleMinX: l[0],
-                visibleMaxX: l[1],
-                visibleMinY: s[0],
-                visibleMaxY: s[1],
-                innerWidth: p,
-                innerHeight: t,
-                flipXY: y
-            };
-            f = h.getSprites();
-            for (v = 0, g = f.length; v < g; v++) {
-                o = f[v];
-                m = o.attr.zIndex;
-                if (m < x) {
-                    m += (A + 1) * 100 + x;
-                    o.attr.zIndex = m;
-                    B = o.getMarker("items");
-                    if (B) {
-                        u = B.attr.zIndex;
-                        if (u === Number.MAX_VALUE) {
-                            B.attr.zIndex = m
-                        } else {
-                            if (u < x) {
-                                B.attr.zIndex = m + u
-                            }
-                        }
-                    }
-                }
-                o.setAttributes(q, true)
-            }
-        }
-        for (A = 0; A < z.length; A++) {
-            d = z[A];
-            e = d.isSide();
-            f = d.getSprites();
-            k = d.getRange();
-            n = d.getVisibleRange();
-            q = {
-                dataMin: k[0],
-                dataMax: k[1],
-                visibleMin: n[0],
-                visibleMax: n[1]
-            };
-            if (e) {
-                q.length = t;
-                q.startGap = w.bottom;
-                q.endGap = w.top
-            } else {
-                q.length = p;
-                q.startGap = w.left;
-                q.endGap = w.right
-            }
-            for (v = 0, g = f.length; v < g; v++) {
-                f[v].setAttributes(q, true)
-            }
-        }
-        C.renderFrame();
-        C.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.grid.CircularGrid", {
-    extend: "Ext.draw.sprite.Circle",
-    alias: "grid.circular",
-    inheritableStatics: {
-        def: {
-            defaults: {
-                r: 1,
-                strokeStyle: "#DDD"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.grid.RadialGrid", {
-    extend: "Ext.draw.sprite.Path",
-    alias: "grid.radial",
-    inheritableStatics: {
-        def: {
-            processors: {
-                startRadius: "number",
-                endRadius: "number"
-            },
-            defaults: {
-                startRadius: 0,
-                endRadius: 1,
-                scalingCenterX: 0,
-                scalingCenterY: 0,
-                strokeStyle: "#DDD"
-            },
-            triggers: {
-                startRadius: "path,bbox",
-                endRadius: "path,bbox"
-            }
-        }
-    },
-    render: function() {
-        this.callParent(arguments)
-    },
-    updatePath: function(d, a) {
-        var b = a.startRadius,
-            c = a.endRadius;
-        d.moveTo(b, 0);
-        d.lineTo(c, 0)
-    }
-});
-Ext.define("Ext.chart.PolarChart", {
-    extend: "Ext.chart.AbstractChart",
-    requires: ["Ext.chart.grid.CircularGrid", "Ext.chart.grid.RadialGrid"],
-    xtype: "polar",
-    isPolar: true,
-    config: {
-        center: [0, 0],
-        radius: 0,
-        innerPadding: 0
-    },
-    getDirectionForAxis: function(a) {
-        return a === "radial" ? "Y" : "X"
-    },
-    applyCenter: function(a, b) {
-        if (b && a[0] === b[0] && a[1] === b[1]) {
-            return
-        }
-        return [+a[0], +a[1]]
-    },
-    updateCenter: function(a) {
-        var g = this,
-            h = g.getAxes(),
-            d = g.getSeries(),
-            c, f, e, b;
-        for (c = 0, f = h.length; c < f; c++) {
-            e = h[c];
-            e.setCenter(a)
-        }
-        for (c = 0, f = d.length; c < f; c++) {
-            b = d[c];
-            b.setCenter(a)
-        }
-    },
-    applyInnerPadding: function(b, a) {
-        return Ext.isNumber(b) ? b : a
-    },
-    doSetSurfaceRect: function(b, c) {
-        var a = this.getMainRect();
-        b.setRect(c);
-        b.matrix.set(1, 0, 0, 1, a[0] - c[0], a[1] - c[1]);
-        b.inverseMatrix.set(1, 0, 0, 1, c[0] - a[0], c[1] - a[1])
-    },
-    applyAxes: function(f, h) {
-        var e = this,
-            g = Ext.Array.from(e.config.series)[0],
-            b, d, c, a;
-        if (g.type === "radar" && f && f.length) {
-            for (b = 0, d = f.length; b < d; b++) {
-                c = f[b];
-                if (c.position === "angular") {
-                    a = true;
-                    break
-                }
-            }
-            if (!a) {
-                f.push({
-                    type: "category",
-                    position: "angular",
-                    fields: g.xField || g.angleField,
-                    style: {
-                        estStepSize: 1
-                    },
-                    grid: true
-                })
-            }
-        }
-        return this.callParent(arguments)
-    },
-    performLayout: function() {
-        var F = this,
-            g = true;
-        try {
-            F.animationSuspendCount++;
-            if (this.callParent() === false) {
-                g = false;
-                return
-            }
-            F.suspendThicknessChanged();
-            var h = F.getSurface("chart").getRect(),
-                v = F.getInsetPadding(),
-                G = F.getInnerPadding(),
-                l = Ext.apply({}, v),
-                d, s = h[2] - v.left - v.right,
-                r = h[3] - v.top - v.bottom,
-                x = [v.left, v.top, s, r],
-                u = F.getSeries(),
-                p, t = s - G * 2,
-                w = r - G * 2,
-                D = [t * 0.5 + G, w * 0.5 + G],
-                j = Math.min(t, w) * 0.5,
-                A = F.getAxes(),
-                f, a, k, m = [],
-                o = [],
-                E = j - G,
-                z, n, b, q, y, c, C;
-            F.setMainRect(x);
-            F.doSetSurfaceRect(F.getSurface(), x);
-            for (z = 0, n = F.surfaceMap.grid && F.surfaceMap.grid.length; z < n; z++) {
-                F.doSetSurfaceRect(F.surfaceMap.grid[z], h)
-            }
-            for (z = 0, n = A.length; z < n; z++) {
-                f = A[z];
-                switch (f.getPosition()) {
-                    case "angular":
-                        m.push(f);
-                        break;
-                    case "radial":
-                        o.push(f);
-                        break
-                }
-            }
-            for (z = 0, n = m.length; z < n; z++) {
-                f = m[z];
-                q = f.getFloating();
-                y = q ? q.value : null;
-                F.doSetSurfaceRect(f.getSurface(), h);
-                a = f.getThickness();
-                for (d in l) {
-                    l[d] += a
-                }
-                s = h[2] - l.left - l.right;
-                r = h[3] - l.top - l.bottom;
-                b = Math.min(s, r) * 0.5;
-                if (z === 0) {
-                    E = b - G
-                }
-                f.setMinimum(0);
-                f.setLength(b);
-                f.getSprites();
-                k = f.sprites[0].attr.lineWidth * 0.5;
-                for (d in l) {
-                    l[d] += k
-                }
-            }
-            for (z = 0, n = o.length; z < n; z++) {
-                f = o[z];
-                F.doSetSurfaceRect(f.getSurface(), h);
-                f.setMinimum(0);
-                f.setLength(E);
-                f.getSprites()
-            }
-            for (z = 0, n = u.length; z < n; z++) {
-                p = u[z];
-                if (p.type === "gauge" && !c) {
-                    c = p
-                } else {
-                    p.setRadius(E)
-                }
-                F.doSetSurfaceRect(p.getSurface(), x)
-            }
-            F.doSetSurfaceRect(F.getSurface("overlay"), h);
-            if (c) {
-                c.setRect(x);
-                C = c.getRadius() - G;
-                F.setRadius(C);
-                F.setCenter(c.getCenter());
-                c.setRadius(C);
-                if (A.length && A[0].getPosition() === "gauge") {
-                    f = A[0];
-                    F.doSetSurfaceRect(f.getSurface(), h);
-                    f.setTotalAngle(c.getTotalAngle());
-                    f.setLength(C)
-                }
-            } else {
-                F.setRadius(j);
-                F.setCenter(D)
-            }
-            F.redraw()
-        } catch (B) {
-            throw B
-        } finally {
-            F.animationSuspendCount--;
-            if (g) {
-                F.resumeThicknessChanged()
-            }
-        }
-    },
-    refloatAxes: function() {
-        var j = this,
-            g = j.getAxes(),
-            h = j.getMainRect(),
-            f, k, b, d, a, c, e;
-        if (!h) {
-            return
-        }
-        e = 0.5 * Math.min(h[2], h[3]);
-        for (d = 0, a = g.length; d < a; d++) {
-            c = g[d];
-            f = c.getFloating();
-            k = f ? f.value : null;
-            if (k !== null) {
-                b = j.getAxis(f.alongAxis);
-                if (c.getPosition() === "angular") {
-                    if (b) {
-                        k = b.getLength() * k / b.getRange()[1]
-                    } else {
-                        k = 0.01 * k * e
-                    }
-                    c.sprites[0].setAttributes({
-                        length: k
-                    }, true)
-                } else {
-                    if (b) {
-                        if (Ext.isString(k)) {
-                            k = b.getCoordFor(k)
-                        }
-                        k = k / (b.getRange()[1] + 1) * Math.PI * 2 - Math.PI * 1.5 + c.getRotation()
-                    } else {
-                        k = Ext.draw.Draw.rad(k)
-                    }
-                    c.sprites[0].setAttributes({
-                        baseRotation: k
-                    }, true)
-                }
-            }
-        }
-    },
-    redraw: function() {
-        var f = this,
-            g = f.getAxes(),
-            d, c = f.getSeries(),
-            b, a, e;
-        for (a = 0, e = g.length; a < e; a++) {
-            d = g[a];
-            d.getSprites()
-        }
-        for (a = 0, e = c.length; a < e; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        f.renderFrame();
-        f.callParent(arguments)
-    },
-    renderFrame: function() {
-        this.refloatAxes();
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.SpaceFillingChart", {
-    extend: "Ext.chart.AbstractChart",
-    xtype: "spacefilling",
-    config: {},
-    performLayout: function() {
-        var j = this;
-        try {
-            j.animationSuspendCount++;
-            if (j.callParent() === false) {
-                return
-            }
-            var k = j.getSurface("chart").getRect(),
-                l = j.getInsetPadding(),
-                a = k[2] - l.left - l.right,
-                m = k[3] - l.top - l.bottom,
-                h = [l.left, l.top, a, m],
-                b = j.getSeries(),
-                d, c, g;
-            j.getSurface().setRect(h);
-            j.setMainRect(h);
-            for (c = 0, g = b.length; c < g; c++) {
-                d = b[c];
-                d.getSurface().setRect(h);
-                if (d.setRect) {
-                    d.setRect(h)
-                }
-                d.getOverlaySurface().setRect(k)
-            }
-            j.redraw()
-        } catch (f) {
-            throw f
-        } finally {
-            j.animationSuspendCount--
-        }
-    },
-    redraw: function() {
-        var e = this,
-            c = e.getSeries(),
-            b, a, d;
-        for (a = 0, d = c.length; a < d; a++) {
-            b = c[a];
-            b.getSprites()
-        }
-        e.renderFrame();
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.axis.sprite.Axis3D", {
-    extend: "Ext.chart.axis.sprite.Axis",
-    alias: "sprite.axis3d",
-    type: "axis3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            },
-            triggers: {
-                depth: "layout"
-            }
-        }
-    },
-    config: {
-        fx: {
-            customDurations: {
-                depth: 0
-            }
-        }
-    },
-    layoutUpdater: function() {
-        var h = this,
-            f = h.getAxis().getChart();
-        if (f.isInitializing) {
-            return
-        }
-        var e = h.attr,
-            d = h.getLayout(),
-            c = d.isDiscrete ? 0 : e.depth,
-            g = f.getInherited().rtl,
-            b = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMin,
-            i = e.dataMin + (e.dataMax - e.dataMin) * e.visibleMax,
-            a = {
-                attr: e,
-                segmenter: h.getSegmenter(),
-                renderer: h.defaultRenderer
-            };
-        if (e.position === "left" || e.position === "right") {
-            e.translationX = 0;
-            e.translationY = i * (e.length - c) / (i - b) + c;
-            e.scalingX = 1;
-            e.scalingY = (-e.length + c) / (i - b);
-            e.scalingCenterY = 0;
-            e.scalingCenterX = 0;
-            h.applyTransformations(true)
-        } else {
-            if (e.position === "top" || e.position === "bottom") {
-                if (g) {
-                    e.translationX = e.length + b * e.length / (i - b) + 1
-                } else {
-                    e.translationX = -b * e.length / (i - b)
-                }
-                e.translationY = 0;
-                e.scalingX = (g ? -1 : 1) * (e.length - c) / (i - b);
-                e.scalingY = 1;
-                e.scalingCenterY = 0;
-                e.scalingCenterX = 0;
-                h.applyTransformations(true)
-            }
-        }
-        if (d) {
-            d.calculateLayout(a);
-            h.setLayoutContext(a)
-        }
-    },
-    renderAxisLine: function(a, j, f, c) {
-        var i = this,
-            h = i.attr,
-            b = h.lineWidth * 0.5,
-            f = i.getLayout(),
-            d = f.isDiscrete ? 0 : h.depth,
-            k = h.position,
-            e, g;
-        if (h.axisLine && h.length) {
-            switch (k) {
-                case "left":
-                    e = a.roundPixel(c[2]) - b;
-                    j.moveTo(e, -h.endGap + d);
-                    j.lineTo(e, h.length + h.startGap);
-                    break;
-                case "right":
-                    j.moveTo(b, -h.endGap);
-                    j.lineTo(b, h.length + h.startGap);
-                    break;
-                case "bottom":
-                    j.moveTo(-h.startGap, b);
-                    j.lineTo(h.length - d + h.endGap, b);
-                    break;
-                case "top":
-                    e = a.roundPixel(c[3]) - b;
-                    j.moveTo(-h.startGap, e);
-                    j.lineTo(h.length + h.endGap, e);
-                    break;
-                case "angular":
-                    j.moveTo(h.centerX + h.length, h.centerY);
-                    j.arc(h.centerX, h.centerY, h.length, 0, Math.PI * 2, true);
-                    break;
-                case "gauge":
-                    g = i.getGaugeAngles();
-                    j.moveTo(h.centerX + Math.cos(g.start) * h.length, h.centerY + Math.sin(g.start) * h.length);
-                    j.arc(h.centerX, h.centerY, h.length, g.start, g.end, true);
-                    break
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Axis3D", {
-    extend: "Ext.chart.axis.Axis",
-    xtype: "axis3d",
-    requires: ["Ext.chart.axis.sprite.Axis3D"],
-    config: {
-        depth: 0
-    },
-    onSeriesChange: function(e) {
-        var g = this,
-            b = "depthchange",
-            f = "onSeriesDepthChange",
-            d, c;
-
-        function a(h) {
-            var i = g.boundSeries;
-            for (d = 0; d < i.length; d++) {
-                c = i[d];
-                c[h](b, f, g)
-            }
-        }
-        a("un");
-        g.callParent(arguments);
-        a("on")
-    },
-    onSeriesDepthChange: function(b, f) {
-        var d = this,
-            g = f,
-            e = d.boundSeries,
-            a, c;
-        if (f > d.getDepth()) {
-            g = f
-        } else {
-            for (a = 0; a < e.length; a++) {
-                c = e[a];
-                if (c !== b && c.getDepth) {
-                    f = c.getDepth();
-                    if (f > g) {
-                        g = f
-                    }
-                }
-            }
-        }
-        d.setDepth(g)
-    },
-    updateDepth: function(d) {
-        var b = this,
-            c = b.getSprites(),
-            a = {
-                depth: d
-            };
-        if (c && c.length) {
-            c[0].setAttributes(a)
-        }
-        if (b.gridSpriteEven && b.gridSpriteOdd) {
-            b.gridSpriteEven.getTemplate().setAttributes(a);
-            b.gridSpriteOdd.getTemplate().setAttributes(a)
-        }
-    },
-    getGridAlignment: function() {
-        switch (this.getPosition()) {
-            case "left":
-            case "right":
-                return "horizontal3d";
-            case "top":
-            case "bottom":
-                return "vertical3d"
-        }
-    }
-});
-Ext.define("Ext.chart.axis.Category", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis",
-    alias: "axis.category",
-    type: "category",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Category3D", {
-    requires: ["Ext.chart.axis.layout.CombineDuplicate", "Ext.chart.axis.segmenter.Names"],
-    extend: "Ext.chart.axis.Axis3D",
-    alias: "axis.category3d",
-    type: "category3d",
-    config: {
-        layout: "combineDuplicate",
-        segmenter: "names"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric", {
-    extend: "Ext.chart.axis.Axis",
-    type: "numeric",
-    alias: ["axis.numeric", "axis.radial"],
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Numeric3D", {
-    extend: "Ext.chart.axis.Axis3D",
-    alias: ["axis.numeric3d"],
-    type: "numeric3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Numeric"],
-    config: {
-        layout: "continuous",
-        segmenter: "numeric",
-        aggregator: "double"
-    }
-});
-Ext.define("Ext.chart.axis.Time", {
-    extend: "Ext.chart.axis.Numeric",
-    alias: "axis.time",
-    type: "time",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.axis.Time3D", {
-    extend: "Ext.chart.axis.Numeric3D",
-    alias: "axis.time3d",
-    type: "time3d",
-    requires: ["Ext.chart.axis.layout.Continuous", "Ext.chart.axis.segmenter.Time"],
-    config: {
-        calculateByLabelSize: true,
-        dateFormat: null,
-        fromDate: null,
-        toDate: null,
-        step: [Ext.Date.DAY, 1],
-        layout: "continuous",
-        segmenter: "time",
-        aggregator: "time"
-    },
-    updateDateFormat: function(a) {
-        this.setRenderer(function(c, b) {
-            return Ext.Date.format(new Date(b), a)
-        })
-    },
-    updateFromDate: function(a) {
-        this.setMinimum(+a)
-    },
-    updateToDate: function(a) {
-        this.setMaximum(+a)
-    },
-    getCoordFor: function(a) {
-        if (Ext.isString(a)) {
-            a = new Date(a)
-        }
-        return +a
-    }
-});
-Ext.define("Ext.chart.grid.HorizontalGrid3D", {
-    extend: "Ext.chart.grid.HorizontalGrid",
-    alias: "grid.horizontal3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render: function(a, k, d) {
-        var f = this.attr,
-            i = a.roundPixel(f.x),
-            h = a.roundPixel(f.y),
-            l = a.matrix.getDX(),
-            c = k.lineWidth * 0.5,
-            j = f.height,
-            e = f.depth,
-            b, g;
-        if (h <= d[1]) {
-            return
-        }
-        b = d[0] + e - l;
-        g = h + c - e;
-        k.beginPath();
-        k.rect(b, g, d[2], j);
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + d[2], g);
-        k.stroke();
-        b = d[0] + i - l;
-        g = h + c;
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.lineTo(b + e, g - e + j);
-        k.lineTo(b, g + j);
-        k.closePath();
-        k.fill();
-        k.beginPath();
-        k.moveTo(b, g);
-        k.lineTo(b + e, g - e);
-        k.stroke()
-    }
-});
-Ext.define("Ext.chart.grid.VerticalGrid3D", {
-    extend: "Ext.chart.grid.VerticalGrid",
-    alias: "grid.vertical3d",
-    inheritableStatics: {
-        def: {
-            processors: {
-                depth: "number"
-            },
-            defaults: {
-                depth: 0
-            }
-        }
-    },
-    render_: function(c, d, f) {
-        var b = this.attr,
-            a = c.roundPixel(b.x),
-            e = d.lineWidth * 0.5;
-        d.beginPath();
-        d.rect(a - e, f[1] - c.matrix.getDY(), b.width, f[3]);
-        d.fill();
-        d.beginPath();
-        d.moveTo(a - e, f[1] - c.matrix.getDY());
-        d.lineTo(a - e, f[1] + f[3] - c.matrix.getDY());
-        d.stroke()
-    },
-    render: function(b, j, e) {
-        var g = this.attr,
-            i = b.roundPixel(g.x),
-            k = b.matrix.getDY(),
-            d = j.lineWidth * 0.5,
-            a = g.width,
-            f = g.depth,
-            c, h;
-        if (i >= e[2]) {
-            return
-        }
-        c = i - d + f;
-        h = e[1] - f - k;
-        j.beginPath();
-        j.rect(c, h, a, e[3]);
-        j.fill();
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c, h + e[3]);
-        j.stroke();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.lineTo(c + f + a, h - f);
-        j.lineTo(c + a, h);
-        j.closePath();
-        j.fill();
-        c = i - d;
-        h = e[3];
-        j.beginPath();
-        j.moveTo(c, h);
-        j.lineTo(c + f, h - f);
-        j.stroke()
-    }
-});
-Ext.define("Ext.chart.interactions.CrossZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "crosszoom",
-    alias: "interaction.crosszoom",
-    isCrossZoom: true,
-    config: {
-        axes: true,
-        gestures: {
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd",
-            dblclick: "onDoubleTap"
-        },
-        undoButton: {}
-    },
-    stopAnimationBeforeSync: false,
-    zoomAnimationInProgress: false,
-    constructor: function() {
-        this.callParent(arguments);
-        this.zoomHistory = []
-    },
-    applyAxes: function(b) {
-        var a = {};
-        if (b === true) {
-            return {
-                top: {},
-                right: {},
-                bottom: {},
-                left: {}
-            }
-        } else {
-            if (Ext.isArray(b)) {
-                a = {};
-                Ext.each(b, function(c) {
-                    a[c] = {}
-                })
-            } else {
-                if (Ext.isObject(b)) {
-                    Ext.iterate(b, function(c, d) {
-                        if (d === true) {
-                            a[c] = {}
-                        } else {
-                            if (d !== false) {
-                                a[c] = d
-                            }
-                        }
-                    })
-                }
-            }
-        }
-        return a
-    },
-    applyUndoButton: function(b, a) {
-        var c = this;
-        if (a) {
-            a.destroy()
-        }
-        if (b) {
-            return Ext.create("Ext.Button", Ext.apply({
-                cls: [],
-                text: "Undo Zoom",
-                disabled: true,
-                handler: function() {
-                    c.undoZoom()
-                }
-            }, b))
-        }
-    },
-    getSurface: function() {
-        return this.getChart() && this.getChart().getSurface("main")
-    },
-    setSeriesOpacity: function(b) {
-        var a = this.getChart() && this.getChart().getSurface("series");
-        if (a) {
-            a.element.setStyle("opacity", b)
-        }
-    },
-    onGestureStart: function(h) {
-        var j = this,
-            i = j.getChart(),
-            d = j.getSurface(),
-            l = i.getInnerRect(),
-            c = i.getInnerPadding(),
-            g = c.left,
-            b = g + l[2],
-            f = c.top,
-            a = f + l[3],
-            n = i.getEventXY(h),
-            m = n[0],
-            k = n[1];
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (m > g && m < b && k > f && k < a) {
-            j.gestureEvent = "drag";
-            j.lockEvents(j.gestureEvent);
-            j.startX = m;
-            j.startY = k;
-            j.selectionRect = d.add({
-                type: "rect",
-                globalAlpha: 0.5,
-                fillStyle: "rgba(80,80,140,0.5)",
-                strokeStyle: "rgba(80,80,140,1)",
-                lineWidth: 2,
-                x: m,
-                y: k,
-                width: 0,
-                height: 0,
-                zIndex: 10000
-            });
-            j.setSeriesOpacity(0.8);
-            return false
-        }
-    },
-    onGesture: function(h) {
-        var j = this;
-        if (j.zoomAnimationInProgress) {
-            return
-        }
-        if (j.getLocks()[j.gestureEvent] === j) {
-            var i = j.getChart(),
-                d = j.getSurface(),
-                l = i.getInnerRect(),
-                c = i.getInnerPadding(),
-                g = c.left,
-                b = g + l[2],
-                f = c.top,
-                a = f + l[3],
-                n = i.getEventXY(h),
-                m = n[0],
-                k = n[1];
-            if (m < g) {
-                m = g
-            } else {
-                if (m > b) {
-                    m = b
-                }
-            }
-            if (k < f) {
-                k = f
-            } else {
-                if (k > a) {
-                    k = a
-                }
-            }
-            j.selectionRect.setAttributes({
-                width: m - j.startX,
-                height: k - j.startY
-            });
-            if (Math.abs(j.startX - m) < 11 || Math.abs(j.startY - k) < 11) {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 0.5
-                })
-            } else {
-                j.selectionRect.setAttributes({
-                    globalAlpha: 1
-                })
-            }
-            d.renderFrame();
-            return false
-        }
-    },
-    onGestureEnd: function(i) {
-        var l = this;
-        if (l.zoomAnimationInProgress) {
-            return
-        }
-        if (l.getLocks()[l.gestureEvent] === l) {
-            var k = l.getChart(),
-                d = l.getSurface(),
-                n = k.getInnerRect(),
-                c = k.getInnerPadding(),
-                g = c.left,
-                b = g + n[2],
-                f = c.top,
-                a = f + n[3],
-                h = n[2],
-                j = n[3],
-                p = k.getEventXY(i),
-                o = p[0],
-                m = p[1];
-            if (o < g) {
-                o = g
-            } else {
-                if (o > b) {
-                    o = b
-                }
-            }
-            if (m < f) {
-                m = f
-            } else {
-                if (m > a) {
-                    m = a
-                }
-            }
-            if (Math.abs(l.startX - o) < 11 || Math.abs(l.startY - m) < 11) {
-                d.remove(l.selectionRect)
-            } else {
-                l.zoomBy([Math.min(l.startX, o) / h, 1 - Math.max(l.startY, m) / j, Math.max(l.startX, o) / h, 1 - Math.min(l.startY, m) / j]);
-                l.selectionRect.setAttributes({
-                    x: Math.min(l.startX, o),
-                    y: Math.min(l.startY, m),
-                    width: Math.abs(l.startX - o),
-                    height: Math.abs(l.startY - m)
-                });
-                l.selectionRect.setAnimation(k.getAnimation() || {
-                    duration: 0
-                });
-                l.selectionRect.setAttributes({
-                    globalAlpha: 0,
-                    x: 0,
-                    y: 0,
-                    width: h,
-                    height: j
-                });
-                l.zoomAnimationInProgress = true;
-                k.suspendThicknessChanged();
-                l.selectionRect.fx.on("animationend", function() {
-                    k.resumeThicknessChanged();
-                    d.remove(l.selectionRect);
-                    l.selectionRect = null;
-                    l.zoomAnimationInProgress = false
-                })
-            }
-            d.renderFrame();
-            l.sync();
-            l.unlockEvents(l.gestureEvent);
-            l.setSeriesOpacity(1);
-            if (!l.zoomAnimationInProgress) {
-                d.remove(l.selectionRect);
-                l.selectionRect = null
-            }
-        }
-    },
-    zoomBy: function(o) {
-        var n = this,
-            a = n.getAxes(),
-            k = n.getChart(),
-            j = k.getAxes(),
-            l = k.getInherited().rtl,
-            f, d = {},
-            c, b;
-        if (l) {
-            o = o.slice();
-            c = 1 - o[0];
-            b = 1 - o[2];
-            o[0] = Math.min(c, b);
-            o[2] = Math.max(c, b)
-        }
-        for (var h = 0; h < j.length; h++) {
-            var g = j[h];
-            f = a[g.getPosition()];
-            if (f && f.allowZoom !== false) {
-                var e = g.isSide(),
-                    m = g.getVisibleRange();
-                d[g.getId()] = m.slice(0);
-                if (!e) {
-                    g.setVisibleRange([(m[1] - m[0]) * o[0] + m[0], (m[1] - m[0]) * o[2] + m[0]])
-                } else {
-                    g.setVisibleRange([(m[1] - m[0]) * o[1] + m[0], (m[1] - m[0]) * o[3] + m[0]])
-                }
-            }
-        }
-        n.zoomHistory.push(d);
-        n.getUndoButton().setDisabled(false)
-    },
-    undoZoom: function() {
-        var c = this.zoomHistory.pop(),
-            d = this.getChart().getAxes();
-        if (c) {
-            for (var a = 0; a < d.length; a++) {
-                var b = d[a];
-                if (c[b.getId()]) {
-                    b.setVisibleRange(c[b.getId()])
-                }
-            }
-        }
-        this.getUndoButton().setDisabled(this.zoomHistory.length === 0);
-        this.sync()
-    },
-    onDoubleTap: function(a) {
-        this.undoZoom()
-    },
-    destroy: function() {
-        this.setUndoButton(null);
-        this.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.interactions.Crosshair", {
-    extend: "Ext.chart.interactions.Abstract",
-    requires: ["Ext.chart.grid.HorizontalGrid", "Ext.chart.grid.VerticalGrid", "Ext.chart.CartesianChart", "Ext.chart.axis.layout.Discrete"],
-    type: "crosshair",
-    alias: "interaction.crosshair",
-    config: {
-        axes: {
-            top: {
-                label: {},
-                rect: {}
-            },
-            right: {
-                label: {},
-                rect: {}
-            },
-            bottom: {
-                label: {},
-                rect: {}
-            },
-            left: {
-                label: {},
-                rect: {}
-            }
-        },
-        lines: {
-            horizontal: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            },
-            vertical: {
-                strokeStyle: "black",
-                lineDash: [5, 5]
-            }
-        },
-        gesture: "drag"
-    },
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyLines: function(a, b) {
-        return Ext.merge(b || {}, a)
-    },
-    updateChart: function(a) {
-        if (a && !a.isCartesian) {
-            Ext.raise("Crosshair interaction can only be used on cartesian charts.")
-        }
-        this.callParent(arguments)
-    },
-    getGestures: function() {
-        var a = this,
-            b = {};
-        b[a.getGesture()] = "onGesture";
-        b[a.getGesture() + "start"] = "onGestureStart";
-        b[a.getGesture() + "end"] = "onGestureEnd";
-        return b
-    },
-    onGestureStart: function(N) {
-        var m = this,
-            O = m.getChart(),
-            B = O.getTheme().getAxis(),
-            A, F = O.getSurface("overlay"),
-            s = O.getInnerRect(),
-            n = s[2],
-            M = s[3],
-            r = O.getEventXY(N),
-            D = r[0],
-            C = r[1],
-            E = O.getAxes(),
-            u = m.getAxes(),
-            h = m.getLines(),
-            q, v, b, d, k, z, G, L, J, o, I, w, l, f, p, j, t, a, g, H, c, K;
-        if (D > 0 && D < n && C > 0 && C < M) {
-            m.lockEvents(m.getGesture());
-            H = Ext.apply({
-                xclass: "Ext.chart.grid.HorizontalGrid",
-                x: 0,
-                y: C,
-                width: n
-            }, h.horizontal);
-            c = Ext.apply({
-                xclass: "Ext.chart.grid.VerticalGrid",
-                x: D,
-                y: 0,
-                height: M
-            }, h.vertical);
-            m.axesLabels = m.axesLabels || {};
-            for (K = 0; K < E.length; K++) {
-                q = E[K];
-                v = q.getSurface();
-                b = v.getRect();
-                w = q.getSprites()[0];
-                d = b[2];
-                k = b[3];
-                z = q.getPosition();
-                G = q.getAlignment();
-                t = q.getTitle();
-                a = t && t.attr.text !== "" && t.getBBox();
-                l = w.attr;
-                f = w.thickness;
-                p = l.axisLine ? l.lineWidth : 0;
-                j = p / 2;
-                I = Math.max(l.majorTickSize, l.minorTickSize) + p;
-                L = m.axesLabels[z] = v.add({
-                    type: "composite"
-                });
-                L.labelRect = L.add(Ext.apply({
-                    type: "rect",
-                    fillStyle: "white",
-                    x: z === "right" ? p : 0,
-                    y: z === "bottom" ? p : 0,
-                    width: d - p - (G === "vertical" && a ? a.width : 0),
-                    height: k - p - (G === "horizontal" && a ? a.height : 0),
-                    translationX: z === "left" && a ? a.width : 0,
-                    translationY: z === "top" && a ? a.height : 0
-                }, u.rect || u[z].rect));
-                if (G === "vertical" && !c.strokeStyle) {
-                    c.strokeStyle = l.strokeStyle
-                }
-                if (G === "horizontal" && !H.strokeStyle) {
-                    H.strokeStyle = l.strokeStyle
-                }
-                A = Ext.merge({}, B.defaults, B[z]);
-                J = Ext.apply({}, q.config.label, A.label);
-                o = u.label || u[z].label;
-                L.labelText = L.add(Ext.apply(J, o, {
-                    type: "text",
-                    x: (function() {
-                        switch (z) {
-                            case "left":
-                                g = a ? a.x + a.width : 0;
-                                return g + (d - g - I) / 2 - j;
-                            case "right":
-                                g = a ? d - a.x : 0;
-                                return I + (d - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })(),
-                    y: (function() {
-                        switch (z) {
-                            case "top":
-                                g = a ? a.y + a.height : 0;
-                                return g + (k - g - I) / 2 - j;
-                            case "bottom":
-                                g = a ? k - a.y : 0;
-                                return I + (k - I - g) / 2 + j;
-                            default:
-                                return 0
-                        }
-                    })()
-                }))
-            }
-            m.horizontalLine = F.add(H);
-            m.verticalLine = F.add(c);
-            return false
-        }
-    },
-    onGesture: function(G) {
-        var K = this;
-        if (K.getLocks()[K.getGesture()] !== K) {
-            return
-        }
-        var u = K.getChart(),
-            z = u.getSurface("overlay"),
-            a = Ext.Array.slice(u.getInnerRect()),
-            r = u.getInnerPadding(),
-            t = r.left,
-            q = r.top,
-            E = a[2],
-            f = a[3],
-            d = u.getEventXY(G),
-            k = d[0],
-            j = d[1],
-            D = u.getAxes(),
-            c, h, m, p, J, w, I, H, s, b, C, g, v, n, l, A, F, o, B;
-        if (k < 0) {
-            k = 0
-        } else {
-            if (k > E) {
-                k = E
-            }
-        }
-        if (j < 0) {
-            j = 0
-        } else {
-            if (j > f) {
-                j = f
-            }
-        }
-        k += t;
-        j += q;
-        for (B = 0; B < D.length; B++) {
-            c = D[B];
-            h = c.getPosition();
-            m = c.getAlignment();
-            p = c.getSurface();
-            J = c.getSprites()[0];
-            w = J.attr.matrix;
-            C = J.attr.textPadding * 2;
-            s = K.axesLabels[h];
-            I = J.getLayoutContext();
-            H = c.getSegmenter();
-            if (s) {
-                if (m === "vertical") {
-                    v = w.getYY();
-                    l = w.getDY();
-                    F = (j - l - q) / v;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        j = Math.round(F) * v + l + q;
-                        F = H.from(Math.round(F));
-                        F = J.attr.data[F]
-                    } else {
-                        F = H.from(F)
-                    }
-                    o = H.renderer(F, I);
-                    s.setAttributes({
-                        translationY: j - q
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        height: b.height + C,
-                        y: -(b.height + C) / 2
-                    });
-                    p.renderFrame()
-                } else {
-                    g = w.getXX();
-                    n = w.getDX();
-                    A = (k - n - t) / g;
-                    if (c.getLayout() instanceof Ext.chart.axis.layout.Discrete) {
-                        k = Math.round(A) * g + n + t;
-                        A = H.from(Math.round(A));
-                        A = J.attr.data[A]
-                    } else {
-                        A = H.from(A)
-                    }
-                    o = H.renderer(A, I);
-                    s.setAttributes({
-                        translationX: k - t
-                    });
-                    s.labelText.setAttributes({
-                        text: o
-                    });
-                    b = s.labelText.getBBox();
-                    s.labelRect.setAttributes({
-                        width: b.width + C,
-                        x: -(b.width + C) / 2
-                    });
-                    p.renderFrame()
-                }
-            }
-        }
-        K.horizontalLine.setAttributes({
-            y: j,
-            strokeStyle: J.attr.strokeStyle
-        });
-        K.verticalLine.setAttributes({
-            x: k,
-            strokeStyle: J.attr.strokeStyle
-        });
-        z.renderFrame();
-        return false
-    },
-    onGestureEnd: function(h) {
-        var l = this,
-            k = l.getChart(),
-            a = k.getSurface("overlay"),
-            j = k.getAxes(),
-            c, g, d, b, f;
-        a.remove(l.verticalLine);
-        a.remove(l.horizontalLine);
-        for (f = 0; f < j.length; f++) {
-            c = j[f];
-            g = c.getPosition();
-            d = c.getSurface();
-            b = l.axesLabels[g];
-            if (b) {
-                delete l.axesLabels[g];
-                d.remove(b)
-            }
-            d.renderFrame()
-        }
-        a.renderFrame();
-        l.unlockEvents(l.getGesture())
-    }
-});
-Ext.define("Ext.chart.interactions.ItemHighlight", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "itemhighlight",
-    alias: "interaction.itemhighlight",
-    isItemHighlight: true,
-    config: {
-        gestures: {
-            tap: "onTapGesture",
-            mousemove: "onMouseMoveGesture",
-            mousedown: "onMouseDownGesture",
-            mouseup: "onMouseUpGesture",
-            mouseleave: "onMouseUpGesture"
-        },
-        sticky: false
-    },
-    stickyHighlightItem: null,
-    onMouseMoveGesture: function(g) {
-        var d = this,
-            h = d.tipItem,
-            a = g.pointerType === "mouse",
-            c, f, b;
-        if (d.getSticky()) {
-            return true
-        }
-        if (d.isDragging) {
-            if (h && a) {
-                h.series.hideTooltip(h);
-                d.tipItem = null
-            }
-        } else {
-            if (!d.stickyHighlightItem) {
-                c = d.getItemForEvent(g);
-                b = d.getChart();
-                if (c !== b.getHighlightItem()) {
-                    d.highlight(c);
-                    d.sync()
-                }
-                if (a) {
-                    if (h && (!c || h.field !== c.field || h.record !== c.record)) {
-                        h.series.hideTooltip(h);
-                        d.tipItem = h = null
-                    }
-                    if (c && (f = c.series.getTooltip())) {
-                        if (f.trackMouse || !h) {
-                            c.series.showTooltip(c, g.getXY())
-                        }
-                        d.tipItem = c
-                    }
-                }
-                return false
-            }
-        }
-    },
-    highlight: function(a) {
-        this.getChart().setHighlightItem(a)
-    },
-    showTooltip: function(b, a) {
-        a.series.showTooltip(a, b.getXY());
-        this.tipItem = a
-    },
-    onMouseDownGesture: function() {
-        this.isDragging = true
-    },
-    onMouseUpGesture: function() {
-        this.isDragging = false
-    },
-    onTapGesture: function(c) {
-        var b = this;
-        if (c.pointerType === "mouse" && !b.getSticky()) {
-            return
-        }
-        var a = b.getItemForEvent(c);
-        if (b.stickyHighlightItem && a && (b.stickyHighlightItem.index === a.index)) {
-            a = null
-        }
-        b.stickyHighlightItem = a;
-        b.highlight(a)
-    }
-});
-Ext.define("Ext.chart.interactions.ItemEdit", {
-    extend: "Ext.chart.interactions.ItemHighlight",
-    requires: ["Ext.tip.ToolTip"],
-    type: "itemedit",
-    alias: "interaction.itemedit",
-    isItemEdit: true,
-    config: {
-        style: null,
-        renderer: null,
-        tooltip: true,
-        gestures: {
-            dragstart: "onDragStart",
-            drag: "onDrag",
-            dragend: "onDragEnd"
-        },
-        cursors: {
-            ewResize: "ew-resize",
-            nsResize: "ns-resize",
-            move: "move"
-        }
-    },
-    item: null,
-    applyTooltip: function(b) {
-        if (b) {
-            var a = Ext.apply({}, b, {
-                renderer: this.defaultTooltipRenderer,
-                constrainPosition: true,
-                shrinkWrapDock: true,
-                autoHide: true,
-                offsetX: 10,
-                offsetY: 10
-            });
-            b = new Ext.tip.ToolTip(a)
-        }
-        return b
-    },
-    defaultTooltipRenderer: function(b, a, f, d) {
-        var c = [];
-        if (f.xField) {
-            c.push(f.xField + ": " + f.xValue)
-        }
-        if (f.yField) {
-            c.push(f.yField + ": " + f.yValue)
-        }
-        b.setHtml(c.join("<br>"))
-    },
-    onDragStart: function(d) {
-        var c = this,
-            a = c.getChart(),
-            b = a.getHighlightItem();
-        if (b) {
-            a.fireEvent("beginitemedit", a, c, c.item = b);
-            return false
-        }
-    },
-    onDrag: function(f) {
-        var d = this,
-            b = d.getChart(),
-            c = b.getHighlightItem(),
-            a = c && c.sprite.type;
-        if (c) {
-            switch (a) {
-                case "barSeries":
-                    return d.onDragBar(f);
-                    break;
-                case "scatterSeries":
-                    return d.onDragScatter(f);
-                    break
-            }
-        }
-    },
-    highlight: function(f) {
-        var e = this,
-            d = e.getChart(),
-            a = d.getFlipXY(),
-            g = e.getCursors(),
-            c = f && f.sprite.type,
-            b = d.el.dom.style;
-        e.callParent([f]);
-        if (f) {
-            switch (c) {
-                case "barSeries":
-                    if (a) {
-                        b.cursor = g.ewResize
-                    } else {
-                        b.cursor = g.nsResize
-                    }
-                    break;
-                case "scatterSeries":
-                    b.cursor = g.move;
-                    break
-            }
-        } else {
-            d.el.dom.style.cursor = "default"
-        }
-    },
-    onDragBar: function(i) {
-        var m = this,
-            k = m.getChart(),
-            l = k.getInherited().rtl,
-            f = k.isCartesian && k.getFlipXY(),
-            q = k.getHighlightItem(),
-            g = q.sprite.getMarker("items"),
-            p = g.getMarkerFor(q.sprite.getId(), q.index),
-            b = q.sprite.getSurface(),
-            c = b.getRect(),
-            r = b.getEventXY(i),
-            o = q.sprite.attr.matrix,
-            j = m.getRenderer(),
-            a, n, d, h;
-        if (f) {
-            h = l ? c[2] - r[0] : r[0]
-        } else {
-            h = c[3] - r[1]
-        }
-        a = {
-            x: p.x,
-            y: h,
-            width: p.width,
-            height: p.height + (p.y - h),
-            radius: p.radius,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(a, m.getStyle());
-        if (Ext.isArray(q.series.getYField())) {
-            h = h - p.y - p.height
-        }
-        m.target = {
-            index: q.index,
-            yField: q.field,
-            yValue: (h - o.getDY()) / o.getYY()
-        };
-        d = [k, {
-            target: m.target,
-            style: a,
-            item: q
-        }];
-        n = Ext.callback(j, null, d, 0, k);
-        if (n) {
-            Ext.apply(a, n)
-        }
-        q.sprite.putMarker("items", a, "itemedit");
-        m.showTooltip(i, m.target, q);
-        b.renderFrame()
-    },
-    onDragScatter: function(n) {
-        var t = this,
-            g = t.getChart(),
-            d = g.getInherited().rtl,
-            l = g.isCartesian && g.getFlipXY(),
-            o = g.getHighlightItem(),
-            b = o.sprite.getMarker("items"),
-            p = b.getMarkerFor(o.sprite.getId(), o.index),
-            j = o.sprite.getSurface(),
-            h = j.getRect(),
-            a = j.getEventXY(n),
-            k = o.sprite.attr.matrix,
-            c = o.series.getXAxis(),
-            f = c && c.getLayout().isContinuous,
-            i = t.getRenderer(),
-            m, u, q, s, r;
-        if (l) {
-            r = d ? h[2] - a[0] : a[0]
-        } else {
-            r = h[3] - a[1]
-        }
-        if (f) {
-            if (l) {
-                s = h[3] - a[1]
-            } else {
-                s = a[0]
-            }
-        } else {
-            s = p.translationX
-        }
-        m = {
-            translationX: s,
-            translationY: r,
-            scalingX: p.scalingX,
-            scalingY: p.scalingY,
-            r: p.r,
-            fillStyle: "none",
-            lineDash: [4, 4],
-            zIndex: 100
-        };
-        Ext.apply(m, t.getStyle());
-        t.target = {
-            index: o.index,
-            yField: o.field,
-            yValue: (r - k.getDY()) / k.getYY()
-        };
-        if (f) {
-            Ext.apply(t.target, {
-                xField: o.series.getXField(),
-                xValue: (s - k.getDX()) / k.getXX()
-            })
-        }
-        q = [g, {
-            target: t.target,
-            style: m,
-            item: o
-        }];
-        u = Ext.callback(i, null, q, 0, g);
-        if (u) {
-            Ext.apply(m, u)
-        }
-        o.sprite.putMarker("items", m, "itemedit");
-        t.showTooltip(n, t.target, o);
-        j.renderFrame()
-    },
-    showTooltip: function(g, f, c) {
-        var d = this.getTooltip(),
-            a, b;
-        if (d && Ext.toolkit !== "modern") {
-            a = d.config;
-            b = this.getChart();
-            Ext.callback(a.renderer, null, [d, c, f, g], 0, b);
-            d.show([g.x + a.offsetX, g.y + a.offsetY])
-        }
-    },
-    hideTooltip: function() {
-        var a = this.getTooltip();
-        if (a && Ext.toolkit !== "modern") {
-            a.hide()
-        }
-    },
-    onDragEnd: function(g) {
-        var d = this,
-            f = d.target,
-            c = d.getChart(),
-            b = c.getStore(),
-            a;
-        if (f) {
-            a = b.getAt(f.index);
-            if (f.yField) {
-                a.set(f.yField, f.yValue, {
-                    convert: false
-                })
-            }
-            if (f.xField) {
-                a.set(f.xField, f.xValue, {
-                    convert: false
-                })
-            }
-            if (f.yField || f.xField) {
-                d.getChart().onDataChanged()
-            }
-            d.target = null
-        }
-        d.hideTooltip();
-        if (d.item) {
-            c.fireEvent("enditemedit", c, d, d.item, f)
-        }
-        d.highlight(d.item = null)
-    },
-    destroy: function() {
-        var a = this.getConfig("tooltip", true);
-        Ext.destroy(a);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.PanZoom", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "panzoom",
-    alias: "interaction.panzoom",
-    requires: ["Ext.draw.Animator"],
-    config: {
-        axes: {
-            top: {},
-            right: {},
-            bottom: {},
-            left: {}
-        },
-        minZoom: null,
-        maxZoom: null,
-        showOverflowArrows: true,
-        panGesture: "drag",
-        zoomGesture: "pinch",
-        zoomOnPanGesture: false,
-        modeToggleButton: {
-            xtype: "segmentedbutton",
-            width: 200,
-            defaults: {
-                ui: "default-toolbar"
-            },
-            cls: Ext.baseCSSPrefix + "panzoom-toggle",
-            items: [{
-                text: "Pan"
-            }, {
-                text: "Zoom"
-            }]
-        },
-        hideLabelInGesture: false
-    },
-    stopAnimationBeforeSync: true,
-    applyAxes: function(b, a) {
-        return Ext.merge(a || {}, b)
-    },
-    applyZoomOnPanGesture: function(a) {
-        this.getChart();
-        if (this.isMultiTouch()) {
-            return false
-        }
-        return a
-    },
-    updateZoomOnPanGesture: function(b) {
-        var a = this.getModeToggleButton();
-        if (!this.isMultiTouch()) {
-            a.show();
-            a.setValue(b ? 1 : 0)
-        } else {
-            a.hide()
-        }
-    },
-    toggleMode: function() {
-        var a = this;
-        if (!a.isMultiTouch()) {
-            a.setZoomOnPanGesture(!a.getZoomOnPanGesture())
-        }
-    },
-    applyModeToggleButton: function(c, b) {
-        var d = this,
-            a = Ext.factory(c, "Ext.button.Segmented", b);
-        if (!a && b) {
-            b.destroy()
-        }
-        if (a && !b) {
-            a.addListener("toggle", function(e) {
-                d.setZoomOnPanGesture(e.getValue() === 1)
-            })
-        }
-        return a
-    },
-    getGestures: function() {
-        var c = this,
-            e = {},
-            d = c.getPanGesture(),
-            b = c.getZoomGesture(),
-            a = Ext.supports.Touch;
-        e[b] = "onZoomGestureMove";
-        e[b + "start"] = "onZoomGestureStart";
-        e[b + "end"] = "onZoomGestureEnd";
-        e[d] = "onPanGestureMove";
-        e[d + "start"] = "onPanGestureStart";
-        e[d + "end"] = "onPanGestureEnd";
-        e.doubletap = "onDoubleTap";
-        return e
-    },
-    onDoubleTap: function(h) {
-        var f = this,
-            c = f.getChart(),
-            g = c.getAxes(),
-            b, a, d;
-        for (a = 0, d = g.length; a < d; a++) {
-            b = g[a];
-            b.setVisibleRange([0, 1])
-        }
-        c.redraw()
-    },
-    onPanGestureStart: function(d) {
-        if (!d || !d.touches || d.touches.length < 2) {
-            var b = this,
-                a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            b.startX = d.getX() - c[0] - a[0];
-            b.startY = d.getY() - c[1] - a[1];
-            b.oldVisibleRanges = null;
-            b.hideLabels();
-            b.getChart().suspendThicknessChanged();
-            b.lockEvents(b.getPanGesture());
-            return false
-        }
-    },
-    onPanGestureMove: function(d) {
-        var b = this;
-        if (b.getLocks()[b.getPanGesture()] === b) {
-            var a = b.getChart().getInnerRect(),
-                c = b.getChart().element.getXY();
-            if (b.getZoomOnPanGesture()) {
-                b.transformAxesBy(b.getZoomableAxes(d), 0, 0, (d.getX() - c[0] - a[0]) / b.startX, b.startY / (d.getY() - c[1] - a[1]))
-            } else {
-                b.transformAxesBy(b.getPannableAxes(d), d.getX() - c[0] - a[0] - b.startX, d.getY() - c[1] - a[1] - b.startY, 1, 1)
-            }
-            b.sync();
-            return false
-        }
-    },
-    onPanGestureEnd: function(b) {
-        var a = this,
-            c = a.getPanGesture();
-        if (a.getLocks()[c] === a) {
-            a.getChart().resumeThicknessChanged();
-            a.showLabels();
-            a.sync();
-            a.unlockEvents(c);
-            return false
-        }
-    },
-    onZoomGestureStart: function(b) {
-        if (b.touches && b.touches.length === 2) {
-            var c = this,
-                i = c.getChart().element.getXY(),
-                f = c.getChart().getInnerRect(),
-                h = i[0] + f[0],
-                d = i[1] + f[1],
-                j = [b.touches[0].point.x - h, b.touches[0].point.y - d, b.touches[1].point.x - h, b.touches[1].point.y - d],
-                g = Math.max(44, Math.abs(j[2] - j[0])),
-                a = Math.max(44, Math.abs(j[3] - j[1]));
-            c.getChart().suspendThicknessChanged();
-            c.lastZoomDistances = [g, a];
-            c.lastPoints = j;
-            c.oldVisibleRanges = null;
-            c.hideLabels();
-            c.lockEvents(c.getZoomGesture());
-            return false
-        }
-    },
-    onZoomGestureMove: function(d) {
-        var f = this;
-        if (f.getLocks()[f.getZoomGesture()] === f) {
-            var i = f.getChart().getInnerRect(),
-                n = f.getChart().element.getXY(),
-                k = n[0] + i[0],
-                h = n[1] + i[1],
-                o = Math.abs,
-                c = f.lastPoints,
-                m = [d.touches[0].point.x - k, d.touches[0].point.y - h, d.touches[1].point.x - k, d.touches[1].point.y - h],
-                g = Math.max(44, o(m[2] - m[0])),
-                b = Math.max(44, o(m[3] - m[1])),
-                a = this.lastZoomDistances || [g, b],
-                l = g / a[0],
-                j = b / a[1];
-            f.transformAxesBy(f.getZoomableAxes(d), i[2] * (l - 1) / 2 + m[2] - c[2] * l, i[3] * (j - 1) / 2 + m[3] - c[3] * j, l, j);
-            f.sync();
-            return false
-        }
-    },
-    onZoomGestureEnd: function(c) {
-        var b = this,
-            a = b.getZoomGesture();
-        if (b.getLocks()[a] === b) {
-            b.getChart().resumeThicknessChanged();
-            b.showLabels();
-            b.sync();
-            b.unlockEvents(a);
-            return false
-        }
-    },
-    hideLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.hideLabels()
-            })
-        }
-    },
-    showLabels: function() {
-        if (this.getHideLabelInGesture()) {
-            this.eachInteractiveAxes(function(a) {
-                a.showLabels()
-            })
-        }
-    },
-    isEventOnAxis: function(c, a) {
-        var b = a.getSurface().getRect();
-        return b[0] <= c.getX() && c.getX() <= b[0] + b[2] && b[1] <= c.getY() && c.getY() <= b[1] + b[3]
-    },
-    getPannableAxes: function(d) {
-        var h = this,
-            a = h.getAxes(),
-            f = h.getChart().getAxes(),
-            c, g = f.length,
-            k = [],
-            j = false,
-            b;
-        if (d) {
-            for (c = 0; c < g; c++) {
-                if (this.isEventOnAxis(d, f[c])) {
-                    j = true;
-                    break
-                }
-            }
-        }
-        for (c = 0; c < g; c++) {
-            b = a[f[c].getPosition()];
-            if (b && b.allowPan !== false && (!j || this.isEventOnAxis(d, f[c]))) {
-                k.push(f[c])
-            }
-        }
-        return k
-    },
-    getZoomableAxes: function(f) {
-        var j = this,
-            a = j.getAxes(),
-            g = j.getChart().getAxes(),
-            l = [],
-            d, h = g.length,
-            c, k = false,
-            b;
-        if (f) {
-            for (d = 0; d < h; d++) {
-                if (this.isEventOnAxis(f, g[d])) {
-                    k = true;
-                    break
-                }
-            }
-        }
-        for (d = 0; d < h; d++) {
-            c = g[d];
-            b = a[c.getPosition()];
-            if (b && b.allowZoom !== false && (!k || this.isEventOnAxis(f, c))) {
-                l.push(c)
-            }
-        }
-        return l
-    },
-    eachInteractiveAxes: function(c) {
-        var d = this,
-            b = d.getAxes(),
-            e = d.getChart().getAxes();
-        for (var a = 0; a < e.length; a++) {
-            if (b[e[a].getPosition()]) {
-                if (false === c.call(this, e[a])) {
-                    return
-                }
-            }
-        }
-    },
-    transformAxesBy: function(d, j, g, h, e) {
-        var f = this.getChart().getInnerRect(),
-            a = this.getAxes(),
-            k, b = this.oldVisibleRanges,
-            l = false;
-        if (!b) {
-            this.oldVisibleRanges = b = {};
-            this.eachInteractiveAxes(function(i) {
-                b[i.getId()] = i.getVisibleRange()
-            })
-        }
-        if (!f) {
-            return
-        }
-        for (var c = 0; c < d.length; c++) {
-            k = a[d[c].getPosition()];
-            l = this.transformAxisBy(d[c], b[d[c].getId()], j, g, h, e, this.minZoom || k.minZoom, this.maxZoom || k.maxZoom) || l
-        }
-        return l
-    },
-    transformAxisBy: function(c, o, r, q, k, i, h, m) {
-        var s = this,
-            b = o[1] - o[0],
-            l = c.getVisibleRange(),
-            g = h || s.getMinZoom() || c.config.minZoom,
-            j = m || s.getMaxZoom() || c.config.maxZoom,
-            a = s.getChart().getInnerRect(),
-            f, p;
-        if (!a) {
-            return
-        }
-        var d = c.isSide(),
-            e = d ? a[3] : a[2],
-            n = d ? -q : r;
-        b /= d ? i : k;
-        if (b < 0) {
-            b = -b
-        }
-        if (b * g > 1) {
-            b = 1
-        }
-        if (b * j < 1) {
-            b = 1 / j
-        }
-        f = o[0];
-        p = o[1];
-        l = l[1] - l[0];
-        if (b === l && l === 1) {
-            return
-        }
-        c.setVisibleRange([(o[0] + o[1] - b) * 0.5 - n / e * b, (o[0] + o[1] + b) * 0.5 - n / e * b]);
-        return (Math.abs(f - c.getVisibleRange()[0]) > 1e-10 || Math.abs(p - c.getVisibleRange()[1]) > 1e-10)
-    },
-    destroy: function() {
-        this.setModeToggleButton(null);
-        this.callParent()
-    }
-});
-Ext.define("Ext.chart.interactions.Rotate", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "rotate",
-    alias: "interaction.rotate",
-    config: {
-        gesture: "rotate",
-        gestures: {
-            rotate: "onRotate",
-            rotateend: "onRotate",
-            dragstart: "onGestureStart",
-            drag: "onGesture",
-            dragend: "onGestureEnd"
-        },
-        rotation: 0
-    },
-    oldRotations: null,
-    getAngle: function(f) {
-        var c = this,
-            b = c.getChart(),
-            d = b.getEventXY(f),
-            a = b.getCenter();
-        return Math.atan2(d[1] - a[1], d[0] - a[0])
-    },
-    getRadius: function(a) {
-        return this.getChart().getRadius()
-    },
-    getEventRadius: function(h) {
-        var f = this,
-            d = f.getChart(),
-            g = d.getEventXY(h),
-            a = d.getCenter(),
-            c = g[0] - a[0],
-            b = g[1] - a[1];
-        return Math.sqrt(c * c + b * b)
-    },
-    onGestureStart: function(d) {
-        var c = this,
-            b = c.getRadius(d),
-            a = c.getEventRadius(d);
-        if (b >= a) {
-            c.lockEvents("drag");
-            c.angle = c.getAngle(d);
-            c.oldRotations = {};
-            return false
-        }
-    },
-    onGesture: function(b) {
-        var a = this,
-            c = a.getAngle(b) - a.angle;
-        if (a.getLocks().drag === a) {
-            a.doRotateTo(c, true);
-            return false
-        }
-    },
-    doRotateTo: function(d, a, b) {
-        var n = this,
-            l = n.getChart(),
-            k = l.getAxes(),
-            f = l.getSeries(),
-            m = n.oldRotations,
-            c, j, g, e, h;
-        if (!b) {
-            l.suspendAnimation()
-        }
-        for (e = 0, h = k.length; e < h; e++) {
-            c = k[e];
-            g = m[c.getId()] || (m[c.getId()] = c.getRotation());
-            c.setRotation(d + (a ? g : 0))
-        }
-        for (e = 0, h = f.length; e < h; e++) {
-            j = f[e];
-            g = m[j.getId()] || (m[j.getId()] = j.getRotation());
-            j.setRotation(d + (a ? g : 0))
-        }
-        n.setRotation(d + (a ? g : 0));
-        n.fireEvent("rotate", n, n.getRotation());
-        n.sync();
-        if (!b) {
-            l.resumeAnimation()
-        }
-    },
-    rotateTo: function(c, b, a) {
-        this.doRotateTo(c, b, a);
-        this.oldRotations = {}
-    },
-    onGestureEnd: function(b) {
-        var a = this;
-        if (a.getLocks().drag === a) {
-            a.onGesture(b);
-            a.unlockEvents("drag");
-            a.fireEvent("rotationEnd", a, a.getRotation());
-            return false
-        }
-    },
-    onRotate: function(a) {}
-});
-Ext.define("Ext.chart.interactions.RotatePie3D", {
-    extend: "Ext.chart.interactions.Rotate",
-    type: "rotatePie3d",
-    alias: "interaction.rotatePie3d",
-    getAngle: function(g) {
-        var a = this.getChart(),
-            f = a.getInherited().rtl,
-            d = f ? -1 : 1,
-            h = g.getXY(),
-            c = a.element.getXY(),
-            b = a.getMainRect();
-        return d * Math.atan2(h[1] - c[1] - b[3] * 0.5, h[0] - c[0] - b[2] * 0.5)
-    },
-    getRadius: function(j) {
-        var f = this.getChart(),
-            a = f.getRadius(),
-            d = f.getSeries(),
-            h = d.length,
-            c = 0,
-            b, g;
-        for (; c < h; c++) {
-            b = d[c];
-            if (b.isPie3D) {
-                g = b.getRadius();
-                if (g > a) {
-                    a = g
-                }
-            }
-        }
-        return a
-    }
-});
-Ext.define("Ext.chart.plugin.ItemEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.chartitemevents",
-    moveEvents: false,
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    itemMouseMoveEvents: {
-        itemmousemove: true,
-        itemmouseover: true,
-        itemmouseout: true
-    },
-    init: function(b) {
-        var a = "handleEvent";
-        this.chart = b;
-        b.addElementListener({
-            click: a,
-            dblclick: a,
-            mousedown: a,
-            mousemove: a,
-            mouseup: a,
-            mouseover: a,
-            mouseout: a,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasItemMouseMoveListeners: function() {
-        var b = this.chart.hasListeners,
-            a;
-        for (a in this.itemMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    handleEvent: function(g) {
-        var d = this,
-            a = d.chart,
-            h = g.type in d.mouseMoveEvents,
-            c = d.lastItem,
-            f, b;
-        if (h && !d.hasItemMouseMoveListeners() && !d.moveEvents) {
-            return
-        }
-        f = a.getEventXY(g);
-        b = a.getItemForPoint(f[0], f[1]);
-        if (h && !Ext.Object.equals(b, c)) {
-            if (c) {
-                a.fireEvent("itemmouseout", a, c, g);
-                c.series.fireEvent("itemmouseout", c.series, c, g)
-            }
-            if (b) {
-                a.fireEvent("itemmouseover", a, b, g);
-                b.series.fireEvent("itemmouseover", b.series, b, g)
-            }
-        }
-        if (b) {
-            a.fireEvent("item" + g.type, a, b, g);
-            b.series.fireEvent("item" + g.type, b.series, b, g)
-        }
-        d.lastItem = b
-    }
-});
-Ext.define("Ext.chart.series.Cartesian", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        xField: null,
-        yField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    updateXAxis: function(a) {
-        a.processData(this)
-    },
-    updateYAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    getItemForPoint: function(a, g) {
-        if (this.getSprites()) {
-            var f = this,
-                d = f.getSprites()[0],
-                b = f.getStore(),
-                e, c;
-            if (f.getHidden()) {
-                return null
-            }
-            if (d) {
-                c = d.getIndexNearPoint(a, g);
-                if (c !== -1) {
-                    e = {
-                        series: f,
-                        category: f.getItemInstancing() ? "items" : "markers",
-                        index: c,
-                        record: b.getData().items[c],
-                        field: f.getYField(),
-                        sprite: d
-                    };
-                    return e
-                }
-            }
-        }
-    },
-    createSprite: function() {
-        var c = this,
-            a = c.callParent(),
-            b = c.getChart(),
-            d = c.getXAxis();
-        a.setAttributes({
-            flipXY: b.getFlipXY(),
-            xAxis: d
-        });
-        if (a.setAggregator && d && d.getAggregator) {
-            if (d.getAggregator) {
-                a.setAggregator({
-                    strategy: d.getAggregator()
-                })
-            } else {
-                a.setAggregator({})
-            }
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = this.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.getItemInstancing(),
-            f = d.sprites,
-            a;
-        if (!c) {
-            return []
-        }
-        if (!f.length) {
-            a = d.createSprite()
-        } else {
-            a = f[0]
-        }
-        if (e) {
-            if (b) {
-                a.itemsMarker.getTemplate().setAnimation(e)
-            }
-            a.setAnimation(e)
-        }
-        return f
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    }
-});
-Ext.define("Ext.chart.series.StackedCartesian", {
-    extend: "Ext.chart.series.Cartesian",
-    config: {
-        stacked: true,
-        splitStacks: true,
-        fullStack: false,
-        fullStackTotal: 100,
-        hidden: []
-    },
-    spriteAnimationCount: 0,
-    themeColorCount: function() {
-        var b = this,
-            a = b.getYField();
-        return Ext.isArray(a) ? a.length : 1
-    },
-    updateStacked: function() {
-        this.processData()
-    },
-    updateSplitStacks: function() {
-        this.processData()
-    },
-    coordinateY: function() {
-        return this.coordinateStacked("Y", 1, 2)
-    },
-    coordinateStacked: function(D, e, m) {
-        var F = this,
-            f = F.getStore(),
-            r = f.getData().items,
-            B = r.length,
-            c = F["get" + D + "Axis"](),
-            x = F.getHidden(),
-            a = F.getSplitStacks(),
-            z = F.getFullStack(),
-            l = F.getFullStackTotal(),
-            p = {
-                min: 0,
-                max: 0
-            },
-            n = F["fieldCategory" + D],
-            C = [],
-            o = [],
-            E = [],
-            h, A = F.getStacked(),
-            g = F.getSprites(),
-            q = [],
-            w, v, u, s, H, y, b, d, G, t;
-        if (!g.length) {
-            return
-        }
-        for (w = 0; w < n.length; w++) {
-            d = n[w];
-            s = F.getFields([d]);
-            H = s.length;
-            for (v = 0; v < B; v++) {
-                C[v] = 0;
-                o[v] = 0;
-                E[v] = 0
-            }
-            for (v = 0; v < H; v++) {
-                if (!x[v]) {
-                    q[v] = F.coordinateData(r, s[v], c)
-                }
-            }
-            if (A && z) {
-                y = [];
-                if (a) {
-                    b = []
-                }
-                for (v = 0; v < B; v++) {
-                    y[v] = 0;
-                    if (a) {
-                        b[v] = 0
-                    }
-                    for (u = 0; u < H; u++) {
-                        G = q[u];
-                        if (!G) {
-                            continue
-                        }
-                        G = G[v];
-                        if (G >= 0 || !a) {
-                            y[v] += G
-                        } else {
-                            if (G < 0) {
-                                b[v] += G
-                            }
-                        }
-                    }
-                }
-            }
-            for (v = 0; v < H; v++) {
-                t = {};
-                if (x[v]) {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = C;
-                    g[v].setAttributes(t);
-                    continue
-                }
-                G = q[v];
-                if (A) {
-                    h = [];
-                    for (u = 0; u < B; u++) {
-                        if (!G[u]) {
-                            G[u] = 0
-                        }
-                        if (G[u] >= 0 || !a) {
-                            if (z && y[u]) {
-                                G[u] *= l / y[u]
-                            }
-                            C[u] = o[u];
-                            o[u] += G[u];
-                            h[u] = o[u]
-                        } else {
-                            if (z && b[u]) {
-                                G[u] *= l / b[u]
-                            }
-                            C[u] = E[u];
-                            E[u] += G[u];
-                            h[u] = E[u]
-                        }
-                    }
-                    t["dataStart" + d] = C;
-                    t["data" + d] = h;
-                    F.getRangeOfData(C, p);
-                    F.getRangeOfData(h, p)
-                } else {
-                    t["dataStart" + d] = C;
-                    t["data" + d] = G;
-                    F.getRangeOfData(G, p)
-                }
-                g[v].setAttributes(t)
-            }
-        }
-        F.dataRange[e] = p.min;
-        F.dataRange[e + m] = p.max;
-        t = {};
-        t["dataMin" + D] = p.min;
-        t["dataMax" + D] = p.max;
-        for (w = 0; w < g.length; w++) {
-            g[w].setAttributes(t)
-        }
-    },
-    getFields: function(f) {
-        var e = this,
-            a = [],
-            c, b, d;
-        for (b = 0, d = f.length; b < d; b++) {
-            c = e["get" + f[b] + "Field"]();
-            if (Ext.isArray(c)) {
-                a.push.apply(a, c)
-            } else {
-                a.push(c)
-            }
-        }
-        return a
-    },
-    updateLabelOverflowPadding: function(a) {
-        this.getLabel().setAttributes({
-            labelOverflowPadding: a
-        })
-    },
-    getSprites: function() {
-        var k = this,
-            j = k.getChart(),
-            c = k.getAnimation() || j && j.getAnimation(),
-            f = k.getFields(k.fieldCategoryY),
-            b = k.getItemInstancing(),
-            h = k.sprites,
-            l, e = k.getHidden(),
-            g = false,
-            d, a = f.length;
-        if (!j) {
-            return []
-        }
-        for (d = 0; d < a; d++) {
-            l = h[d];
-            if (!l) {
-                l = k.createSprite();
-                l.setAttributes({
-                    zIndex: -d
-                });
-                l.setField(f[d]);
-                g = true;
-                e.push(false);
-                if (b) {
-                    l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))
-                } else {
-                    l.setAttributes(k.getStyleByIndex(d))
-                }
-            }
-            if (c) {
-                if (b) {
-                    l.itemsMarker.getTemplate().setAnimation(c)
-                }
-                l.setAnimation(c)
-            }
-        }
-        if (g) {
-            k.updateHidden(e)
-        }
-        return h
-    },
-    getItemForPoint: function(k, j) {
-        if (this.getSprites()) {
-            var h = this,
-                b, g, m, a = h.getItemInstancing(),
-                f = h.getSprites(),
-                l = h.getStore(),
-                c = h.getHidden(),
-                n, d, e;
-            for (b = 0, g = f.length; b < g; b++) {
-                if (!c[b]) {
-                    m = f[b];
-                    d = m.getIndexNearPoint(k, j);
-                    if (d !== -1) {
-                        e = h.getYField();
-                        n = {
-                            series: h,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: l.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: m
-                        };
-                        return n
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(e) {
-        var g = this,
-            f = g.getSprites(),
-            h = g.getTitle(),
-            j = g.getYField(),
-            d = g.getHidden(),
-            k = f.length === 1,
-            b, l, c, a;
-        for (c = 0; c < f.length; c++) {
-            b = g.getStyleByIndex(c);
-            l = b.fillStyle;
-            if (h) {
-                if (Ext.isArray(h)) {
-                    a = h[c]
-                } else {
-                    if (k) {
-                        a = h
-                    }
-                }
-            } else {
-                if (Ext.isArray(j)) {
-                    a = j[c]
-                } else {
-                    a = g.getId()
-                }
-            }
-            e.push({
-                name: a,
-                mark: (Ext.isObject(l) ? l.stops && l.stops[0].color : l) || b.strokeStyle || "black",
-                disabled: d[c],
-                series: g.getId(),
-                index: c
-            })
-        }
-    },
-    onSpriteAnimationStart: function(a) {
-        this.spriteAnimationCount++;
-        if (this.spriteAnimationCount === 1) {
-            this.fireEvent("animationstart")
-        }
-    },
-    onSpriteAnimationEnd: function(a) {
-        this.spriteAnimationCount--;
-        if (this.spriteAnimationCount === 0) {
-            this.fireEvent("animationend")
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Series", {
-    extend: "Ext.draw.sprite.Sprite",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataMinX: "number",
-                dataMaxX: "number",
-                dataMinY: "number",
-                dataMaxY: "number",
-                rangeX: "data",
-                rangeY: "data",
-                dataX: "data",
-                dataY: "data"
-            },
-            defaults: {
-                dataMinX: 0,
-                dataMaxX: 1,
-                dataMinY: 0,
-                dataMaxY: 1,
-                rangeX: null,
-                rangeY: null,
-                dataX: null,
-                dataY: null
-            },
-            triggers: {
-                dataX: "bbox",
-                dataY: "bbox",
-                dataMinX: "bbox",
-                dataMaxX: "bbox",
-                dataMinY: "bbox",
-                dataMaxY: "bbox"
-            }
-        }
-    },
-    config: {
-        store: null,
-        series: null,
-        field: null
-    }
-});
-Ext.define("Ext.chart.series.sprite.Cartesian", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                labels: "default",
-                labelOverflowPadding: "number",
-                selectionTolerance: "number",
-                flipXY: "bool",
-                renderer: "default",
-                visibleMinX: "number",
-                visibleMinY: "number",
-                visibleMaxX: "number",
-                visibleMaxY: "number",
-                innerWidth: "number",
-                innerHeight: "number"
-            },
-            defaults: {
-                labels: null,
-                labelOverflowPadding: 10,
-                selectionTolerance: 20,
-                flipXY: false,
-                renderer: null,
-                transformFillStroke: false,
-                visibleMinX: 0,
-                visibleMinY: 0,
-                visibleMaxX: 1,
-                visibleMaxY: 1,
-                innerWidth: 1,
-                innerHeight: 1
-            },
-            triggers: {
-                dataX: "dataX,bbox",
-                dataY: "dataY,bbox",
-                visibleMinX: "panzoom",
-                visibleMinY: "panzoom",
-                visibleMaxX: "panzoom",
-                visibleMaxY: "panzoom",
-                innerWidth: "panzoom",
-                innerHeight: "panzoom"
-            },
-            updaters: {
-                dataX: function(a) {
-                    this.processDataX();
-                    this.scheduleUpdater(a, "dataY", ["dataY"])
-                },
-                dataY: function() {
-                    this.processDataY()
-                },
-                panzoom: function(c) {
-                    var e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        g = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = this.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * g / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = g / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    this.applyTransformations(true)
-                }
-            }
-        }
-    },
-    processDataY: Ext.emptyFn,
-    processDataX: Ext.emptyFn,
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.dataMinX;
-        b.y = a.dataMinY;
-        b.width = a.dataMaxX - a.dataMinX;
-        b.height = a.dataMaxY - a.dataMinY
-    },
-    binarySearch: function(d) {
-        var b = this.attr.dataX,
-            f = 0,
-            a = b.length;
-        if (d <= b[0]) {
-            return f
-        }
-        if (d >= b[a - 1]) {
-            return a - 1
-        }
-        while (f + 1 < a) {
-            var c = (f + a) >> 1,
-                e = b[c];
-            if (e === d) {
-                return c
-            } else {
-                if (e < d) {
-                    f = c
-                } else {
-                    a = c
-                }
-            }
-        }
-        return f
-    },
-    render: function(b, c, g) {
-        var f = this,
-            a = f.attr,
-            e = a.inverseMatrix.clone();
-        e.appendMatrix(b.inverseMatrix);
-        if (a.dataX === null || a.dataX === undefined) {
-            return
-        }
-        if (a.dataY === null || a.dataY === undefined) {
-            return
-        }
-        if (e.getXX() * e.getYX() || e.getXY() * e.getYY()) {
-            console.log("Cartesian Series sprite does not support rotation/sheering");
-            return
-        }
-        var d = e.transformList([
-            [g[0] - 1, g[3] + 1],
-            [g[0] + g[2] + 1, -1]
-        ]);
-        d = d[0].concat(d[1]);
-        f.renderClipped(b, c, d, g)
-    },
-    renderClipped: Ext.emptyFn,
-    getIndexNearPoint: function(f, e) {
-        var w = this,
-            q = w.attr.matrix,
-            h = w.attr.dataX,
-            g = w.attr.dataY,
-            k = w.attr.selectionTolerance,
-            t, r, c = -1,
-            j = q.clone().prependMatrix(w.surfaceMatrix).inverse(),
-            u = j.transformPoint([f, e]),
-            b = j.transformPoint([f - k, e - k]),
-            n = j.transformPoint([f + k, e + k]),
-            a = Math.min(b[0], n[0]),
-            s = Math.max(b[0], n[0]),
-            l = Math.min(b[1], n[1]),
-            d = Math.max(b[1], n[1]),
-            m, v, o, p;
-        for (o = 0, p = h.length; o < p; o++) {
-            m = h[o];
-            v = g[o];
-            if (m > a && m < s && v > l && v < d) {
-                if (c === -1 || (Math.abs(m - u[0]) < t) && (Math.abs(v - u[1]) < r)) {
-                    t = Math.abs(m - u[0]);
-                    r = Math.abs(v - u[1]);
-                    c = o
-                }
-            }
-        }
-        return c
-    }
-});
-Ext.define("Ext.chart.series.sprite.StackedCartesian", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                groupCount: "number",
-                groupOffset: "number",
-                dataStartY: "data"
-            },
-            defaults: {
-                selectionTolerance: 20,
-                groupCount: 1,
-                groupOffset: 0,
-                dataStartY: null
-            },
-            triggers: {
-                dataStartY: "dataY,bbox"
-            }
-        }
-    },
-    getIndexNearPoint: function(e, d) {
-        var o = this,
-            q = o.attr.matrix,
-            h = o.attr.dataX,
-            f = o.attr.dataY,
-            u = o.attr.dataStartY,
-            l = o.attr.selectionTolerance,
-            s = 0.5,
-            r = Infinity,
-            b = -1,
-            k = q.clone().prependMatrix(this.surfaceMatrix).inverse(),
-            t = k.transformPoint([e, d]),
-            a = k.transformPoint([e - l, d - l]),
-            n = k.transformPoint([e + l, d + l]),
-            m = Math.min(a[1], n[1]),
-            c = Math.max(a[1], n[1]),
-            j, g;
-        for (var p = 0; p < h.length; p++) {
-            if (Math.min(u[p], f[p]) <= c && m <= Math.max(u[p], f[p])) {
-                j = Math.abs(h[p] - t[0]);
-                g = Math.max(-Math.min(f[p] - t[1], t[1] - u[p]), 0);
-                if (j < s && g <= r) {
-                    s = j;
-                    r = g;
-                    b = p
-                }
-            }
-        }
-        return b
-    }
-});
-Ext.define("Ext.chart.series.sprite.Area", {
-    alias: "sprite.areaSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                step: "bool"
-            },
-            defaults: {
-                step: false
-            }
-        }
-    },
-    renderClipped: function(q, s, A) {
-        var B = this,
-            p = B.attr,
-            l = p.dataX,
-            j = p.dataY,
-            C = p.dataStartY,
-            t = p.matrix,
-            h, g, v, f, d, z, w, e = t.elements[0],
-            m = t.elements[4],
-            o = t.elements[3],
-            k = t.elements[5],
-            c = B.surfaceMatrix,
-            n = {},
-            r = Math.min(A[0], A[2]),
-            u = Math.max(A[0], A[2]),
-            b = Math.max(0, this.binarySearch(r)),
-            a = Math.min(l.length - 1, this.binarySearch(u) + 1);
-        s.beginPath();
-        z = l[b] * e + m;
-        w = j[b] * o + k;
-        s.moveTo(z, w);
-        if (p.step) {
-            d = w;
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g)
-            }
-        }
-        if (C) {
-            if (p.step) {
-                f = l[a] * e + m;
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(f, g);
-                    s.lineTo(f = h, g)
-                }
-            } else {
-                for (v = a; v >= b; v--) {
-                    h = l[v] * e + m;
-                    g = C[v] * o + k;
-                    s.lineTo(h, g)
-                }
-            }
-        } else {
-            s.lineTo(l[a] * e + m, g);
-            s.lineTo(l[a] * e + m, k);
-            s.lineTo(z, k);
-            s.lineTo(z, j[v] * o + k)
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.fill();
-        if (p.transformFillStroke) {
-            p.inverseMatrix.toContext(s)
-        }
-        s.beginPath();
-        s.moveTo(z, w);
-        if (p.step) {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, d);
-                s.lineTo(h, d = g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        } else {
-            for (v = b; v <= a; v++) {
-                h = l[v] * e + m;
-                g = j[v] * o + k;
-                s.lineTo(h, g);
-                n.translationX = c.x(h, g);
-                n.translationY = c.y(h, g);
-                B.putMarker("markers", n, v, !p.renderer)
-            }
-        }
-        if (p.transformFillStroke) {
-            p.matrix.toContext(s)
-        }
-        s.stroke()
-    }
-});
-Ext.define("Ext.chart.series.Area", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.area",
-    type: "area",
-    seriesType: "areaSeries",
-    requires: ["Ext.chart.series.sprite.Area"],
-    config: {
-        splitStacks: false
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar", {
-    alias: "sprite.barSeries",
-    extend: "Ext.chart.series.sprite.StackedCartesian",
-    inheritableStatics: {
-        def: {
-            processors: {
-                minBarWidth: "number",
-                maxBarWidth: "number",
-                minGapWidth: "number",
-                radius: "number",
-                inGroupGapWidth: "number"
-            },
-            defaults: {
-                minBarWidth: 2,
-                maxBarWidth: 100,
-                minGapWidth: 5,
-                inGroupGapWidth: 3,
-                radius: 0
-            }
-        }
-    },
-    drawLabel: function(k, i, s, h, o) {
-        var q = this,
-            n = q.attr,
-            f = q.getMarker("labels"),
-            d = f.getTemplate(),
-            l = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            j = n.labelOverflowPadding,
-            b = d.attr.display,
-            m = d.attr.orientation,
-            g, e, a, r, t, p;
-        l.x = c.x(i, h);
-        l.y = c.y(i, h);
-        if (!n.flipXY) {
-            l.rotationRads = -Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        l.calloutVertical = !n.flipXY;
-        switch (m) {
-            case "horizontal":
-                l.rotationRads = 0;
-                l.calloutVertical = false;
-                break;
-            case "vertical":
-                l.rotationRads = -Math.PI * 0.5;
-                l.calloutVertical = true;
-                break
-        }
-        l.text = k;
-        if (d.attr.renderer) {
-            p = [k, f, l, {
-                store: q.getStore()
-            }, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                l.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        l.text = r.text
-                    }
-                    t = true
-                }
-            }
-        }
-        a = q.getMarkerBBox("labels", o, true);
-        if (!a) {
-            q.putMarker("labels", l, o);
-            a = q.getMarkerBBox("labels", o, true)
-        }
-        e = (a.width / 2 + j);
-        if (s > h) {
-            e = -e
-        }
-        if ((m === "horizontal" && n.flipXY) || (m === "vertical" && !n.flipXY) || !m) {
-            g = (b === "insideStart") ? s + e : h - e
-        } else {
-            g = (b === "insideStart") ? s + j * 2 : h - j * 2
-        }
-        l.x = c.x(i, g);
-        l.y = c.y(i, g);
-        g = (b === "insideStart") ? s - e : h + e;
-        l.calloutPlaceX = c.x(i, g);
-        l.calloutPlaceY = c.y(i, g);
-        g = (b === "insideStart") ? s : h;
-        l.calloutStartX = c.x(i, g);
-        l.calloutStartY = c.y(i, g);
-        if (s > h) {
-            e = -e
-        }
-        if (Math.abs(h - s) <= e * 2 || b === "outside") {
-            l.callout = 1
-        } else {
-            l.callout = 0
-        }
-        if (t) {
-            Ext.apply(l, r)
-        }
-        q.putMarker("labels", l, o)
-    },
-    drawBar: function(l, b, d, c, h, k, a, e) {
-        var g = this,
-            j = {},
-            f = g.attr.renderer,
-            i;
-        j.x = c;
-        j.y = h;
-        j.width = k - c;
-        j.height = a - h;
-        j.radius = g.attr.radius;
-        if (f) {
-            i = Ext.callback(f, null, [g, j, {
-                store: g.getStore()
-            }, e], 0, g.getSeries());
-            Ext.apply(j, i)
-        }
-        g.putMarker("items", j, e, !f)
-    },
-    renderClipped: function(G, u, F, C) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var q = this,
-            o = q.attr,
-            w = o.dataX,
-            v = o.dataY,
-            H = o.labels,
-            n = o.dataStartY,
-            m = o.groupCount,
-            E = o.groupOffset - (m - 1) * 0.5,
-            z = o.inGroupGapWidth,
-            t = u.lineWidth,
-            D = o.matrix,
-            B = D.elements[0],
-            j = D.elements[3],
-            e = D.elements[4],
-            d = G.roundPixel(D.elements[5]) - 1,
-            J = (B < 0 ? -1 : 1) * B - o.minGapWidth,
-            k = (Math.min(J, o.maxBarWidth) - z * (m - 1)) / m,
-            A = G.roundPixel(Math.max(o.minBarWidth, k)),
-            c = q.surfaceMatrix,
-            g, I, b, h, K, a, l = 0.5 * o.lineWidth,
-            L = Math.min(F[0], F[2]),
-            x = Math.max(F[0], F[2]),
-            y = Math.max(0, Math.floor(L)),
-            p = Math.min(w.length - 1, Math.ceil(x)),
-            f = H && q.getMarker("labels"),
-            s, r;
-        for (K = y; K <= p; K++) {
-            s = n ? n[K] : 0;
-            r = v[K];
-            a = w[K] * B + e + E * (A + z);
-            g = G.roundPixel(a - A / 2) + l;
-            h = G.roundPixel(r * j + d + t);
-            I = G.roundPixel(a + A / 2) - l;
-            b = G.roundPixel(s * j + d + t);
-            q.drawBar(u, G, F, g, h - l, I, b - l, K);
-            if (f && H[K] != null) {
-                q.drawLabel(H[K], a, b, h, K)
-            }
-            q.putMarker("markers", {
-                translationX: c.x(a, h),
-                translationY: c.y(a, h)
-            }, K, true)
-        }
-    },
-    getIndexNearPoint: function(l, k) {
-        var m = this,
-            g = m.attr,
-            h = g.dataX,
-            a = m.getSurface(),
-            b = a.getRect() || [0, 0, 0, 0],
-            j = b[3],
-            e, d, c, n, f = -1;
-        if (g.flipXY) {
-            e = j - k;
-            if (a.getInherited().rtl) {
-                d = b[2] - l
-            } else {
-                d = l
-            }
-        } else {
-            e = l;
-            d = j - k
-        }
-        for (c = 0; c < h.length; c++) {
-            n = m.getMarkerBBox("items", c);
-            if (Ext.draw.Draw.isPointInBBox(e, d, n)) {
-                f = c;
-                break
-            }
-        }
-        return f
-    }
-});
-Ext.define("Ext.chart.series.Bar", {
-    extend: "Ext.chart.series.StackedCartesian",
-    alias: "series.bar",
-    type: "bar",
-    seriesType: "barSeries",
-    requires: ["Ext.chart.series.sprite.Bar", "Ext.draw.sprite.Rect"],
-    config: {
-        itemInstancing: {
-            type: "rect",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    radius: 0
-                }
-            }
-        }
-    },
-    getItemForPoint: function(a, f) {
-        if (this.getSprites()) {
-            var d = this,
-                c = d.getChart(),
-                e = c.getInnerPadding(),
-                b = c.getInherited().rtl;
-            arguments[0] = a + (b ? e.right : -e.left);
-            arguments[1] = f + e.bottom;
-            return d.callParent(arguments)
-        }
-    },
-    updateXAxis: function(a) {
-        a.setLabelInSpan(true);
-        this.callParent(arguments)
-    },
-    updateHidden: function(a) {
-        this.callParent(arguments);
-        this.updateStacked()
-    },
-    updateStacked: function(c) {
-        var e = this,
-            g = e.getSprites(),
-            d = g.length,
-            f = [],
-            a = {},
-            b;
-        for (b = 0; b < d; b++) {
-            if (!g[b].attr.hidden) {
-                f.push(g[b])
-            }
-        }
-        d = f.length;
-        if (e.getStacked()) {
-            a.groupCount = 1;
-            a.groupOffset = 0;
-            for (b = 0; b < d; b++) {
-                f[b].setAttributes(a)
-            }
-        } else {
-            a.groupCount = f.length;
-            for (b = 0; b < d; b++) {
-                a.groupOffset = b;
-                f[b].setAttributes(a)
-            }
-        }
-        e.callParent(arguments)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Bar3D", {
-    extend: "Ext.chart.series.sprite.Bar",
-    alias: "sprite.bar3dSeries",
-    requires: ["Ext.draw.gradient.Linear"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                depthWidthRatio: "number",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            defaults: {
-                depthWidthRatio: 1 / 3,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                transformFillStroke: true
-            },
-            triggers: {
-                groupCount: "panzoom"
-            },
-            updaters: {
-                panzoom: function(c) {
-                    var g = this,
-                        e = c.visibleMaxX - c.visibleMinX,
-                        d = c.visibleMaxY - c.visibleMinY,
-                        b = c.flipXY ? c.innerHeight : c.innerWidth,
-                        h = !c.flipXY ? c.innerHeight : c.innerWidth,
-                        a = g.getSurface(),
-                        f = a ? a.getInherited().rtl : false;
-                    if (f && !c.flipXY) {
-                        c.translationX = b + c.visibleMinX * b / e
-                    } else {
-                        c.translationX = -c.visibleMinX * b / e
-                    }
-                    c.translationY = -c.visibleMinY * (h - g.depth) / d;
-                    c.scalingX = (f && !c.flipXY ? -1 : 1) * b / e;
-                    c.scalingY = (h - g.depth) / d;
-                    c.scalingCenterX = 0;
-                    c.scalingCenterY = 0;
-                    g.applyTransformations(true)
-                }
-            }
-        }
-    },
-    config: {
-        showStroke: false
-    },
-    depth: 0,
-    drawBar: function(p, b, d, c, l, o, a, h) {
-        var k = this,
-            i = k.attr,
-            n = {},
-            j = i.renderer,
-            m, g, f, e;
-        n.x = (c + o) * 0.5;
-        n.y = l;
-        n.width = (o - c) * 0.75;
-        n.height = a - l;
-        n.depth = g = n.width * i.depthWidthRatio;
-        n.orientation = i.flipXY ? "horizontal" : "vertical";
-        n.saturationFactor = i.saturationFactor;
-        n.brightnessFactor = i.brightnessFactor;
-        n.colorSpread = i.colorSpread;
-        if (g !== k.depth) {
-            k.depth = g;
-            f = k.getSeries();
-            f.fireEvent("depthchange", f, g)
-        }
-        if (j) {
-            e = [k, n, {
-                store: k.getStore()
-            }, h];
-            m = Ext.callback(j, null, e, 0, k.getSeries());
-            Ext.apply(n, m)
-        }
-        k.putMarker("items", n, h, !j)
-    }
-});
-Ext.define("Ext.chart.series.sprite.Box", {
-    extend: "Ext.draw.sprite.Sprite",
-    alias: "sprite.box",
-    type: "box",
-    inheritableStatics: {
-        def: {
-            processors: {
-                x: "number",
-                y: "number",
-                width: "number",
-                height: "number",
-                depth: "number",
-                orientation: "enums(vertical,horizontal)",
-                showStroke: "bool",
-                saturationFactor: "number",
-                brightnessFactor: "number",
-                colorSpread: "number"
-            },
-            triggers: {
-                x: "bbox",
-                y: "bbox",
-                width: "bbox",
-                height: "bbox",
-                depth: "bbox",
-                orientation: "bbox"
-            },
-            defaults: {
-                x: 0,
-                y: 0,
-                width: 8,
-                height: 8,
-                depth: 8,
-                orientation: "vertical",
-                showStroke: false,
-                saturationFactor: 1,
-                brightnessFactor: 1,
-                colorSpread: 1,
-                lineJoin: "bevel"
-            }
-        }
-    },
-    constructor: function(a) {
-        this.callParent([a]);
-        this.topGradient = new Ext.draw.gradient.Linear({});
-        this.rightGradient = new Ext.draw.gradient.Linear({});
-        this.frontGradient = new Ext.draw.gradient.Linear({})
-    },
-    updatePlainBBox: function(d) {
-        var c = this.attr,
-            b = c.x,
-            g = c.y,
-            e = c.width,
-            a = c.height,
-            f = c.depth;
-        d.x = b - e * 0.5;
-        d.width = e + f;
-        if (a > 0) {
-            d.y = g;
-            d.height = a + f
-        } else {
-            d.y = g + f;
-            d.height = a - f
-        }
-    },
-    render: function(l, m) {
-        var u = this,
-            k = u.attr,
-            r = k.x,
-            j = k.y,
-            f = j + k.height,
-            i = j < f,
-            e = k.width * 0.5,
-            v = k.depth,
-            d = k.orientation === "horizontal",
-            g = k.globalAlpha < 1,
-            c = k.fillStyle,
-            n = Ext.draw.Color.create(c.isGradient ? c.getStops()[0].color : c),
-            h = k.saturationFactor,
-            o = k.brightnessFactor,
-            t = k.colorSpread,
-            b = n.getHSV(),
-            a = {},
-            s, q, p;
-        if (!k.showStroke) {
-            m.strokeStyle = Ext.draw.Color.RGBA_NONE
-        }
-        if (i) {
-            p = j;
-            j = f;
-            f = p
-        }
-        u.topGradient.setDegrees(d ? 0 : 80);
-        u.topGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.11) * o, 0, 1))
-        }]);
-        u.rightGradient.setDegrees(d ? 45 : 90);
-        u.rightGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.14) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.4) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.32) * o, 0, 1))
-        }]);
-        if (d) {
-            u.frontGradient.setDegrees(0)
-        } else {
-            u.frontGradient.setRadians(Math.atan2(j - f, e * 2))
-        }
-        u.frontGradient.setStops([{
-            offset: 0,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 - t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 + t * 0.1) * o, 0, 1))
-        }, {
-            offset: 1,
-            color: Ext.draw.Color.fromHSV(b[0], Ext.Number.constrain(b[1] * (1 + t * 0.1) * h, 0, 1), Ext.Number.constrain((0.5 - t * 0.23) * o, 0, 1))
-        }]);
-        if (g || i) {
-            m.beginPath();
-            m.moveTo(r - e, f);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r + e + v, f + v);
-            m.lineTo(r + e, f);
-            m.closePath();
-            a.x = r - e;
-            a.y = j;
-            a.width = e + v;
-            a.height = v;
-            m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        if (g) {
-            m.beginPath();
-            m.moveTo(r - e, j);
-            m.lineTo(r - e + v, j + v);
-            m.lineTo(r - e + v, f + v);
-            m.lineTo(r - e, f);
-            m.closePath();
-            a.x = r + e;
-            a.y = f;
-            a.width = v;
-            a.height = j + v - f;
-            m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-            m.fillStroke(k)
-        }
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, q);
-        m.lineTo(r - e + v, j + v);
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e, q);
-        m.closePath();
-        a.x = r - e;
-        a.y = j;
-        a.width = e + v;
-        a.height = v;
-        m.fillStyle = (d ? u.rightGradient : u.topGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        m.beginPath();
-        m.moveTo(s, l.roundPixel(j));
-        m.lineTo(r + e + v, j + v);
-        m.lineTo(r + e + v, f + v);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r + e;
-        a.y = f;
-        a.width = v;
-        a.height = j + v - f;
-        m.fillStyle = (d ? u.topGradient : u.rightGradient).generateGradient(m, a);
-        m.fillStroke(k);
-        s = l.roundPixel(r + e);
-        q = l.roundPixel(j);
-        m.beginPath();
-        m.moveTo(r - e, f);
-        m.lineTo(r - e, q);
-        m.lineTo(s, q);
-        m.lineTo(s, f);
-        m.closePath();
-        a.x = r - e;
-        a.y = f;
-        a.width = e * 2;
-        a.height = j - f;
-        m.fillStyle = u.frontGradient.generateGradient(m, a);
-        m.fillStroke(k)
-    }
-});
-Ext.define("Ext.chart.series.Bar3D", {
-    extend: "Ext.chart.series.Bar",
-    requires: ["Ext.chart.series.sprite.Bar3D", "Ext.chart.series.sprite.Box"],
-    alias: "series.bar3d",
-    type: "bar3d",
-    seriesType: "bar3dSeries",
-    config: {
-        itemInstancing: {
-            type: "box",
-            fx: {
-                customDurations: {
-                    x: 0,
-                    y: 0,
-                    width: 0,
-                    height: 0,
-                    depth: 0
-                }
-            }
-        },
-        highlightCfg: {
-            opacity: 0.8
-        }
-    },
-    getSprites: function() {
-        var c = this.callParent(arguments),
-            b, d, a;
-        for (a = 0; a < c.length; a++) {
-            b = c[a];
-            d = b.attr.zIndex;
-            if (d < 0) {
-                b.setAttributes({
-                    zIndex: -d
-                })
-            }
-            if (b.setSeries) {
-                b.setSeries(this)
-            }
-        }
-        return c
-    },
-    getDepth: function() {
-        var a = this.getSprites()[0];
-        return a ? (a.depth || 0) : 0
-    },
-    getItemForPoint: function(m, k) {
-        if (this.getSprites()) {
-            var j = this,
-                b, o, a = j.getItemInstancing(),
-                h = j.getSprites(),
-                n = j.getStore(),
-                c = j.getHidden(),
-                g = j.getChart(),
-                l = g.getInnerPadding(),
-                f = g.getInherited().rtl,
-                p, d, e;
-            m = m + (f ? l.right : -l.left);
-            k = k + l.bottom;
-            for (b = h.length - 1; b >= 0; b--) {
-                if (!c[b]) {
-                    o = h[b];
-                    d = o.getIndexNearPoint(m, k);
-                    if (d !== -1) {
-                        e = j.getYField();
-                        p = {
-                            series: j,
-                            index: d,
-                            category: a ? "items" : "markers",
-                            record: n.getData().items[d],
-                            field: typeof e === "string" ? e : e[b],
-                            sprite: o
-                        };
-                        return p
-                    }
-                }
-            }
-            return null
-        }
-    }
-});
-Ext.define("Ext.draw.LimitedCache", {
-    config: {
-        limit: 40,
-        feeder: function() {
-            return 0
-        },
-        scope: null
-    },
-    cache: null,
-    constructor: function(a) {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0;
-        this.initConfig(a)
-    },
-    get: function(e) {
-        var c = this.cache,
-            b = this.getLimit(),
-            a = this.getFeeder(),
-            d = this.getScope() || this;
-        if (c[e]) {
-            return c[e].value
-        }
-        if (c.list[c.tail]) {
-            delete c[c.list[c.tail].cacheId]
-        }
-        c[e] = c.list[c.tail] = {
-            value: a.apply(d, Array.prototype.slice.call(arguments, 1)),
-            cacheId: e
-        };
-        c.tail++;
-        if (c.tail === b) {
-            c.tail = 0
-        }
-        return c[e].value
-    },
-    clear: function() {
-        this.cache = {};
-        this.cache.list = [];
-        this.cache.tail = 0
-    }
-});
-Ext.define("Ext.draw.SegmentTree", {
-    config: {
-        strategy: "double"
-    },
-    time: function(m, l, n, c, E, d, e) {
-        var f = 0,
-            o, A, s = new Date(n[m.startIdx[0]]),
-            x = new Date(n[m.endIdx[l - 1]]),
-            D = Ext.Date,
-            u = [
-                [D.MILLI, 1, "ms1", null],
-                [D.MILLI, 2, "ms2", "ms1"],
-                [D.MILLI, 5, "ms5", "ms1"],
-                [D.MILLI, 10, "ms10", "ms5"],
-                [D.MILLI, 50, "ms50", "ms10"],
-                [D.MILLI, 100, "ms100", "ms50"],
-                [D.MILLI, 500, "ms500", "ms100"],
-                [D.SECOND, 1, "s1", "ms500"],
-                [D.SECOND, 10, "s10", "s1"],
-                [D.SECOND, 30, "s30", "s10"],
-                [D.MINUTE, 1, "mi1", "s10"],
-                [D.MINUTE, 5, "mi5", "mi1"],
-                [D.MINUTE, 10, "mi10", "mi5"],
-                [D.MINUTE, 30, "mi30", "mi10"],
-                [D.HOUR, 1, "h1", "mi30"],
-                [D.HOUR, 6, "h6", "h1"],
-                [D.HOUR, 12, "h12", "h6"],
-                [D.DAY, 1, "d1", "h12"],
-                [D.DAY, 7, "d7", "d1"],
-                [D.MONTH, 1, "mo1", "d1"],
-                [D.MONTH, 3, "mo3", "mo1"],
-                [D.MONTH, 6, "mo6", "mo3"],
-                [D.YEAR, 1, "y1", "mo3"],
-                [D.YEAR, 5, "y5", "y1"],
-                [D.YEAR, 10, "y10", "y5"],
-                [D.YEAR, 100, "y100", "y10"]
-            ],
-            z, b, k = f,
-            F = l,
-            j = false,
-            r = m.startIdx,
-            h = m.endIdx,
-            w = m.minIdx,
-            C = m.maxIdx,
-            a = m.open,
-            y = m.close,
-            g = m.minX,
-            q = m.minY,
-            p = m.maxX,
-            B = m.maxY,
-            v, t;
-        for (z = 0; l > f + 1 && z < u.length; z++) {
-            s = new Date(n[r[0]]);
-            b = u[z];
-            s = D.align(s, b[0], b[1]);
-            if (D.diff(s, x, b[0]) > n.length * 2 * b[1]) {
-                continue
-            }
-            if (b[3] && m.map["time_" + b[3]]) {
-                o = m.map["time_" + b[3]][0];
-                A = m.map["time_" + b[3]][1]
-            } else {
-                o = k;
-                A = F
-            }
-            f = l;
-            t = s;
-            j = true;
-            r[l] = r[o];
-            h[l] = h[o];
-            w[l] = w[o];
-            C[l] = C[o];
-            a[l] = a[o];
-            y[l] = y[o];
-            g[l] = g[o];
-            q[l] = q[o];
-            p[l] = p[o];
-            B[l] = B[o];
-            t = Ext.Date.add(t, b[0], b[1]);
-            for (v = o + 1; v < A; v++) {
-                if (n[h[v]] < +t) {
-                    h[l] = h[v];
-                    y[l] = y[v];
-                    if (B[v] > B[l]) {
-                        B[l] = B[v];
-                        p[l] = p[v];
-                        C[l] = C[v]
-                    }
-                    if (q[v] < q[l]) {
-                        q[l] = q[v];
-                        g[l] = g[v];
-                        w[l] = w[v]
-                    }
-                } else {
-                    l++;
-                    r[l] = r[v];
-                    h[l] = h[v];
-                    w[l] = w[v];
-                    C[l] = C[v];
-                    a[l] = a[v];
-                    y[l] = y[v];
-                    g[l] = g[v];
-                    q[l] = q[v];
-                    p[l] = p[v];
-                    B[l] = B[v];
-                    t = Ext.Date.add(t, b[0], b[1])
-                }
-            }
-            if (l > f) {
-                m.map["time_" + b[2]] = [f, l]
-            }
-        }
-    },
-    "double": function(h, u, j, a, t, b, c) {
-        var e = 0,
-            k, f = 1,
-            n, d, v, g, s, l, m, r, q, p, o;
-        while (u > e + 1) {
-            k = e;
-            e = u;
-            f += f;
-            for (n = k; n < e; n += 2) {
-                if (n === e - 1) {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n];
-                    g = h.minIdx[n];
-                    s = h.maxIdx[n];
-                    l = h.open[n];
-                    m = h.close[n];
-                    r = h.minX[n];
-                    q = h.minY[n];
-                    p = h.maxX[n];
-                    o = h.maxY[n]
-                } else {
-                    d = h.startIdx[n];
-                    v = h.endIdx[n + 1];
-                    l = h.open[n];
-                    m = h.close[n];
-                    if (h.minY[n] <= h.minY[n + 1]) {
-                        g = h.minIdx[n];
-                        r = h.minX[n];
-                        q = h.minY[n]
-                    } else {
-                        g = h.minIdx[n + 1];
-                        r = h.minX[n + 1];
-                        q = h.minY[n + 1]
-                    }
-                    if (h.maxY[n] >= h.maxY[n + 1]) {
-                        s = h.maxIdx[n];
-                        p = h.maxX[n];
-                        o = h.maxY[n]
-                    } else {
-                        s = h.maxIdx[n + 1];
-                        p = h.maxX[n + 1];
-                        o = h.maxY[n + 1]
-                    }
-                }
-                h.startIdx[u] = d;
-                h.endIdx[u] = v;
-                h.minIdx[u] = g;
-                h.maxIdx[u] = s;
-                h.open[u] = l;
-                h.close[u] = m;
-                h.minX[u] = r;
-                h.minY[u] = q;
-                h.maxX[u] = p;
-                h.maxY[u] = o;
-                u++
-            }
-            h.map["double_" + f] = [e, u]
-        }
-    },
-    none: Ext.emptyFn,
-    aggregateData: function(h, a, r, c, d) {
-        var b = h.length,
-            e = [],
-            s = [],
-            f = [],
-            q = [],
-            j = [],
-            p = [],
-            n = [],
-            o = [],
-            m = [],
-            k = [],
-            g = {
-                startIdx: e,
-                endIdx: s,
-                minIdx: f,
-                maxIdx: q,
-                open: j,
-                minX: p,
-                minY: n,
-                maxX: o,
-                maxY: m,
-                close: k
-            },
-            l;
-        for (l = 0; l < b; l++) {
-            e[l] = l;
-            s[l] = l;
-            f[l] = l;
-            q[l] = l;
-            j[l] = a[l];
-            p[l] = h[l];
-            n[l] = c[l];
-            o[l] = h[l];
-            m[l] = r[l];
-            k[l] = d[l]
-        }
-        g.map = {
-            original: [0, b]
-        };
-        if (b) {
-            this[this.getStrategy()](g, b, h, a, r, c, d)
-        }
-        return g
-    },
-    binarySearchMin: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.startIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.startIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.startIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return g
-    },
-    binarySearchMax: function(c, g, a, e) {
-        var b = this.dataX;
-        if (e <= b[c.endIdx[0]]) {
-            return g
-        }
-        if (e >= b[c.endIdx[a - 1]]) {
-            return a - 1
-        }
-        while (g + 1 < a) {
-            var d = (g + a) >> 1,
-                f = b[c.endIdx[d]];
-            if (f === e) {
-                return d
-            } else {
-                if (f < e) {
-                    g = d
-                } else {
-                    a = d
-                }
-            }
-        }
-        return a
-    },
-    constructor: function(a) {
-        this.initConfig(a)
-    },
-    setData: function(d, a, b, c, e) {
-        if (!b) {
-            e = c = b = a
-        }
-        this.dataX = d;
-        this.dataOpen = a;
-        this.dataHigh = b;
-        this.dataLow = c;
-        this.dataClose = e;
-        if (d.length === b.length && d.length === c.length) {
-            this.cache = this.aggregateData(d, a, b, c, e)
-        }
-    },
-    getAggregation: function(d, k, i) {
-        if (!this.cache) {
-            return null
-        }
-        var c = Infinity,
-            g = this.dataX[this.dataX.length - 1] - this.dataX[0],
-            l = this.cache.map,
-            m = l.original,
-            a, e, j, b, f, h;
-        for (a in l) {
-            e = l[a];
-            j = e[1] - e[0] - 1;
-            b = g / j;
-            if (i <= b && b < c) {
-                m = e;
-                c = b
-            }
-        }
-        f = Math.max(this.binarySearchMin(this.cache, m[0], m[1], d), m[0]);
-        h = Math.min(this.binarySearchMax(this.cache, m[0], m[1], k) + 1, m[1]);
-        return {
-            data: this.cache,
-            start: f,
-            end: h
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Aggregative", {
-    extend: "Ext.chart.series.sprite.Cartesian",
-    requires: ["Ext.draw.LimitedCache", "Ext.draw.SegmentTree"],
-    inheritableStatics: {
-        def: {
-            processors: {
-                dataHigh: "data",
-                dataLow: "data",
-                dataClose: "data"
-            },
-            aliases: {
-                dataOpen: "dataY"
-            },
-            defaults: {
-                dataHigh: null,
-                dataLow: null,
-                dataClose: null
-            }
-        }
-    },
-    config: {
-        aggregator: {}
-    },
-    applyAggregator: function(b, a) {
-        return Ext.factory(b, Ext.draw.SegmentTree, a)
-    },
-    constructor: function() {
-        this.callParent(arguments)
-    },
-    processDataY: function() {
-        var d = this,
-            b = d.attr,
-            e = b.dataHigh,
-            a = b.dataLow,
-            f = b.dataClose,
-            c = b.dataY;
-        d.callParent(arguments);
-        if (b.dataX && c && c.length > 0) {
-            if (e) {
-                d.getAggregator().setData(b.dataX, b.dataY, e, a, f)
-            } else {
-                d.getAggregator().setData(b.dataX, b.dataY)
-            }
-        }
-    },
-    getGapWidth: function() {
-        return 1
-    },
-    renderClipped: function(b, c, g, f) {
-        var e = this,
-            d = Math.min(g[0], g[2]),
-            a = Math.max(g[0], g[2]),
-            h = e.getAggregator() && e.getAggregator().getAggregation(d, a, (a - d) / f[2] * e.getGapWidth());
-        if (h) {
-            e.dataStart = h.data.startIdx[h.start];
-            e.dataEnd = h.data.endIdx[h.end - 1];
-            e.renderAggregates(h.data, h.start, h.end, b, c, g, f)
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.CandleStick", {
-    alias: "sprite.candlestickSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                raiseStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                dropStyle: function(b, a) {
-                    return Ext.merge({}, a || {}, b)
-                },
-                barWidth: "number",
-                padding: "number",
-                ohlcType: "enums(candlestick,ohlc)"
-            },
-            defaults: {
-                raiseStyle: {
-                    strokeStyle: "green",
-                    fillStyle: "green"
-                },
-                dropStyle: {
-                    strokeStyle: "red",
-                    fillStyle: "red"
-                },
-                planar: false,
-                barWidth: 15,
-                padding: 3,
-                lineJoin: "miter",
-                miterLimit: 5,
-                ohlcType: "candlestick"
-            },
-            triggers: {
-                raiseStyle: "raiseStyle",
-                dropStyle: "dropStyle"
-            },
-            updaters: {
-                raiseStyle: function() {
-                    this.raiseTemplate && this.raiseTemplate.setAttributes(this.attr.raiseStyle)
-                },
-                dropStyle: function() {
-                    this.dropTemplate && this.dropTemplate.setAttributes(this.attr.dropStyle)
-                }
-            }
-        }
-    },
-    candlestick: function(i, c, a, e, h, f, b) {
-        var d = Math.min(c, h),
-            g = Math.max(c, h);
-        i.moveTo(f, e);
-        i.lineTo(f, g);
-        i.moveTo(f + b, g);
-        i.lineTo(f + b, d);
-        i.lineTo(f - b, d);
-        i.lineTo(f - b, g);
-        i.closePath();
-        i.moveTo(f, a);
-        i.lineTo(f, d)
-    },
-    ohlc: function(b, d, e, a, f, c, g) {
-        b.moveTo(c, e);
-        b.lineTo(c, a);
-        b.moveTo(c, d);
-        b.lineTo(c - g, d);
-        b.moveTo(c, f);
-        b.lineTo(c + g, f)
-    },
-    constructor: function() {
-        this.callParent(arguments);
-        this.raiseTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        });
-        this.dropTemplate = new Ext.draw.sprite.Rect({
-            parent: this
-        })
-    },
-    getGapWidth: function() {
-        var a = this.attr,
-            b = a.barWidth,
-            c = a.padding;
-        return b + c
-    },
-    renderAggregates: function(d, c, b, t, u, z) {
-        var D = this,
-            s = this.attr,
-            j = s.dataX,
-            v = s.matrix,
-            e = v.getXX(),
-            r = v.getYY(),
-            l = v.getDX(),
-            h = v.getDY(),
-            o = s.barWidth / e,
-            C, k = s.ohlcType,
-            f = Math.round(o * 0.5 * e),
-            a = d.open,
-            y = d.close,
-            B = d.maxY,
-            p = d.minY,
-            q = d.startIdx,
-            m, g, E, n, A, x, w = s.lineWidth * t.devicePixelRatio / 2;
-        w -= Math.floor(w);
-        u.save();
-        C = this.raiseTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] <= y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore();
-        u.save();
-        C = this.dropTemplate;
-        C.useAttributes(u, z);
-        u.beginPath();
-        for (x = c; x < b; x++) {
-            if (a[x] > y[x]) {
-                m = Math.round(a[x] * r + h) + w;
-                g = Math.round(B[x] * r + h) + w;
-                E = Math.round(p[x] * r + h) + w;
-                n = Math.round(y[x] * r + h) + w;
-                A = Math.round(j[q[x]] * e + l) + w;
-                D[k](u, m, g, E, n, A, f)
-            }
-        }
-        u.fillStroke(C.attr);
-        u.restore()
-    }
-});
-Ext.define("Ext.chart.series.CandleStick", {
-    extend: "Ext.chart.series.Cartesian",
-    requires: ["Ext.chart.series.sprite.CandleStick"],
-    alias: "series.candlestick",
-    type: "candlestick",
-    seriesType: "candlestickSeries",
-    config: {
-        openField: null,
-        highField: null,
-        lowField: null,
-        closeField: null
-    },
-    fieldCategoryY: ["Open", "High", "Low", "Close"],
-    themeColorCount: function() {
-        return 2
-    }
-});
-Ext.define("Ext.chart.series.Polar", {
-    extend: "Ext.chart.series.Series",
-    config: {
-        rotation: 0,
-        radius: null,
-        center: [0, 0],
-        offsetX: 0,
-        offsetY: 0,
-        showInLegend: true,
-        xField: null,
-        yField: null,
-        angleField: null,
-        radiusField: null,
-        xAxis: null,
-        yAxis: null
-    },
-    directions: ["X", "Y"],
-    fieldCategoryX: ["X"],
-    fieldCategoryY: ["Y"],
-    deprecatedConfigs: {
-        field: "angleField",
-        lengthField: "radiusField"
-    },
-    constructor: function(b) {
-        var c = this,
-            a = c.getConfigurator(),
-            e = a.configs,
-            d;
-        if (b) {
-            for (d in c.deprecatedConfigs) {
-                if (d in b && !(b in e)) {
-                    Ext.raise("'" + d + "' config has been deprecated. Please use the '" + c.deprecatedConfigs[d] + "' config instead.")
-                }
-            }
-        }
-        c.callParent([b])
-    },
-    getXField: function() {
-        return this.getAngleField()
-    },
-    updateXField: function(a) {
-        this.setAngleField(a)
-    },
-    getYField: function() {
-        return this.getRadiusField()
-    },
-    updateYField: function(a) {
-        this.setRadiusField(a)
-    },
-    applyXAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    applyYAxis: function(a, b) {
-        return this.getChart().getAxis(a) || b
-    },
-    getXRange: function() {
-        return [this.dataRange[0], this.dataRange[2]]
-    },
-    getYRange: function() {
-        return [this.dataRange[1], this.dataRange[3]]
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b
-    },
-    isStoreDependantColorCount: true,
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            centerX: 0,
-            centerY: 0,
-            rotationCenterX: 0,
-            rotationCenterY: 0
-        }
-    },
-    applyRotation: function(a) {
-        return Ext.draw.sprite.AttributeParser.angle(a)
-    },
-    updateRotation: function(a) {
-        var b = this.getSprites();
-        if (b && b[0]) {
-            b[0].setAttributes({
-                baseRotation: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.Gauge", {
-    alias: "series.gauge",
-    extend: "Ext.chart.series.Polar",
-    type: "gauge",
-    seriesType: "pieslice",
-    requires: ["Ext.draw.sprite.Sector"],
-    config: {
-        needle: false,
-        needleLength: 90,
-        needleWidth: 4,
-        donut: 30,
-        showInLegend: false,
-        value: null,
-        colors: null,
-        sectors: null,
-        minimum: 0,
-        maximum: 100,
-        rotation: 0,
-        totalAngle: Math.PI / 2,
-        rect: [0, 0, 1, 1],
-        center: [0.5, 0.75],
-        radius: 0.5,
-        wholeDisk: false
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateNeedle: function(b) {
-        var a = this,
-            d = a.getSprites(),
-            c = a.valueToAngle(a.getValue());
-        if (d && d.length) {
-            d[0].setAttributes({
-                startAngle: (b ? c : 0),
-                endAngle: c,
-                strokeOpacity: (b ? 1 : 0),
-                lineWidth: (b ? a.getNeedleWidth() : 0)
-            });
-            a.doUpdateStyles()
-        }
-    },
-    themeColorCount: function() {
-        var c = this,
-            a = c.getStore(),
-            b = a && a.getCount() || 0;
-        return b + (c.getNeedle() ? 0 : 1)
-    },
-    updateColors: function(a, b) {
-        var f = this,
-            h = f.getSectors(),
-            j = h && h.length,
-            e = f.getSprites(),
-            c = Ext.Array.clone(a),
-            g = a && a.length,
-            d;
-        if (!g || !a[0]) {
-            return
-        }
-        for (d = 0; d < j; d++) {
-            c[d + 1] = h[d].color || c[d + 1] || a[d % g]
-        }
-        if (e.length) {
-            e[0].setAttributes({
-                strokeStyle: c[0]
-            })
-        }
-        this.setSubStyle({
-            fillStyle: c,
-            strokeStyle: c
-        });
-        this.doUpdateStyles()
-    },
-    updateRect: function(f) {
-        var d = this.getWholeDisk(),
-            c = d ? Math.PI : this.getTotalAngle() / 2,
-            g = this.getDonut() / 100,
-            e, b, a;
-        if (c <= Math.PI / 2) {
-            e = 2 * Math.sin(c);
-            b = 1 - g * Math.cos(c)
-        } else {
-            e = 2;
-            b = 1 - Math.cos(c)
-        }
-        a = Math.min(f[2] / e, f[3] / b);
-        this.setRadius(a);
-        this.setCenter([f[2] / 2, a + (f[3] - b * a) / 2])
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            centerX: a[0],
-            centerY: a[1],
-            rotationCenterX: a[0],
-            rotationCenterY: a[1]
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a - (this.getTotalAngle() + Math.PI) / 2
-        });
-        this.doUpdateStyles()
-    },
-    doUpdateShape: function(b, f) {
-        var a, d = this.getSectors(),
-            c = (d && d.length) || 0,
-            e = this.getNeedleLength() / 100;
-        a = [b * e, b];
-        while (c--) {
-            a.push(b)
-        }
-        this.setSubStyle({
-            endRho: a,
-            startRho: b / 100 * f
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        var b = this.getDonut();
-        this.doUpdateShape(a, b)
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.doUpdateShape(a, b)
-    },
-    valueToAngle: function(a) {
-        a = this.applyValue(a);
-        return this.getTotalAngle() * (a - this.getMinimum()) / (this.getMaximum() - this.getMinimum())
-    },
-    applyValue: function(a) {
-        return Math.min(this.getMaximum(), Math.max(a, this.getMinimum()))
-    },
-    updateValue: function(b) {
-        var a = this,
-            c = a.getNeedle(),
-            e = a.valueToAngle(b),
-            d = a.getSprites();
-        d[0].rendererData.value = b;
-        d[0].setAttributes({
-            startAngle: (c ? e : 0),
-            endAngle: e
-        });
-        a.doUpdateStyles()
-    },
-    processData: function() {
-        var f = this,
-            j = f.getStore(),
-            a, d, h, b, g, e = j && j.first(),
-            c, i;
-        if (e) {
-            c = f.getXField();
-            if (c) {
-                i = e.get(c)
-            }
-        }
-        if (a = f.getXAxis()) {
-            d = a.getMinimum();
-            h = a.getMaximum();
-            b = a.getSprites()[0].fx;
-            g = b.getDuration();
-            b.setDuration(0);
-            if (Ext.isNumber(d)) {
-                f.setMinimum(d)
-            } else {
-                a.setMinimum(f.getMinimum())
-            }
-            if (Ext.isNumber(h)) {
-                f.setMaximum(h)
-            } else {
-                a.setMaximum(f.getMaximum())
-            }
-            b.setDuration(g)
-        }
-        if (!Ext.isNumber(i)) {
-            i = f.getMinimum()
-        }
-        f.setValue(i)
-    },
-    getDefaultSpriteConfig: function() {
-        return {
-            type: this.seriesType,
-            renderer: this.getRenderer(),
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationCenterX: 0,
-                    rotationCenterY: 0,
-                    centerX: 0,
-                    centerY: 0,
-                    startRho: 0,
-                    endRho: 0,
-                    baseRotation: 0
-                }
-            }
-        }
-    },
-    normalizeSectors: function(f) {
-        var d = this,
-            c = (f && f.length) || 0,
-            b, e, g, a;
-        if (c) {
-            for (b = 0; b < c; b++) {
-                e = f[b];
-                if (typeof e === "number") {
-                    f[b] = {
-                        start: (b > 0 ? f[b - 1].end : d.getMinimum()),
-                        end: Math.min(e, d.getMaximum())
-                    };
-                    if (b == (c - 1) && f[b].end < d.getMaximum()) {
-                        f[b + 1] = {
-                            start: f[b].end,
-                            end: d.getMaximum()
-                        }
-                    }
-                } else {
-                    if (typeof e.start === "number") {
-                        g = Math.max(e.start, d.getMinimum())
-                    } else {
-                        g = (b > 0 ? f[b - 1].end : d.getMinimum())
-                    }
-                    if (typeof e.end === "number") {
-                        a = Math.min(e.end, d.getMaximum())
-                    } else {
-                        a = d.getMaximum()
-                    }
-                    f[b].start = g;
-                    f[b].end = a
-                }
-            }
-        } else {
-            f = [{
-                start: d.getMinimum(),
-                end: d.getMaximum()
-            }]
-        }
-        return f
-    },
-    getSprites: function() {
-        var j = this,
-            m = j.getStore(),
-            l = j.getValue(),
-            c, g;
-        if (!m && !Ext.isNumber(l)) {
-            return []
-        }
-        var h = j.getChart(),
-            b = j.getAnimation() || h && h.getAnimation(),
-            f = j.sprites,
-            k = 0,
-            o, n, e, d, a = [];
-        if (f && f.length) {
-            f[0].setAnimation(b);
-            return f
-        }
-        d = {
-            store: m,
-            field: j.getXField(),
-            angleField: j.getXField(),
-            value: l,
-            series: j
-        };
-        o = j.createSprite();
-        o.setAttributes({
-            zIndex: 10
-        }, true);
-        o.rendererData = d;
-        o.rendererIndex = k++;
-        a.push(j.getNeedleWidth());
-        j.getLabel().getTemplate().setField(true);
-        n = j.normalizeSectors(j.getSectors());
-        for (c = 0, g = n.length; c < g; c++) {
-            e = {
-                startAngle: j.valueToAngle(n[c].start),
-                endAngle: j.valueToAngle(n[c].end),
-                label: n[c].label,
-                fillStyle: n[c].color,
-                strokeOpacity: 0,
-                doCallout: false,
-                labelOverflowPadding: -1
-            };
-            Ext.apply(e, n[c].style);
-            o = j.createSprite();
-            o.rendererData = d;
-            o.rendererIndex = k++;
-            o.setAttributes(e, true);
-            a.push(e.lineWidth)
-        }
-        j.setSubStyle({
-            lineWidth: a
-        });
-        j.doUpdateStyles();
-        return f
-    }
-});
-Ext.define("Ext.chart.series.sprite.Line", {
-    alias: "sprite.lineSeries",
-    extend: "Ext.chart.series.sprite.Aggregative",
-    inheritableStatics: {
-        def: {
-            processors: {
-                smooth: "bool",
-                fillArea: "bool",
-                step: "bool",
-                preciseStroke: "bool",
-                xAxis: "default",
-                yCap: "default"
-            },
-            defaults: {
-                smooth: false,
-                fillArea: false,
-                step: false,
-                preciseStroke: true,
-                xAxis: null,
-                yCap: Math.pow(2, 20),
-                yJump: 50
-            },
-            triggers: {
-                dataX: "dataX,bbox,smooth",
-                dataY: "dataY,bbox,smooth",
-                smooth: "smooth"
-            },
-            updaters: {
-                smooth: function(a) {
-                    var c = a.dataX,
-                        b = a.dataY;
-                    if (a.smooth && c && b && c.length > 2 && b.length > 2) {
-                        this.smoothX = Ext.draw.Draw.spline(c);
-                        this.smoothY = Ext.draw.Draw.spline(b)
-                    } else {
-                        delete this.smoothX;
-                        delete this.smoothY
-                    }
-                }
-            }
-        }
-    },
-    list: null,
-    updatePlainBBox: function(d) {
-        var b = this.attr,
-            c = Math.min(0, b.dataMinY),
-            a = Math.max(0, b.dataMaxY);
-        d.x = b.dataMinX;
-        d.y = c;
-        d.width = b.dataMaxX - b.dataMinX;
-        d.height = a - c
-    },
-    drawStrip: function(a, c) {
-        a.moveTo(c[0], c[1]);
-        for (var b = 2, d = c.length; b < d; b += 2) {
-            a.lineTo(c[b], c[b + 1])
-        }
-    },
-    drawStraightStroke: function(p, q, e, d, u, h) {
-        var w = this,
-            o = w.attr,
-            n = o.renderer,
-            g = o.step,
-            a = true,
-            l = {
-                type: "line",
-                smooth: false,
-                step: g
-            },
-            m = [],
-            l, z, v, f, k, j, t, c, s, b, r;
-        for (r = 3; r < u.length; r += 3) {
-            t = u[r - 3];
-            c = u[r - 2];
-            k = u[r];
-            j = u[r + 1];
-            s = u[r + 3];
-            b = u[r + 4];
-            if (n) {
-                l.x = k;
-                l.y = j;
-                l.x0 = t;
-                l.y0 = c;
-                v = [w, l, w.rendererData, e + r / 3];
-                z = Ext.callback(n, null, v, 0, w.getSeries())
-            }
-            if (Ext.isNumber(k + j + t + c)) {
-                if (a) {
-                    q.beginPath();
-                    q.moveTo(t, c);
-                    m.push(t, c);
-                    f = t;
-                    a = false
-                }
-            } else {
-                continue
-            }
-            if (g) {
-                q.lineTo(k, c);
-                m.push(k, c)
-            }
-            q.lineTo(k, j);
-            m.push(k, j);
-            if (z || !(Ext.isNumber(s + b))) {
-                q.save();
-                Ext.apply(q, z);
-                if (o.fillArea) {
-                    q.lineTo(k, h);
-                    q.lineTo(f, h);
-                    q.closePath();
-                    q.fill()
-                }
-                q.beginPath();
-                w.drawStrip(q, m);
-                m = [];
-                q.stroke();
-                q.restore();
-                q.beginPath();
-                a = true
-            }
-        }
-    },
-    calculateScale: function(c, a) {
-        var b = 0,
-            d = c;
-        while (d < a && c > 0) {
-            b++;
-            d += c >> b
-        }
-        return Math.pow(2, b > 0 ? b - 1 : b)
-    },
-    drawSmoothStroke: function(u, v, c, b, C, f) {
-        var G = this,
-            t = G.attr,
-            d = t.step,
-            z = t.matrix,
-            s = t.renderer,
-            e = z.getXX(),
-            p = z.getYY(),
-            m = z.getDX(),
-            k = z.getDY(),
-            r = G.smoothX,
-            q = G.smoothY,
-            I = G.calculateScale(t.dataX.length, b),
-            o, F, n, E, h, g, B, a, A, w, H, D, l = {
-                type: "line",
-                smooth: true,
-                step: d
-            };
-        v.beginPath();
-        v.moveTo(r[c * 3] * e + m, q[c * 3] * p + k);
-        for (A = 0, w = c * 3 + 1; A < C.length - 3; A += 3, w += 3 * I) {
-            o = r[w] * e + m;
-            F = q[w] * p + k;
-            n = r[w + 1] * e + m;
-            E = q[w + 1] * p + k;
-            h = u.roundPixel(C[A + 3]);
-            g = C[A + 4];
-            B = u.roundPixel(C[A]);
-            a = C[A + 1];
-            if (s) {
-                l.x0 = B;
-                l.y0 = a;
-                l.cx1 = o;
-                l.cy1 = F;
-                l.cx2 = n;
-                l.cy2 = E;
-                l.x = h;
-                l.y = g;
-                D = [G, l, G.rendererData, c + A / 3 + 1];
-                H = Ext.callback(s, null, D, 0, G.getSeries());
-                v.save();
-                Ext.apply(v, H)
-            }
-            if (t.fillArea) {
-                v.moveTo(B, a);
-                v.bezierCurveTo(o, F, n, E, h, g);
-                v.lineTo(h, f);
-                v.lineTo(B, f);
-                v.lineTo(B, a);
-                v.closePath();
-                v.fill();
-                v.beginPath()
-            }
-            v.moveTo(B, a);
-            v.bezierCurveTo(o, F, n, E, h, g);
-            v.stroke();
-            v.moveTo(B, a);
-            v.closePath();
-            if (s) {
-                v.restore()
-            }
-            v.beginPath();
-            v.moveTo(h, g)
-        }
-        v.beginPath()
-    },
-    drawLabel: function(k, i, h, o, a) {
-        var q = this,
-            n = q.attr,
-            e = q.getMarker("labels"),
-            d = e.getTemplate(),
-            m = q.labelCfg || (q.labelCfg = {}),
-            c = q.surfaceMatrix,
-            g, f, j = n.labelOverflowPadding,
-            l, b, r, p, s;
-        m.x = c.x(i, h);
-        m.y = c.y(i, h);
-        if (n.flipXY) {
-            m.rotationRads = Math.PI * 0.5
-        } else {
-            m.rotationRads = 0
-        }
-        m.text = k;
-        if (d.attr.renderer) {
-            p = [k, e, m, q.rendererData, o];
-            r = Ext.callback(d.attr.renderer, null, p, 0, q.getSeries());
-            if (typeof r === "string") {
-                m.text = r
-            } else {
-                if (typeof r === "object") {
-                    if ("text" in r) {
-                        m.text = r.text
-                    }
-                    s = true
-                }
-            }
-        }
-        b = q.getMarkerBBox("labels", o, true);
-        if (!b) {
-            q.putMarker("labels", m, o);
-            b = q.getMarkerBBox("labels", o, true)
-        }
-        l = b.height / 2;
-        g = i;
-        switch (d.attr.display) {
-            case "under":
-                f = h - l - j;
-                break;
-            case "rotate":
-                g += j;
-                f = h - j;
-                m.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                f = h + l + j
-        }
-        m.x = c.x(g, f);
-        m.y = c.y(g, f);
-        if (s) {
-            Ext.apply(m, r)
-        }
-        q.putMarker("labels", m, o)
-    },
-    drawMarker: function(j, h, d) {
-        var g = this,
-            e = g.attr,
-            f = e.renderer,
-            c = g.surfaceMatrix,
-            b = {},
-            i, a;
-        if (f && g.getMarker("markers")) {
-            b.type = "marker";
-            b.x = j;
-            b.y = h;
-            a = [g, b, g.rendererData, d];
-            i = Ext.callback(f, null, a, 0, g.getSeries());
-            if (i) {
-                Ext.apply(b, i)
-            }
-        }
-        b.translationX = c.x(j, h);
-        b.translationY = c.y(j, h);
-        delete b.x;
-        delete b.y;
-        g.putMarker("markers", b, d, !f)
-    },
-    drawStroke: function(a, c, h, b, f, e) {
-        var d = this,
-            g = d.attr.smooth && d.smoothX && d.smoothY;
-        if (g) {
-            d.drawSmoothStroke(a, c, h, b, f, e)
-        } else {
-            d.drawStraightStroke(a, c, h, b, f, e)
-        }
-    },
-    renderAggregates: function(B, w, l, N, o, I, D) {
-        var m = this,
-            k = m.attr,
-            s = k.dataX,
-            r = k.dataY,
-            h = k.labels,
-            v = k.xAxis,
-            a = k.yCap,
-            g = k.smooth && m.smoothX && m.smoothY,
-            d = h && m.getMarker("labels"),
-            t = m.getMarker("markers"),
-            E = k.matrix,
-            u = N.devicePixelRatio,
-            C = E.getXX(),
-            f = E.getYY(),
-            c = E.getDX(),
-            b = E.getDY(),
-            q = m.list || (m.list = []),
-            F = B.minX,
-            e = B.maxX,
-            j = B.minY,
-            P = B.maxY,
-            U = B.startIdx,
-            S = true,
-            Q, T, L, K, R, G;
-        m.rendererData = {
-            store: m.getStore()
-        };
-        q.length = 0;
-        for (R = w; R < l; R++) {
-            var O = F[R],
-                p = e[R],
-                M = j[R],
-                n = P[R];
-            if (O < p) {
-                q.push(O * C + c, M * f + b, U[R]);
-                q.push(p * C + c, n * f + b, U[R])
-            } else {
-                if (O > p) {
-                    q.push(p * C + c, n * f + b, U[R]);
-                    q.push(O * C + c, M * f + b, U[R])
-                } else {
-                    q.push(p * C + c, n * f + b, U[R])
-                }
-            }
-        }
-        if (q.length) {
-            for (R = 0; R < q.length; R += 3) {
-                L = q[R];
-                K = q[R + 1];
-                if (Ext.isNumber(L + K)) {
-                    if (K > a) {
-                        K = a
-                    } else {
-                        if (K < -a) {
-                            K = -a
-                        }
-                    }
-                    q[R + 1] = K
-                } else {
-                    S = false;
-                    continue
-                }
-                G = q[R + 2];
-                if (t) {
-                    m.drawMarker(L, K, G)
-                }
-                if (d && h[G]) {
-                    m.drawLabel(h[G], L, K, G, D)
-                }
-            }
-            m.isContinuousLine = S;
-            if (g && !S) {
-                Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")
-            }
-            if (v) {
-                T = v.getAlignment() === "vertical";
-                if (Ext.isNumber(v.floatingAtCoord)) {
-                    Q = (T ? D[2] : D[3]) - v.floatingAtCoord
-                } else {
-                    Q = T ? D[0] : D[1]
-                }
-            } else {
-                Q = k.flipXY ? D[0] : D[1]
-            }
-            if (k.preciseStroke) {
-                if (k.fillArea) {
-                    o.fill()
-                }
-                if (k.transformFillStroke) {
-                    k.inverseMatrix.toContext(o)
-                }
-                m.drawStroke(N, o, w, l, q, Q);
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                o.stroke()
-            } else {
-                m.drawStroke(N, o, w, l, q, Q);
-                if (S && g && k.fillArea && !k.renderer) {
-                    var A = s[s.length - 1] * C + c + u,
-                        z = r[r.length - 1] * f + b,
-                        J = s[0] * C + c - u,
-                        H = r[0] * f + b;
-                    o.lineTo(A, z);
-                    o.lineTo(A, Q - k.lineWidth);
-                    o.lineTo(J, Q - k.lineWidth);
-                    o.lineTo(J, H)
-                }
-                if (k.transformFillStroke) {
-                    k.matrix.toContext(o)
-                }
-                if (k.fillArea) {
-                    o.fillStroke(k, true)
-                } else {
-                    o.stroke(true)
-                }
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.Line", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.line",
-    type: "line",
-    seriesType: "lineSeries",
-    requires: ["Ext.chart.series.sprite.Line"],
-    config: {
-        selectionTolerance: 20,
-        smooth: false,
-        step: false,
-        fill: undefined,
-        aggregator: {
-            strategy: "double"
-        }
-    },
-    defaultSmoothness: 3,
-    overflowBuffer: 1,
-    themeMarkerCount: function() {
-        return 1
-    },
-    getDefaultSpriteConfig: function() {
-        var d = this,
-            e = d.callParent(arguments),
-            c = Ext.apply({}, d.getStyle()),
-            b, a = false;
-        if (typeof d.config.fill != "undefined") {
-            if (d.config.fill) {
-                a = true;
-                if (typeof c.fillStyle == "undefined") {
-                    if (typeof c.strokeStyle == "undefined") {
-                        b = d.getStyleWithTheme();
-                        c.fillStyle = b.fillStyle;
-                        c.strokeStyle = b.strokeStyle
-                    } else {
-                        c.fillStyle = c.strokeStyle
-                    }
-                }
-            }
-        } else {
-            if (c.fillStyle) {
-                a = true
-            }
-        }
-        if (!a) {
-            delete c.fillStyle
-        }
-        c = Ext.apply(e || {}, c);
-        return Ext.apply(c, {
-            fillArea: a,
-            step: d.config.step,
-            smooth: d.config.smooth,
-            selectionTolerance: d.config.selectionTolerance
-        })
-    },
-    updateStep: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.step !== b) {
-            a.setAttributes({
-                step: b
-            })
-        }
-    },
-    updateFill: function(b) {
-        var a = this.getSprites()[0];
-        if (a && a.attr.fillArea !== b) {
-            a.setAttributes({
-                fillArea: b
-            })
-        }
-    },
-    updateSmooth: function(a) {
-        var b = this.getSprites()[0];
-        if (b && b.attr.smooth !== a) {
-            b.setAttributes({
-                smooth: a
-            })
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.PieSlice", {
-    extend: "Ext.draw.sprite.Sector",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pieslice",
-    inheritableStatics: {
-        def: {
-            processors: {
-                doCallout: "bool",
-                label: "string",
-                rotateLabels: "bool",
-                labelOverflowPadding: "number",
-                renderer: "default"
-            },
-            defaults: {
-                doCallout: true,
-                rotateLabels: true,
-                label: "",
-                labelOverflowPadding: 10,
-                renderer: null
-            }
-        }
-    },
-    config: {
-        rendererData: null,
-        rendererIndex: 0,
-        series: null
-    },
-    setGradientBBox: function(q, k) {
-        var j = this,
-            i = j.attr,
-            g = (i.fillStyle && i.fillStyle.isGradient) || (i.strokeStyle && i.strokeStyle.isGradient);
-        if (g && !i.constrainGradients) {
-            var b = j.getMidAngle(),
-                d = i.margin,
-                e = i.centerX,
-                c = i.centerY,
-                a = i.endRho,
-                l = i.matrix,
-                o = l.getScaleX(),
-                n = l.getScaleY(),
-                m = o * a,
-                f = n * a,
-                p = {
-                    width: m + m,
-                    height: f + f
-                };
-            if (d) {
-                e += d * Math.cos(b);
-                c += d * Math.sin(b)
-            }
-            p.x = l.x(e, c) - m;
-            p.y = l.y(e, c) - f;
-            q.setGradientBBox(p)
-        } else {
-            j.callParent([q, k])
-        }
-    },
-    render: function(b, c, g, f) {
-        var e = this,
-            a = e.attr,
-            h = {},
-            d;
-        if (a.renderer) {
-            h = {
-                type: "sector",
-                text: a.text,
-                centerX: a.centerX,
-                centerY: a.centerY,
-                margin: a.margin,
-                startAngle: Math.min(a.startAngle, a.endAngle),
-                endAngle: Math.max(a.startAngle, a.endAngle),
-                startRho: Math.min(a.startRho, a.endRho),
-                endRho: Math.max(a.startRho, a.endRho)
-            };
-            d = Ext.callback(a.renderer, null, [e, h, e.rendererData, e.rendererIndex], 0, e.getSeries());
-            e.setAttributes(d);
-            e.useAttributes(c, g)
-        }
-        e.callParent([b, c, g, f]);
-        if (a.label && e.getMarker("labels")) {
-            e.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            s = z.attr,
-            r = s.attributeId,
-            t = Math.min(s.startAngle, s.endAngle),
-            p = Math.max(s.startAngle, s.endAngle),
-            k = (t + p) * 0.5,
-            n = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            f = Math.sin(k),
-            c = Math.cos(k),
-            v = Math.min(s.startRho, s.endRho) + n,
-            m = Math.max(s.startRho, s.endRho) + n,
-            l = (v + m) * 0.5,
-            b = z.surfaceMatrix,
-            o = z.labelCfg || (z.labelCfg = {}),
-            e = z.getMarker("labels"),
-            d = e.getTemplate(),
-            a = d.getCalloutLine(),
-            q = a && a.length || 40,
-            u, j, i, A, w;
-        b.appendMatrix(s.matrix);
-        o.text = s.label;
-        j = h + c * l;
-        i = g + f * l;
-        o.x = b.x(j, i);
-        o.y = b.y(j, i);
-        j = h + c * m;
-        i = g + f * m;
-        o.calloutStartX = b.x(j, i);
-        o.calloutStartY = b.y(j, i);
-        j = h + c * (m + q);
-        i = g + f * (m + q);
-        o.calloutPlaceX = b.x(j, i);
-        o.calloutPlaceY = b.y(j, i);
-        if (!s.rotateLabels) {
-            o.rotationRads = 0
-        } else {
-            switch (d.attr.orientation) {
-                case "horizontal":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0)) + Math.PI / 2;
-                    break;
-                case "vertical":
-                    o.rotationRads = k + Math.atan2(b.y(1, 0) - b.y(0, 0), b.x(1, 0) - b.x(0, 0));
-                    break
-            }
-        }
-        o.calloutColor = (a && a.color) || z.attr.fillStyle;
-        if (a) {
-            if (a.width) {
-                o.calloutWidth = a.width
-            }
-        } else {
-            o.calloutHasLine = false
-        }
-        o.globalAlpha = s.globalAlpha * s.fillOpacity;
-        o.hidden = (s.startAngle == s.endAngle);
-        if (d.attr.renderer) {
-            w = [z.attr.label, e, o, z.rendererData, z.rendererIndex];
-            A = Ext.callback(d.attr.renderer, null, w, 0, z.getSeries());
-            if (typeof A === "string") {
-                o.text = A
-            } else {
-                Ext.apply(o, A)
-            }
-        }
-        z.putMarker("labels", o, r);
-        u = z.getMarkerBBox("labels", r, true);
-        if (u) {
-            if (s.doCallout) {
-                if (d.attr.display === "outside") {
-                    z.putMarker("labels", {
-                        callout: 1
-                    }, r)
-                } else {
-                    if (d.attr.display === "inside") {
-                        z.putMarker("labels", {
-                            callout: 0
-                        }, r)
-                    } else {
-                        z.putMarker("labels", {
-                            callout: 1 - z.sliceContainsLabel(s, u)
-                        }, r)
-                    }
-                }
-            } else {
-                z.putMarker("labels", {
-                    globalAlpha: z.sliceContainsLabel(s, u)
-                }, r)
-            }
-        }
-    },
-    sliceContainsLabel: function(d, f) {
-        var e = d.labelOverflowPadding,
-            h = (d.endRho + d.startRho) / 2,
-            g = h + (f.width + e) / 2,
-            i = h - (f.width + e) / 2,
-            j, c, b, a;
-        if (e < 0) {
-            return 1
-        }
-        if (f.width + e * 2 > (d.endRho - d.startRho)) {
-            return 0
-        }
-        c = Math.sqrt(d.endRho * d.endRho - g * g);
-        b = Math.sqrt(d.endRho * d.endRho - i * i);
-        j = Math.abs(d.endAngle - d.startAngle);
-        a = (j > Math.PI / 2 ? i : Math.abs(Math.tan(j / 2)) * i);
-        if (f.height + e * 2 > Math.min(c, b, a) * 2) {
-            return 0
-        }
-        return 1
-    }
-});
-Ext.define("Ext.chart.series.Pie", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.PieSlice"],
-    type: "pie",
-    alias: "series.pie",
-    seriesType: "pieslice",
-    config: {
-        donut: 0,
-        rotation: 0,
-        clockwise: true,
-        totalAngle: 2 * Math.PI,
-        hidden: [],
-        radiusFactor: 100,
-        highlightCfg: {
-            margin: 20
-        },
-        style: {}
-    },
-    directions: ["X"],
-    applyLabel: function(a, b) {
-        if (Ext.isObject(a) && !Ext.isString(a.orientation)) {
-            Ext.apply(a = Ext.Object.chain(a), {
-                orientation: "vertical"
-            })
-        }
-        return this.callParent([a, b])
-    },
-    updateLabelData: function() {
-        var h = this,
-            j = h.getStore(),
-            g = j.getData().items,
-            e = h.getSprites(),
-            a = h.getLabel().getTemplate().getField(),
-            d = h.getHidden(),
-            b, f, c, k;
-        if (e.length && a) {
-            c = [];
-            for (b = 0, f = g.length; b < f; b++) {
-                c.push(g[b].get(a))
-            }
-            for (b = 0, f = e.length; b < f; b++) {
-                k = e[b];
-                k.setAttributes({
-                    label: c[b]
-                });
-                k.putMarker("labels", {
-                    hidden: d[b]
-                }, k.attr.attributeId)
-            }
-        }
-    },
-    coordinateX: function() {
-        var t = this,
-            f = t.getStore(),
-            q = f.getData().items,
-            c = q.length,
-            b = t.getXField(),
-            e = t.getYField(),
-            l, a = 0,
-            m, k, s = 0,
-            o = t.getHidden(),
-            d = [],
-            p, g = 0,
-            h = t.getTotalAngle(),
-            r = t.getClockwise() ? 1 : -1,
-            j = t.getSprites(),
-            n;
-        if (!j) {
-            return
-        }
-        for (p = 0; p < c; p++) {
-            l = Math.abs(Number(q[p].get(b))) || 0;
-            k = e && Math.abs(Number(q[p].get(e))) || 0;
-            if (!o[p]) {
-                a += l;
-                if (k > s) {
-                    s = k
-                }
-            }
-            d[p] = a;
-            if (p >= o.length) {
-                o[p] = false
-            }
-        }
-        o.length = c;
-        t.maxY = s;
-        if (a !== 0) {
-            m = h / a
-        }
-        for (p = 0; p < c; p++) {
-            j[p].setAttributes({
-                startAngle: g,
-                endAngle: g = (m ? r * d[p] * m : 0),
-                globalAlpha: 1
-            })
-        }
-        if (c < t.sprites.length) {
-            for (p = c; p < t.sprites.length; p++) {
-                n = t.sprites[p];
-                n.getMarker("labels").clear(n.getId());
-                n.releaseMarker("labels");
-                n.destroy()
-            }
-            t.sprites.length = c
-        }
-        for (p = c; p < t.sprites.length; p++) {
-            j[p].setAttributes({
-                startAngle: h,
-                endAngle: h,
-                globalAlpha: 0
-            })
-        }
-        t.getChart().refreshLegendStore()
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            startRho: a * this.getDonut() * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    getStyleByIndex: function(c) {
-        var g = this,
-            j = g.getStore(),
-            k = j.getAt(c),
-            f = g.getYField(),
-            d = g.getRadius(),
-            a = {},
-            e, b, h;
-        if (k) {
-            h = f && Math.abs(Number(k.get(f))) || 0;
-            e = d * g.getDonut() * 0.01;
-            b = d * g.getRadiusFactor() * 0.01;
-            a = g.callParent([c]);
-            a.startRho = e;
-            a.endRho = g.maxY ? (e + (b - e) * h / g.maxY) : b
-        }
-        return a
-    },
-    updateDonut: function(b) {
-        var a = this.getRadius();
-        this.setStyle({
-            startRho: a * b * 0.01,
-            endRho: a * this.getRadiusFactor() * 0.01
-        });
-        this.doUpdateStyles()
-    },
-    rotationOffset: -Math.PI / 2,
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getSprites: function() {
-        var k = this,
-            h = k.getChart(),
-            n = k.getStore();
-        if (!h || !n) {
-            return []
-        }
-        k.getColors();
-        k.getSubStyle();
-        var j = n.getData().items,
-            b = j.length,
-            d = k.getAnimation() || h && h.getAnimation(),
-            g = k.sprites,
-            o, l = 0,
-            f, e, c = false,
-            m = k.getLabel(),
-            a = m.getTemplate();
-        f = {
-            store: n,
-            field: k.getXField(),
-            angleField: k.getXField(),
-            radiusField: k.getYField(),
-            series: k
-        };
-        for (e = 0; e < b; e++) {
-            o = g[e];
-            if (!o) {
-                o = k.createSprite();
-                if (k.getHighlight()) {
-                    o.config.highlight = k.getHighlight();
-                    o.addModifier("highlight", true)
-                }
-                if (a.getField()) {
-                    a.setAttributes({
-                        labelOverflowPadding: k.getLabelOverflowPadding()
-                    });
-                    a.fx.setCustomDurations({
-                        callout: 200
-                    })
-                }
-                o.setAttributes(k.getStyleByIndex(e));
-                o.rendererData = f;
-                o.rendererIndex = l++;
-                c = true
-            }
-            o.setAnimation(d)
-        }
-        if (c) {
-            k.doUpdateStyles()
-        }
-        return k.sprites
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        if (!this.getClockwise()) {
-            d *= -1;
-            f *= -1;
-            c *= -1;
-            f -= g;
-            c -= g
-        } else {
-            f += g;
-            c += g
-        }
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForAngle: function(a) {
-        var h = this,
-            f = h.getSprites(),
-            d;
-        a %= Math.PI * 2;
-        while (a < 0) {
-            a += Math.PI * 2
-        }
-        if (f) {
-            var j = h.getStore(),
-                g = j.getData().items,
-                c = h.getHidden(),
-                b = 0,
-                e = j.getCount();
-            for (; b < e; b++) {
-                if (!c[b]) {
-                    d = f[b].attr;
-                    if (d.startAngle <= a && d.endAngle >= a) {
-                        return {
-                            series: h,
-                            sprite: f[b],
-                            index: b,
-                            record: g[b],
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-        }
-        return null
-    },
-    getItemForPoint: function(f, e) {
-        var t = this,
-            c = t.getSprites();
-        if (c) {
-            var s = t.getCenter(),
-                q = t.getOffsetX(),
-                p = t.getOffsetY(),
-                j = f - s[0] + q,
-                h = e - s[1] + p,
-                b = t.getStore(),
-                g = t.getDonut(),
-                o = b.getData().items,
-                r = Math.atan2(h, j) - t.getRotation(),
-                a = Math.sqrt(j * j + h * h),
-                l = t.getRadius() * g * 0.01,
-                m = t.getHidden(),
-                n, d, k;
-            for (n = 0, d = o.length; n < d; n++) {
-                if (!m[n]) {
-                    k = c[n].attr;
-                    if (a >= l + k.margin && a <= k.endRho + k.margin) {
-                        if (t.betweenAngle(r, k.startAngle, k.endAngle)) {
-                            return {
-                                series: t,
-                                sprite: c[n],
-                                index: n,
-                                record: o[n],
-                                field: t.getXField()
-                            }
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            j = h.getStore();
-        if (j) {
-            var g = j.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                c = h.getXField(),
-                e = h.getHidden(),
-                d, a, k;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                k = a.fillStyle;
-                if (Ext.isObject(k)) {
-                    k = k.stops && k.stops[0].color
-                }
-                f.push({
-                    name: b ? String(g[d].get(b)) : c + " " + d,
-                    mark: k || a.strokeStyle || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.series.sprite.Pie3DPart", {
-    extend: "Ext.draw.sprite.Path",
-    mixins: {
-        markerHolder: "Ext.chart.MarkerHolder"
-    },
-    alias: "sprite.pie3dPart",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                margin: "number",
-                thickness: "number",
-                bevelWidth: "number",
-                distortion: "number",
-                baseColor: "color",
-                colorSpread: "number",
-                baseRotation: "number",
-                part: "enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",
-                label: "string"
-            },
-            aliases: {
-                rho: "endRho"
-            },
-            triggers: {
-                centerX: "path,bbox",
-                centerY: "path,bbox",
-                startAngle: "path,partZIndex",
-                endAngle: "path,partZIndex",
-                startRho: "path",
-                endRho: "path,bbox",
-                margin: "path,bbox",
-                thickness: "path",
-                distortion: "path",
-                baseRotation: "path,partZIndex",
-                baseColor: "partZIndex,partColor",
-                colorSpread: "partColor",
-                part: "path,partZIndex",
-                globalAlpha: "canvas,alpha"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: Math.PI * 2,
-                endAngle: Math.PI * 2,
-                startRho: 0,
-                endRho: 150,
-                margin: 0,
-                thickness: 35,
-                distortion: 0.5,
-                baseRotation: 0,
-                baseColor: "white",
-                colorSpread: 1,
-                miterLimit: 1,
-                bevelWidth: 5,
-                strokeOpacity: 0,
-                part: "top",
-                label: ""
-            },
-            updaters: {
-                alpha: "alphaUpdater",
-                partColor: "partColorUpdater",
-                partZIndex: "partZIndexUpdater"
-            }
-        }
-    },
-    bevelParams: [],
-    constructor: function(a) {
-        this.callParent([a]);
-        this.bevelGradient = new Ext.draw.gradient.Linear({
-            stops: [{
-                offset: 0,
-                color: "rgba(255,255,255,0)"
-            }, {
-                offset: 0.7,
-                color: "rgba(255,255,255,0.6)"
-            }, {
-                offset: 1,
-                color: "rgba(255,255,255,0)"
-            }]
-        })
-    },
-    alphaUpdater: function(a) {
-        var d = this,
-            c = a.globalAlpha,
-            b = d.oldOpacity;
-        if (c !== b && (c === 1 || b === 1)) {
-            d.scheduleUpdater(a, "path", ["globalAlpha"]);
-            d.oldOpacity = c
-        }
-    },
-    partColorUpdater: function(a) {
-        var d = Ext.draw.Color.fly(a.baseColor),
-            b = d.toString(),
-            e = a.colorSpread,
-            c;
-        switch (a.part) {
-            case "top":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createLighter(0.1 * e)
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e)
-                    }]
-                });
-                break;
-            case "bottom":
-                c = new Ext.draw.gradient.Radial({
-                    start: {
-                        x: 0,
-                        y: 0,
-                        r: 0
-                    },
-                    end: {
-                        x: 0,
-                        y: 0,
-                        r: 1
-                    },
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.2 * e)
-                    }, {
-                        offset: 1,
-                        color: d.toString()
-                    }]
-                });
-                break;
-            case "outerFront":
-            case "outerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.15 * e).toString()
-                    }, {
-                        offset: 0.3,
-                        color: b
-                    }, {
-                        offset: 0.8,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.25 * e).toString()
-                    }]
-                });
-                break;
-            case "start":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "end":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 1,
-                        color: d.createLighter(0.2 * e).toString()
-                    }]
-                });
-                break;
-            case "innerFront":
-            case "innerBack":
-                c = new Ext.draw.gradient.Linear({
-                    stops: [{
-                        offset: 0,
-                        color: d.createDarker(0.1 * e).toString()
-                    }, {
-                        offset: 0.2,
-                        color: d.createLighter(0.2 * e).toString()
-                    }, {
-                        offset: 0.7,
-                        color: b
-                    }, {
-                        offset: 1,
-                        color: d.createDarker(0.1 * e).toString()
-                    }]
-                });
-                break
-        }
-        a.fillStyle = c;
-        a.canvasAttributes.fillStyle = c
-    },
-    partZIndexUpdater: function(a) {
-        var c = Ext.draw.sprite.AttributeParser.angle,
-            e = a.baseRotation,
-            d = a.startAngle,
-            b = a.endAngle,
-            f;
-        switch (a.part) {
-            case "top":
-                a.zIndex = 5;
-                break;
-            case "outerFront":
-                d = c(d + e);
-                b = c(b + e);
-                if (d >= 0 && b < 0) {
-                    f = Math.sin(d)
-                } else {
-                    if (d <= 0 && b > 0) {
-                        f = Math.sin(b)
-                    } else {
-                        if (d >= 0 && b > 0) {
-                            if (d > b) {
-                                f = 0
-                            } else {
-                                f = Math.max(Math.sin(d), Math.sin(b))
-                            }
-                        } else {
-                            f = 1
-                        }
-                    }
-                }
-                a.zIndex = 4 + f;
-                break;
-            case "outerBack":
-                a.zIndex = 1;
-                break;
-            case "start":
-                a.zIndex = 4 + Math.sin(c(d + e));
-                break;
-            case "end":
-                a.zIndex = 4 + Math.sin(c(b + e));
-                break;
-            case "innerFront":
-                a.zIndex = 2;
-                break;
-            case "innerBack":
-                a.zIndex = 4 + Math.sin(c((d + b) / 2 + e));
-                break;
-            case "bottom":
-                a.zIndex = 0;
-                break
-        }
-        a.dirtyZIndex = true
-    },
-    updatePlainBBox: function(k) {
-        var f = this.attr,
-            a = f.part,
-            b = f.baseRotation,
-            e = f.centerX,
-            d = f.centerY,
-            j, c, i, h, g, l;
-        if (a === "start") {
-            c = f.startAngle + b
-        } else {
-            if (a === "end") {
-                c = f.endAngle + b
-            }
-        }
-        if (Ext.isNumber(c)) {
-            g = Math.sin(c);
-            l = Math.cos(c);
-            i = Math.min(e + l * f.startRho, e + l * f.endRho);
-            h = d + g * f.startRho * f.distortion;
-            k.x = i;
-            k.y = h;
-            k.width = l * (f.endRho - f.startRho);
-            k.height = f.thickness + g * (f.endRho - f.startRho) * 2;
-            return
-        }
-        if (a === "innerFront" || a === "innerBack") {
-            j = f.startRho
-        } else {
-            j = f.endRho
-        }
-        k.width = j * 2;
-        k.height = j * f.distortion * 2 + f.thickness;
-        k.x = f.centerX - j;
-        k.y = f.centerY - j * f.distortion
-    },
-    updateTransformedBBox: function(a) {
-        if (this.attr.part === "start" || this.attr.part === "end") {
-            return this.callParent(arguments)
-        }
-        return this.updatePlainBBox(a)
-    },
-    updatePath: function(a) {
-        if (!this.attr.globalAlpha) {
-            return
-        }
-        if (this.attr.endAngle < this.attr.startAngle) {
-            return
-        }
-        this[this.attr.part + "Renderer"](a)
-    },
-    render: function(b, c) {
-        var d = this,
-            a = d.attr;
-        if (!a.globalAlpha) {
-            return
-        }
-        d.callParent([b, c]);
-        d.bevelRenderer(b, c);
-        if (a.label && d.getMarker("labels")) {
-            d.placeLabel()
-        }
-    },
-    placeLabel: function() {
-        var z = this,
-            u = z.attr,
-            t = u.attributeId,
-            p = u.margin,
-            c = u.distortion,
-            i = u.centerX,
-            h = u.centerY,
-            j = u.baseRotation,
-            v = u.startAngle + j,
-            r = u.endAngle + j,
-            m = (v + r) / 2,
-            w = u.startRho + p,
-            o = u.endRho + p,
-            n = (w + o) / 2,
-            a = Math.sin(m),
-            b = Math.cos(m),
-            e = z.surfaceMatrix,
-            g = z.getMarker("labels"),
-            f = g.getTemplate(),
-            d = f.getCalloutLine(),
-            s = d && d.length || 40,
-            q = {},
-            l, k;
-        e.appendMatrix(u.matrix);
-        q.text = u.label;
-        l = i + b * n;
-        k = h + a * n * c;
-        q.x = e.x(l, k);
-        q.y = e.y(l, k);
-        l = i + b * o;
-        k = h + a * o * c;
-        q.calloutStartX = e.x(l, k);
-        q.calloutStartY = e.y(l, k);
-        l = i + b * (o + s);
-        k = h + a * (o + s) * c;
-        q.calloutPlaceX = e.x(l, k);
-        q.calloutPlaceY = e.y(l, k);
-        q.calloutWidth = 2;
-        z.putMarker("labels", q, t);
-        z.putMarker("labels", {
-            callout: 1
-        }, t)
-    },
-    bevelRenderer: function(b, c) {
-        var f = this,
-            a = f.attr,
-            e = a.bevelWidth,
-            g = f.bevelParams,
-            d;
-        for (d = 0; d < g.length; d++) {
-            c.beginPath();
-            c.ellipse.apply(c, g[d]);
-            c.save();
-            c.lineWidth = e;
-            c.strokeOpacity = e ? 1 : 0;
-            c.strokeGradient = f.bevelGradient;
-            c.stroke(a);
-            c.restore()
-        }
-    },
-    lidRenderer: function(o, m) {
-        var k = this.attr,
-            g = k.margin,
-            c = k.distortion,
-            i = k.centerX,
-            h = k.centerY,
-            f = k.baseRotation,
-            j = k.startAngle + f,
-            e = k.endAngle + f,
-            d = (j + e) / 2,
-            l = k.startRho,
-            b = k.endRho,
-            n = Math.sin(e),
-            a = Math.cos(e);
-        i += Math.cos(d) * g;
-        h += Math.sin(d) * g * c;
-        o.ellipse(i, h + m, l, l * c, 0, j, e, false);
-        o.lineTo(i + a * b, h + m + n * b * c);
-        o.ellipse(i, h + m, b, b * c, 0, e, j, true);
-        o.closePath()
-    },
-    topRenderer: function(a) {
-        this.lidRenderer(a, 0)
-    },
-    bottomRenderer: function(b) {
-        var a = this.attr;
-        if (a.globalAlpha < 1 || a.shadowColor !== Ext.draw.Color.RGBA_NONE) {
-            this.lidRenderer(b, a.thickness)
-        }
-    },
-    sideRenderer: function(l, s) {
-        var o = this.attr,
-            k = o.margin,
-            g = o.centerX,
-            f = o.centerY,
-            e = o.distortion,
-            h = o.baseRotation,
-            p = o.startAngle + h,
-            m = o.endAngle + h,
-            a = o.thickness,
-            q = o.startRho,
-            j = o.endRho,
-            r = (s === "start" && p) || (s === "end" && m),
-            b = Math.sin(r),
-            d = Math.cos(r),
-            c = o.globalAlpha < 1,
-            n = s === "start" && d < 0 || s === "end" && d > 0 || c,
-            i;
-        if (n) {
-            i = (p + m) / 2;
-            g += Math.cos(i) * k;
-            f += Math.sin(i) * k * e;
-            l.moveTo(g + d * q, f + b * q * e);
-            l.lineTo(g + d * j, f + b * j * e);
-            l.lineTo(g + d * j, f + b * j * e + a);
-            l.lineTo(g + d * q, f + b * q * e + a);
-            l.closePath()
-        }
-    },
-    startRenderer: function(a) {
-        this.sideRenderer(a, "start")
-    },
-    endRenderer: function(a) {
-        this.sideRenderer(a, "end")
-    },
-    rimRenderer: function(q, e, o, j) {
-        var w = this,
-            s = w.attr,
-            p = s.margin,
-            h = s.centerX,
-            g = s.centerY,
-            d = s.distortion,
-            i = s.baseRotation,
-            t = Ext.draw.sprite.AttributeParser.angle,
-            u = s.startAngle + i,
-            r = s.endAngle + i,
-            k = t((u + r) / 2),
-            a = s.thickness,
-            b = s.globalAlpha < 1,
-            c, n, v;
-        w.bevelParams = [];
-        u = t(u);
-        r = t(r);
-        h += Math.cos(k) * p;
-        g += Math.sin(k) * p * d;
-        c = u >= 0 && r >= 0;
-        n = u <= 0 && r <= 0;
-
-        function l() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, u, true);
-            q.lineTo(h + Math.cos(u) * e, g + Math.sin(u) * e * d);
-            v = [h, g, e, e * d, 0, u, Math.PI, false];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function f() {
-            q.ellipse(h, g + a, e, e * d, 0, 0, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, 0, true];
-            if (!o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function x() {
-            q.ellipse(h, g + a, e, e * d, 0, Math.PI, r, false);
-            q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-            v = [h, g, e, e * d, 0, r, Math.PI, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-
-        function m() {
-            q.ellipse(h, g + a, e, e * d, 0, u, 0, false);
-            q.lineTo(h + e, g);
-            v = [h, g, e, e * d, 0, 0, u, true];
-            if (o) {
-                w.bevelParams.push(v)
-            }
-            q.ellipse.apply(q, v);
-            q.closePath()
-        }
-        if (j) {
-            if (!o || b) {
-                if (u >= 0 && r < 0) {
-                    l()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        f()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, 0, Math.PI, false);
-                                q.lineTo(h - e, g);
-                                v = [h, g, e, e * d, 0, Math.PI, 0, true];
-                                if (!o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                l();
-                                f()
-                            } else {
-                                v = [h, g, e, e * d, 0, u, r, false];
-                                if (c && !o || n && o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d + a);
-                                q.ellipse(h, g + a, e, e * d, 0, r, u, true);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        } else {
-            if (o || b) {
-                if (u >= 0 && r < 0) {
-                    x()
-                } else {
-                    if (u <= 0 && r > 0) {
-                        m()
-                    } else {
-                        if (u <= 0 && r < 0) {
-                            if (u > r) {
-                                x();
-                                m()
-                            } else {
-                                q.ellipse(h, g + a, e, e * d, 0, u, r, false);
-                                q.lineTo(h + Math.cos(r) * e, g + Math.sin(r) * e * d);
-                                v = [h, g, e, e * d, 0, r, u, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        } else {
-                            if (u > r) {
-                                q.ellipse(h, g + a, e, e * d, 0, -Math.PI, 0, false);
-                                q.lineTo(h + e, g);
-                                v = [h, g, e, e * d, 0, 0, -Math.PI, true];
-                                if (o) {
-                                    w.bevelParams.push(v)
-                                }
-                                q.ellipse.apply(q, v);
-                                q.closePath()
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    },
-    innerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, true)
-    },
-    innerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.startRho, true, false)
-    },
-    outerFrontRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, true)
-    },
-    outerBackRenderer: function(a) {
-        this.rimRenderer(a, this.attr.endRho, false, false)
-    }
-});
-Ext.define("Ext.draw.PathUtil", function() {
-    var a = Math.abs,
-        c = Math.pow,
-        e = Math.cos,
-        b = Math.acos,
-        d = Math.sqrt,
-        f = Math.PI;
-    return {
-        singleton: true,
-        requires: ["Ext.draw.overrides.Path", "Ext.draw.overrides.sprite.Path", "Ext.draw.overrides.sprite.Instancing", "Ext.draw.overrides.Surface"],
-        cubicRoots: function(m) {
-            var z = m[0],
-                x = m[1],
-                w = m[2],
-                v = m[3];
-            if (z === 0) {
-                return this.quadraticRoots(x, w, v)
-            }
-            var s = x / z,
-                r = w / z,
-                q = v / z,
-                k = (3 * r - c(s, 2)) / 9,
-                j = (9 * s * r - 27 * q - 2 * c(s, 3)) / 54,
-                p = c(k, 3) + c(j, 2),
-                n = [],
-                h, g, o, l, u, y = Ext.Number.sign;
-            if (p >= 0) {
-                h = y(j + d(p)) * c(a(j + d(p)), 1 / 3);
-                g = y(j - d(p)) * c(a(j - d(p)), 1 / 3);
-                n[0] = -s / 3 + (h + g);
-                n[1] = -s / 3 - (h + g) / 2;
-                n[2] = n[1];
-                o = a(d(3) * (h - g) / 2);
-                if (o !== 0) {
-                    n[1] = -1;
-                    n[2] = -1
-                }
-            } else {
-                l = b(j / d(-c(k, 3)));
-                n[0] = 2 * d(-k) * e(l / 3) - s / 3;
-                n[1] = 2 * d(-k) * e((l + 2 * f) / 3) - s / 3;
-                n[2] = 2 * d(-k) * e((l + 4 * f) / 3) - s / 3
-            }
-            for (u = 0; u < 3; u++) {
-                if (n[u] < 0 || n[u] > 1) {
-                    n[u] = -1
-                }
-            }
-            return n
-        },
-        quadraticRoots: function(h, g, n) {
-            var m, l, k, j;
-            if (h === 0) {
-                return this.linearRoot(g, n)
-            }
-            m = g * g - 4 * h * n;
-            if (m === 0) {
-                k = [-g / (2 * h)]
-            } else {
-                if (m > 0) {
-                    l = d(m);
-                    k = [(-g - l) / (2 * h), (-g + l) / (2 * h)]
-                } else {
-                    return []
-                }
-            }
-            for (j = 0; j < k.length; j++) {
-                if (k[j] < 0 || k[j] > 1) {
-                    k[j] = -1
-                }
-            }
-            return k
-        },
-        linearRoot: function(h, g) {
-            var i = -g / h;
-            if (h === 0 || i < 0 || i > 1) {
-                return []
-            }
-            return [i]
-        },
-        bezierCoeffs: function(h, g, k, j) {
-            var i = [];
-            i[0] = -h + 3 * g - 3 * k + j;
-            i[1] = 3 * h - 6 * g + 3 * k;
-            i[2] = -3 * h + 3 * g;
-            i[3] = h;
-            return i
-        },
-        cubicLineIntersections: function(I, G, F, E, l, k, j, h, M, p, K, n) {
-            var u = [],
-                N = [],
-                D = p - n,
-                z = K - M,
-                y = M * (n - p) - p * (K - M),
-                L = this.bezierCoeffs(I, G, F, E),
-                J = this.bezierCoeffs(l, k, j, h),
-                H, x, w, v, g, q, o, m;
-            u[0] = D * L[0] + z * J[0];
-            u[1] = D * L[1] + z * J[1];
-            u[2] = D * L[2] + z * J[2];
-            u[3] = D * L[3] + z * J[3] + y;
-            x = this.cubicRoots(u);
-            for (H = 0; H < x.length; H++) {
-                v = x[H];
-                if (v < 0 || v > 1) {
-                    continue
-                }
-                g = v * v;
-                q = g * v;
-                o = L[0] * q + L[1] * g + L[2] * v + L[3];
-                m = J[0] * q + J[1] * g + J[2] * v + J[3];
-                if ((K - M) !== 0) {
-                    w = (o - M) / (K - M)
-                } else {
-                    w = (m - p) / (n - p)
-                }
-                if (!(w < 0 || w > 1)) {
-                    N.push([o, m])
-                }
-            }
-            return N
-        },
-        splitCubic: function(g, q, p, o, m) {
-            var j = m * m,
-                n = m * j,
-                i = m - 1,
-                h = i * i,
-                k = i * h,
-                l = n * o - 3 * j * i * p + 3 * m * h * q - k * g;
-            return [
-                [g, m * q - i * g, j * p - 2 * m * i * q + h * g, l],
-                [l, j * o - 2 * m * i * p + h * q, m * o - i * p, o]
-            ]
-        },
-        cubicDimension: function(p, o, l, k) {
-            var j = 3 * (-p + 3 * (o - l) + k),
-                i = 6 * (p - 2 * o + l),
-                h = -3 * (p - o),
-                q, n, g = Math.min(p, k),
-                m = Math.max(p, k),
-                r;
-            if (j === 0) {
-                if (i === 0) {
-                    return [g, m]
-                } else {
-                    q = -h / i;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                }
-            } else {
-                r = i * i - 4 * j * h;
-                if (r >= 0) {
-                    r = d(r);
-                    q = (r - i) / 2 / j;
-                    if (0 < q && q < 1) {
-                        n = this.interpolateCubic(p, o, l, k, q);
-                        g = Math.min(g, n);
-                        m = Math.max(m, n)
-                    }
-                    if (r > 0) {
-                        q -= r / j;
-                        if (0 < q && q < 1) {
-                            n = this.interpolateCubic(p, o, l, k, q);
-                            g = Math.min(g, n);
-                            m = Math.max(m, n)
-                        }
-                    }
-                }
-            }
-            return [g, m]
-        },
-        interpolateCubic: function(h, g, l, k, i) {
-            if (i === 0) {
-                return h
-            }
-            if (i === 1) {
-                return k
-            }
-            var j = (1 - i) / i;
-            return i * i * i * (k + j * (3 * l + j * (3 * g + j * h)))
-        },
-        cubicsIntersections: function(r, q, p, o, A, z, y, v, g, F, E, D, m, l, k, i) {
-            var C = this,
-                x = C.cubicDimension(r, q, p, o),
-                B = C.cubicDimension(A, z, y, v),
-                n = C.cubicDimension(g, F, E, D),
-                s = C.cubicDimension(m, l, k, i),
-                j, h, u, t, w = [];
-            if (x[0] > n[1] || x[1] < n[0] || B[0] > s[1] || B[1] < s[0]) {
-                return []
-            }
-            if (a(A - z) < 1 && a(y - v) < 1 && a(r - o) < 1 && a(q - p) < 1 && a(m - l) < 1 && a(k - i) < 1 && a(g - D) < 1 && a(F - E) < 1) {
-                return [
-                    [(r + o) * 0.5, (A + z) * 0.5]
-                ]
-            }
-            j = C.splitCubic(r, q, p, o, 0.5);
-            h = C.splitCubic(A, z, y, v, 0.5);
-            u = C.splitCubic(g, F, E, D, 0.5);
-            t = C.splitCubic(m, l, k, i, 0.5);
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[0].concat(h[0], u[1], t[1])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[0], t[0])));
-            w.push.apply(w, C.cubicsIntersections.apply(C, j[1].concat(h[1], u[1], t[1])));
-            return w
-        },
-        linesIntersection: function(k, p, j, o, h, n, q, m) {
-            var l = (j - k) * (m - n) - (o - p) * (q - h),
-                i, g;
-            if (l === 0) {
-                return null
-            }
-            i = ((q - h) * (p - n) - (k - h) * (m - n)) / l;
-            g = ((j - k) * (p - n) - (o - p) * (k - h)) / l;
-            if (i >= 0 && i <= 1 && g >= 0 && g <= 1) {
-                return [k + i * (j - k), p + i * (o - p)]
-            }
-            return null
-        },
-        pointOnLine: function(j, m, h, l, g, n) {
-            var k, i;
-            if (a(h - j) < a(l - m)) {
-                i = j;
-                j = m;
-                m = i;
-                i = h;
-                h = l;
-                l = i;
-                i = g;
-                g = n;
-                n = i
-            }
-            k = (g - j) / (h - j);
-            if (k < 0 || k > 1) {
-                return false
-            }
-            return a(m + k * (l - m) - n) < 4
-        },
-        pointOnCubic: function(w, u, s, r, l, k, h, g, p, o) {
-            var C = this,
-                B = C.bezierCoeffs(w, u, s, r),
-                A = C.bezierCoeffs(l, k, h, g),
-                z, v, n, m, q;
-            B[3] -= p;
-            A[3] -= o;
-            n = C.cubicRoots(B);
-            m = C.cubicRoots(A);
-            for (z = 0; z < n.length; z++) {
-                q = n[z];
-                for (v = 0; v < m.length; v++) {
-                    if (q >= 0 && q <= 1 && a(q - m[v]) < 0.05) {
-                        return true
-                    }
-                }
-            }
-            return false
-        }
-    }
-});
-Ext.define("Ext.chart.series.Pie3D", {
-    extend: "Ext.chart.series.Polar",
-    requires: ["Ext.chart.series.sprite.Pie3DPart", "Ext.draw.PathUtil"],
-    type: "pie3d",
-    seriesType: "pie3d",
-    alias: "series.pie3d",
-    isPie3D: true,
-    config: {
-        rect: [0, 0, 0, 0],
-        thickness: 35,
-        distortion: 0.5,
-        donut: false,
-        hidden: [],
-        highlightCfg: {
-            margin: 20
-        },
-        shadow: false
-    },
-    rotationOffset: -Math.PI / 2,
-    setField: function(a) {
-        return this.setXField(a)
-    },
-    getField: function() {
-        return this.getXField()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            baseRotation: a + this.rotationOffset
-        });
-        this.doUpdateStyles()
-    },
-    updateDistortion: function() {
-        this.setRadius()
-    },
-    updateThickness: function() {
-        this.setRadius()
-    },
-    updateColors: function(a) {
-        this.setSubStyle({
-            baseColor: a
-        })
-    },
-    applyShadow: function(a) {
-        if (a === true) {
-            a = {
-                shadowColor: "rgba(0,0,0,0.8)",
-                shadowBlur: 30
-            }
-        } else {
-            if (!Ext.isObject(a)) {
-                a = {
-                    shadowColor: Ext.draw.Color.RGBA_NONE
-                }
-            }
-        }
-        return a
-    },
-    updateShadow: function(g) {
-        var e = this,
-            f = e.getSprites(),
-            d = e.spritesPerSlice,
-            c = f && f.length,
-            b, a;
-        for (b = 1; b < c; b += d) {
-            a = f[b];
-            if (a.attr.part = "bottom") {
-                a.setAttributes(g)
-            }
-        }
-    },
-    getStyleByIndex: function(b) {
-        var d = this.callParent([b]),
-            c = this.getStyle(),
-            a = d.fillStyle || d.fill || d.color,
-            e = c.strokeStyle || c.stroke;
-        if (a) {
-            d.baseColor = a;
-            delete d.fillStyle;
-            delete d.fill;
-            delete d.color
-        }
-        if (e) {
-            d.strokeStyle = e
-        }
-        return d
-    },
-    doUpdateStyles: function() {
-        var g = this,
-            h = g.getSprites(),
-            f = g.spritesPerSlice,
-            e = h && h.length,
-            c = 0,
-            b = 0,
-            a, d;
-        for (; c < e; c += f, b++) {
-            d = g.getStyleByIndex(b);
-            for (a = 0; a < f; a++) {
-                h[c + a].setAttributes(d)
-            }
-        }
-    },
-    coordinateX: function() {
-        var w = this,
-            m = w.getChart(),
-            u = m && m.getAnimation(),
-            f = w.getStore(),
-            t = f.getData().items,
-            d = t.length,
-            b = w.getXField(),
-            p = w.getRotation(),
-            s = w.getHidden(),
-            n, c = 0,
-            h, e = [],
-            k = w.getSprites(),
-            a = k.length,
-            l = w.spritesPerSlice,
-            g = 0,
-            o = Math.PI * 2,
-            v = 1e-10,
-            r, q;
-        for (r = 0; r < d; r++) {
-            n = Math.abs(Number(t[r].get(b))) || 0;
-            if (!s[r]) {
-                c += n
-            }
-            e[r] = c;
-            if (r >= s.length) {
-                s[r] = false
-            }
-        }
-        s.length = d;
-        if (c === 0) {
-            return
-        }
-        h = 2 * Math.PI / c;
-        for (r = 0; r < d; r++) {
-            e[r] *= h
-        }
-        for (r = 0; r < a; r++) {
-            k[r].setAnimation(u)
-        }
-        for (r = 0; r < d; r++) {
-            for (q = 0; q < l; q++) {
-                k[r * l + q].setAttributes({
-                    startAngle: g,
-                    endAngle: e[r] - v,
-                    globalAlpha: 1,
-                    baseRotation: p
-                })
-            }
-            g = e[r]
-        }
-        for (r *= l; r < a; r++) {
-            k[r].setAnimation(u);
-            k[r].setAttributes({
-                startAngle: o,
-                endAngle: o,
-                globalAlpha: 0,
-                baseRotation: p
-            })
-        }
-    },
-    updateLabelData: function() {
-        var l = this,
-            m = l.getStore(),
-            k = m.getData().items,
-            h = l.getSprites(),
-            b = l.getLabel().getTemplate().getField(),
-            f = l.getHidden(),
-            a = l.spritesPerSlice,
-            d, c, g, e, n;
-        if (h.length && b) {
-            e = [];
-            for (d = 0, g = k.length; d < g; d++) {
-                e.push(k[d].get(b))
-            }
-            for (d = 0, c = 0, g = h.length; d < g; d += a, c++) {
-                n = h[d];
-                n.setAttributes({
-                    label: e[c]
-                });
-                n.putMarker("labels", {
-                    hidden: f[c]
-                }, n.attr.attributeId)
-            }
-        }
-    },
-    applyRadius: function() {
-        var f = this,
-            d = f.getChart(),
-            h = d.getInnerPadding(),
-            e = d.getMainRect() || [0, 0, 1, 1],
-            c = e[2] - h * 2,
-            a = e[3] - h * 2 - f.getThickness(),
-            g = c / 2,
-            b = g * f.getDistortion();
-        if (b > a / 2) {
-            return a / (f.getDistortion() * 2)
-        } else {
-            return g
-        }
-    },
-    getSprites: function() {
-        var y = this,
-            e = y.getStore();
-        if (!e) {
-            return []
-        }
-        var n = y.getChart(),
-            p = y.getSurface(),
-            t = e.getData().items,
-            l = y.spritesPerSlice,
-            a = t.length,
-            v = y.getAnimation() || n && n.getAnimation(),
-            x = y.getCenter(),
-            w = y.getOffsetX(),
-            u = y.getOffsetY(),
-            b = y.getRadius(),
-            q = y.getRotation(),
-            d = y.getHighlight(),
-            c = {
-                centerX: x[0] + w,
-                centerY: x[1] + u - y.getThickness() / 2,
-                endRho: b,
-                startRho: b * y.getDonut() / 100,
-                thickness: y.getThickness(),
-                distortion: y.getDistortion()
-            },
-            k = y.sprites,
-            h = y.getLabel(),
-            f = h.getTemplate(),
-            m, g, o, s, r;
-        for (s = 0; s < a; s++) {
-            g = Ext.apply({}, this.getStyleByIndex(s), c);
-            if (!k[s * l]) {
-                for (r = 0; r < y.partNames.length; r++) {
-                    o = p.add({
-                        type: "pie3dPart",
-                        part: y.partNames[r]
-                    });
-                    if (r === 0 && f.getField()) {
-                        o.bindMarker("labels", h)
-                    }
-                    o.fx.setDurationOn("baseRotation", q);
-                    if (d) {
-                        o.config.highlight = d;
-                        o.addModifier("highlight", true)
-                    }
-                    o.setAttributes(g);
-                    k.push(o)
-                }
-            } else {
-                m = k.slice(s * l, (s + 1) * l);
-                for (r = 0; r < m.length; r++) {
-                    o = m[r];
-                    if (v) {
-                        o.setAnimation(v)
-                    }
-                    o.setAttributes(g)
-                }
-            }
-        }
-        return k
-    },
-    betweenAngle: function(d, f, c) {
-        var e = Math.PI * 2,
-            g = this.rotationOffset;
-        f += g;
-        c += g;
-        d -= f;
-        c -= f;
-        d %= e;
-        c %= e;
-        d += e;
-        c += e;
-        d %= e;
-        c %= e;
-        return d < c || c === 0
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            g = h.getSprites();
-        if (g) {
-            var l = h.getStore(),
-                b = l.getData().items,
-                a = h.spritesPerSlice,
-                e = h.getHidden(),
-                c, f, m, d;
-            for (c = 0, f = b.length; c < f; c++) {
-                if (!e[c]) {
-                    d = c * a;
-                    m = g[d];
-                    if (m.hitTest([k, j])) {
-                        return {
-                            series: h,
-                            sprite: g.slice(d, d + a),
-                            index: c,
-                            record: b[c],
-                            category: "sprites",
-                            field: h.getXField()
-                        }
-                    }
-                }
-            }
-            return null
-        }
-    },
-    provideLegendInfo: function(f) {
-        var h = this,
-            k = h.getStore();
-        if (k) {
-            var g = k.getData().items,
-                b = h.getLabel().getTemplate().getField(),
-                j = h.getField(),
-                e = h.getHidden(),
-                d, a, c;
-            for (d = 0; d < g.length; d++) {
-                a = h.getStyleByIndex(d);
-                c = a.baseColor;
-                f.push({
-                    name: b ? String(g[d].get(b)) : j + " " + d,
-                    mark: c || "black",
-                    disabled: e[d],
-                    series: h.getId(),
-                    index: d
-                })
-            }
-        }
-    }
-}, function() {
-    var b = this.prototype,
-        a = Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;
-    b.partNames = a.replace(/^enums\(|\)/g, "").split(",");
-    b.spritesPerSlice = b.partNames.length
-});
-Ext.define("Ext.chart.series.sprite.Polar", {
-    extend: "Ext.chart.series.sprite.Series",
-    inheritableStatics: {
-        def: {
-            processors: {
-                centerX: "number",
-                centerY: "number",
-                startAngle: "number",
-                endAngle: "number",
-                startRho: "number",
-                endRho: "number",
-                baseRotation: "number",
-                labels: "default",
-                labelOverflowPadding: "number"
-            },
-            defaults: {
-                centerX: 0,
-                centerY: 0,
-                startAngle: 0,
-                endAngle: Math.PI,
-                startRho: 0,
-                endRho: 150,
-                baseRotation: 0,
-                labels: null,
-                labelOverflowPadding: 10
-            },
-            triggers: {
-                centerX: "bbox",
-                centerY: "bbox",
-                startAngle: "bbox",
-                endAngle: "bbox",
-                startRho: "bbox",
-                endRho: "bbox",
-                baseRotation: "bbox"
-            }
-        }
-    },
-    updatePlainBBox: function(b) {
-        var a = this.attr;
-        b.x = a.centerX - a.endRho;
-        b.y = a.centerY + a.endRho;
-        b.width = a.endRho * 2;
-        b.height = a.endRho * 2
-    }
-});
-Ext.define("Ext.chart.series.sprite.Radar", {
-    alias: "sprite.radar",
-    extend: "Ext.chart.series.sprite.Polar",
-    getDataPointXY: function(d) {
-        var u = this,
-            n = u.attr,
-            f = n.centerX,
-            e = n.centerY,
-            o = n.matrix,
-            t = n.dataMinX,
-            s = n.dataMaxX,
-            k = n.dataX,
-            j = n.dataY,
-            l = n.endRho,
-            p = n.startRho,
-            g = n.baseRotation,
-            i, h, m, c, b, a, q;
-        if (n.rangeY) {
-            q = n.rangeY[1]
-        } else {
-            q = n.dataMaxY
-        }
-        c = (k[d] - t) / (s - t + 1) * 2 * Math.PI + g;
-        m = j[d] / q * (l - p) + p;
-        b = f + Math.cos(c) * m;
-        a = e + Math.sin(c) * m;
-        i = o.x(b, a);
-        h = o.y(b, a);
-        return [i, h]
-    },
-    render: function(a, l) {
-        var h = this,
-            f = h.attr,
-            g = f.dataX,
-            b = g.length,
-            e = h.surfaceMatrix,
-            d = {},
-            c, k, j, m;
-        l.beginPath();
-        for (c = 0; c < b; c++) {
-            m = h.getDataPointXY(c);
-            k = m[0];
-            j = m[1];
-            if (c === 0) {
-                l.moveTo(k, j)
-            }
-            l.lineTo(k, j);
-            d.translationX = e.x(k, j);
-            d.translationY = e.y(k, j);
-            h.putMarker("markers", d, c, true)
-        }
-        l.closePath();
-        l.fillStroke(f)
-    }
-});
-Ext.define("Ext.chart.series.Radar", {
-    extend: "Ext.chart.series.Polar",
-    type: "radar",
-    seriesType: "radar",
-    alias: "series.radar",
-    requires: ["Ext.chart.series.sprite.Radar"],
-    themeColorCount: function() {
-        return 1
-    },
-    isStoreDependantColorCount: false,
-    themeMarkerCount: function() {
-        return 1
-    },
-    updateAngularAxis: function(a) {
-        a.processData(this)
-    },
-    updateRadialAxis: function(a) {
-        a.processData(this)
-    },
-    coordinateX: function() {
-        return this.coordinate("X", 0, 2)
-    },
-    coordinateY: function() {
-        return this.coordinate("Y", 1, 2)
-    },
-    updateCenter: function(a) {
-        this.setStyle({
-            translationX: a[0] + this.getOffsetX(),
-            translationY: a[1] + this.getOffsetY()
-        });
-        this.doUpdateStyles()
-    },
-    updateRadius: function(a) {
-        this.setStyle({
-            endRho: a
-        });
-        this.doUpdateStyles()
-    },
-    updateRotation: function(a) {
-        this.setStyle({
-            rotationRads: a
-        });
-        this.doUpdateStyles()
-    },
-    updateTotalAngle: function(a) {
-        this.processData()
-    },
-    getItemForPoint: function(k, j) {
-        var h = this,
-            m = h.sprites && h.sprites[0],
-            f = m.attr,
-            g = f.dataX,
-            a = g.length,
-            l = h.getStore(),
-            e = h.getMarker(),
-            b, o, p, d, n, c;
-        if (h.getHidden()) {
-            return null
-        }
-        if (m && e) {
-            c = m.getMarker("markers");
-            for (d = 0; d < a; d++) {
-                n = c.getBBoxFor(d);
-                b = (n.width + n.height) * 0.25;
-                p = m.getDataPointXY(d);
-                if (Math.abs(p[0] - k) < b && Math.abs(p[1] - j) < b) {
-                    o = {
-                        series: h,
-                        sprite: m,
-                        index: d,
-                        category: "markers",
-                        record: l.getData().items[d],
-                        field: h.getYField()
-                    };
-                    return o
-                }
-            }
-        }
-        return h.callParent(arguments)
-    },
-    getDefaultSpriteConfig: function() {
-        var a = this.callParent(),
-            b = {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0,
-                    rotationRads: 0,
-                    dataMinX: 0,
-                    dataMaxX: 0
-                }
-            };
-        if (a.fx) {
-            Ext.apply(a.fx, b)
-        } else {
-            a.fx = b
-        }
-        return a
-    },
-    getSprites: function() {
-        var d = this,
-            c = d.getChart(),
-            e = d.getAnimation() || c && c.getAnimation(),
-            b = d.sprites[0],
-            a;
-        if (!c) {
-            return []
-        }
-        if (!b) {
-            b = d.createSprite()
-        }
-        if (e) {
-            a = b.getMarker("markers");
-            if (a) {
-                a.getTemplate().setAnimation(e)
-            }
-            b.setAnimation(e)
-        }
-        return d.sprites
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getSubStyleWithTheme(),
-            c = a.fillStyle;
-        if (Ext.isArray(c)) {
-            c = c[0]
-        }
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.series.sprite.Scatter", {
-    alias: "sprite.scatterSeries",
-    extend: "Ext.chart.series.sprite.Cartesian",
-    renderClipped: function(r, s, w, u) {
-        if (this.cleanRedraw) {
-            return
-        }
-        var C = this,
-            q = C.attr,
-            l = q.dataX,
-            h = q.dataY,
-            z = q.labels,
-            j = C.getSeries(),
-            b = z && C.getMarker("labels"),
-            t = C.attr.matrix,
-            c = t.getXX(),
-            p = t.getYY(),
-            m = t.getDX(),
-            k = t.getDY(),
-            n = {},
-            D, B, d = r.getInherited().rtl && !q.flipXY ? -1 : 1,
-            a, A, o, e, g, f, v;
-        if (q.flipXY) {
-            a = u[1] - c * d;
-            A = u[1] + u[3] + c * d;
-            o = u[0] - p;
-            e = u[0] + u[2] + p
-        } else {
-            a = u[0] - c * d;
-            A = u[0] + u[2] + c * d;
-            o = u[1] - p;
-            e = u[1] + u[3] + p
-        }
-        for (v = 0; v < l.length; v++) {
-            g = l[v];
-            f = h[v];
-            g = g * c + m;
-            f = f * p + k;
-            if (a <= g && g <= A && o <= f && f <= e) {
-                if (q.renderer) {
-                    n = {
-                        type: "items",
-                        translationX: g,
-                        translationY: f
-                    };
-                    B = [C, n, {
-                        store: C.getStore()
-                    }, v];
-                    D = Ext.callback(q.renderer, null, B, 0, j);
-                    n = Ext.apply(n, D)
-                } else {
-                    n.translationX = g;
-                    n.translationY = f
-                }
-                C.putMarker("items", n, v, !q.renderer);
-                if (b && z[v]) {
-                    C.drawLabel(z[v], g, f, v, u)
-                }
-            }
-        }
-    },
-    drawLabel: function(j, h, g, p, a) {
-        var r = this,
-            m = r.attr,
-            d = r.getMarker("labels"),
-            c = d.getTemplate(),
-            l = r.labelCfg || (r.labelCfg = {}),
-            b = r.surfaceMatrix,
-            f, e, i = m.labelOverflowPadding,
-            o = m.flipXY,
-            k, n, s, q;
-        l.text = j;
-        n = r.getMarkerBBox("labels", p, true);
-        if (!n) {
-            r.putMarker("labels", l, p);
-            n = r.getMarkerBBox("labels", p, true)
-        }
-        if (o) {
-            l.rotationRads = Math.PI * 0.5
-        } else {
-            l.rotationRads = 0
-        }
-        k = n.height / 2;
-        f = h;
-        switch (c.attr.display) {
-            case "under":
-                e = g - k - i;
-                break;
-            case "rotate":
-                f += i;
-                e = g - i;
-                l.rotationRads = -Math.PI / 4;
-                break;
-            default:
-                e = g + k + i
-        }
-        l.x = b.x(f, e);
-        l.y = b.y(f, e);
-        if (c.attr.renderer) {
-            q = [j, d, l, {
-                store: r.getStore()
-            }, p];
-            s = Ext.callback(c.attr.renderer, null, q, 0, r.getSeries());
-            if (typeof s === "string") {
-                l.text = s
-            } else {
-                Ext.apply(l, s)
-            }
-        }
-        r.putMarker("labels", l, p)
-    }
-});
-Ext.define("Ext.chart.series.Scatter", {
-    extend: "Ext.chart.series.Cartesian",
-    alias: "series.scatter",
-    type: "scatter",
-    seriesType: "scatterSeries",
-    requires: ["Ext.chart.series.sprite.Scatter"],
-    config: {
-        itemInstancing: {
-            fx: {
-                customDurations: {
-                    translationX: 0,
-                    translationY: 0
-                }
-            }
-        }
-    },
-    themeMarkerCount: function() {
-        return 1
-    },
-    applyMarker: function(b, a) {
-        this.getItemInstancing();
-        this.setItemInstancing(b);
-        return this.callParent(arguments)
-    },
-    provideLegendInfo: function(d) {
-        var b = this,
-            a = b.getMarkerStyleByIndex(0),
-            c = a.fillStyle;
-        d.push({
-            name: b.getTitle() || b.getYField() || b.getId(),
-            mark: (Ext.isObject(c) ? c.stops && c.stops[0].color : c) || a.strokeStyle || "black",
-            disabled: b.getHidden(),
-            series: b.getId(),
-            index: 0
-        })
-    }
-});
-Ext.define("Ext.chart.theme.Blue", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue", "chart.theme.Blue"],
-    config: {
-        baseColor: "#4d7fe6"
-    }
-});
-Ext.define("Ext.chart.theme.BlueGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.blue-gradients", "chart.theme.Blue:gradients"],
-    config: {
-        baseColor: "#4d7fe6",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category1", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1", "chart.theme.Category1"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"]
-    }
-});
-Ext.define("Ext.chart.theme.Category1Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category1-gradients", "chart.theme.Category1:gradients"],
-    config: {
-        colors: ["#f0a50a", "#c20024", "#2044ba", "#810065", "#7eae29"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category2", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2", "chart.theme.Category2"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"]
-    }
-});
-Ext.define("Ext.chart.theme.Category2Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category2-gradients", "chart.theme.Category2:gradients"],
-    config: {
-        colors: ["#6d9824", "#87146e", "#2a9196", "#d39006", "#1e40ac"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category3", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3", "chart.theme.Category3"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"]
-    }
-});
-Ext.define("Ext.chart.theme.Category3Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category3-gradients", "chart.theme.Category3:gradients"],
-    config: {
-        colors: ["#fbbc29", "#ce2e4e", "#7e0062", "#158b90", "#57880e"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category4", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4", "chart.theme.Category4"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"]
-    }
-});
-Ext.define("Ext.chart.theme.Category4Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category4-gradients", "chart.theme.Category4:gradients"],
-    config: {
-        colors: ["#ef5773", "#fcbd2a", "#4f770d", "#1d3eaa", "#9b001f"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category5", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5", "chart.theme.Category5"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"]
-    }
-});
-Ext.define("Ext.chart.theme.Category5Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category5-gradients", "chart.theme.Category5:gradients"],
-    config: {
-        colors: ["#7eae29", "#fdbe2a", "#910019", "#27b4bc", "#d74dbc"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Category6", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6", "chart.theme.Category6"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"]
-    }
-});
-Ext.define("Ext.chart.theme.Category6Gradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.category6-gradients", "chart.theme.Category6:gradients"],
-    config: {
-        colors: ["#44dce1", "#0b2592", "#996e05", "#7fb325", "#b821a1"],
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.DefaultGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.default-gradients", "chart.theme.Base:gradients"],
-    config: {
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Green", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green", "chart.theme.Green"],
-    config: {
-        baseColor: "#b1da5a"
-    }
-});
-Ext.define("Ext.chart.theme.GreenGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.green-gradients", "chart.theme.Green:gradients"],
-    config: {
-        baseColor: "#b1da5a",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Midnight", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.midnight", "chart.theme.Midnight"],
-    config: {
-        colors: ["#A837FF", "#4AC0F2", "#FF4D35", "#FF8809", "#61C102", "#FF37EA"],
-        chart: {
-            defaults: {
-                background: "rgb(52, 52, 53)"
-            }
-        },
-        axis: {
-            defaults: {
-                style: {
-                    strokeStyle: "rgb(224, 224, 227)"
-                },
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                title: {
-                    fillStyle: "rgb(224, 224, 227)"
-                },
-                grid: {
-                    strokeStyle: "rgb(112, 112, 115)"
-                }
-            }
-        },
-        series: {
-            defaults: {
-                label: {
-                    fillStyle: "rgb(224, 224, 227)"
-                }
-            }
-        },
-        sprites: {
-            text: {
-                fillStyle: "rgb(224, 224, 227)"
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Muted", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.muted", "chart.theme.Muted"],
-    config: {
-        colors: ["#8ca640", "#974144", "#4091ba", "#8e658e", "#3b8d8b", "#b86465", "#d2af69", "#6e8852", "#3dcc7e", "#a6bed1", "#cbaa4b", "#998baa"]
-    }
-});
-Ext.define("Ext.chart.theme.Purple", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple", "chart.theme.Purple"],
-    config: {
-        baseColor: "#da5abd"
-    }
-});
-Ext.define("Ext.chart.theme.PurpleGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.purple-gradients", "chart.theme.Purple:gradients"],
-    config: {
-        baseColor: "#da5abd",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Red", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red", "chart.theme.Red"],
-    config: {
-        baseColor: "#e84b67"
-    }
-});
-Ext.define("Ext.chart.theme.RedGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.red-gradients", "chart.theme.Red:gradients"],
-    config: {
-        baseColor: "#e84b67",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Sky", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky", "chart.theme.Sky"],
-    config: {
-        baseColor: "#4ce0e7"
-    }
-});
-Ext.define("Ext.chart.theme.SkyGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.sky-gradients", "chart.theme.Sky:gradients"],
-    config: {
-        baseColor: "#4ce0e7",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.chart.theme.Yellow", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow", "chart.theme.Yellow"],
-    config: {
-        baseColor: "#fec935"
-    }
-});
-Ext.define("Ext.chart.theme.YellowGradients", {
-    extend: "Ext.chart.theme.Base",
-    singleton: true,
-    alias: ["chart.theme.yellow-gradients", "chart.theme.Yellow:gradients"],
-    config: {
-        baseColor: "#fec935",
-        gradients: {
-            type: "linear",
-            degrees: 90
-        }
-    }
-});
-Ext.define("Ext.draw.Point", {
-    requires: ["Ext.draw.Draw", "Ext.draw.Matrix"],
-    isPoint: true,
-    x: 0,
-    y: 0,
-    length: 0,
-    angle: 0,
-    angleUnits: "degrees",
-    statics: {
-        fly: (function() {
-            var a = null;
-            return function(b, c) {
-                if (!a) {
-                    a = new Ext.draw.Point()
-                }
-                a.constructor(b, c);
-                return a
-            }
-        })()
-    },
-    constructor: function(a, c) {
-        var b = this;
-        if (typeof a === "number") {
-            b.x = a;
-            if (typeof c === "number") {
-                b.y = c
-            } else {
-                b.y = a
-            }
-        } else {
-            if (Ext.isArray(a)) {
-                b.x = a[0];
-                b.y = a[1]
-            } else {
-                if (a) {
-                    b.x = a.x;
-                    b.y = a.y
-                }
-            }
-        }
-        b.calculatePolar()
-    },
-    calculateCartesian: function() {
-        var b = this,
-            a = b.length,
-            c = b.angle;
-        if (b.angleUnits === "degrees") {
-            c = Ext.draw.Draw.rad(c)
-        }
-        b.x = Math.cos(c) * a;
-        b.y = Math.sin(c) * a
-    },
-    calculatePolar: function() {
-        var b = this,
-            a = b.x,
-            c = b.y;
-        b.length = Math.sqrt(a * a + c * c);
-        b.angle = Math.atan2(c, a);
-        if (b.angleUnits === "degrees") {
-            b.angle = Ext.draw.Draw.degrees(b.angle)
-        }
-    },
-    setX: function(a) {
-        this.x = a;
-        this.calculatePolar()
-    },
-    setY: function(a) {
-        this.y = a;
-        this.calculatePolar()
-    },
-    set: function(a, b) {
-        this.constructor(a, b)
-    },
-    setAngle: function(a) {
-        this.angle = a;
-        this.calculateCartesian()
-    },
-    setLength: function(a) {
-        this.length = a;
-        this.calculateCartesian()
-    },
-    setPolar: function(b, a) {
-        this.angle = b;
-        this.length = a;
-        this.calculateCartesian()
-    },
-    clone: function() {
-        return new Ext.draw.Point(this.x, this.y)
-    },
-    add: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x + b.x, this.y + b.y)
-    },
-    sub: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return new Ext.draw.Point(this.x - b.x, this.y - b.y)
-    },
-    mul: function(a) {
-        return new Ext.draw.Point(this.x * a, this.y * a)
-    },
-    div: function(a) {
-        return new Ext.draw.Point(this.x / a, this.y / a)
-    },
-    dot: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x * b.x + this.y * b.y
-    },
-    equals: function(a, c) {
-        var b = Ext.draw.Point.fly(a, c);
-        return this.x === b.x && this.y === b.y
-    },
-    rotate: function(f, c) {
-        var d, e, b, g, a;
-        if (this.angleUnits === "degrees") {
-            f = Ext.draw.Draw.rad(f);
-            d = Math.sin(f);
-            e = Math.cos(f)
-        }
-        if (c) {
-            b = c.x;
-            g = c.y
-        } else {
-            b = 0;
-            g = 0
-        }
-        a = Ext.draw.Matrix.fly([e, d, -d, e, b - e * b + g * d, g - e * g + b * -d]).transformPoint(this);
-        return new Ext.draw.Point(a)
-    },
-    transform: function(a) {
-        if (a && a.isMatrix) {
-            return new Ext.draw.Point(a.transformPoint(this))
-        } else {
-            if (arguments.length === 6) {
-                return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))
-            } else {
-                Ext.raise("Invalid parameters.")
-            }
-        }
-    },
-    round: function() {
-        return new Ext.draw.Point(Math.round(this.x), Math.round(this.y))
-    },
-    ceil: function() {
-        return new Ext.draw.Point(Math.ceil(this.x), Math.ceil(this.y))
-    },
-    floor: function() {
-        return new Ext.draw.Point(Math.floor(this.x), Math.floor(this.y))
-    },
-    abs: function(a, b) {
-        return new Ext.draw.Point(Math.abs(this.x), Math.abs(this.y))
-    },
-    normalize: function(c) {
-        var b = this.x,
-            f = this.y,
-            a, e, d;
-        c = c || 1;
-        if (b === 0) {
-            a = 0;
-            e = c * Ext.Number.sign(f)
-        } else {
-            d = f / b;
-            a = c / Math.sqrt(1 + d * d);
-            e = a * d
-        }
-        return new Ext.draw.Point(a, e)
-    },
-    getDistanceToLine: function(c, b) {
-        if (arguments.length === 4) {
-            c = new Ext.draw.Point(arguments[0], arguments[1]);
-            b = new Ext.draw.Point(arguments[2], arguments[3])
-        }
-        var d = b.sub(c).normalize(),
-            a = c.sub(this);
-        return a.sub(d.mul(a.dot(d)))
-    },
-    isZero: function() {
-        return this.x === 0 && this.y === 0
-    },
-    isNumber: function() {
-        return Ext.isNumber(this.x + this.y)
-    }
-});
-Ext.define("Ext.draw.plugin.SpriteEvents", {
-    extend: "Ext.plugin.Abstract",
-    alias: "plugin.spriteevents",
-    requires: ["Ext.draw.PathUtil"],
-    mouseMoveEvents: {
-        mousemove: true,
-        mouseover: true,
-        mouseout: true
-    },
-    spriteMouseMoveEvents: {
-        spritemousemove: true,
-        spritemouseover: true,
-        spritemouseout: true
-    },
-    init: function(a) {
-        var b = "handleEvent";
-        this.drawContainer = a;
-        a.addElementListener({
-            click: b,
-            dblclick: b,
-            mousedown: b,
-            mousemove: b,
-            mouseup: b,
-            mouseover: b,
-            mouseout: b,
-            priority: 1001,
-            scope: this
-        })
-    },
-    hasSpriteMouseMoveListeners: function() {
-        var b = this.drawContainer.hasListeners,
-            a;
-        for (a in this.spriteMouseMoveEvents) {
-            if (a in b) {
-                return true
-            }
-        }
-        return false
-    },
-    hitTestEvent: function(f) {
-        var b = this.drawContainer.getItems(),
-            a, d, c;
-        for (c = b.length - 1; c >= 0; c--) {
-            a = b.get(c);
-            d = a.hitTestEvent(f);
-            if (d) {
-                return d
-            }
-        }
-        return null
-    },
-    handleEvent: function(f) {
-        var d = this,
-            b = d.drawContainer,
-            g = f.type in d.mouseMoveEvents,
-            a = d.lastSprite,
-            c;
-        if (g && !d.hasSpriteMouseMoveListeners()) {
-            return
-        }
-        c = d.hitTestEvent(f);
-        if (g && !Ext.Object.equals(c, a)) {
-            if (a) {
-                b.fireEvent("spritemouseout", a, f)
-            }
-            if (c) {
-                b.fireEvent("spritemouseover", c, f)
-            }
-        }
-        if (c) {
-            b.fireEvent("sprite" + f.type, c, f)
-        }
-        d.lastSprite = c
-    }
-});
-Ext.define("Ext.chart.TipSurface", {
-    extend: "Ext.draw.Container",
-    spriteArray: false,
-    renderFirst: true,
-    constructor: function(a) {
-        this.callParent([a]);
-        if (a.sprites) {
-            this.spriteArray = [].concat(a.sprites);
-            delete a.sprites
-        }
-    },
-    onRender: function() {
-        var c = this,
-            b = 0,
-            a = 0,
-            d, e;
-        this.callParent(arguments);
-        e = c.spriteArray;
-        if (c.renderFirst && e) {
-            c.renderFirst = false;
-            for (a = e.length; b < a; b++) {
-                d = c.surface.add(e[b]);
-                d.setAttributes({
-                    hidden: false
-                }, true)
-            }
-        }
-    }
-});
-Ext.define("Ext.chart.interactions.ItemInfo", {
-    extend: "Ext.chart.interactions.Abstract",
-    type: "iteminfo",
-    alias: "interaction.iteminfo",
-    config: {
-        extjsGestures: {
-            start: {
-                event: "click",
-                handler: "onInfoGesture"
-            },
-            move: {
-                event: "mousemove",
-                handler: "onInfoGesture"
-            },
-            end: {
-                event: "mouseleave",
-                handler: "onInfoGesture"
-            }
-        }
-    },
-    item: null,
-    onInfoGesture: function(f, a) {
-        var c = this,
-            b = c.getItemForEvent(f),
-            d = b && b.series.tooltip;
-        if (d) {
-            d.onMouseMove.call(d, f)
-        }
-        if (b !== c.item) {
-            if (b) {
-                b.series.showTip(b)
-            } else {
-                c.item.series.hideTip(c.item)
-            }
-            c.item = b
-        }
-        return false
-    }
-});
\ No newline at end of file
diff --git a/serverside/jsmod/6.1-3/charts.js.original b/serverside/jsmod/6.1-3/charts.js.original
deleted file mode 100644
index 2b8dd713bdd4e76d779e6b231b21d41c860a930a..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.1-3/charts.js.original
+++ /dev/null
@@ -1 +0,0 @@
-Ext.define("Ext.draw.ContainerBase",{extend:"Ext.panel.Panel",requires:["Ext.window.Window"],previewTitleText:"Chart Preview",previewAltText:"Chart preview",layout:"container",addElementListener:function(){var b=this,a=arguments;if(b.rendered){b.el.on.apply(b.el,a)}else{b.on("render",function(){b.el.on.apply(b.el,a)})}},removeElementListener:function(){var b=this,a=arguments;if(b.rendered){b.el.un.apply(b.el,a)}},afterRender:function(){this.callParent(arguments);this.initAnimator()},getItems:function(){var b=this,a=b.items;if(!a||!a.isMixedCollection){b.initItems()}return b.items},onRender:function(){this.callParent(arguments);this.element=this.el;this.innerElement=this.body},setItems:function(a){this.items=a;return a},setSurfaceSize:function(b,a){this.resizeHandler({width:b,height:a});this.renderFrame()},onResize:function(c,a,b,e){var d=this;d.callParent([c,a,b,e]);d.setBodySize({width:c,height:a})},preview:function(){var a=this.getImage();new Ext.window.Window({title:this.previewTitleText,closeable:true,renderTo:Ext.getBody(),autoShow:true,maximizeable:true,maximized:true,border:true,layout:{type:"hbox",pack:"center",align:"middle"},items:{xtype:"container",items:{xtype:"image",mode:"img",cls:Ext.baseCSSPrefix+"chart-image",alt:this.previewAltText,src:a.data,listeners:{afterrender:function(){var e=this,b=e.imgEl.dom,d=a.type==="svg"?1:(window.devicePixelRatio||1),c;if(!b.naturalWidth||!b.naturalHeight){b.onload=function(){var g=b.naturalWidth,f=b.naturalHeight;e.setWidth(Math.floor(g/d));e.setHeight(Math.floor(f/d))}}else{c=e.getSize();e.setWidth(Math.floor(c.width/d));e.setHeight(Math.floor(c.height/d))}}}}}})},privates:{getTargetEl:function(){return this.innerElement},reattachToBody:function(){var a=this;if(a.pendingDetachSize){a.onBodyResize()}a.pendingDetachSize=false;a.callParent()}}});Ext.define("Ext.draw.SurfaceBase",{extend:"Ext.Widget",getOwnerBody:function(){return this.ownerCt.body},destroy:function(){var a=this;if(a.hasListeners.destroy){a.fireEvent("destroy",a)}a.callParent()}});Ext.define("Ext.draw.Color",{statics:{colorToHexRe:/(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,rgbToHexRe:/\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/,rgbaToHexRe:/\s*rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\.\d]+)\)/,hexRe:/\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,NONE:"none",RGBA_NONE:"rgba(0, 0, 0, 0)"},isColor:true,lightnessFactor:0.2,constructor:function(d,b,a,c){this.setRGB(d,b,a,c)},setRGB:function(e,c,a,d){var b=this;b.r=Math.min(255,Math.max(0,e));b.g=Math.min(255,Math.max(0,c));b.b=Math.min(255,Math.max(0,a));if(d===undefined){b.a=1}else{b.a=Math.min(1,Math.max(0,d))}},getGrayscale:function(){return this.r*0.3+this.g*0.59+this.b*0.11},getHSL:function(){var i=this,a=i.r/255,f=i.g/255,j=i.b/255,k=Math.max(a,f,j),d=Math.min(a,f,j),m=k-d,e,n=0,c=0.5*(k+d);if(d!==k){n=(c<=0.5)?m/(k+d):m/(2-k-d);if(a===k){e=60*(f-j)/m}else{if(f===k){e=120+60*(j-a)/m}else{e=240+60*(a-f)/m}}if(e<0){e+=360}if(e>=360){e-=360}}return[e,n,c]},getHSV:function(){var i=this,a=i.r/255,f=i.g/255,j=i.b/255,k=Math.max(a,f,j),d=Math.min(a,f,j),c=k-d,e,m=0,l=k;if(d!=k){m=l?c/l:0;if(a===k){e=60*(f-j)/c}else{if(f===k){e=60*(j-a)/c+120}else{e=60*(a-f)/c+240}}if(e<0){e+=360}if(e>=360){e-=360}}return[e,m,l]},setHSL:function(g,f,e){var i=this,d=Math.abs,j,b,a;g=(g%360+360)%360;f=f>1?1:f<0?0:f;e=e>1?1:e<0?0:e;if(f===0||g===null){e*=255;i.setRGB(e,e,e)}else{g/=60;j=f*(1-d(2*e-1));b=j*(1-d(g%2-1));a=e-j/2;a*=255;j*=255;b*=255;switch(Math.floor(g)){case 0:i.setRGB(j+a,b+a,a);break;case 1:i.setRGB(b+a,j+a,a);break;case 2:i.setRGB(a,j+a,b+a);break;case 3:i.setRGB(a,b+a,j+a);break;case 4:i.setRGB(b+a,a,j+a);break;case 5:i.setRGB(j+a,a,b+a);break}}return i},setHSV:function(f,e,d){var g=this,i,b,a;f=(f%360+360)%360;e=e>1?1:e<0?0:e;d=d>1?1:d<0?0:d;if(e===0||f===null){d*=255;g.setRGB(d,d,d)}else{f/=60;i=d*e;b=i*(1-Math.abs(f%2-1));a=d-i;a*=255;i*=255;b*=255;switch(Math.floor(f)){case 0:g.setRGB(i+a,b+a,a);break;case 1:g.setRGB(b+a,i+a,a);break;case 2:g.setRGB(a,i+a,b+a);break;case 3:g.setRGB(a,b+a,i+a);break;case 4:g.setRGB(b+a,a,i+a);break;case 5:g.setRGB(i+a,a,b+a);break}}return g},createLighter:function(b){if(!b&&b!==0){b=this.lightnessFactor}var a=this.getHSL();a[2]=Ext.Number.constrain(a[2]+b,0,1);return Ext.draw.Color.fromHSL(a[0],a[1],a[2])},createDarker:function(a){if(!a&&a!==0){a=this.lightnessFactor}return this.createLighter(-a)},toString:function(){var f=this,c=Math.round;if(f.a===1){var e=c(f.r).toString(16),d=c(f.g).toString(16),a=c(f.b).toString(16);e=(e.length===1)?"0"+e:e;d=(d.length===1)?"0"+d:d;a=(a.length===1)?"0"+a:a;return["#",e,d,a].join("")}else{return"rgba("+[c(f.r),c(f.g),c(f.b),f.a===0?0:f.a.toFixed(15)].join(", ")+")"}},toHex:function(b){if(Ext.isArray(b)){b=b[0]}if(!Ext.isString(b)){return""}if(b.substr(0,1)==="#"){return b}var e=Ext.draw.Color.colorToHexRe.exec(b);if(Ext.isArray(e)){var f=parseInt(e[2],10),d=parseInt(e[3],10),a=parseInt(e[4],10),c=a|(d<<8)|(f<<16);return e[1]+"#"+("000000"+c.toString(16)).slice(-6)}else{return""}},setFromString:function(j){var e,h,f,c,d=1,i=parseInt;if(j===Ext.draw.Color.NONE){this.r=this.g=this.b=this.a=0;return this}if((j.length===4||j.length===7)&&j.substr(0,1)==="#"){e=j.match(Ext.draw.Color.hexRe);if(e){h=i(e[1],16)>>0;f=i(e[2],16)>>0;c=i(e[3],16)>>0;if(j.length===4){h+=(h*16);f+=(f*16);c+=(c*16)}}}else{if((e=j.match(Ext.draw.Color.rgbToHexRe))){h=+e[1];f=+e[2];c=+e[3]}else{if((e=j.match(Ext.draw.Color.rgbaToHexRe))){h=+e[1];f=+e[2];c=+e[3];d=+e[4]}else{if(Ext.draw.Color.ColorList.hasOwnProperty(j.toLowerCase())){return this.setFromString(Ext.draw.Color.ColorList[j.toLowerCase()])}}}}if(typeof h==="undefined"){return this}this.r=h;this.g=f;this.b=c;this.a=d;return this}},function(){var a=new this();this.addStatics({fly:function(f,e,c,d){switch(arguments.length){case 1:a.setFromString(f);break;case 3:case 4:a.setRGB(f,e,c,d);break;default:return null}return a},ColorList:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},fromHSL:function(d,c,b){return(new this(0,0,0,0)).setHSL(d,c,b)},fromHSV:function(d,c,b){return(new this(0,0,0,0)).setHSL(d,c,b)},fromString:function(b){return(new this(0,0,0,0)).setFromString(b)},create:function(b){if(b instanceof this){return b}else{if(Ext.isArray(b)){return new Ext.draw.Color(b[0],b[1],b[2],b[3])}else{if(Ext.isString(b)){return Ext.draw.Color.fromString(b)}else{if(arguments.length>2){return new Ext.draw.Color(arguments[0],arguments[1],arguments[2],arguments[3])}else{return new Ext.draw.Color(0,0,0,0)}}}}}})});Ext.define("Ext.draw.sprite.AnimationParser",function(){function a(d,c,b){return d+(c-d)*b}return{singleton:true,attributeRe:/^url\(#([a-zA-Z\-]+)\)$/,requires:["Ext.draw.Color"],color:{parseInitial:function(c,b){if(Ext.isString(c)){c=Ext.draw.Color.create(c)}if(Ext.isString(b)){b=Ext.draw.Color.create(b)}if((c instanceof Ext.draw.Color)&&(b instanceof Ext.draw.Color)){return[[c.r,c.g,c.b,c.a],[b.r,b.g,b.b,b.a]]}else{return[c||b,b||c]}},compute:function(d,c,b){if(!Ext.isArray(d)||!Ext.isArray(c)){return c||d}else{return[a(d[0],c[0],b),a(d[1],c[1],b),a(d[2],c[2],b),a(d[3],c[3],b)]}},serve:function(c){var b=Ext.draw.Color.fly(c[0],c[1],c[2],c[3]);return b.toString()}},number:{parse:function(b){return b===null?null:+b},compute:function(d,c,b){if(!Ext.isNumber(d)||!Ext.isNumber(c)){return c||d}else{return a(d,c,b)}}},angle:{parseInitial:function(c,b){if(b-c>Math.PI){b-=Math.PI*2}else{if(b-c<-Math.PI){b+=Math.PI*2}}return[c,b]},compute:function(d,c,b){if(!Ext.isNumber(d)||!Ext.isNumber(c)){return c||d}else{return a(d,c,b)}}},path:{parseInitial:function(m,n){var c=m.toStripes(),o=n.toStripes(),e,d,k=c.length,p=o.length,h,f,b,g=o[p-1],l=[g[g.length-2],g[g.length-1]];for(e=k;e<p;e++){c.push(c[k-1].slice(0))}for(e=p;e<k;e++){o.push(l.slice(0))}b=c.length;o.path=n;o.temp=new Ext.draw.Path();for(e=0;e<b;e++){h=c[e];f=o[e];k=h.length;p=f.length;o.temp.commands.push("M");for(d=p;d<k;d+=6){f.push(l[0],l[1],l[0],l[1],l[0],l[1])}g=o[o.length-1];l=[g[g.length-2],g[g.length-1]];for(d=k;d<p;d+=6){h.push(l[0],l[1],l[0],l[1],l[0],l[1])}for(e=0;e<f.length;e++){f[e]-=h[e]}for(e=2;e<f.length;e+=6){o.temp.commands.push("C")}}return[c,o]},compute:function(c,l,m){if(m>=1){return l.path}var e=0,f=c.length,d=0,b,k,h,n=l.temp.params,g=0;for(;e<f;e++){k=c[e];h=l[e];b=k.length;for(d=0;d<b;d++){n[g++]=h[d]*m+k[d]}}return l.temp}},data:{compute:function(h,j,k,g){var m=h.length-1,b=j.length-1,e=Math.max(m,b),d,l,c;if(!g||g===h){g=[]}g.length=e+1;for(c=0;c<=e;c++){d=h[Math.min(c,m)];l=j[Math.min(c,b)];if(Ext.isNumber(d)){if(!Ext.isNumber(l)){l=0}g[c]=(l-d)*k+d}else{g[c]=l}}return g}},text:{compute:function(d,c,b){return d.substr(0,Math.round(d.length*(1-b)))+c.substr(Math.round(c.length*(1-b)))}},limited:"number",limited01:"number"}});(function(){if(!Ext.global.Float32Array){var a=function(d){if(typeof d==="number"){this.length=d}else{if("length" in d){this.length=d.length;for(var c=0,b=d.length;c<b;c++){this[c]=+d[c]}}}};a.prototype=[];Ext.global.Float32Array=a}})();Ext.define("Ext.draw.Draw",{singleton:true,radian:Math.PI/180,pi2:Math.PI*2,reflectFn:function(b){return b},rad:function(a){return(a%360)*this.radian},degrees:function(a){return(a/this.radian)%360},isBBoxIntersect:function(b,a,c){c=c||0;return(Math.max(b.x,a.x)-c>Math.min(b.x+b.width,a.x+a.width))||(Math.max(b.y,a.y)-c>Math.min(b.y+b.height,a.y+a.height))},isPointInBBox:function(a,c,b){return !!b&&a>=b.x&&a<=(b.x+b.width)&&c>=b.y&&c<=(b.y+b.height)},spline:function(m){var e,c,k=m.length,b,h,l,f,a=0,g=new Float32Array(m.length),n=new Float32Array(m.length*3-2);g[0]=0;g[k-1]=0;for(e=1;e<k-1;e++){g[e]=(m[e+1]+m[e-1]-2*m[e])-g[e-1];a=1/(4-a);g[e]*=a}for(e=k-2;e>0;e--){a=3.732050807568877+48.248711305964385/(-13.928203230275537+Math.pow(0.07179676972449123,e));g[e]-=g[e+1]*a}f=m[0];b=f-g[0];for(e=0,c=0;e<k-1;c+=3){l=f;h=b;e++;f=m[e];b=f-g[e];n[c]=l;n[c+1]=(b+2*h)/3;n[c+2]=(b*2+h)/3}n[c]=f;return n},getAnchors:function(e,d,i,h,t,s,o){o=o||4;var n=Math.PI,p=n/2,k=Math.abs,a=Math.sin,b=Math.cos,f=Math.atan,r,q,g,j,m,l,v,u,c;r=(i-e)/o;q=(t-i)/o;if((h>=d&&h>=s)||(h<=d&&h<=s)){g=j=p}else{g=f((i-e)/k(h-d));if(d<h){g=n-g}j=f((t-i)/k(h-s));if(s<h){j=n-j}}c=p-((g+j)%(n*2))/2;if(c>p){c-=n}g+=c;j+=c;m=i-r*a(g);l=h+r*b(g);v=i+q*a(j);u=h+q*b(j);if((h>d&&l<d)||(h<d&&l>d)){m+=k(d-l)*(m-i)/(l-h);l=d}if((h>s&&u<s)||(h<s&&u>s)){v-=k(s-u)*(v-i)/(u-h);u=s}return{x1:m,y1:l,x2:v,y2:u}},smooth:function(l,j,o){var k=l.length,h,g,c,b,q,p,n,m,f=[],e=[],d,a;for(d=0;d<k-1;d++){h=l[d];g=j[d];if(d===0){n=h;m=g;f.push(n);e.push(m);if(k===1){break}}c=l[d+1];b=j[d+1];q=l[d+2];p=j[d+2];if(!Ext.isNumber(q+p)){f.push(n,c,c);e.push(m,b,b);break}a=this.getAnchors(h,g,c,b,q,p,o);f.push(n,a.x1,c);e.push(m,a.y1,b);n=a.x2;m=a.y2}return{smoothX:f,smoothY:e}},beginUpdateIOS:Ext.os.is.iOS?function(){this.iosUpdateEl=Ext.getBody().createChild({style:"position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; background: rgba(0,0,0,0.001); z-index: 100000"})}:Ext.emptyFn,endUpdateIOS:function(){this.iosUpdateEl=Ext.destroy(this.iosUpdateEl)}});Ext.define("Ext.draw.gradient.Gradient",{requires:["Ext.draw.Color"],isGradient:true,config:{stops:[]},applyStops:function(f){var e=[],d=f.length,c,b,a;for(c=0;c<d;c++){b=f[c];a=b.color;if(!(a&&a.isColor)){a=Ext.draw.Color.fly(a||Ext.draw.Color.NONE)}e.push({offset:Math.min(1,Math.max(0,"offset" in b?b.offset:b.position||0)),color:a.toString()})}e.sort(function(h,g){return h.offset-g.offset});return e},onClassExtended:function(a,b){if(!b.alias&&b.type){b.alias="gradient."+b.type}},constructor:function(a){this.initConfig(a)},generateGradient:Ext.emptyFn});Ext.define("Ext.draw.gradient.GradientDefinition",{singleton:true,urlStringRe:/^url\(#([\w\-]+)\)$/,gradients:{},add:function(a){var b=this.gradients,c,e,d;for(c=0,e=a.length;c<e;c++){d=a[c];if(Ext.isString(d.id)){b[d.id]=d}}},get:function(d){var a=this.gradients,b=d.match(this.urlStringRe),c;if(b&&b[1]&&(c=a[b[1]])){return c||d}return d}});Ext.define("Ext.draw.sprite.AttributeParser",{singleton:true,attributeRe:/^url\(#([a-zA-Z\-]+)\)$/,requires:["Ext.draw.Color","Ext.draw.gradient.GradientDefinition"],"default":Ext.identityFn,string:function(a){return String(a)},number:function(a){if(Ext.isNumber(+a)){return a}},angle:function(a){if(Ext.isNumber(a)){a%=Math.PI*2;if(a<-Math.PI){a+=Math.PI*2}else{if(a>=Math.PI){a-=Math.PI*2}}return a}},data:function(a){if(Ext.isArray(a)){return a.slice()}else{if(a instanceof Float32Array){return new Float32Array(a)}}},bool:function(a){return !!a},color:function(a){if(a instanceof Ext.draw.Color){return a.toString()}else{if(a instanceof Ext.draw.gradient.Gradient){return a}else{if(!a){return Ext.draw.Color.NONE}else{if(Ext.isString(a)){if(a.substr(0,3)==="url"){a=Ext.draw.gradient.GradientDefinition.get(a);if(Ext.isString(a)){return a}}else{return Ext.draw.Color.fly(a).toString()}}}}}if(a.type==="linear"){return Ext.create("Ext.draw.gradient.Linear",a)}else{if(a.type==="radial"){return Ext.create("Ext.draw.gradient.Radial",a)}else{if(a.type==="pattern"){return Ext.create("Ext.draw.gradient.Pattern",a)}else{return Ext.draw.Color.NONE}}}},limited:function(a,b){return function(c){c=+c;return Ext.isNumber(c)?Math.min(Math.max(c,a),b):undefined}},limited01:function(a){a=+a;return Ext.isNumber(a)?Math.min(Math.max(a,0),1):undefined},enums:function(){var d={},a=Array.prototype.slice.call(arguments,0),b,c;for(b=0,c=a.length;b<c;b++){d[a[b]]=true}return function(e){return e in d?e:undefined}}});Ext.define("Ext.draw.sprite.AttributeDefinition",{requires:["Ext.draw.sprite.AttributeParser","Ext.draw.sprite.AnimationParser"],config:{defaults:{$value:{},lazy:true},aliases:{},animationProcessors:{},processors:{$value:{},lazy:true},dirtyTriggers:{},triggers:{},updaters:{}},inheritableStatics:{processorFactoryRe:/^(\w+)\(([\w\-,]*)\)$/},spriteClass:null,constructor:function(a){var b=this;b.initConfig(a)},applyDefaults:function(b,a){a=Ext.apply(a||{},this.normalize(b));return a},applyAliases:function(b,a){return Ext.apply(a||{},b)},applyProcessors:function(e,i){this.getAnimationProcessors();var j=i||{},h=Ext.draw.sprite.AttributeParser,a=this.self.processorFactoryRe,g={},d,b,c,f;for(b in e){f=e[b];if(typeof f==="string"){c=f.match(a);if(c){f=h[c[1]].apply(h,c[2].split(","))}else{if(h[f]){g[b]=f;d=true;f=h[f]}}}j[b]=f}if(d){this.setAnimationProcessors(g)}return j},applyAnimationProcessors:function(c,a){var e=Ext.draw.sprite.AnimationParser,b,d;if(!a){a={}}for(b in c){d=c[b];if(d==="none"){a[b]=null}else{if(Ext.isString(d)&&!(b in a)){if(d in e){while(Ext.isString(e[d])){d=e[d]}a[b]=e[d]}}else{if(Ext.isObject(d)){a[b]=d}}}}return a},updateDirtyTriggers:function(a){this.setTriggers(a)},applyTriggers:function(b,c){if(!c){c={}}for(var a in b){c[a]=b[a].split(",")}return c},applyUpdaters:function(b,a){return Ext.apply(a||{},b)},batchedNormalize:function(f,n){if(!f){return{}}var j=this.getProcessors(),d=this.getAliases(),a=f.translation||f.translate,o={},g,h,b,e,p,c,m,l,k;if("rotation" in f){p=f.rotation}else{p=("rotate" in f)?f.rotate:undefined}if("scaling" in f){c=f.scaling}else{c=("scale" in f)?f.scale:undefined}if(typeof c!=="undefined"){if(Ext.isNumber(c)){o.scalingX=c;o.scalingY=c}else{if("x" in c){o.scalingX=c.x}if("y" in c){o.scalingY=c.y}if("centerX" in c){o.scalingCenterX=c.centerX}if("centerY" in c){o.scalingCenterY=c.centerY}}}if(typeof p!=="undefined"){if(Ext.isNumber(p)){p=Ext.draw.Draw.rad(p);o.rotationRads=p}else{if("rads" in p){o.rotationRads=p.rads}else{if("degrees" in p){if(Ext.isArray(p.degrees)){o.rotationRads=Ext.Array.map(p.degrees,function(i){return Ext.draw.Draw.rad(i)})}else{o.rotationRads=Ext.draw.Draw.rad(p.degrees)}}}if("centerX" in p){o.rotationCenterX=p.centerX}if("centerY" in p){o.rotationCenterY=p.centerY}}}if(typeof a!=="undefined"){if("x" in a){o.translationX=a.x}if("y" in a){o.translationY=a.y}}if("matrix" in f){m=Ext.draw.Matrix.create(f.matrix);k=m.split();o.matrix=m;o.rotationRads=k.rotation;o.rotationCenterX=0;o.rotationCenterY=0;o.scalingX=k.scaleX;o.scalingY=k.scaleY;o.scalingCenterX=0;o.scalingCenterY=0;o.translationX=k.translateX;o.translationY=k.translateY}for(b in f){e=f[b];if(typeof e==="undefined"){continue}else{if(Ext.isArray(e)){if(b in d){b=d[b]}if(b in j){o[b]=[];for(g=0,h=e.length;g<h;g++){l=j[b].call(this,e[g]);if(typeof l!=="undefined"){o[b][g]=l}}}else{if(n){o[b]=e}}}else{if(b in d){b=d[b]}if(b in j){e=j[b].call(this,e);if(typeof e!=="undefined"){o[b]=e}}else{if(n){o[b]=e}}}}}return o},normalize:function(i,j){if(!i){return{}}var f=this.getProcessors(),d=this.getAliases(),a=i.translation||i.translate,k={},b,e,l,c,h,g;if("rotation" in i){l=i.rotation}else{l=("rotate" in i)?i.rotate:undefined}if("scaling" in i){c=i.scaling}else{c=("scale" in i)?i.scale:undefined}if(a){if("x" in a){k.translationX=a.x}if("y" in a){k.translationY=a.y}}if(typeof c!=="undefined"){if(Ext.isNumber(c)){k.scalingX=c;k.scalingY=c}else{if("x" in c){k.scalingX=c.x}if("y" in c){k.scalingY=c.y}if("centerX" in c){k.scalingCenterX=c.centerX}if("centerY" in c){k.scalingCenterY=c.centerY}}}if(typeof l!=="undefined"){if(Ext.isNumber(l)){l=Ext.draw.Draw.rad(l);k.rotationRads=l}else{if("rads" in l){k.rotationRads=l.rads}else{if("degrees" in l){k.rotationRads=Ext.draw.Draw.rad(l.degrees)}}if("centerX" in l){k.rotationCenterX=l.centerX}if("centerY" in l){k.rotationCenterY=l.centerY}}}if("matrix" in i){h=Ext.draw.Matrix.create(i.matrix);g=h.split();k.matrix=h;k.rotationRads=g.rotation;k.rotationCenterX=0;k.rotationCenterY=0;k.scalingX=g.scaleX;k.scalingY=g.scaleY;k.scalingCenterX=0;k.scalingCenterY=0;k.translationX=g.translateX;k.translationY=g.translateY}for(b in i){e=i[b];if(typeof e==="undefined"){continue}if(b in d){b=d[b]}if(b in f){e=f[b].call(this,e);if(typeof e!=="undefined"){k[b]=e}}else{if(j){k[b]=e}}}return k},setBypassingNormalization:function(a,c,b){return c.pushDown(a,b)},set:function(a,c,b){b=this.normalize(b);return this.setBypassingNormalization(a,c,b)}});Ext.define("Ext.draw.Matrix",{isMatrix:true,statics:{createAffineMatrixFromTwoPair:function(h,t,g,s,k,o,i,j){var v=g-h,u=s-t,e=i-k,q=j-o,d=1/(v*v+u*u),p=v*e+u*q,n=e*u-v*q,m=-p*h-n*t,l=n*h-p*t;return new this(p*d,-n*d,n*d,p*d,m*d+k,l*d+o)},createPanZoomFromTwoPair:function(q,e,p,c,h,s,n,g){if(arguments.length===2){return this.createPanZoomFromTwoPair.apply(this,q.concat(e))}var k=p-q,j=c-e,d=(q+p)*0.5,b=(e+c)*0.5,o=n-h,a=g-s,f=(h+n)*0.5,l=(s+g)*0.5,m=k*k+j*j,i=o*o+a*a,t=Math.sqrt(i/m);return new this(t,0,0,t,f-t*d,l-t*b)},fly:(function(){var a=null,b=function(c){a.elements=c;return a};return function(c){if(!a){a=new Ext.draw.Matrix()}a.elements=c;Ext.draw.Matrix.fly=b;return a}})(),create:function(a){if(a instanceof this){return a}return new this(a)}},constructor:function(e,d,a,f,c,b){if(e&&e.length===6){this.elements=e.slice()}else{if(e!==undefined){this.elements=[e,d,a,f,c,b]}else{this.elements=[1,0,0,1,0,0]}}},prepend:function(a,l,h,g,m,k){var b=this.elements,d=b[0],j=b[1],e=b[2],c=b[3],i=b[4],f=b[5];b[0]=a*d+h*j;b[1]=l*d+g*j;b[2]=a*e+h*c;b[3]=l*e+g*c;b[4]=a*i+h*f+m;b[5]=l*i+g*f+k;return this},prependMatrix:function(a){return this.prepend.apply(this,a.elements)},append:function(a,l,h,g,m,k){var b=this.elements,d=b[0],j=b[1],e=b[2],c=b[3],i=b[4],f=b[5];b[0]=a*d+l*e;b[1]=a*j+l*c;b[2]=h*d+g*e;b[3]=h*j+g*c;b[4]=m*d+k*e+i;b[5]=m*j+k*c+f;return this},appendMatrix:function(a){return this.append.apply(this,a.elements)},set:function(f,e,a,g,c,b){var d=this.elements;d[0]=f;d[1]=e;d[2]=a;d[3]=g;d[4]=c;d[5]=b;return this},inverse:function(i){var g=this.elements,o=g[0],m=g[1],l=g[2],k=g[3],j=g[4],h=g[5],n=1/(o*k-m*l);o*=n;m*=n;l*=n;k*=n;if(i){i.set(k,-m,-l,o,l*h-k*j,m*j-o*h);return i}else{return new Ext.draw.Matrix(k,-m,-l,o,l*h-k*j,m*j-o*h)}},translate:function(a,c,b){if(b){return this.prepend(1,0,0,1,a,c)}else{return this.append(1,0,0,1,a,c)}},scale:function(f,e,c,a,b){var d=this;if(e==null){e=f}if(c===undefined){c=0}if(a===undefined){a=0}if(b){return d.prepend(f,0,0,e,c-c*f,a-a*e)}else{return d.append(f,0,0,e,c-c*f,a-a*e)}},rotate:function(g,e,c,b){var d=this,f=Math.cos(g),a=Math.sin(g);e=e||0;c=c||0;if(b){return d.prepend(f,a,-a,f,e-f*e+c*a,c-f*c-e*a)}else{return d.append(f,a,-a,f,e-f*e+c*a,c-f*c-e*a)}},rotateFromVector:function(a,h,c){var e=this,g=Math.sqrt(a*a+h*h),f=a/g,b=h/g;if(c){return e.prepend(f,b,-b,f,0,0)}else{return e.append(f,b,-b,f,0,0)}},clone:function(){return new Ext.draw.Matrix(this.elements)},flipX:function(){return this.append(-1,0,0,1,0,0)},flipY:function(){return this.append(1,0,0,-1,0,0)},skewX:function(a){return this.append(1,0,Math.tan(a),1,0,0)},skewY:function(a){return this.append(1,Math.tan(a),0,1,0,0)},shearX:function(a){return this.append(1,0,a,1,0,0)},shearY:function(a){return this.append(1,a,0,1,0,0)},reset:function(){return this.set(1,0,0,1,0,0)},precisionCompensate:function(j,g){var c=this.elements,f=c[0],e=c[1],i=c[2],h=c[3],d=c[4],b=c[5],a=e*i-f*h;g.b=j*e/f;g.c=j*i/h;g.d=j;g.xx=f/j;g.yy=h/j;g.dx=(b*f*i-d*f*h)/a/j;g.dy=(d*e*h-b*f*h)/a/j},precisionCompensateRect:function(j,g){var b=this.elements,f=b[0],e=b[1],i=b[2],h=b[3],c=b[4],a=b[5],d=i/f;g.b=j*e/f;g.c=j*d;g.d=j*h/f;g.xx=f/j;g.yy=f/j;g.dx=(a*i-c*h)/(e*d-h)/j;g.dy=-(a*f-c*e)/(e*d-h)/j},x:function(a,c){var b=this.elements;return a*b[0]+c*b[2]+b[4]},y:function(a,c){var b=this.elements;return a*b[1]+c*b[3]+b[5]},get:function(b,a){return +this.elements[b+a*2].toFixed(4)},transformPoint:function(b){var c=this.elements,a,d;if(b.isPoint){a=b.x;d=b.y}else{a=b[0];d=b[1]}return[a*c[0]+d*c[2]+c[4],a*c[1]+d*c[3]+c[5]]},transformBBox:function(q,i,j){var b=this.elements,d=q.x,r=q.y,g=q.width*0.5,o=q.height*0.5,a=b[0],s=b[1],n=b[2],k=b[3],e=d+g,c=r+o,p,f,m;if(i){g-=i;o-=i;m=[Math.sqrt(b[0]*b[0]+b[2]*b[2]),Math.sqrt(b[1]*b[1]+b[3]*b[3])];p=Math.abs(g*a)+Math.abs(o*n)+Math.abs(m[0]*i);f=Math.abs(g*s)+Math.abs(o*k)+Math.abs(m[1]*i)}else{p=Math.abs(g*a)+Math.abs(o*n);f=Math.abs(g*s)+Math.abs(o*k)}if(!j){j={}}j.x=e*a+c*n+b[4]-p;j.y=e*s+c*k+b[5]-f;j.width=p+p;j.height=f+f;return j},transformList:function(e){var b=this.elements,a=b[0],h=b[2],l=b[4],k=b[1],g=b[3],j=b[5],f=e.length,c,d;for(d=0;d<f;d++){c=e[d];e[d]=[c[0]*a+c[1]*h+l,c[0]*k+c[1]*g+j]}return e},isIdentity:function(){var a=this.elements;return a[0]===1&&a[1]===0&&a[2]===0&&a[3]===1&&a[4]===0&&a[5]===0},isEqual:function(a){var c=a&&a.isMatrix?a.elements:a,b=this.elements;return b[0]===c[0]&&b[1]===c[1]&&b[2]===c[2]&&b[3]===c[3]&&b[4]===c[4]&&b[5]===c[5]},equals:function(a){return this.isEqual(a)},toArray:function(){var a=this.elements;return[a[0],a[2],a[4],a[1],a[3],a[5]]},toVerticalArray:function(){return this.elements.slice()},toString:function(){var a=this;return[a.get(0,0),a.get(0,1),a.get(1,0),a.get(1,1),a.get(2,0),a.get(2,1)].join(",")},toContext:function(a){a.transform.apply(a,this.elements);return this},toSvg:function(){var a=this.elements;return"matrix("+a[0].toFixed(9)+","+a[1].toFixed(9)+","+a[2].toFixed(9)+","+a[3].toFixed(9)+","+a[4].toFixed(9)+","+a[5].toFixed(9)+")"},getScaleX:function(){var a=this.elements;return Math.sqrt(a[0]*a[0]+a[2]*a[2])},getScaleY:function(){var a=this.elements;return Math.sqrt(a[1]*a[1]+a[3]*a[3])},getXX:function(){return this.elements[0]},getXY:function(){return this.elements[1]},getYX:function(){return this.elements[2]},getYY:function(){return this.elements[3]},getDX:function(){return this.elements[4]},getDY:function(){return this.elements[5]},split:function(){var b=this.elements,d=b[0],c=b[1],e=b[3],a={translateX:b[4],translateY:b[5]};a.rotate=a.rotation=Math.atan2(c,d);a.scaleX=d/Math.cos(a.rotate);a.scaleY=e/d*a.scaleX;return a}},function(){function b(e,c,d){e[c]={get:function(){return this.elements[d]},set:function(f){this.elements[d]=f}}}if(Object.defineProperties){var a={};b(a,"a",0);b(a,"b",1);b(a,"c",2);b(a,"d",3);b(a,"e",4);b(a,"f",5);Object.defineProperties(this.prototype,a)}this.prototype.multiply=this.prototype.appendMatrix});Ext.define("Ext.draw.modifier.Modifier",{mixins:{observable:"Ext.mixin.Observable"},config:{previous:null,next:null,sprite:null},constructor:function(a){this.mixins.observable.constructor.call(this,a)},updateNext:function(a){if(a){a.setPrevious(this)}},updatePrevious:function(a){if(a){a.setNext(this)}},prepareAttributes:function(a){if(this._previous){this._previous.prepareAttributes(a)}},popUp:function(a,b){if(this._next){this._next.popUp(a,b)}else{Ext.apply(a,b)}},pushDown:function(a,c){if(this._previous){return this._previous.pushDown(a,c)}else{for(var b in c){if(c[b]===a[b]){delete c[b]}}return c}}});Ext.define("Ext.draw.modifier.Target",{requires:["Ext.draw.Matrix"],extend:"Ext.draw.modifier.Modifier",alias:"modifier.target",statics:{uniqueId:0},prepareAttributes:function(a){var b=this.getPrevious();if(b){b.prepareAttributes(a)}a.attributeId="attribute-"+Ext.draw.modifier.Target.uniqueId++;if(!a.hasOwnProperty("canvasAttributes")){a.bbox={plain:{dirty:true},transform:{dirty:true}};a.dirty=true;a.pendingUpdaters={};a.canvasAttributes={};a.matrix=new Ext.draw.Matrix();a.inverseMatrix=new Ext.draw.Matrix()}},applyChanges:function(f,k){Ext.apply(f,k);var l=this.getSprite(),o=f.pendingUpdaters,h=l.self.def.getTriggers(),p,a,m,b,e,n,d,c,g;for(b in k){e=true;if((p=h[b])){l.scheduleUpdaters(f,p,[b])}if(f.template&&k.removeFromInstance&&k.removeFromInstance[b]){delete f[b]}}if(!e){return}if(o.canvas){n=o.canvas;delete o.canvas;for(d=0,g=n.length;d<g;d++){b=n[d];f.canvasAttributes[b]=f[b]}}if(f.hasOwnProperty("children")){a=f.children;for(d=0,g=a.length;d<g;d++){m=a[d];Ext.apply(m.pendingUpdaters,o);if(n){for(c=0;c<n.length;c++){b=n[c];m.canvasAttributes[b]=m[b]}}l.callUpdaters(m)}}l.setDirty(true);l.callUpdaters(f)},popUp:function(a,b){this.applyChanges(a,b)},pushDown:function(a,b){var c=this.getPrevious();if(c){b=c.pushDown(a,b)}this.applyChanges(a,b);return b}});Ext.define("Ext.draw.TimingFunctions",function(){var g=Math.pow,j=Math.sin,m=Math.cos,l=Math.sqrt,e=Math.PI,b=["quad","cube","quart","quint"],c={pow:function(o,i){return g(o,i||6)},expo:function(i){return g(2,8*(i-1))},circ:function(i){return 1-l(1-i*i)},sine:function(i){return 1-j((1-i)*e/2)},back:function(i,o){o=o||1.616;return i*i*((o+1)*i-o)},bounce:function(q){for(var o=0,i=1;1;o+=i,i/=2){if(q>=(7-4*o)/11){return i*i-g((11-6*o-11*q)/4,2)}}},elastic:function(o,i){return g(2,10*--o)*m(20*o*e*(i||1)/3)}},k={},a,f,d;function h(i){return function(o){return g(o,i)}}function n(i,o){k[i+"In"]=function(p){return o(p)};k[i+"Out"]=function(p){return 1-o(1-p)};k[i+"InOut"]=function(p){return(p<=0.5)?o(2*p)/2:(2-o(2*(1-p)))/2}}for(d=0,f=b.length;d<f;++d){c[b[d]]=h(d+2)}for(a in c){n(a,c[a])}k.linear=Ext.identityFn;k.easeIn=k.quadIn;k.easeOut=k.quadOut;k.easeInOut=k.quadInOut;return{singleton:true,easingMap:k}},function(a){Ext.apply(a,a.easingMap)});Ext.define("Ext.draw.Animator",{uses:["Ext.draw.Draw"],singleton:true,frameCallbacks:{},frameCallbackId:0,scheduled:0,frameStartTimeOffset:Ext.now(),animations:[],running:false,animationTime:function(){return Ext.AnimationQueue.frameStartTime-this.frameStartTimeOffset},add:function(b){var a=this;if(!a.contains(b)){a.animations.push(b);a.ignite();if("fireEvent" in b){b.fireEvent("animationstart",b)}}},remove:function(d){var c=this,e=c.animations,b=0,a=e.length;for(;b<a;++b){if(e[b]===d){e.splice(b,1);if("fireEvent" in d){d.fireEvent("animationend",d)}return}}},contains:function(a){return Ext.Array.indexOf(this.animations,a)>-1},empty:function(){return this.animations.length===0},step:function(d){var c=this,f=c.animations,e,a=0,b=f.length;for(;a<b;a++){e=f[a];e.step(d);if(!e.animating){f.splice(a,1);a--;b--;if(e.fireEvent){e.fireEvent("animationend",e)}}}},schedule:function(c,a){a=a||this;var b="frameCallback"+(this.frameCallbackId++);if(Ext.isString(c)){c=a[c]}Ext.draw.Animator.frameCallbacks[b]={fn:c,scope:a,once:true};this.scheduled++;Ext.draw.Animator.ignite();return b},scheduleIf:function(e,b){b=b||this;var c=Ext.draw.Animator.frameCallbacks,a,d;if(Ext.isString(e)){e=b[e]}for(d in c){a=c[d];if(a.once&&a.fn===e&&a.scope===b){return null}}return this.schedule(e,b)},cancel:function(a){if(Ext.draw.Animator.frameCallbacks[a]&&Ext.draw.Animator.frameCallbacks[a].once){this.scheduled--;delete Ext.draw.Animator.frameCallbacks[a]}},addFrameCallback:function(c,a){a=a||this;if(Ext.isString(c)){c=a[c]}var b="frameCallback"+(this.frameCallbackId++);Ext.draw.Animator.frameCallbacks[b]={fn:c,scope:a};return b},removeFrameCallback:function(a){delete Ext.draw.Animator.frameCallbacks[a]},fireFrameCallbacks:function(){var c=this.frameCallbacks,d,b,a;for(d in c){a=c[d];b=a.fn;if(Ext.isString(b)){b=a.scope[b]}b.call(a.scope);if(c[d]&&a.once){this.scheduled--;delete c[d]}}},handleFrame:function(){this.step(this.animationTime());this.fireFrameCallbacks();if(!this.scheduled&&this.empty()){Ext.AnimationQueue.stop(this.handleFrame,this);this.running=false;Ext.draw.Draw.endUpdateIOS()}},ignite:function(){if(!this.running){this.running=true;Ext.AnimationQueue.start(this.handleFrame,this);Ext.draw.Draw.beginUpdateIOS()}}});Ext.define("Ext.draw.modifier.Animation",{requires:["Ext.draw.TimingFunctions","Ext.draw.Animator"],extend:"Ext.draw.modifier.Modifier",alias:"modifier.animation",config:{easing:Ext.identityFn,duration:0,customEasings:{},customDurations:{},customDuration:null},constructor:function(a){var b=this;b.anyAnimation=b.anySpecialAnimations=false;b.animating=0;b.animatingPool=[];b.callParent([a])},prepareAttributes:function(a){if(!a.hasOwnProperty("timers")){a.animating=false;a.timers={};a.animationOriginal=Ext.Object.chain(a);a.animationOriginal.prototype=a}if(this._previous){this._previous.prepareAttributes(a.animationOriginal)}},updateSprite:function(a){this.setConfig(a.config.fx)},updateDuration:function(a){this.anyAnimation=a>0},applyEasing:function(a){if(typeof a==="string"){a=Ext.draw.TimingFunctions.easingMap[a]}return a},applyCustomEasings:function(a,e){e=e||{};var g,d,b,h,c,f;for(d in a){g=true;h=a[d];b=d.split(",");if(typeof h==="string"){h=Ext.draw.TimingFunctions.easingMap[h]}for(c=0,f=b.length;c<f;c++){e[b[c]]=h}}if(g){this.anySpecialAnimations=g}return e},setEasingOn:function(a,e){a=Ext.Array.from(a).slice();var c={},d=a.length,b=0;for(;b<d;b++){c[a[b]]=e}this.setCustomEasings(c)},clearEasingOn:function(a){a=Ext.Array.from(a,true);var b=0,c=a.length;for(;b<c;b++){delete this._customEasings[a[b]]}},applyCustomDurations:function(g,h){h=h||{};var e,c,f,a,b,d;for(c in g){e=true;f=g[c];a=c.split(",");for(b=0,d=a.length;b<d;b++){h[a[b]]=f}}if(e){this.anySpecialAnimations=e}return h},applyCustomDuration:function(a,b){if(a){this.getCustomDurations();this.setCustomDurations(a)}},setDurationOn:function(b,e){b=Ext.Array.from(b).slice();var a={},c=0,d=b.length;for(;c<d;c++){a[b[c]]=e}this.setCustomDurations(a)},clearDurationOn:function(a){a=Ext.Array.from(a,true);var b=0,c=a.length;for(;b<c;b++){delete this._customDurations[a[b]]}},setAnimating:function(a,b){var e=this,d=e.animatingPool;if(a.animating!==b){a.animating=b;if(b){d.push(a);if(e.animating===0){Ext.draw.Animator.add(e)}e.animating++}else{for(var c=d.length;c--;){if(d[c]===a){d.splice(c,1)}}e.animating=d.length}}},setAttrs:function(r,t){var s=this,m=r.timers,h=s._sprite.self.def._animationProcessors,f=s._easing,e=s._duration,j=s._customDurations,i=s._customEasings,g=s.anySpecialAnimations,n=s.anyAnimation||g,o=r.animationOriginal,d=false,k,u,l,p,c,q,a;if(!n){for(u in t){if(r[u]===t[u]){delete t[u]}else{r[u]=t[u]}delete o[u];delete m[u]}return t}else{for(u in t){l=t[u];p=r[u];if(l!==p&&p!==undefined&&p!==null&&(c=h[u])){q=f;a=e;if(g){if(u in i){q=i[u]}if(u in j){a=j[u]}}if(p&&p.isGradient||l&&l.isGradient){a=0}if(a){if(!m[u]){m[u]={}}k=m[u];k.start=0;k.easing=q;k.duration=a;k.compute=c.compute;k.serve=c.serve||Ext.identityFn;k.remove=t.removeFromInstance&&t.removeFromInstance[u];if(c.parseInitial){var b=c.parseInitial(p,l);k.source=b[0];k.target=b[1]}else{if(c.parse){k.source=c.parse(p);k.target=c.parse(l)}else{k.source=p;k.target=l}}o[u]=l;delete t[u];d=true;continue}else{delete o[u]}}else{delete o[u]}delete m[u]}}if(d&&!r.animating){s.setAnimating(r,true)}return t},updateAttributes:function(g){if(!g.animating){return{}}var h={},e=false,d=g.timers,f=g.animationOriginal,c=Ext.draw.Animator.animationTime(),a,b,i;if(g.lastUpdate===c){return null}for(a in d){b=d[a];if(!b.start){b.start=c;i=0}else{i=(c-b.start)/b.duration}if(i>=1){h[a]=f[a];delete f[a];if(d[a].remove){h.removeFromInstance=h.removeFromInstance||{};h.removeFromInstance[a]=true}delete d[a]}else{h[a]=b.serve(b.compute(b.source,b.target,b.easing(i),g[a]));e=true}}g.lastUpdate=c;this.setAnimating(g,e);return h},pushDown:function(a,b){b=this.callParent([a.animationOriginal,b]);return this.setAttrs(a,b)},popUp:function(a,b){a=a.prototype;b=this.setAttrs(a,b);if(this._next){return this._next.popUp(a,b)}else{return Ext.apply(a,b)}},step:function(g){var f=this,c=f.animatingPool.slice(),e=c.length,b=0,a,d;for(;b<e;b++){a=c[b];d=f.updateAttributes(a);if(d&&f._next){f._next.popUp(a,d)}}},stop:function(){this.step();var d=this,b=d.animatingPool,a,c;for(a=0,c=b.length;a<c;a++){b[a].animating=false}d.animatingPool.length=0;d.animating=0;Ext.draw.Animator.remove(d)},destroy:function(){this.animatingPool.length=0;this.animating=0;this.callParent()}});Ext.define("Ext.draw.modifier.Highlight",{extend:"Ext.draw.modifier.Modifier",alias:"modifier.highlight",config:{enabled:false,highlightStyle:null},preFx:true,applyHighlightStyle:function(b,a){a=a||{};if(this.getSprite()){Ext.apply(a,this.getSprite().self.def.normalize(b))}else{Ext.apply(a,b)}return a},prepareAttributes:function(a){if(!a.hasOwnProperty("highlightOriginal")){a.highlighted=false;a.highlightOriginal=Ext.Object.chain(a);a.highlightOriginal.prototype=a;a.highlightOriginal.removeFromInstance={}}if(this._previous){this._previous.prepareAttributes(a.highlightOriginal)}},updateSprite:function(b,a){if(b){if(this.getHighlightStyle()){this._highlightStyle=b.self.def.normalize(this.getHighlightStyle())}this.setHighlightStyle(b.config.highlight)}b.self.def.setConfig({defaults:{highlighted:false},processors:{highlighted:"bool"}});this.setSprite(b)},filterChanges:function(a,d){var e=this,f=a.highlightOriginal,c=e.getHighlightStyle(),b;if(a.highlighted){for(b in d){if(c.hasOwnProperty(b)){f[b]=d[b];delete d[b]}}}for(b in d){if(b!=="highlighted"&&f[b]===d[b]){delete d[b]}}return d},pushDown:function(e,g){var f=this.getHighlightStyle(),c=e.highlightOriginal,i=c.removeFromInstance,d,a,h,b;if(g.hasOwnProperty("highlighted")){d=g.highlighted;delete g.highlighted;if(this._previous){g=this._previous.pushDown(c,g)}g=this.filterChanges(e,g);if(d!==e.highlighted){if(d){for(a in f){if(a in g){c[a]=g[a]}else{h=e.template&&e.template.ownAttr;if(h&&!e.prototype.hasOwnProperty(a)){i[a]=true;c[a]=h.animationOriginal[a]}else{b=c.timers[a];if(b&&b.remove){i[a]=true}c[a]=e[a]}}if(c[a]!==f[a]){g[a]=f[a]}}}else{for(a in f){if(!(a in g)){g[a]=c[a]}delete c[a]}g.removeFromInstance=g.removeFromInstance||{};Ext.apply(g.removeFromInstance,i);c.removeFromInstance={}}g.highlighted=d}}else{if(this._previous){g=this._previous.pushDown(c,g)}g=this.filterChanges(e,g)}return g},popUp:function(a,b){b=this.filterChanges(a,b);Ext.draw.modifier.Modifier.prototype.popUp.call(this,a,b)}});Ext.define("Ext.draw.sprite.Sprite",{alias:"sprite.sprite",mixins:{observable:"Ext.mixin.Observable"},requires:["Ext.draw.Draw","Ext.draw.gradient.Gradient","Ext.draw.sprite.AttributeDefinition","Ext.draw.modifier.Target","Ext.draw.modifier.Animation","Ext.draw.modifier.Highlight"],isSprite:true,statics:{defaultHitTestOptions:{fill:true,stroke:true}},inheritableStatics:{def:{processors:{strokeStyle:"color",fillStyle:"color",strokeOpacity:"limited01",fillOpacity:"limited01",lineWidth:"number",lineCap:"enums(butt,round,square)",lineJoin:"enums(round,bevel,miter)",lineDash:"data",lineDashOffset:"number",miterLimit:"number",shadowColor:"color",shadowOffsetX:"number",shadowOffsetY:"number",shadowBlur:"number",globalAlpha:"limited01",globalCompositeOperation:"enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",hidden:"bool",transformFillStroke:"bool",zIndex:"number",translationX:"number",translationY:"number",rotationRads:"number",rotationCenterX:"number",rotationCenterY:"number",scalingX:"number",scalingY:"number",scalingCenterX:"number",scalingCenterY:"number",constrainGradients:"bool"},aliases:{stroke:"strokeStyle",fill:"fillStyle",color:"fillStyle","stroke-width":"lineWidth","stroke-linecap":"lineCap","stroke-linejoin":"lineJoin","stroke-miterlimit":"miterLimit","text-anchor":"textAlign",opacity:"globalAlpha",translateX:"translationX",translateY:"translationY",rotateRads:"rotationRads",rotateCenterX:"rotationCenterX",rotateCenterY:"rotationCenterY",scaleX:"scalingX",scaleY:"scalingY",scaleCenterX:"scalingCenterX",scaleCenterY:"scalingCenterY"},defaults:{hidden:false,zIndex:0,strokeStyle:"none",fillStyle:"none",lineWidth:1,lineDash:[],lineDashOffset:0,lineCap:"butt",lineJoin:"miter",miterLimit:10,shadowColor:"none",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0,globalAlpha:1,strokeOpacity:1,fillOpacity:1,transformFillStroke:false,translationX:0,translationY:0,rotationRads:0,rotationCenterX:null,rotationCenterY:null,scalingX:1,scalingY:1,scalingCenterX:null,scalingCenterY:null,constrainGradients:false},triggers:{zIndex:"zIndex",globalAlpha:"canvas",globalCompositeOperation:"canvas",transformFillStroke:"canvas",strokeStyle:"canvas",fillStyle:"canvas",strokeOpacity:"canvas",fillOpacity:"canvas",lineWidth:"canvas",lineCap:"canvas",lineJoin:"canvas",lineDash:"canvas",lineDashOffset:"canvas",miterLimit:"canvas",shadowColor:"canvas",shadowOffsetX:"canvas",shadowOffsetY:"canvas",shadowBlur:"canvas",translationX:"transform",translationY:"transform",rotationRads:"transform",rotationCenterX:"transform",rotationCenterY:"transform",scalingX:"transform",scalingY:"transform",scalingCenterX:"transform",scalingCenterY:"transform",constrainGradients:"canvas"},updaters:{bbox:"bboxUpdater",zIndex:function(a){a.dirtyZIndex=true},transform:function(a){a.dirtyTransform=true;a.bbox.transform.dirty=true}}}},config:{parent:null,surface:null},onClassExtended:function(d,c){var b=d.superclass.self.def.initialConfig,e=c.inheritableStatics&&c.inheritableStatics.def,a;if(e){a=Ext.Object.merge({},b,e);d.def=new Ext.draw.sprite.AttributeDefinition(a);delete c.inheritableStatics.def}else{d.def=new Ext.draw.sprite.AttributeDefinition(b)}d.def.spriteClass=d},constructor:function(b){var d=this,c=d.self.def,e=c.getDefaults(),a;b=Ext.isObject(b)?b:{};d.id=b.id||Ext.id(null,"ext-sprite-");d.attr={};d.mixins.observable.constructor.apply(d,arguments);a=Ext.Array.from(b.modifiers,true);d.prepareModifiers(a);d.initializeAttributes();d.setAttributes(e,true);d.setAttributes(b)},getDirty:function(){return this.attr.dirty},setDirty:function(b){this.attr.dirty=b;if(b){var a=this.getParent();if(a){a.setDirty(true)}}},addModifier:function(a,b){var c=this;if(!(a instanceof Ext.draw.modifier.Modifier)){a=Ext.factory(a,null,null,"modifier")}a.setSprite(c);if(a.preFx||a.config&&a.config.preFx){if(c.fx.getPrevious()){c.fx.getPrevious().setNext(a)}a.setNext(c.fx)}else{c.topModifier.getPrevious().setNext(a);a.setNext(c.topModifier)}if(b){c.initializeAttributes()}return a},prepareModifiers:function(d){var c=this,a,b;c.topModifier=new Ext.draw.modifier.Target({sprite:c});c.fx=new Ext.draw.modifier.Animation({sprite:c});c.fx.setNext(c.topModifier);for(a=0,b=d.length;a<b;a++){c.addModifier(d[a],false)}},getAnimation:function(){return this.fx},setAnimation:function(a){this.fx.setConfig(a)},initializeAttributes:function(){this.topModifier.prepareAttributes(this.attr)},callUpdaters:function(d){var e=this,h=d.pendingUpdaters,i=e.self.def.getUpdaters(),c=false,a=false,b,g,f;e.callUpdaters=Ext.emptyFn;do{c=false;for(g in h){c=true;b=h[g];delete h[g];f=i[g];if(typeof f==="string"){f=e[f]}if(f){f.call(e,d,b)}}a=a||c}while(c);delete e.callUpdaters;if(a){e.setDirty(true)}},scheduleUpdaters:function(a,e,c){var f;if(c){for(var b=0,d=e.length;b<d;b++){f=e[b];this.scheduleUpdater(a,f,c)}}else{for(f in e){c=e[f];this.scheduleUpdater(a,f,c)}}},scheduleUpdater:function(a,c,b){b=b||[];var d=a.pendingUpdaters;if(c in d){if(b.length){d[c]=Ext.Array.merge(d[c],b)}}else{d[c]=b}},setAttributes:function(d,g,c){var a=this.attr,b,e,f;if(g){if(c){this.topModifier.pushDown(a,d)}else{f={};for(b in d){e=d[b];if(e!==a[b]){f[b]=e}}this.topModifier.pushDown(a,f)}}else{this.topModifier.pushDown(a,this.self.def.normalize(d))}},setAttributesBypassingNormalization:function(b,a){return this.setAttributes(b,true,a)},bboxUpdater:function(b){var c=b.rotationRads!==0,a=b.scalingX!==1||b.scalingY!==1,d=b.rotationCenterX===null||b.rotationCenterY===null,e=b.scalingCenterX===null||b.scalingCenterY===null;b.bbox.plain.dirty=true;b.bbox.transform.dirty=true;if(c&&d||a&&e){this.scheduleUpdater(b,"transform")}},getBBox:function(d){var e=this,a=e.attr,f=a.bbox,c=f.plain,b=f.transform;if(c.dirty){e.updatePlainBBox(c);c.dirty=false}if(!d){e.applyTransformations();if(b.dirty){e.updateTransformedBBox(b,c);b.dirty=false}return b}return c},updatePlainBBox:Ext.emptyFn,updateTransformedBBox:function(a,b){this.attr.matrix.transformBBox(b,0,a)},getBBoxCenter:function(a){var b=this.getBBox(a);if(b){return[b.x+b.width*0.5,b.y+b.height*0.5]}else{return[0,0]}},hide:function(){this.attr.hidden=true;this.setDirty(true);return this},show:function(){this.attr.hidden=false;this.setDirty(true);return this},useAttributes:function(i,f){this.applyTransformations();var d=this.attr,h=d.canvasAttributes,e=h.strokeStyle,g=h.fillStyle,b=h.lineDash,c=h.lineDashOffset,a;if(e){if(e.isGradient){i.strokeStyle="black";i.strokeGradient=e}else{i.strokeGradient=false}}if(g){if(g.isGradient){i.fillStyle="black";i.fillGradient=g}else{i.fillGradient=false}}if(b){i.setLineDash(b)}if(Ext.isNumber(c+i.lineDashOffset)){i.lineDashOffset=c}for(a in h){if(h[a]!==undefined&&h[a]!==i[a]){i[a]=h[a]}}this.setGradientBBox(i,f)},setGradientBBox:function(b,c){var a=this.attr;if(a.constrainGradients){b.setGradientBBox({x:c[0],y:c[1],width:c[2],height:c[3]})}else{b.setGradientBBox(this.getBBox(a.transformFillStroke))}},applyTransformations:function(b){if(!b&&!this.attr.dirtyTransform){return}var r=this,k=r.attr,p=r.getBBoxCenter(true),g=p[0],f=p[1],q=k.translationX,o=k.translationY,j=k.scalingX,i=k.scalingY===null?k.scalingX:k.scalingY,m=k.scalingCenterX===null?g:k.scalingCenterX,l=k.scalingCenterY===null?f:k.scalingCenterY,s=k.rotationRads,e=k.rotationCenterX===null?g:k.rotationCenterX,d=k.rotationCenterY===null?f:k.rotationCenterY,c=Math.cos(s),a=Math.sin(s),n,h;if(j===1&&i===1){m=0;l=0}if(s===0){e=0;d=0}n=m*(1-j)-e;h=l*(1-i)-d;k.matrix.elements=[c*j,a*j,-a*i,c*i,c*n-a*h+e+q,a*n+c*h+d+o];k.matrix.inverse(k.inverseMatrix);k.dirtyTransform=false;k.bbox.transform.dirty=true},transform:function(b,c){var a=this.attr,e=a.matrix,d;if(b&&b.isMatrix){d=b.elements}else{d=b}e.prepend.apply(e,d.slice());e.inverse(a.inverseMatrix);if(c){this.updateTransformAttributes()}a.dirtyTransform=false;a.bbox.transform.dirty=true;this.setDirty(true);return this},updateTransformAttributes:function(){var a=this.attr,b=a.matrix.split();a.rotationRads=b.rotate;a.rotationCenterX=0;a.rotationCenterY=0;a.scalingX=b.scaleX;a.scalingY=b.scaleY;a.scalingCenterX=0;a.scalingCenterY=0;a.translationX=b.translateX;a.translationY=b.translateY},resetTransform:function(b){var a=this.attr;a.matrix.reset();a.inverseMatrix.reset();if(!b){this.updateTransformAttributes()}a.dirtyTransform=false;a.bbox.transform.dirty=true;this.setDirty(true);return this},setTransform:function(a,b){this.resetTransform(true);this.transform.call(this,a,b);return this},preRender:Ext.emptyFn,render:Ext.emptyFn,hitTest:function(b,c){if(this.isVisible()){var a=b[0],f=b[1],e=this.getBBox(),d=e&&a>=e.x&&a<=(e.x+e.width)&&f>=e.y&&f<=(e.y+e.height);if(d){return{sprite:this}}}return null},isVisible:function(){var e=this.attr,f=this.getParent(),g=f&&(f.isSurface||f.isVisible()),d=g&&!e.hidden&&e.globalAlpha,b=Ext.draw.Color.NONE,a=Ext.draw.Color.RGBA_NONE,c=e.fillOpacity&&e.fillStyle!==b&&e.fillStyle!==a,i=e.strokeOpacity&&e.strokeStyle!==b&&e.strokeStyle!==a,h=d&&(c||i);return !!h},repaint:function(){var a=this.getSurface();if(a){a.renderFrame()}},remove:function(){var a=this.getSurface();if(a&&a.isSurface){return a.remove(this)}return null},destroy:function(){var b=this,a=b.topModifier,c;while(a){c=a;a=a.getPrevious();c.destroy()}delete b.attr;b.remove();if(b.fireEvent("beforedestroy",b)!==false){b.fireEvent("destroy",b)}b.callParent()}},function(){this.def=new Ext.draw.sprite.AttributeDefinition(this.def);this.def.spriteClass=this});Ext.define("Ext.draw.Path",{requires:["Ext.draw.Draw"],statics:{pathRe:/,?([achlmqrstvxz]),?/gi,pathRe2:/-/gi,pathSplitRe:/\s|,/g},svgString:"",constructor:function(a){var b=this;b.commands=[];b.params=[];b.cursor=null;b.startX=0;b.startY=0;if(a){b.fromSvgString(a)}},clear:function(){var a=this;a.params.length=0;a.commands.length=0;a.cursor=null;a.startX=0;a.startY=0;a.dirt()},dirt:function(){this.svgString=""},moveTo:function(a,c){var b=this;if(!b.cursor){b.cursor=[a,c]}b.params.push(a,c);b.commands.push("M");b.startX=a;b.startY=c;b.cursor[0]=a;b.cursor[1]=c;b.dirt()},lineTo:function(a,c){var b=this;if(!b.cursor){b.cursor=[a,c];b.params.push(a,c);b.commands.push("M")}else{b.params.push(a,c);b.commands.push("L")}b.cursor[0]=a;b.cursor[1]=c;b.dirt()},bezierCurveTo:function(c,e,b,d,a,g){var f=this;if(!f.cursor){f.moveTo(c,e)}f.params.push(c,e,b,d,a,g);f.commands.push("C");f.cursor[0]=a;f.cursor[1]=g;f.dirt()},quadraticCurveTo:function(b,e,a,d){var c=this;if(!c.cursor){c.moveTo(b,e)}c.bezierCurveTo((2*b+c.cursor[0])/3,(2*e+c.cursor[1])/3,(2*b+a)/3,(2*e+d)/3,a,d)},closePath:function(){var a=this;if(a.cursor){a.cursor=null;a.commands.push("Z");a.dirt()}},arcTo:function(A,f,z,d,j,i,v){var E=this;if(i===undefined){i=j}if(v===undefined){v=0}if(!E.cursor){E.moveTo(A,f);return}if(j===0||i===0){E.lineTo(A,f);return}z-=A;d-=f;var B=E.cursor[0]-A,g=E.cursor[1]-f,C=z*g-d*B,b,a,l,r,k,q,x=Math.sqrt(B*B+g*g),u=Math.sqrt(z*z+d*d),t,e,c;if(C===0){E.lineTo(A,f);return}if(i!==j){b=Math.cos(v);a=Math.sin(v);l=b/j;r=a/i;k=-a/j;q=b/i;var D=l*B+r*g;g=k*B+q*g;B=D;D=l*z+r*d;d=k*z+q*d;z=D}else{B/=j;g/=i;z/=j;d/=i}e=B*u+z*x;c=g*u+d*x;t=1/(Math.sin(Math.asin(Math.abs(C)/(x*u))*0.5)*Math.sqrt(e*e+c*c));e*=t;c*=t;var o=(e*B+c*g)/(B*B+g*g),m=(e*z+c*d)/(z*z+d*d);var n=B*o-e,p=g*o-c,h=z*m-e,y=d*m-c,w=Math.atan2(p,n),s=Math.atan2(y,h);if(C>0){if(s<w){s+=Math.PI*2}}else{if(w<s){w+=Math.PI*2}}if(i!==j){e=b*e*j-a*c*i+A;c=a*c*i+b*c*i+f;E.lineTo(b*j*n-a*i*p+e,a*j*n+b*i*p+c);E.ellipse(e,c,j,i,v,w,s,C<0)}else{e=e*j+A;c=c*i+f;E.lineTo(j*n+e,i*p+c);E.ellipse(e,c,j,i,v,w,s,C<0)}},ellipse:function(h,f,c,a,q,n,d,e){var o=this,g=o.params,b=g.length,m,l,k;if(d-n>=Math.PI*2){o.ellipse(h,f,c,a,q,n,n+Math.PI,e);o.ellipse(h,f,c,a,q,n+Math.PI,d,e);return}if(!e){if(d<n){d+=Math.PI*2}m=o.approximateArc(g,h,f,c,a,q,n,d)}else{if(n<d){n+=Math.PI*2}m=o.approximateArc(g,h,f,c,a,q,d,n);for(l=b,k=g.length-2;l<k;l+=2,k-=2){var p=g[l];g[l]=g[k];g[k]=p;p=g[l+1];g[l+1]=g[k+1];g[k+1]=p}}if(!o.cursor){o.cursor=[g[g.length-2],g[g.length-1]];o.commands.push("M")}else{o.cursor[0]=g[g.length-2];o.cursor[1]=g[g.length-1];o.commands.push("L")}for(l=2;l<m;l+=6){o.commands.push("C")}o.dirt()},arc:function(b,f,a,d,c,e){this.ellipse(b,f,a,a,0,d,c,e)},rect:function(b,e,c,a){if(c==0||a==0){return}var d=this;d.moveTo(b,e);d.lineTo(b+c,e);d.lineTo(b+c,e+a);d.lineTo(b,e+a);d.closePath()},approximateArc:function(s,i,f,o,n,d,x,v){var e=Math.cos(d),z=Math.sin(d),k=Math.cos(x),l=Math.sin(x),q=e*k*o-z*l*n,y=-e*l*o-z*k*n,p=z*k*o+e*l*n,w=-z*l*o+e*k*n,m=Math.PI/2,r=2,j=q,u=y,h=p,t=w,b=0.547443256150549,C,g,A,a,B,c;v-=x;if(v<0){v+=Math.PI*2}s.push(q+i,p+f);while(v>=m){s.push(j+u*b+i,h+t*b+f,j*b+u+i,h*b+t+f,u+i,t+f);r+=6;v-=m;C=j;j=u;u=-C;C=h;h=t;t=-C}if(v){g=(0.3294738052815987+0.012120855841304373*v)*v;A=Math.cos(v);a=Math.sin(v);B=A+g*a;c=a-g*A;s.push(j+u*g+i,h+t*g+f,j*B+u*c+i,h*B+t*c+f,j*A+u*a+i,h*A+t*a+f);r+=6}return r},arcSvg:function(j,h,r,m,w,t,c){if(j<0){j=-j}if(h<0){h=-h}var x=this,u=x.cursor[0],f=x.cursor[1],a=(u-t)/2,y=(f-c)/2,d=Math.cos(r),s=Math.sin(r),o=a*d+y*s,v=-a*s+y*d,i=o/j,g=v/h,p=i*i+g*g,e=(u+t)*0.5,b=(f+c)*0.5,l=0,k=0;if(p>=1){p=Math.sqrt(p);j*=p;h*=p}else{p=Math.sqrt(1/p-1);if(m===w){p=-p}l=p*j*g;k=-p*h*i;e+=d*l-s*k;b+=s*l+d*k}var q=Math.atan2((v-k)/h,(o-l)/j),n=Math.atan2((-v-k)/h,(-o-l)/j)-q;if(w){if(n<=0){n+=Math.PI*2}}else{if(n>=0){n-=Math.PI*2}}x.ellipse(e,b,j,h,r,q,q+n,1-w)},fromSvgString:function(e){if(!e){return}var m=this,h,l={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0,A:7,C:6,H:1,L:2,M:2,Q:4,S:4,T:2,V:1,Z:0},k="",g,f,c=0,b=0,d=false,j,n,a;if(Ext.isString(e)){h=e.replace(Ext.draw.Path.pathRe," $1 ").replace(Ext.draw.Path.pathRe2," -").split(Ext.draw.Path.pathSplitRe)}else{if(Ext.isArray(e)){h=e.join(",").split(Ext.draw.Path.pathSplitRe)}}for(j=0,n=0;j<h.length;j++){if(h[j]!==""){h[n++]=h[j]}}h.length=n;m.clear();for(j=0;j<h.length;){k=d;d=h[j];a=(d.toUpperCase()!==d);j++;switch(d){case"M":m.moveTo(c=+h[j],b=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b=+h[j+1]);j+=2}break;case"L":m.lineTo(c=+h[j],b=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b=+h[j+1]);j+=2}break;case"A":while(j<n&&!l.hasOwnProperty(h[j])){m.arcSvg(+h[j],+h[j+1],+h[j+2]*Math.PI/180,+h[j+3],+h[j+4],c=+h[j+5],b=+h[j+6]);j+=7}break;case"C":while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(+h[j],+h[j+1],g=+h[j+2],f=+h[j+3],c=+h[j+4],b=+h[j+5]);j+=6}break;case"Z":m.closePath();break;case"m":m.moveTo(c+=+h[j],b+=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2}break;case"l":m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2;while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b+=+h[j+1]);j+=2}break;case"a":while(j<n&&!l.hasOwnProperty(h[j])){m.arcSvg(+h[j],+h[j+1],+h[j+2]*Math.PI/180,+h[j+3],+h[j+4],c+=+h[j+5],b+=+h[j+6]);j+=7}break;case"c":while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+(+h[j]),b+(+h[j+1]),g=c+(+h[j+2]),f=b+(+h[j+3]),c+=+h[j+4],b+=+h[j+5]);j+=6}break;case"z":m.closePath();break;case"s":if(!(k==="c"||k==="C"||k==="s"||k==="S")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+c-g,b+b-f,g=c+(+h[j]),f=b+(+h[j+1]),c+=+h[j+2],b+=+h[j+3]);j+=4}break;case"S":if(!(k==="c"||k==="C"||k==="s"||k==="S")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.bezierCurveTo(c+c-g,b+b-f,g=+h[j],f=+h[j+1],c=(+h[j+2]),b=(+h[j+3]));j+=4}break;case"q":while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+(+h[j]),f=b+(+h[j+1]),c+=+h[j+2],b+=+h[j+3]);j+=4}break;case"Q":while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=+h[j],f=+h[j+1],c=+h[j+2],b=+h[j+3]);j+=4}break;case"t":if(!(k==="q"||k==="Q"||k==="t"||k==="T")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+c-g,f=b+b-f,c+=+h[j+1],b+=+h[j+2]);j+=2}break;case"T":if(!(k==="q"||k==="Q"||k==="t"||k==="T")){g=c;f=b}while(j<n&&!l.hasOwnProperty(h[j])){m.quadraticCurveTo(g=c+c-g,f=b+b-f,c=(+h[j+1]),b=(+h[j+2]));j+=2}break;case"h":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c+=+h[j],b);j++}break;case"H":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c=+h[j],b);j++}break;case"v":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c,b+=+h[j]);j++}break;case"V":while(j<n&&!l.hasOwnProperty(h[j])){m.lineTo(c,b=+h[j]);j++}break}}},clone:function(){var a=this,b=new Ext.draw.Path();b.params=a.params.slice(0);b.commands=a.commands.slice(0);b.cursor=a.cursor?a.cursor.slice(0):null;b.startX=a.startX;b.startY=a.startY;b.svgString=a.svgString;return b},transform:function(j){if(j.isIdentity()){return}var a=j.getXX(),f=j.getYX(),m=j.getDX(),l=j.getXY(),e=j.getYY(),k=j.getDY(),b=this.params,c=0,d=b.length,h,g;for(;c<d;c+=2){h=b[c];g=b[c+1];b[c]=h*a+g*f+m;b[c+1]=h*l+g*e+k}this.dirt()},getDimension:function(f){if(!f){f={}}if(!this.commands||!this.commands.length){f.x=0;f.y=0;f.width=0;f.height=0;return f}f.left=Infinity;f.top=Infinity;f.right=-Infinity;f.bottom=-Infinity;var d=0,c=0,b=this.commands,g=this.params,e=b.length,a,h;for(;d<e;d++){switch(b[d]){case"M":case"L":a=g[c];h=g[c+1];f.left=Math.min(a,f.left);f.top=Math.min(h,f.top);f.right=Math.max(a,f.right);f.bottom=Math.max(h,f.bottom);c+=2;break;case"C":this.expandDimension(f,a,h,g[c],g[c+1],g[c+2],g[c+3],a=g[c+4],h=g[c+5]);c+=6;break}}f.x=f.left;f.y=f.top;f.width=f.right-f.left;f.height=f.bottom-f.top;return f},getDimensionWithTransform:function(n,f){if(!this.commands||!this.commands.length){if(!f){f={}}f.x=0;f.y=0;f.width=0;f.height=0;return f}f.left=Infinity;f.top=Infinity;f.right=-Infinity;f.bottom=-Infinity;var a=n.getXX(),k=n.getYX(),q=n.getDX(),p=n.getXY(),h=n.getYY(),o=n.getDY(),e=0,d=0,b=this.commands,c=this.params,g=b.length,m,l;for(;e<g;e++){switch(b[e]){case"M":case"L":m=c[d]*a+c[d+1]*k+q;l=c[d]*p+c[d+1]*h+o;f.left=Math.min(m,f.left);f.top=Math.min(l,f.top);f.right=Math.max(m,f.right);f.bottom=Math.max(l,f.bottom);d+=2;break;case"C":this.expandDimension(f,m,l,c[d]*a+c[d+1]*k+q,c[d]*p+c[d+1]*h+o,c[d+2]*a+c[d+3]*k+q,c[d+2]*p+c[d+3]*h+o,m=c[d+4]*a+c[d+5]*k+q,l=c[d+4]*p+c[d+5]*h+o);d+=6;break}}if(!f){f={}}f.x=f.left;f.y=f.top;f.width=f.right-f.left;f.height=f.bottom-f.top;return f},expandDimension:function(i,d,p,k,g,j,e,c,o){var m=this,f=i.left,a=i.right,q=i.top,n=i.bottom,h=m.dim||(m.dim=[]);m.curveDimension(d,k,j,c,h);f=Math.min(f,h[0]);a=Math.max(a,h[1]);m.curveDimension(p,g,e,o,h);q=Math.min(q,h[0]);n=Math.max(n,h[1]);i.left=f;i.right=a;i.top=q;i.bottom=n},curveDimension:function(p,n,k,j,h){var i=3*(-p+3*(n-k)+j),g=6*(p-2*n+k),f=-3*(p-n),o,m,e=Math.min(p,j),l=Math.max(p,j),q;if(i===0){if(g===0){h[0]=e;h[1]=l;return}else{o=-f/g;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}}}else{q=g*g-4*i*f;if(q>=0){q=Math.sqrt(q);o=(q-g)/2/i;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}if(q>0){o-=q/i;if(0<o&&o<1){m=this.interpolate(p,n,k,j,o);e=Math.min(e,m);l=Math.max(l,m)}}}}h[0]=e;h[1]=l},interpolate:function(f,e,j,i,g){if(g===0){return f}if(g===1){return i}var h=(1-g)/g;return g*g*g*(i+h*(3*j+h*(3*e+h*f)))},fromStripes:function(g){var e=this,c=0,d=g.length,b,a,f;e.clear();for(;c<d;c++){f=g[c];e.params.push.apply(e.params,f);e.commands.push("M");for(b=2,a=f.length;b<a;b+=6){e.commands.push("C")}}if(!e.cursor){e.cursor=[]}e.cursor[0]=e.params[e.params.length-2];e.cursor[1]=e.params[e.params.length-1];e.dirt()},toStripes:function(k){var o=k||[],p,n,m,b,a,h,g,f,e,c=this.commands,d=this.params,l=c.length;for(f=0,e=0;f<l;f++){switch(c[f]){case"M":p=[h=b=d[e++],g=a=d[e++]];o.push(p);break;case"L":n=d[e++];m=d[e++];p.push((b+b+n)/3,(a+a+m)/3,(b+n+n)/3,(a+m+m)/3,b=n,a=m);break;case"C":p.push(d[e++],d[e++],d[e++],d[e++],b=d[e++],a=d[e++]);break;case"Z":n=h;m=g;p.push((b+b+n)/3,(a+a+m)/3,(b+n+n)/3,(a+m+m)/3,b=n,a=m);break}}return o},updateSvgString:function(){var b=[],a=this.commands,f=this.params,e=a.length,d=0,c=0;for(;d<e;d++){switch(a[d]){case"M":b.push("M"+f[c]+","+f[c+1]);c+=2;break;case"L":b.push("L"+f[c]+","+f[c+1]);c+=2;break;case"C":b.push("C"+f[c]+","+f[c+1]+" "+f[c+2]+","+f[c+3]+" "+f[c+4]+","+f[c+5]);c+=6;break;case"Z":b.push("Z");break}}this.svgString=b.join("")},toString:function(){if(!this.svgString){this.updateSvgString()}return this.svgString}});Ext.define("Ext.draw.overrides.Path",{override:"Ext.draw.Path",rayOrigin:{x:-10000,y:-10000},isPointInPath:function(o,n){var m=this,c=m.commands,q=Ext.draw.PathUtil,p=m.rayOrigin,f=m.params,l=c.length,e=null,d=null,b=0,a=0,k=0,h,g;for(h=0,g=0;h<l;h++){switch(c[h]){case"M":if(e!==null){if(q.linesIntersection(e,d,b,a,p.x,p.y,o,n)){k+=1}}e=b=f[g];d=a=f[g+1];g+=2;break;case"L":if(q.linesIntersection(b,a,f[g],f[g+1],p.x,p.y,o,n)){k+=1}b=f[g];a=f[g+1];g+=2;break;case"C":k+=q.cubicLineIntersections(b,f[g],f[g+2],f[g+4],a,f[g+1],f[g+3],f[g+5],p.x,p.y,o,n).length;b=f[g+4];a=f[g+5];g+=6;break;case"Z":if(e!==null){if(q.linesIntersection(e,d,b,a,p.x,p.y,o,n)){k+=1}}break}}return k%2===1},isPointOnPath:function(n,m){var l=this,c=l.commands,o=Ext.draw.PathUtil,f=l.params,k=c.length,e=null,d=null,b=0,a=0,h,g;for(h=0,g=0;h<k;h++){switch(c[h]){case"M":if(e!==null){if(o.pointOnLine(e,d,b,a,n,m)){return true}}e=b=f[g];d=a=f[g+1];g+=2;break;case"L":if(o.pointOnLine(b,a,f[g],f[g+1],n,m)){return true}b=f[g];a=f[g+1];g+=2;break;case"C":if(o.pointOnCubic(b,f[g],f[g+2],f[g+4],a,f[g+1],f[g+3],f[g+5],n,m)){return true}b=f[g+4];a=f[g+5];g+=6;break;case"Z":if(e!==null){if(o.pointOnLine(e,d,b,a,n,m)){return true}}break}}return false},getSegmentIntersections:function(t,d,s,c,r,b,o,a){var w=this,g=arguments.length,v=Ext.draw.PathUtil,f=w.commands,u=w.params,k=f.length,m=null,l=null,h=0,e=0,x=[],q,n,p;for(q=0,n=0;q<k;q++){switch(f[q]){case"M":if(m!==null){switch(g){case 4:p=v.linesIntersection(m,l,h,e,t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,m,l,h,e);x.push.apply(x,p);break}}m=h=u[n];l=e=u[n+1];n+=2;break;case"L":switch(g){case 4:p=v.linesIntersection(h,e,u[n],u[n+1],t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,h,e,u[n],u[n+1]);x.push.apply(x,p);break}h=u[n];e=u[n+1];n+=2;break;case"C":switch(g){case 4:p=v.cubicLineIntersections(h,u[n],u[n+2],u[n+4],e,u[n+1],u[n+3],u[n+5],t,d,s,c);x.push.apply(x,p);break;case 8:p=v.cubicsIntersections(h,u[n],u[n+2],u[n+4],e,u[n+1],u[n+3],u[n+5],t,s,r,o,d,c,b,a);x.push.apply(x,p);break}h=u[n+4];e=u[n+5];n+=6;break;case"Z":if(m!==null){switch(g){case 4:p=v.linesIntersection(m,l,h,e,t,d,s,c);if(p){x.push(p)}break;case 8:p=v.cubicLineIntersections(t,s,r,o,d,c,b,a,m,l,h,e);x.push.apply(x,p);break}}break}}return x},getIntersections:function(o){var m=this,c=m.commands,g=m.params,l=c.length,f=null,e=null,b=0,a=0,d=[],k,h,n;for(k=0,h=0;k<l;k++){switch(c[k]){case"M":if(f!==null){n=o.getSegmentIntersections.call(o,f,e,b,a);d.push.apply(d,n)}f=b=g[h];e=a=g[h+1];h+=2;break;case"L":n=o.getSegmentIntersections.call(o,b,a,g[h],g[h+1]);d.push.apply(d,n);b=g[h];a=g[h+1];h+=2;break;case"C":n=o.getSegmentIntersections.call(o,b,a,g[h],g[h+1],g[h+2],g[h+3],g[h+4],g[h+5]);d.push.apply(d,n);b=g[h+4];a=g[h+5];h+=6;break;case"Z":if(f!==null){n=o.getSegmentIntersections.call(o,f,e,b,a);d.push.apply(d,n)}break}}return d}});Ext.define("Ext.draw.sprite.Path",{extend:"Ext.draw.sprite.Sprite",requires:["Ext.draw.Draw","Ext.draw.Path"],alias:["sprite.path","Ext.draw.Sprite"],type:"path",isPath:true,inheritableStatics:{def:{processors:{path:function(b,a){if(!(b instanceof Ext.draw.Path)){b=new Ext.draw.Path(b)}return b}},aliases:{d:"path"},triggers:{path:"bbox"},updaters:{path:function(a){var b=a.path;if(!b||b.bindAttr!==a){b=new Ext.draw.Path();b.bindAttr=a;a.path=b}b.clear();this.updatePath(b,a);this.scheduleUpdater(a,"bbox",["path"])}}}},updatePlainBBox:function(a){if(this.attr.path){this.attr.path.getDimension(a)}},updateTransformedBBox:function(a){if(this.attr.path){this.attr.path.getDimensionWithTransform(this.attr.matrix,a)}},render:function(b,c){var d=this.attr.matrix,a=this.attr;if(!a.path||a.path.params.length===0){return}d.toContext(c);c.appendPath(a.path);c.fillStroke(a)},updatePath:function(b,a){}});Ext.define("Ext.draw.overrides.sprite.Path",{override:"Ext.draw.sprite.Path",requires:["Ext.draw.Color"],isPointInPath:function(c,g){var b=this.attr;if(b.fillStyle===Ext.draw.Color.RGBA_NONE){return this.isPointOnPath(c,g)}var e=b.path,d=b.matrix,f,a;if(!d.isIdentity()){f=e.params.slice(0);e.transform(b.matrix)}a=e.isPointInPath(c,g);if(f){e.params=f}return a},isPointOnPath:function(c,g){var b=this.attr,e=b.path,d=b.matrix,f,a;if(!d.isIdentity()){f=e.params.slice(0);e.transform(b.matrix)}a=e.isPointOnPath(c,g);if(f){e.params=f}return a},hitTest:function(i,l){var e=this,c=e.attr,k=c.path,g=c.matrix,h=i[0],f=i[1],d=e.callParent([i,l]),j=null,a,b;if(!d){return j}l=l||Ext.draw.sprite.Sprite.defaultHitTestOptions;if(!g.isIdentity()){a=k.params.slice(0);k.transform(c.matrix)}if(l.fill&&l.stroke){b=c.fillStyle!==Ext.draw.Color.NONE&&c.fillStyle!==Ext.draw.Color.RGBA_NONE;if(b){if(k.isPointInPath(h,f)){j={sprite:e}}}else{if(k.isPointInPath(h,f)||k.isPointOnPath(h,f)){j={sprite:e}}}}else{if(l.stroke&&!l.fill){if(k.isPointOnPath(h,f)){j={sprite:e}}}else{if(l.fill&&!l.stroke){if(k.isPointInPath(h,f)){j={sprite:e}}}}}if(a){k.params=a}return j},getIntersections:function(j){if(!(j.isSprite&&j.isPath)){return[]}var e=this.attr,d=j.attr,i=e.path,h=d.path,g=e.matrix,a=d.matrix,c,f,b;if(!g.isIdentity()){c=i.params.slice(0);i.transform(e.matrix)}if(!a.isIdentity()){f=h.params.slice(0);h.transform(d.matrix)}b=i.getIntersections(h);if(c){i.params=c}if(f){h.params=f}return b}});Ext.define("Ext.draw.sprite.Circle",{extend:"Ext.draw.sprite.Path",alias:"sprite.circle",type:"circle",inheritableStatics:{def:{processors:{cx:"number",cy:"number",r:"number"},aliases:{radius:"r",x:"cx",y:"cy",centerX:"cx",centerY:"cy"},defaults:{cx:0,cy:0,r:4},triggers:{cx:"path",cy:"path",r:"path"}}},updatePlainBBox:function(c){var b=this.attr,a=b.cx,e=b.cy,d=b.r;c.x=a-d;c.y=e-d;c.width=d+d;c.height=d+d},updateTransformedBBox:function(d){var g=this.attr,f=g.cx,e=g.cy,a=g.r,h=g.matrix,j=h.getScaleX(),i=h.getScaleY(),c,b;c=j*a;b=i*a;d.x=h.x(f,e)-c;d.y=h.y(f,e)-b;d.width=c+c;d.height=b+b},updatePath:function(b,a){b.arc(a.cx,a.cy,a.r,0,Math.PI*2,false)}});Ext.define("Ext.draw.sprite.Arc",{extend:"Ext.draw.sprite.Circle",alias:"sprite.arc",type:"arc",inheritableStatics:{def:{processors:{startAngle:"number",endAngle:"number",anticlockwise:"bool"},aliases:{from:"startAngle",to:"endAngle",start:"startAngle",end:"endAngle"},defaults:{startAngle:0,endAngle:Math.PI*2,anticlockwise:false},triggers:{startAngle:"path",endAngle:"path",anticlockwise:"path"}}},updatePath:function(b,a){b.arc(a.cx,a.cy,a.r,a.startAngle,a.endAngle,a.anticlockwise)}});Ext.define("Ext.draw.sprite.Arrow",{extend:"Ext.draw.sprite.Path",alias:"sprite.arrow",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*1.5,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c*0.7,",",e-c*0.4,"l",[c*0.6,0,0,-c*0.4,c,c*0.8,-c,c*0.8,0,-c*0.4,-c*0.6,0],"z"))}});Ext.define("Ext.draw.sprite.Composite",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.composite",type:"composite",isComposite:true,config:{sprites:[]},constructor:function(){this.sprites=[];this.sprites.map={};this.callParent(arguments)},add:function(c){if(!c){return null}if(!c.isSprite){c=Ext.create("sprite."+c.type,c);c.setParent(this);c.setSurface(this.getSurface())}var d=this,a=d.attr,b=c.applyTransformations;c.applyTransformations=function(){if(c.attr.dirtyTransform){a.dirtyTransform=true;a.bbox.plain.dirty=true;a.bbox.transform.dirty=true}b.call(c)};d.sprites.push(c);d.sprites.map[c.id]=c.getId();a.bbox.plain.dirty=true;a.bbox.transform.dirty=true;return c},updateSurface:function(a){for(var b=0,c=this.sprites.length;b<c;b++){this.sprites[b].setSurface(a)}},addAll:function(b){if(b.isSprite||b.type){this.add(b)}else{if(Ext.isArray(b)){var a=0;while(a<b.length){this.add(b[a++])}}}},updatePlainBBox:function(g){var e=this,b=Infinity,h=-Infinity,f=Infinity,a=-Infinity,j,k,c,d;for(c=0,d=e.sprites.length;c<d;c++){j=e.sprites[c];j.applyTransformations();k=j.getBBox();if(b>k.x){b=k.x}if(h<k.x+k.width){h=k.x+k.width}if(f>k.y){f=k.y}if(a<k.y+k.height){a=k.y+k.height}}g.x=b;g.y=f;g.width=h-b;g.height=a-f},render:function(a,b,f){var d=this.attr.matrix,c,e;d.toContext(b);for(c=0,e=this.sprites.length;c<e;c++){a.renderSprite(this.sprites[c],f)}},destroy:function(){var c=this,d=c.sprites,b=d.length,a;c.callParent();for(a=0;a<b;a++){d[a].destroy()}d.length=0}});Ext.define("Ext.draw.sprite.Cross",{extend:"Ext.draw.sprite.Path",alias:"sprite.cross",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size/1.7,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c,",",e,"l",[-c,-c,c,-c,c,c,c,-c,c,c,-c,c,c,c,-c,c,-c,-c,-c,c,-c,-c,"z"]))}});Ext.define("Ext.draw.sprite.Diamond",{extend:"Ext.draw.sprite.Path",alias:"sprite.diamond",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*1.25,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString(["M",a,e-c,"l",c,c,-c,c,-c,-c,c,-c,"z"])}});Ext.define("Ext.draw.sprite.Ellipse",{extend:"Ext.draw.sprite.Path",alias:"sprite.ellipse",type:"ellipse",inheritableStatics:{def:{processors:{cx:"number",cy:"number",rx:"number",ry:"number",axisRotation:"number"},aliases:{radius:"r",x:"cx",y:"cy",centerX:"cx",centerY:"cy",radiusX:"rx",radiusY:"ry"},defaults:{cx:0,cy:0,rx:1,ry:1,axisRotation:0},triggers:{cx:"path",cy:"path",rx:"path",ry:"path",axisRotation:"path"}}},updatePlainBBox:function(c){var b=this.attr,a=b.cx,f=b.cy,e=b.rx,d=b.ry;c.x=a-e;c.y=f-d;c.width=e+e;c.height=d+d},updateTransformedBBox:function(d){var i=this.attr,f=i.cx,e=i.cy,c=i.rx,b=i.ry,l=b/c,m=i.matrix.clone(),a,q,k,j,p,o,n,g;m.append(1,0,0,l,0,e*(1-l));a=m.getXX();k=m.getYX();p=m.getDX();q=m.getXY();j=m.getYY();o=m.getDY();n=Math.sqrt(a*a+k*k)*c;g=Math.sqrt(q*q+j*j)*c;d.x=f*a+e*k+p-n;d.y=f*q+e*j+o-g;d.width=n+n;d.height=g+g},updatePath:function(b,a){b.ellipse(a.cx,a.cy,a.rx,a.ry,a.axisRotation,0,Math.PI*2,false)}});Ext.define("Ext.draw.sprite.EllipticalArc",{extend:"Ext.draw.sprite.Ellipse",alias:"sprite.ellipticalArc",type:"ellipticalArc",inheritableStatics:{def:{processors:{startAngle:"number",endAngle:"number",anticlockwise:"bool"},aliases:{from:"startAngle",to:"endAngle",start:"startAngle",end:"endAngle"},defaults:{startAngle:0,endAngle:Math.PI*2,anticlockwise:false},triggers:{startAngle:"path",endAngle:"path",anticlockwise:"path"}}},updatePath:function(b,a){b.ellipse(a.cx,a.cy,a.rx,a.ry,a.axisRotation,a.startAngle,a.endAngle,a.anticlockwise)}});Ext.define("Ext.draw.sprite.Rect",{extend:"Ext.draw.sprite.Path",alias:"sprite.rect",type:"rect",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number",radius:"number"},aliases:{},triggers:{x:"path",y:"path",width:"path",height:"path",radius:"path"},defaults:{x:0,y:0,width:8,height:8,radius:0}}},updatePlainBBox:function(b){var a=this.attr;b.x=a.x;b.y=a.y;b.width=a.width;b.height=a.height},updateTransformedBBox:function(a,b){this.attr.matrix.transformBBox(b,this.attr.radius,a)},updatePath:function(f,d){var c=d.x,g=d.y,e=d.width,b=d.height,a=Math.min(d.radius,Math.abs(d.height)*0.5,Math.abs(d.width)*0.5);if(a===0){f.rect(c,g,e,b)}else{f.moveTo(c+a,g);f.arcTo(c+e,g,c+e,g+b,a);f.arcTo(c+e,g+b,c,g+b,a);f.arcTo(c,g+b,c,g,a);f.arcTo(c,g,c+a,g,a)}}});Ext.define("Ext.draw.sprite.Image",{extend:"Ext.draw.sprite.Rect",alias:"sprite.image",type:"image",statics:{imageLoaders:{}},inheritableStatics:{def:{processors:{src:"string"},defaults:{src:"",width:null,height:null}}},render:function(c,o){var j=this,h=j.attr,n=h.matrix,a=h.src,l=h.x,k=h.y,b=h.width,m=h.height,g=Ext.draw.sprite.Image.imageLoaders[a],f,d,e;if(g&&g.done){n.toContext(o);d=g.image;o.drawImage(d,l,k,b||(d.naturalWidth||d.width)/c.devicePixelRatio,m||(d.naturalHeight||d.height)/c.devicePixelRatio)}else{if(!g){f=new Image();g=Ext.draw.sprite.Image.imageLoaders[a]={image:f,done:false,pendingSprites:[j],pendingSurfaces:[c]};f.width=b;f.height=m;f.onload=function(){if(!g.done){g.done=true;for(e=0;e<g.pendingSprites.length;e++){g.pendingSprites[e].setDirty(true)}for(e in g.pendingSurfaces){g.pendingSurfaces[e].renderFrame()}}};f.src=a}else{Ext.Array.include(g.pendingSprites,j);Ext.Array.include(g.pendingSurfaces,c)}}}});Ext.define("Ext.draw.sprite.Instancing",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.instancing",type:"instancing",isInstancing:true,config:{template:null},instances:null,applyTemplate:function(a){if(!a.isSprite){if(!a.xclass&&!a.type){a.type="circle"}a=Ext.create(a.xclass||"sprite."+a.type,a)}a.setParent(this);return a},updateTemplate:function(a,b){if(b){delete b.ownAttr}a.setSurface(this.getSurface());a.ownAttr=a.attr;this.clearAll()},updateSurface:function(a){var b=this.getTemplate();if(b){b.setSurface(a)}},get:function(a){return this.instances[a]},getCount:function(){return this.instances.length},clearAll:function(){var a=this.getTemplate();a.attr.children=this.instances=[];this.position=0},createInstance:function(d,f,c){var e=this.getTemplate(),b=e.attr,a=Ext.Object.chain(b);e.topModifier.prepareAttributes(a);e.attr=a;e.setAttributes(d,f,c);a.template=e;this.instances.push(a);e.attr=b;this.position++;return a},getBBox:function(){return null},getBBoxFor:function(b,d){var c=this.getTemplate(),a=c.attr,e;c.attr=this.instances[b];e=c.getBBox(d);c.attr=a;return e},isVisible:function(){var b=this.attr,c=this.getParent(),a;a=c&&c.isSurface&&!b.hidden&&b.globalAlpha;return !!a},isInstanceVisible:function(c){var e=this,d=e.getTemplate(),b=d.attr,f=e.instances,a=false;if(!Ext.isNumber(c)||c<0||c>=f.length||!e.isVisible()){return a}d.attr=f[c];a=d.isVisible(point,options);d.attr=b;return a},render:function(b,l,d,h){var g=this,j=g.getTemplate(),k=g.attr.matrix,c=j.attr,a=g.instances,e,f=g.position;k.toContext(l);j.preRender(b,l,d,h);j.useAttributes(l,h);for(e=0;e<f;e++){if(a[e].dirtyZIndex){break}}for(e=0;e<f;e++){if(a[e].hidden){continue}l.save();j.attr=a[e];j.useAttributes(l,h);j.render(b,l,d,h);l.restore()}j.attr=c},setAttributesFor:function(c,e,f){var d=this.getTemplate(),b=d.attr,a=this.instances[c];if(!a){return}d.attr=a;if(f){e=Ext.apply({},e)}else{e=d.self.def.normalize(e)}d.topModifier.pushDown(a,e);d.attr=b},destroy:function(){var b=this,a=b.getTemplate();b.instances=null;if(a){a.destroy()}b.callParent()}});Ext.define("Ext.draw.overrides.sprite.Instancing",{override:"Ext.draw.sprite.Instancing",hitTest:function(f,j){var e=this,g=e.getTemplate(),b=g.attr,a=e.instances,d=a.length,c=0,h=null;if(!e.isVisible()){return h}for(;c<d;c++){g.attr=a[c];h=g.hitTest(f,j);if(h){h.isInstance=true;h.template=h.sprite;h.sprite=this;h.instance=a[c];h.index=c;return h}}g.attr=b;return h}});Ext.define("Ext.draw.sprite.Line",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.line",type:"line",inheritableStatics:{def:{processors:{fromX:"number",fromY:"number",toX:"number",toY:"number"},defaults:{fromX:0,fromY:0,toX:1,toY:1,strokeStyle:"black"},aliases:{x1:"fromX",y1:"fromY",x2:"toX",y2:"toY"}}},updateLineBBox:function(b,i,s,g,r,f){var o=this.attr,q=o.matrix,h=o.lineWidth/2,m,l,d,c,k,j,n;if(i){n=q.transformPoint([s,g]);s=n[0];g=n[1];n=q.transformPoint([r,f]);r=n[0];f=n[1]}m=Math.min(s,r);d=Math.max(s,r);l=Math.min(g,f);c=Math.max(g,f);var t=Math.atan2(d-m,c-l),a=Math.sin(t),e=Math.cos(t),k=h*e,j=h*a;m-=k;l-=j;d+=k;c+=j;b.x=m;b.y=l;b.width=d-m;b.height=c-l},updatePlainBBox:function(b){var a=this.attr;this.updateLineBBox(b,false,a.fromX,a.fromY,a.toX,a.toY)},updateTransformedBBox:function(b,c){var a=this.attr;this.updateLineBBox(b,true,a.fromX,a.fromY,a.toX,a.toY)},render:function(b,c){var a=this.attr,d=this.attr.matrix;d.toContext(c);c.beginPath();c.moveTo(a.fromX,a.fromY);c.lineTo(a.toX,a.toY);c.stroke()}});Ext.define("Ext.draw.sprite.Plus",{extend:"Ext.draw.sprite.Path",alias:"sprite.plus",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size/1.3,a=b.x-b.lineWidth/2,e=b.y;d.fromSvgString("M".concat(a-c/2,",",e-c/2,"l",[0,-c,c,0,0,c,c,0,0,c,-c,0,0,c,-c,0,0,-c,-c,0,0,-c,"z"]))}});Ext.define("Ext.draw.sprite.Sector",{extend:"Ext.draw.sprite.Path",alias:"sprite.sector",type:"sector",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",margin:"number"},aliases:{rho:"endRho"},triggers:{centerX:"path,bbox",centerY:"path,bbox",startAngle:"path,bbox",endAngle:"path,bbox",startRho:"path,bbox",endRho:"path,bbox",margin:"path,bbox"},defaults:{centerX:0,centerY:0,startAngle:0,endAngle:0,startRho:0,endRho:150,margin:0,path:"M 0,0"}}},getMidAngle:function(){return this.midAngle||0},updatePath:function(j,h){var g=Math.min(h.startAngle,h.endAngle),c=Math.max(h.startAngle,h.endAngle),b=this.midAngle=(g+c)*0.5,d=h.margin,f=h.centerX,e=h.centerY,i=Math.min(h.startRho,h.endRho),a=Math.max(h.startRho,h.endRho);if(d){f+=d*Math.cos(b);e+=d*Math.sin(b)}j.moveTo(f+i*Math.cos(g),e+i*Math.sin(g));j.lineTo(f+a*Math.cos(g),e+a*Math.sin(g));j.arc(f,e,a,g,c,false);j.lineTo(f+i*Math.cos(c),e+i*Math.sin(c));j.arc(f,e,i,c,g,true)}});Ext.define("Ext.draw.sprite.Square",{extend:"Ext.draw.sprite.Rect",alias:"sprite.square",inheritableStatics:{def:{processors:{size:"number"},defaults:{size:4},triggers:{size:"size"},updaters:{size:function(a){var c=a.size,b=a.lineWidth/2;this.setAttributes({x:a.x-c-b,y:a.y-c,height:2*c,width:2*c})}}}}});Ext.define("Ext.draw.TextMeasurer",{singleton:true,requires:["Ext.util.TextMetrics"],measureDiv:null,measureCache:{},precise:Ext.isIE8,measureDivTpl:{tag:"div",style:{overflow:"hidden",position:"relative","float":"left",width:0,height:0},children:{tag:"div",style:{display:"block",position:"absolute",x:-100000,y:-100000,padding:0,margin:0,"z-index":-100000,"white-space":"nowrap"}}},actualMeasureText:function(g,b){var e=Ext.draw.TextMeasurer,f=e.measureDiv,a=100000,c;if(!f){var d=Ext.Element.create({style:{overflow:"hidden",position:"relative","float":"left",width:0,height:0}});e.measureDiv=f=Ext.Element.create({style:{position:"absolute",x:a,y:a,"z-index":-a,"white-space":"nowrap",display:"block",padding:0,margin:0}});Ext.getBody().appendChild(d);d.appendChild(f)}if(b){f.setStyle({font:b,lineHeight:"normal"})}f.setText("("+g+")");c=f.getSize();f.setText("()");c.width-=f.getSize().width;return c},measureTextSingleLine:function(h,d){if(this.precise){return this.preciseMeasureTextSingleLine(h,d)}h=h.toString();var a=this.measureCache,g=h.split(""),c=0,j=0,l,b,e,f,k;if(!a[d]){a[d]={}}a=a[d];if(a[h]){return a[h]}for(e=0,f=g.length;e<f;e++){b=g[e];if(!(l=a[b])){k=this.actualMeasureText(b,d);l=a[b]=k}c+=l.width;j=Math.max(j,l.height)}return a[h]={width:c,height:j}},preciseMeasureTextSingleLine:function(c,a){c=c.toString();var b=this.measureDiv||(this.measureDiv=Ext.getBody().createChild(this.measureDivTpl).down("div"));b.setStyle({font:a||""});return Ext.util.TextMetrics.measure(b,c)},measureText:function(e,b){var h=e.split("\n"),d=h.length,f=0,a=0,j,c,g;if(d===1){return this.measureTextSingleLine(e,b)}g=[];for(c=0;c<d;c++){j=this.measureTextSingleLine(h[c],b);g.push(j);f+=j.height;a=Math.max(a,j.width)}return{width:a,height:f,sizes:g}}});Ext.define("Ext.draw.sprite.Text",function(){var d={"xx-small":true,"x-small":true,small:true,medium:true,large:true,"x-large":true,"xx-large":true};var b={normal:true,bold:true,bolder:true,lighter:true,100:true,200:true,300:true,400:true,500:true,600:true,700:true,800:true,900:true};var a={start:"start",left:"start",center:"center",middle:"center",end:"end",right:"end"};var c={top:"top",hanging:"hanging",middle:"middle",center:"middle",alphabetic:"alphabetic",ideographic:"ideographic",bottom:"bottom"};return{extend:"Ext.draw.sprite.Sprite",requires:["Ext.draw.TextMeasurer","Ext.draw.Color"],alias:"sprite.text",type:"text",lineBreakRe:/\r?\n/g,inheritableStatics:{def:{animationProcessors:{text:"text"},processors:{x:"number",y:"number",text:"string",fontSize:function(e){if(Ext.isNumber(+e)){return e+"px"}else{if(e.match(Ext.dom.Element.unitRe)){return e}else{if(e in d){return e}}}},fontStyle:"enums(,italic,oblique)",fontVariant:"enums(,small-caps)",fontWeight:function(e){if(e in b){return String(e)}else{return""}},fontFamily:"string",textAlign:function(e){return a[e]||"center"},textBaseline:function(e){return c[e]||"alphabetic"},font:"string"},aliases:{"font-size":"fontSize","font-family":"fontFamily","font-weight":"fontWeight","font-variant":"fontVariant","text-anchor":"textAlign"},defaults:{fontStyle:"",fontVariant:"",fontWeight:"",fontSize:"10px",fontFamily:"sans-serif",font:"10px sans-serif",textBaseline:"alphabetic",textAlign:"start",strokeStyle:"rgba(0, 0, 0, 0)",fillStyle:"#000",x:0,y:0,text:""},triggers:{fontStyle:"fontX,bbox",fontVariant:"fontX,bbox",fontWeight:"fontX,bbox",fontSize:"fontX,bbox",fontFamily:"fontX,bbox",font:"font,bbox,canvas",textBaseline:"bbox",textAlign:"bbox",x:"bbox",y:"bbox",text:"bbox"},updaters:{fontX:"makeFontShorthand",font:"parseFontShorthand"}}},constructor:function(e){if(e&&e.font){e=Ext.clone(e);for(var f in e){if(f!=="font"&&f.indexOf("font")===0){delete e[f]}}}Ext.draw.sprite.Sprite.prototype.constructor.call(this,e)},fontValuesMap:{italic:"fontStyle",oblique:"fontStyle","small-caps":"fontVariant",bold:"fontWeight",bolder:"fontWeight",lighter:"fontWeight","100":"fontWeight","200":"fontWeight","300":"fontWeight","400":"fontWeight","500":"fontWeight","600":"fontWeight","700":"fontWeight","800":"fontWeight","900":"fontWeight","xx-small":"fontSize","x-small":"fontSize",small:"fontSize",medium:"fontSize",large:"fontSize","x-large":"fontSize","xx-large":"fontSize"},makeFontShorthand:function(e){var f=[];if(e.fontStyle){f.push(e.fontStyle)}if(e.fontVariant){f.push(e.fontVariant)}if(e.fontWeight){f.push(e.fontWeight)}if(e.fontSize){f.push(e.fontSize)}if(e.fontFamily){f.push(e.fontFamily)}this.setAttributes({font:f.join(" ")},true)},parseFontShorthand:function(j){var m=j.font,k=m.length,l={},n=this.fontValuesMap,e=0,i,g,f,h;while(e<k&&i!==-1){i=m.indexOf(" ",e);if(i<0){f=m.substr(e)}else{if(i>e){f=m.substr(e,i-e)}else{continue}}g=f.indexOf("/");if(g>0){f=f.substr(0,g)}else{if(g===0){continue}}if(f!=="normal"&&f!=="inherit"){h=n[f];if(h){l[h]=f}else{if(f.match(Ext.dom.Element.unitRe)){l.fontSize=f}else{l.fontFamily=m.substr(e);break}}}e=i+1}if(!l.fontStyle){l.fontStyle=""}if(!l.fontVariant){l.fontVariant=""}if(!l.fontWeight){l.fontWeight=""}this.setAttributes(l,true)},fontProperties:{fontStyle:true,fontVariant:true,fontWeight:true,fontSize:true,fontFamily:true},setAttributes:function(g,i,e){var f,h;if(g&&g.font){h={};for(f in g){if(!(f in this.fontProperties)){h[f]=g[f]}}g=h}this.callParent([g,i,e])},getBBox:function(g){var h=this,f=h.attr.bbox.plain,e=h.getSurface();if(f.dirty){h.updatePlainBBox(f);f.dirty=false}if(e.getInherited().rtl&&e.getFlipRtlText()){h.updatePlainBBox(f,true)}return h.callParent([g])},rtlAlignments:{start:"end",center:"center",end:"start"},updatePlainBBox:function(k,B){var C=this,w=C.attr,o=w.x,n=w.y,q=[],t=w.font,r=w.text,s=w.textBaseline,l=w.textAlign,u=(B&&C.oldSize)?C.oldSize:(C.oldSize=Ext.draw.TextMeasurer.measureText(r,t)),z=C.getSurface(),p=z.getInherited().rtl,v=p&&z.getFlipRtlText(),h=z.getRect(),f=u.sizes,g=u.height,j=u.width,m=f?f.length:0,e,A=0;switch(s){case"hanging":case"top":break;case"ideographic":case"bottom":n-=g;break;case"alphabetic":n-=g*0.8;break;case"middle":n-=g*0.5;break}if(v){o=h[2]-h[0]-o;l=C.rtlAlignments[l]}switch(l){case"start":if(p){for(;A<m;A++){e=f[A].width;q.push(-(j-e))}}break;case"end":o-=j;if(p){break}for(;A<m;A++){e=f[A].width;q.push(j-e)}break;case"center":o-=j*0.5;for(;A<m;A++){e=f[A].width;q.push((p?-1:1)*(j-e)*0.5)}break}w.textAlignOffsets=q;k.x=o;k.y=n;k.width=j;k.height=g},setText:function(e){this.setAttributes({text:e},true)},render:function(e,q,k){var h=this,g=h.attr,p=Ext.draw.Matrix.fly(g.matrix.elements.slice(0)),o=h.getBBox(true),s=g.textAlignOffsets,m=Ext.draw.Color.RGBA_NONE,l,j,f,r,n;if(g.text.length===0){return}r=g.text.split(h.lineBreakRe);n=o.height/r.length;l=g.bbox.plain.x;j=g.bbox.plain.y+n*0.78;p.toContext(q);if(e.getInherited().rtl){l+=g.bbox.plain.width}for(f=0;f<r.length;f++){if(q.fillStyle!==m){q.fillText(r[f],l+(s[f]||0),j+n*f)}if(q.strokeStyle!==m){q.strokeText(r[f],l+(s[f]||0),j+n*f)}}}}});Ext.define("Ext.draw.sprite.Tick",{extend:"Ext.draw.sprite.Line",alias:"sprite.tick",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"tick",y:"tick",size:"tick"},updaters:{tick:function(b){var d=b.size*1.5,c=b.lineWidth/2,a=b.x,e=b.y;this.setAttributes({fromX:a-c,fromY:e-d,toX:a-c,toY:e+d})}}}}});Ext.define("Ext.draw.sprite.Triangle",{extend:"Ext.draw.sprite.Path",alias:"sprite.triangle",inheritableStatics:{def:{processors:{x:"number",y:"number",size:"number"},defaults:{x:0,y:0,size:4},triggers:{x:"path",y:"path",size:"path"}}},updatePath:function(d,b){var c=b.size*2.2,a=b.x,e=b.y;d.fromSvgString("M".concat(a,",",e,"m0-",c*0.58,"l",c*0.5,",",c*0.87,"-",c,",0z"))}});Ext.define("Ext.draw.gradient.Linear",{extend:"Ext.draw.gradient.Gradient",requires:["Ext.draw.Color"],type:"linear",config:{degrees:0,radians:0},applyRadians:function(b,a){if(Ext.isNumber(b)){return b}return a},applyDegrees:function(b,a){if(Ext.isNumber(b)){return b}return a},updateRadians:function(a){this.setDegrees(Ext.draw.Draw.degrees(a))},updateDegrees:function(a){this.setRadians(Ext.draw.Draw.rad(a))},generateGradient:function(q,o){var c=this.getRadians(),p=Math.cos(c),j=Math.sin(c),m=o.width,f=o.height,d=o.x+m*0.5,b=o.y+f*0.5,n=this.getStops(),g=n.length,k,a,e;if(Ext.isNumber(d+b)&&f>0&&m>0){a=(Math.sqrt(f*f+m*m)*Math.abs(Math.cos(c-Math.atan(f/m))))/2;k=q.createLinearGradient(d+p*a,b+j*a,d-p*a,b-j*a);for(e=0;e<g;e++){k.addColorStop(n[e].offset,n[e].color)}return k}return Ext.draw.Color.NONE}});Ext.define("Ext.draw.gradient.Radial",{extend:"Ext.draw.gradient.Gradient",type:"radial",config:{start:{x:0,y:0,r:0},end:{x:0,y:0,r:1}},applyStart:function(a,b){if(!b){return a}var c={x:b.x,y:b.y,r:b.r};if("x" in a){c.x=a.x}else{if("centerX" in a){c.x=a.centerX}}if("y" in a){c.y=a.y}else{if("centerY" in a){c.y=a.centerY}}if("r" in a){c.r=a.r}else{if("radius" in a){c.r=a.radius}}return c},applyEnd:function(b,a){if(!a){return b}var c={x:a.x,y:a.y,r:a.r};if("x" in b){c.x=b.x}else{if("centerX" in b){c.x=b.centerX}}if("y" in b){c.y=b.y}else{if("centerY" in b){c.y=b.centerY}}if("r" in b){c.r=b.r}else{if("radius" in b){c.r=b.radius}}return c},generateGradient:function(n,m){var a=this.getStart(),b=this.getEnd(),k=m.width*0.5,d=m.height*0.5,j=m.x+k,f=m.y+d,g=n.createRadialGradient(j+a.x*k,f+a.y*d,a.r*Math.max(k,d),j+b.x*k,f+b.y*d,b.r*Math.max(k,d)),l=this.getStops(),e=l.length,c;for(c=0;c<e;c++){g.addColorStop(l[c].offset,l[c].color)}return g}});Ext.define("Ext.draw.Surface",{extend:"Ext.draw.SurfaceBase",xtype:"surface",requires:["Ext.draw.sprite.*","Ext.draw.gradient.*","Ext.draw.sprite.AttributeDefinition","Ext.draw.Matrix","Ext.draw.Draw"],uses:["Ext.draw.engine.Canvas"],devicePixelRatio:window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI,deprecated:{"5.1.0":{statics:{methods:{stableSort:function(a){return Ext.Array.sort(a,function(d,c){return d.attr.zIndex-c.attr.zIndex})}}}}},config:{cls:Ext.baseCSSPrefix+"surface",rect:null,background:null,items:[],dirty:false,flipRtlText:false},isSurface:true,isPendingRenderFrame:false,dirtyPredecessorCount:0,constructor:function(a){var b=this;b.predecessors=[];b.successors=[];b.map={};b.callParent([a]);b.matrix=new Ext.draw.Matrix();b.inverseMatrix=b.matrix.inverse()},roundPixel:function(a){return Math.round(this.devicePixelRatio*a)/this.devicePixelRatio},waitFor:function(a){var b=this,c=b.predecessors;if(!Ext.Array.contains(c,a)){c.push(a);a.successors.push(b);if(a.getDirty()){b.dirtyPredecessorCount++}}},updateDirty:function(d){var c=this.successors,e=c.length,b=0,a;for(;b<e;b++){a=c[b];if(d){a.dirtyPredecessorCount++;a.setDirty(true)}else{a.dirtyPredecessorCount--;if(a.dirtyPredecessorCount===0&&a.isPendingRenderFrame){a.renderFrame()}}}},applyBackground:function(a,b){this.setDirty(true);if(Ext.isString(a)){a={fillStyle:a}}return Ext.factory(a,Ext.draw.sprite.Rect,b)},applyRect:function(a,b){if(b&&a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]){return}if(Ext.isArray(a)){return[a[0],a[1],a[2],a[3]]}else{if(Ext.isObject(a)){return[a.x||a.left,a.y||a.top,a.width||(a.right-a.left),a.height||(a.bottom-a.top)]}}},updateRect:function(i){var h=this,c=i[0],f=i[1],g=c+i[2],a=f+i[3],e=h.getBackground(),d=h.element;d.setLocalXY(Math.floor(c),Math.floor(f));d.setSize(Math.ceil(g-Math.floor(c)),Math.ceil(a-Math.floor(f)));if(e){e.setAttributes({x:0,y:0,width:Math.ceil(g-Math.floor(c)),height:Math.ceil(a-Math.floor(f))})}h.setDirty(true)},resetTransform:function(){this.matrix.set(1,0,0,1,0,0);this.inverseMatrix.set(1,0,0,1,0,0);this.setDirty(true)},get:function(a){return this.map[a]||this.getItems()[a]},add:function(){var g=this,e=Array.prototype.slice.call(arguments),j=Ext.isArray(e[0]),a=g.map,c=[],f,k,h,b,d;f=Ext.Array.clean(j?e[0]:e);if(!f.length){return c}for(b=0,d=f.length;b<d;b++){k=f[b];h=null;if(k.isSprite&&!a[k.getId()]){h=k}else{if(!a[k.id]){h=this.createItem(k)}}if(h){a[h.getId()]=h;c.push(h);h.setParent(g);h.setSurface(g);g.onAdd(h)}}f=g.getItems();if(f){f.push.apply(f,c)}g.dirtyZIndex=true;g.setDirty(true);if(!j&&c.length===1){return c[0]}else{return c}},onAdd:Ext.emptyFn,remove:function(a,c){var b=this,e,d;if(a){if(a.charAt){a=b.map[a]}if(!a||!a.isSprite){return null}if(a.isDestroyed||a.isDestroying){return a}e=a.getId();d=b.map[e];delete b.map[e];if(c){a.destroy()}if(!d){return a}a.setParent(null);a.setSurface(null);Ext.Array.remove(b.getItems(),a);b.dirtyZIndex=true;b.setDirty(true)}return a||null},removeAll:function(d){var a=this.getItems(),b=a.length-1,c;if(d){for(;b>=0;b--){a[b].destroy()}}else{for(;b>=0;b--){c=a[b];c.setParent(null);c.setSurface(null)}}a.length=0;this.map={};this.dirtyZIndex=true},applyItems:function(a){if(this.getItems()){this.removeAll(true)}return Ext.Array.from(this.add(a))},createItem:function(a){return Ext.create(a.xclass||"sprite."+a.type,a)},getBBox:function(f,b){var f=Ext.Array.from(f),c=Infinity,h=-Infinity,g=Infinity,a=-Infinity,j,k,d,e;for(d=0,e=f.length;d<e;d++){j=f[d];k=j.getBBox(b);if(c>k.x){c=k.x}if(h<k.x+k.width){h=k.x+k.width}if(g>k.y){g=k.y}if(a<k.y+k.height){a=k.y+k.height}}return{x:c,y:g,width:h-c,height:a-g}},emptyRect:[0,0,0,0],getEventXY:function(d){var g=this,f=g.getInherited().rtl,c=d.getXY(),a=g.getOwnerBody(),i=a.getXY(),h=g.getRect()||g.emptyRect,j=[],b;if(f){b=a.getWidth();j[0]=i[0]-c[0]-h[0]+b}else{j[0]=c[0]-i[0]-h[0]}j[1]=c[1]-i[1]-h[1];return j},clear:Ext.emptyFn,orderByZIndex:function(){var d=this,a=d.getItems(),e=false,b,c;if(d.getDirty()){for(b=0,c=a.length;b<c;b++){if(a[b].attr.dirtyZIndex){e=true;break}}if(e){Ext.Array.sort(a,function(g,f){return g.attr.zIndex-f.attr.zIndex});this.setDirty(true)}for(b=0,c=a.length;b<c;b++){a[b].attr.dirtyZIndex=false}}},repaint:function(){var a=this;a.repaint=Ext.emptyFn;Ext.defer(function(){delete a.repaint;a.element.repaint()},1)},renderFrame:function(){var g=this;if(!g.element){return}if(g.dirtyPredecessorCount>0){g.isPendingRenderFrame=true;return}var f=g.getRect(),c=g.getBackground(),a=g.getItems(),e,b,d;if(!f){return}g.orderByZIndex();if(g.getDirty()){g.clear();g.clearTransform();if(c){g.renderSprite(c)}for(b=0,d=a.length;b<d;b++){e=a[b];if(g.renderSprite(e)===false){return}e.attr.textPositionCount=g.textPosition}g.setDirty(false)}},renderSprite:Ext.emptyFn,clearTransform:Ext.emptyFn,destroy:function(){var a=this;a.removeAll(true);a.predecessors=null;a.successors=null;a.callParent()}});Ext.define("Ext.draw.overrides.Surface",{override:"Ext.draw.Surface",hitTest:function(b,c){var f=this,g=f.getItems(),e,d,a;c=c||Ext.draw.sprite.Sprite.defaultHitTestOptions;for(e=g.length-1;e>=0;e--){d=g[e];if(d.hitTest){a=d.hitTest(b,c);if(a){return a}}}return null},hitTestEvent:function(b,a){var c=this.getEventXY(b);return this.hitTest(c,a)}});Ext.define("Ext.draw.engine.SvgContext",{requires:["Ext.draw.Color"],toSave:["strokeOpacity","strokeStyle","fillOpacity","fillStyle","globalAlpha","lineWidth","lineCap","lineJoin","lineDash","lineDashOffset","miterLimit","shadowOffsetX","shadowOffsetY","shadowBlur","shadowColor","globalCompositeOperation","position","fillGradient","strokeGradient"],strokeOpacity:1,strokeStyle:"none",fillOpacity:1,fillStyle:"none",lineDash:[],lineDashOffset:0,globalAlpha:1,lineWidth:1,lineCap:"butt",lineJoin:"miter",miterLimit:10,shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0,shadowColor:"none",globalCompositeOperation:"src",urlStringRe:/^url\(#([\w\-]+)\)$/,constructor:function(a){this.surface=a;this.state=[];this.matrix=new Ext.draw.Matrix();this.path=null;this.clear()},clear:function(){this.group=this.surface.mainGroup;this.position=0;this.path=null},getElement:function(a){return this.surface.getSvgElement(this.group,a,this.position++)},removeElement:function(d){var d=Ext.fly(d),h,g,b,f,a,e,c;if(!d){return}if(d.dom.tagName==="g"){a=d.dom.gradients;for(c in a){a[c].destroy()}}else{h=d.getAttribute("fill");g=d.getAttribute("stroke");b=h&&h.match(this.urlStringRe);f=g&&g.match(this.urlStringRe);if(b&&b[1]){e=Ext.fly(b[1]);if(e){e.destroy()}}if(f&&f[1]){e=Ext.fly(f[1]);if(e){e.destroy()}}}d.destroy()},save:function(){var c=this.toSave,e={},d=this.getElement("g"),b,a;for(a=0;a<c.length;a++){b=c[a];if(b in this){e[b]=this[b]}}this.position=0;e.matrix=this.matrix.clone();this.state.push(e);this.group=d;return d},restore:function(){var d=this.toSave,e=this.state.pop(),c=this.group.dom.childNodes,b,a;while(c.length>this.position){this.removeElement(c[c.length-1])}for(a=0;a<d.length;a++){b=d[a];if(b in e){this[b]=e[b]}else{delete this[b]}}this.setTransform.apply(this,e.matrix.elements);this.group=this.group.getParent()},transform:function(f,b,e,g,d,c){if(this.path){var a=Ext.draw.Matrix.fly([f,b,e,g,d,c]).inverse();this.path.transform(a)}this.matrix.append(f,b,e,g,d,c)},setTransform:function(e,a,d,f,c,b){if(this.path){this.path.transform(this.matrix)}this.matrix.reset();this.transform(e,a,d,f,c,b)},scale:function(a,b){this.transform(a,0,0,b,0,0)},rotate:function(d){var c=Math.cos(d),a=Math.sin(d),b=-Math.sin(d),e=Math.cos(d);this.transform(c,a,b,e,0,0)},translate:function(a,b){this.transform(1,0,0,1,a,b)},setGradientBBox:function(a){this.bbox=a},beginPath:function(){this.path=new Ext.draw.Path()},moveTo:function(a,b){if(!this.path){this.beginPath()}this.path.moveTo(a,b);this.path.element=null},lineTo:function(a,b){if(!this.path){this.beginPath()}this.path.lineTo(a,b);this.path.element=null},rect:function(b,d,c,a){this.moveTo(b,d);this.lineTo(b+c,d);this.lineTo(b+c,d+a);this.lineTo(b,d+a);this.closePath()},strokeRect:function(b,d,c,a){this.beginPath();this.rect(b,d,c,a);this.stroke()},fillRect:function(b,d,c,a){this.beginPath();this.rect(b,d,c,a);this.fill()},closePath:function(){if(!this.path){this.beginPath()}this.path.closePath();this.path.element=null},arcSvg:function(d,a,f,g,c,b,e){if(!this.path){this.beginPath()}this.path.arcSvg(d,a,f,g,c,b,e);this.path.element=null},arc:function(b,f,a,d,c,e){if(!this.path){this.beginPath()}this.path.arc(b,f,a,d,c,e);this.path.element=null},ellipse:function(a,h,g,f,d,c,b,e){if(!this.path){this.beginPath()}this.path.ellipse(a,h,g,f,d,c,b,e);this.path.element=null},arcTo:function(b,e,a,d,g,f,c){if(!this.path){this.beginPath()}this.path.arcTo(b,e,a,d,g,f,c);this.path.element=null},bezierCurveTo:function(d,f,b,e,a,c){if(!this.path){this.beginPath()}this.path.bezierCurveTo(d,f,b,e,a,c);this.path.element=null},strokeText:function(d,a,e){d=String(d);if(this.strokeStyle){var b=this.getElement("text"),c=this.surface.getSvgElement(b,"tspan",0);this.surface.setElementAttributes(b,{x:a,y:e,transform:this.matrix.toSvg(),stroke:this.strokeStyle,fill:"none",opacity:this.globalAlpha,"stroke-opacity":this.strokeOpacity,style:"font: "+this.font,"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset});if(this.lineDash.length){this.surface.setElementAttributes(b,{"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset})}if(c.dom.firstChild){c.dom.removeChild(c.dom.firstChild)}this.surface.setElementAttributes(c,{"alignment-baseline":"alphabetic"});c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))}},fillText:function(d,a,e){d=String(d);if(this.fillStyle){var b=this.getElement("text"),c=this.surface.getSvgElement(b,"tspan",0);this.surface.setElementAttributes(b,{x:a,y:e,transform:this.matrix.toSvg(),fill:this.fillStyle,opacity:this.globalAlpha,"fill-opacity":this.fillOpacity,style:"font: "+this.font});if(c.dom.firstChild){c.dom.removeChild(c.dom.firstChild)}this.surface.setElementAttributes(c,{"alignment-baseline":"alphabetic"});c.dom.appendChild(document.createTextNode(Ext.String.htmlDecode(d)))}},drawImage:function(c,k,i,l,e,p,n,a,g){var f=this,d=f.getElement("image"),j=k,h=i,b=typeof l==="undefined"?c.width:l,m=typeof e==="undefined"?c.height:e,o=null;if(typeof g!=="undefined"){o=k+" "+i+" "+l+" "+e;j=p;h=n;b=a;m=g}d.dom.setAttributeNS("http://www.w3.org/1999/xlink","href",c.src);f.surface.setElementAttributes(d,{viewBox:o,x:j,y:h,width:b,height:m,opacity:f.globalAlpha,transform:f.matrix.toSvg()})},fill:function(){if(!this.path){return}if(this.fillStyle){var c,a=this.fillGradient,d=this.bbox,b=this.path.element;if(!b){c=this.path.toString();b=this.path.element=this.getElement("path");this.surface.setElementAttributes(b,{d:c,transform:this.matrix.toSvg()})}this.surface.setElementAttributes(b,{fill:a&&d?a.generateGradient(this,d):this.fillStyle,"fill-opacity":this.fillOpacity*this.globalAlpha})}},stroke:function(){if(!this.path){return}if(this.strokeStyle){var c,b=this.strokeGradient,d=this.bbox,a=this.path.element;if(!a||!this.path.svgString){c=this.path.toString();if(!c){return}a=this.path.element=this.getElement("path");this.surface.setElementAttributes(a,{fill:"none",d:c,transform:this.matrix.toSvg()})}this.surface.setElementAttributes(a,{stroke:b&&d?b.generateGradient(this,d):this.strokeStyle,"stroke-linecap":this.lineCap,"stroke-linejoin":this.lineJoin,"stroke-width":this.lineWidth,"stroke-opacity":this.strokeOpacity*this.globalAlpha,"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset});if(this.lineDash.length){this.surface.setElementAttributes(a,{"stroke-dasharray":this.lineDash.join(","),"stroke-dashoffset":this.lineDashOffset})}}},fillStroke:function(a,e){var b=this,d=b.fillStyle,g=b.strokeStyle,c=b.fillOpacity,f=b.strokeOpacity;if(e===undefined){e=a.transformFillStroke}if(!e){a.inverseMatrix.toContext(b)}if(d&&c!==0){b.fill()}if(g&&f!==0){b.stroke()}},appendPath:function(a){this.path=a.clone()},setLineDash:function(a){this.lineDash=a},getLineDash:function(){return this.lineDash},createLinearGradient:function(d,g,b,e){var f=this,c=f.surface.getNextDef("linearGradient"),a=f.group.dom.gradients||(f.group.dom.gradients={}),h;f.surface.setElementAttributes(c,{x1:d,y1:g,x2:b,y2:e,gradientUnits:"userSpaceOnUse"});h=new Ext.draw.engine.SvgContext.Gradient(f,f.surface,c);a[c.dom.id]=h;return h},createRadialGradient:function(b,j,d,a,i,c){var g=this,e=g.surface.getNextDef("radialGradient"),f=g.group.dom.gradients||(g.group.dom.gradients={}),h;g.surface.setElementAttributes(e,{fx:b,fy:j,cx:a,cy:i,r:c,gradientUnits:"userSpaceOnUse"});h=new Ext.draw.engine.SvgContext.Gradient(g,g.surface,e,d/c);f[e.dom.id]=h;return h}});Ext.define("Ext.draw.engine.SvgContext.Gradient",{statics:{map:{}},constructor:function(c,a,d,b){var f=this.statics().map,e;e=f[d.dom.id];if(e){e.element=null}f[d.dom.id]=this;this.ctx=c;this.surface=a;this.element=d;this.position=0;this.compression=b||0},addColorStop:function(d,b){var c=this.surface.getSvgElement(this.element,"stop",this.position++),a=this.compression;this.surface.setElementAttributes(c,{offset:(((1-a)*d+a)*100).toFixed(2)+"%","stop-color":b,"stop-opacity":Ext.draw.Color.fly(b).a.toFixed(15)})},toString:function(){var a=this.element.dom.childNodes;while(a.length>this.position){Ext.fly(a[a.length-1]).destroy()}return"url(#"+this.element.getId()+")"},destroy:function(){var b=this.statics().map,a=this.element;if(a&&a.dom){delete b[a.dom.id];a.destroy()}this.callParent()}});Ext.define("Ext.draw.engine.Svg",{extend:"Ext.draw.Surface",requires:["Ext.draw.engine.SvgContext"],statics:{BBoxTextCache:{}},config:{highPrecision:false},getElementConfig:function(){return{reference:"element",style:{position:"absolute"},children:[{reference:"innerElement",style:{width:"100%",height:"100%",position:"relative"},children:[{tag:"svg",reference:"svgElement",namespace:"http://www.w3.org/2000/svg",width:"100%",height:"100%",version:1.1}]}]}},constructor:function(a){var b=this;b.callParent([a]);b.mainGroup=b.createSvgNode("g");b.defElement=b.createSvgNode("defs");b.svgElement.appendChild(b.mainGroup);b.svgElement.appendChild(b.defElement);b.ctx=new Ext.draw.engine.SvgContext(b)},createSvgNode:function(a){var b=document.createElementNS("http://www.w3.org/2000/svg",a);return Ext.get(b)},getSvgElement:function(d,b,a){var c;if(d.dom.childNodes.length>a){c=d.dom.childNodes[a];if(c.tagName===b){return Ext.get(c)}else{Ext.destroy(c)}}c=Ext.get(this.createSvgNode(b));if(a===0){d.insertFirst(c)}else{c.insertAfter(Ext.fly(d.dom.childNodes[a-1]))}c.cache={};return c},setElementAttributes:function(d,b){var f=d.dom,a=d.cache,c,e;for(c in b){e=b[c];if(a[c]!==e){a[c]=e;f.setAttribute(c,e)}}},getNextDef:function(a){return this.getSvgElement(this.defElement,a,this.defPosition++)},clearTransform:function(){var a=this;a.mainGroup.set({transform:a.matrix.toSvg()})},clear:function(){this.ctx.clear();this.defPosition=0},renderSprite:function(b){var d=this,c=d.getRect(),a=d.ctx;if(b.attr.hidden||b.attr.globalAlpha===0){a.save();a.restore();return}b.element=a.save();b.preRender(this);b.useAttributes(a,c);if(false===b.render(this,a,[0,0,c[2],c[3]])){return false}b.setDirty(false);a.restore()},flatten:function(e,b){var c='<?xml version="1.0" standalone="yes"?>',f=Ext.getClassName(this),a,g,d;c+='<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" width="'+e.width+'" height="'+e.height+'">';for(d=0;d<b.length;d++){a=b[d];if(Ext.getClassName(a)!==f){continue}g=a.getRect();c+='<g transform="translate('+g[0]+","+g[1]+')">';c+=this.serializeNode(a.svgElement.dom);c+="</g>"}c+="</svg>";return{data:"data:image/svg+xml;utf8,"+encodeURIComponent(c),type:"svg"}},serializeNode:function(d){var b="",c,f,a,e;if(d.nodeType===document.TEXT_NODE){return d.nodeValue}b+="<"+d.nodeName;if(d.attributes.length){for(c=0,f=d.attributes.length;c<f;c++){a=d.attributes[c];b+=" "+a.name+'="'+a.value+'"'}}b+=">";if(d.childNodes&&d.childNodes.length){for(c=0,f=d.childNodes.length;c<f;c++){e=d.childNodes[c];b+=this.serializeNode(e)}}b+="</"+d.nodeName+">";return b},destroy:function(){var a=this;a.ctx.destroy();a.mainGroup.destroy();delete a.mainGroup;delete a.ctx;a.callParent()},remove:function(a,b){if(a&&a.element){if(this.ctx){this.ctx.removeElement(a.element)}else{a.element.destroy()}a.element=null}this.callParent(arguments)}});Ext.draw||(Ext.draw={});Ext.draw.engine||(Ext.draw.engine={});Ext.draw.engine.excanvas=true;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){Ext.onReady(function(){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.lineDash=j.lineDash;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.lineDash=[];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(an,j){var ah,Z,aj,ar,al,ak,ao,av;var ai=an.runtimeStyle.width;var am=an.runtimeStyle.height;an.runtimeStyle.width="auto";an.runtimeStyle.height="auto";var ag=an.width;var aq=an.height;an.runtimeStyle.width=ai;an.runtimeStyle.height=am;if(arguments.length==3){ah=arguments[1];Z=arguments[2];al=ak=0;ao=aj=ag;av=ar=aq}else{if(arguments.length==5){ah=arguments[1];Z=arguments[2];aj=arguments[3];ar=arguments[4];al=ak=0;ao=ag;av=aq}else{if(arguments.length==9){al=arguments[1];ak=arguments[2];ao=arguments[3];av=arguments[4];ah=arguments[5];Z=arguments[6];aj=arguments[7];ar=arguments[8]}else{throw Error("Invalid number of arguments")}}}var au=V(this,ah,Z);var at=[];var i=10;var p=10;var ap=this.m_;at.push(" <g_vml_:group",' coordsize="',d*i,",",d*p,'"',' coordorigin="0,0"',' style="width:',n(i*ap[0][0]),"px;height:",n(p*ap[1][1]),"px;position:absolute;","top:",n(au.y/d),"px;left:",n(au.x/d),"px; rotation:",n(Math.atan(ap[0][1]/ap[1][1])*180/Math.PI),";");at.push('" >','<g_vml_:image src="',an.src,'"',' style="width:',d*aj,"px;"," height:",d*ar,'px"',' cropleft="',al/ag,'"',' croptop="',ak/aq,'"',' cropright="',(ag-al-ao)/ag,'"',' cropbottom="',(aq-ak-av)/aq,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",at.join(""))};q.setLineDash=function(i){if(i.length===1){i=i.slice();i[1]=i[0]}this.lineDash=i};q.getLineDash=function(){return this.lineDash};q.stroke=function(ak){var ai=[];var m=10;var al=10;ai.push("<g_vml_:shape",' filled="',!!ak,'"',' style="position:absolute;width:',m,"px;height:",al,'px;left:0px;top:0px;"',' coordorigin="0,0"',' coordsize="',d*m,",",d*al,'"',' stroked="',!ak,'"',' path="');var Z={x:null,y:null};var aj={x:null,y:null};for(var ag=0;ag<this.currentPath_.length;ag++){var j=this.currentPath_[ag];var ah;switch(j.type){case"moveTo":ah=j;ai.push(" m ",n(j.x),",",n(j.y));break;case"lineTo":ai.push(" l ",n(j.x),",",n(j.y));break;case"close":ai.push(" x ");j=null;break;case"bezierCurveTo":ai.push(" c ",n(j.cp1x),",",n(j.cp1y),",",n(j.cp2x),",",n(j.cp2y),",",n(j.x),",",n(j.y));break;case"at":case"wa":ai.push(" ",j.type," ",n(j.x-this.arcScaleX_*j.radius),",",n(j.y-this.arcScaleY_*j.radius)," ",n(j.x+this.arcScaleX_*j.radius),",",n(j.y+this.arcScaleY_*j.radius)," ",n(j.xStart),",",n(j.yStart)," ",n(j.xEnd),",",n(j.yEnd));break}if(j){if(Z.x==null||j.x<Z.x){Z.x=j.x}if(aj.x==null||j.x>aj.x){aj.x=j.x}if(Z.y==null||j.y<Z.y){Z.y=j.y}if(aj.y==null||j.y>aj.y){aj.y=j.y}}}ai.push(' ">');if(!ak){w(this,ai)}else{G(this,ai,Z,aj)}ai.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",ai.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,'"',' dashstyle="',m.lineDash.join(" "),'"',' 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/3;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;left:0px;top:0px;">');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})()}Ext.define("Ext.draw.engine.Canvas",{extend:"Ext.draw.Surface",requires:["Ext.draw.engine.excanvas","Ext.draw.Animator","Ext.draw.Color"],config:{highPrecision:false},statics:{contextOverrides:{setGradientBBox:function(a){this.bbox=a},fill:function(){var c=this.fillStyle,a=this.fillGradient,b=this.fillOpacity,d=this.globalAlpha,e=this.bbox;if(c!==Ext.draw.Color.RGBA_NONE&&b!==0){if(a&&e){this.fillStyle=a.generateGradient(this,e)}if(b!==1){this.globalAlpha=d*b}this.$fill();if(b!==1){this.globalAlpha=d}if(a&&e){this.fillStyle=c}}},stroke:function(){var e=this.strokeStyle,c=this.strokeGradient,a=this.strokeOpacity,b=this.globalAlpha,d=this.bbox;if(e!==Ext.draw.Color.RGBA_NONE&&a!==0){if(c&&d){this.strokeStyle=c.generateGradient(this,d)}if(a!==1){this.globalAlpha=b*a}this.$stroke();if(a!==1){this.globalAlpha=b}if(c&&d){this.strokeStyle=e}}},fillStroke:function(d,e){var j=this,i=this.fillStyle,h=this.fillOpacity,f=this.strokeStyle,c=this.strokeOpacity,b=j.shadowColor,a=j.shadowBlur,g=Ext.draw.Color.RGBA_NONE;if(e===undefined){e=d.transformFillStroke}if(!e){d.inverseMatrix.toContext(j)}if(i!==g&&h!==0){j.fill();j.shadowColor=g;j.shadowBlur=0}if(f!==g&&c!==0){j.stroke()}j.shadowColor=b;j.shadowBlur=a},setLineDash:function(a){if(this.$setLineDash){this.$setLineDash(a)}},getLineDash:function(){if(this.$getLineDash){return this.$getLineDash()}},ellipse:function(g,e,c,a,j,b,f,d){var i=Math.cos(j),h=Math.sin(j);this.transform(i*c,h*c,-h*a,i*a,g,e);this.arc(0,0,1,b,f,d);this.transform(i/c,-h/a,h/c,i/a,-(i*g+h*e)/c,(h*g-i*e)/a)},appendPath:function(f){var e=this,c=0,b=0,a=f.commands,g=f.params,d=a.length;e.beginPath();for(;c<d;c++){switch(a[c]){case"M":e.moveTo(g[b],g[b+1]);b+=2;break;case"L":e.lineTo(g[b],g[b+1]);b+=2;break;case"C":e.bezierCurveTo(g[b],g[b+1],g[b+2],g[b+3],g[b+4],g[b+5]);b+=6;break;case"Z":e.closePath();break}}},save:function(){var c=this.toSave,d=c.length,e=d&&{},b=0,a;for(;b<d;b++){a=c[b];if(a in this){e[a]=this[a]}}this.state.push(e);this.$save()},restore:function(){var b=this.state.pop(),a;if(b){for(a in b){this[a]=b[a]}}this.$restore()}}},splitThreshold:3000,toSave:["fillGradient","strokeGradient"],element:{reference:"element",style:{position:"absolute"},children:[{reference:"innerElement",style:{width:"100%",height:"100%",position:"relative"}}]},createCanvas:function(){var c=Ext.Element.create({tag:"canvas",cls:Ext.baseCSSPrefix+"surface-canvas"});window.G_vmlCanvasManager&&G_vmlCanvasManager.initElement(c.dom);var d=Ext.draw.engine.Canvas.contextOverrides,a=c.dom.getContext("2d"),b;if(a.ellipse){delete d.ellipse}a.state=[];a.toSave=this.toSave;for(b in d){a["$"+b]=a[b]}Ext.apply(a,d);if(this.getHighPrecision()){this.enablePrecisionCompensation(a)}else{this.disablePrecisionCompensation(a)}this.innerElement.appendChild(c);this.canvases.push(c);this.contexts.push(a)},updateHighPrecision:function(d){var e=this.contexts,c=e.length,b,a;for(b=0;b<c;b++){a=e[b];if(d){this.enablePrecisionCompensation(a)}else{this.disablePrecisionCompensation(a)}}},precisionNames:["rect","fillRect","strokeRect","clearRect","moveTo","lineTo","arc","arcTo","save","restore","updatePrecisionCompensate","setTransform","transform","scale","translate","rotate","quadraticCurveTo","bezierCurveTo","createLinearGradient","createRadialGradient","fillText","strokeText","drawImage"],disablePrecisionCompensation:function(b){var a=Ext.draw.engine.Canvas.contextOverrides,f=this.precisionNames,e=f.length,d,c;for(d=0;d<e;d++){c=f[d];if(!(c in a)){delete b[c]}}this.setDirty(true)},enablePrecisionCompensation:function(j){var c=this,a=1,g=1,l=0,k=0,i=new Ext.draw.Matrix(),b=[],e={},d=Ext.draw.engine.Canvas.contextOverrides,h=j.constructor.prototype;var f={toSave:c.toSave,rect:function(m,p,n,o){return h.rect.call(this,m*a+l,p*g+k,n*a,o*g)},fillRect:function(m,p,n,o){this.updatePrecisionCompensateRect();h.fillRect.call(this,m*a+l,p*g+k,n*a,o*g);this.updatePrecisionCompensate()},strokeRect:function(m,p,n,o){this.updatePrecisionCompensateRect();h.strokeRect.call(this,m*a+l,p*g+k,n*a,o*g);this.updatePrecisionCompensate()},clearRect:function(m,p,n,o){return h.clearRect.call(this,m*a+l,p*g+k,n*a,o*g)},moveTo:function(m,n){return h.moveTo.call(this,m*a+l,n*g+k)},lineTo:function(m,n){return h.lineTo.call(this,m*a+l,n*g+k)},arc:function(n,r,m,p,o,q){this.updatePrecisionCompensateRect();h.arc.call(this,n*a+l,r*a+k,m*a,p,o,q);this.updatePrecisionCompensate()},arcTo:function(o,q,n,p,m){this.updatePrecisionCompensateRect();h.arcTo.call(this,o*a+l,q*g+k,n*a+l,p*g+k,m*a);this.updatePrecisionCompensate()},save:function(){b.push(i);i=i.clone();d.save.call(this);h.save.call(this)},restore:function(){i=b.pop();d.restore.call(this);h.restore.call(this);this.updatePrecisionCompensate()},updatePrecisionCompensate:function(){i.precisionCompensate(c.devicePixelRatio,e);a=e.xx;g=e.yy;l=e.dx;k=e.dy;h.setTransform.call(this,c.devicePixelRatio,e.b,e.c,e.d,0,0)},updatePrecisionCompensateRect:function(){i.precisionCompensateRect(c.devicePixelRatio,e);a=e.xx;g=e.yy;l=e.dx;k=e.dy;h.setTransform.call(this,c.devicePixelRatio,e.b,e.c,e.d,0,0)},setTransform:function(q,o,n,m,r,p){i.set(q,o,n,m,r,p);this.updatePrecisionCompensate()},transform:function(q,o,n,m,r,p){i.append(q,o,n,m,r,p);this.updatePrecisionCompensate()},scale:function(n,m){this.transform(n,0,0,m,0,0)},translate:function(n,m){this.transform(1,0,0,1,n,m)},rotate:function(o){var n=Math.cos(o),m=Math.sin(o);this.transform(n,m,-m,n,0,0)},quadraticCurveTo:function(n,p,m,o){h.quadraticCurveTo.call(this,n*a+l,p*g+k,m*a+l,o*g+k)},bezierCurveTo:function(r,p,o,n,m,q){h.bezierCurveTo.call(this,r*a+l,p*g+k,o*a+l,n*g+k,m*a+l,q*g+k)},createLinearGradient:function(n,p,m,o){this.updatePrecisionCompensateRect();var q=h.createLinearGradient.call(this,n*a+l,p*g+k,m*a+l,o*g+k);this.updatePrecisionCompensate();return q},createRadialGradient:function(p,r,o,n,q,m){this.updatePrecisionCompensateRect();var s=h.createLinearGradient.call(this,p*a+l,r*a+k,o*a,n*a+l,q*a+k,m*a);this.updatePrecisionCompensate();return s},fillText:function(o,m,p,n){h.setTransform.apply(this,i.elements);if(typeof n==="undefined"){h.fillText.call(this,o,m,p)}else{h.fillText.call(this,o,m,p,n)}this.updatePrecisionCompensate()},strokeText:function(o,m,p,n){h.setTransform.apply(this,i.elements);if(typeof n==="undefined"){h.strokeText.call(this,o,m,p)}else{h.strokeText.call(this,o,m,p,n)}this.updatePrecisionCompensate()},fill:function(){var m=this.fillGradient,n=this.bbox;this.updatePrecisionCompensateRect();if(m&&n){this.fillStyle=m.generateGradient(this,n)}h.fill.call(this);this.updatePrecisionCompensate()},stroke:function(){var m=this.strokeGradient,n=this.bbox;this.updatePrecisionCompensateRect();if(m&&n){this.strokeStyle=m.generateGradient(this,n)}h.stroke.call(this);this.updatePrecisionCompensate()},drawImage:function(u,s,r,q,p,o,n,m,t){switch(arguments.length){case 3:return h.drawImage.call(this,u,s*a+l,r*g+k);case 5:return h.drawImage.call(this,u,s*a+l,r*g+k,q*a,p*g);case 9:return h.drawImage.call(this,u,s,r,q,p,o*a+l,n*g*k,m*a,t*g)}}};Ext.apply(j,f);this.setDirty(true)},updateRect:function(a){this.callParent([a]);var C=this,p=Math.floor(a[0]),e=Math.floor(a[1]),g=Math.ceil(a[0]+a[2]),B=Math.ceil(a[1]+a[3]),u=C.devicePixelRatio,D=C.canvases,d=g-p,y=B-e,n=Math.round(C.splitThreshold/u),c=C.xSplits=Math.ceil(d/n),f=C.ySplits=Math.ceil(y/n),v,s,q,A,z,x,o,m;for(s=0,z=0;s<f;s++,z+=n){for(v=0,A=0;v<c;v++,A+=n){q=s*c+v;if(q>=D.length){C.createCanvas()}x=D[q].dom;x.style.left=A+"px";x.style.top=z+"px";m=Math.min(n,y-z);if(m*u!==x.height){x.height=m*u;x.style.height=m+"px"}o=Math.min(n,d-A);if(o*u!==x.width){x.width=o*u;x.style.width=o+"px"}C.applyDefaults(C.contexts[q])}}for(q+=1;q<D.length;q++){D[q].destroy()}C.activeCanvases=c*f;D.length=C.activeCanvases;C.clear()},clearTransform:function(){var f=this,a=f.xSplits,g=f.ySplits,d=f.contexts,h=f.splitThreshold,l=f.devicePixelRatio,e,c,b,m;for(e=0;e<a;e++){for(c=0;c<g;c++){b=c*a+e;m=d[b];m.translate(-h*e,-h*c);m.scale(l,l);f.matrix.toContext(m)}}},renderSprite:function(q){var C=this,b=C.getRect(),e=C.matrix,g=q.getParent(),v=Ext.draw.Matrix.fly([1,0,0,1,0,0]),p=C.splitThreshold/C.devicePixelRatio,c=C.xSplits,m=C.ySplits,A,z,s,a,r,o,d=0,B,n=0,f,l=b[2],y=b[3],x,u,t;while(g&&(g!==C)){v.prependMatrix(g.matrix||g.attr&&g.attr.matrix);g=g.getParent()}v.prependMatrix(e);a=q.getBBox();if(a){a=v.transformBBox(a)}q.preRender(C);if(q.attr.hidden||q.attr.globalAlpha===0){q.setDirty(false);return}for(u=0,z=0;u<m;u++,z+=p){for(x=0,A=0;x<c;x++,A+=p){t=u*c+x;s=C.contexts[t];r=Math.min(p,l-A);o=Math.min(p,y-z);d=A;B=d+r;n=z;f=n+o;if(a){if(a.x>B||a.x+a.width<d||a.y>f||a.y+a.height<n){continue}}s.save();q.useAttributes(s,b);if(false===q.render(C,s,[d,n,r,o],b)){return false}s.restore()}}q.setDirty(false)},flatten:function(n,a){var k=document.createElement("canvas"),f=Ext.getClassName(this),g=this.devicePixelRatio,l=k.getContext("2d"),b,c,h,e,d,m;k.width=Math.ceil(n.width*g);k.height=Math.ceil(n.height*g);for(e=0;e<a.length;e++){b=a[e];if(Ext.getClassName(b)!==f){continue}h=b.getRect();for(d=0;d<b.canvases.length;d++){c=b.canvases[d];m=c.getOffsetsTo(c.getParent());l.drawImage(c.dom,(h[0]+m[0])*g,(h[1]+m[1])*g)}}return{data:k.toDataURL(),type:"png"}},applyDefaults:function(a){var b=Ext.draw.Color.RGBA_NONE;a.strokeStyle=b;a.fillStyle=b;a.textAlign="start";a.textBaseline="alphabetic";a.miterLimit=1},clear:function(){var d=this,e=d.activeCanvases,c,b,a;for(c=0;c<e;c++){b=d.canvases[c].dom;a=d.contexts[c];a.setTransform(1,0,0,1,0,0);a.clearRect(0,0,b.width,b.height)}d.setDirty(true)},destroy:function(){var c=this,a,b=c.canvases.length;for(a=0;a<b;a++){c.contexts[a]=null;c.canvases[a].destroy();c.canvases[a]=null}delete c.contexts;delete c.canvases;c.callParent()},privates:{initElement:function(){var a=this;a.callParent();a.canvases=[];a.contexts=[];a.activeCanvases=(a.xSplits=0)*(a.ySplits=0)}}},function(){var c=this,b=c.prototype,a=10000000000;if(Ext.os.is.Android4&&Ext.browser.is.Chrome){a=3000}else{if(Ext.is.iOS){a=2200}}b.splitThreshold=a});Ext.define("Ext.draw.Container",{extend:"Ext.draw.ContainerBase",alternateClassName:"Ext.draw.Component",xtype:"draw",defaultType:"surface",isDrawContainer:true,requires:["Ext.draw.Surface","Ext.draw.engine.Svg","Ext.draw.engine.Canvas","Ext.draw.gradient.GradientDefinition"],engine:"Ext.draw.engine.Canvas",config:{cls:Ext.baseCSSPrefix+"draw-container",resizeHandler:null,sprites:null,gradients:[]},defaultDownloadServerUrl:"http://svg.sencha.io",supportedFormats:["png","pdf","jpeg","gif"],supportedOptions:{version:Ext.isNumber,data:Ext.isString,format:function(a){return Ext.Array.indexOf(this.supportedFormats,a)>=0},filename:Ext.isString,width:Ext.isNumber,height:Ext.isNumber,scale:Ext.isNumber,pdf:Ext.isObject,jpeg:Ext.isObject},initAnimator:function(){this.frameCallbackId=Ext.draw.Animator.addFrameCallback("renderFrame",this)},applyGradients:function(b){var a=[],c,f,d,e;if(!Ext.isArray(b)){return a}for(c=0,f=b.length;c<f;c++){d=b[c];if(!Ext.isObject(d)){continue}if(typeof d.type!=="string"){d.type="linear"}if(d.angle){d.degrees=d.angle;delete d.angle}if(Ext.isObject(d.stops)){d.stops=(function(i){var g=[],h;for(e in i){h=i[e];h.offset=e/100;g.push(h)}return g})(d.stops)}a.push(d)}Ext.draw.gradient.GradientDefinition.add(a);return a},applySprites:function(f){if(!f){return}f=Ext.Array.from(f);var e=f.length,b=[],d,a,c;for(d=0;d<e;d++){c=f[d];a=c.surface;if(!(a&&a.isSurface)){if(Ext.isString(a)){a=this.getSurface(a)}else{a=this.getSurface("main")}}c=a.add(c);b.push(c)}return b},onBodyResize:function(){var b=this.element,a;if(!b){return}a=b.getSize();if(a.width&&a.height){this.setBodySize(a)}},setBodySize:function(c){var d=this,b=d.getResizeHandler()||d.defaultResizeHandler,a;d.fireEvent("bodyresize",d,c);a=b.call(d,c);if(a!==false){d.renderFrame()}},defaultResizeHandler:function(a){this.getItems().each(function(b){b.setRect([0,0,a.width,a.height])})},getSurface:function(d){d=this.getId()+"-"+(d||"main");var c=this,b=c.getItems(),a=b.get(d);if(!a){a=c.add({xclass:c.engine,id:d});c.onBodyResize()}return a},renderFrame:function(){var e=this,a=e.getItems(),b,d,c;for(b=0,d=a.length;b<d;b++){c=a.items[b];if(c.isSurface){c.renderFrame()}}},getImage:function(k){var l=this.innerElement.getSize(),a=Array.prototype.slice.call(this.items.items),d,g,c=this.surfaceZIndexes,f,e,b,h;for(e=1;e<a.length;e++){b=a[e];h=c[b.type];f=e-1;while(f>=0&&c[a[f].type]>h){a[f+1]=a[f];f--}a[f+1]=b}d=a[0].flatten(l,a);if(k==="image"){g=new Image();g.src=d.data;d.data=g;return d}if(k==="stream"){d.data=d.data.replace(/^data:image\/[^;]+/,"data:application/octet-stream");return d}return d},download:function(d){var e=this,a=[],b,c,f;d=Ext.apply({version:2,data:e.getImage().data},d);for(c in d){if(d.hasOwnProperty(c)){f=d[c];if(c in e.supportedOptions){if(e.supportedOptions[c].call(e,f)){a.push({tag:"input",type:"hidden",name:c,value:Ext.String.htmlEncode(Ext.isObject(f)?Ext.JSON.encode(f):f)})}}}}b=Ext.dom.Helper.markup({tag:"html",children:[{tag:"head"},{tag:"body",children:[{tag:"form",method:"POST",action:d.url||e.defaultDownloadServerUrl,children:a},{tag:"script",type:"text/javascript",children:'document.getElementsByTagName("form")[0].submit();'}]}]});window.open("","ImageDownload_"+Date.now()).document.write(b)},destroy:function(){var a=this.frameCallbackId;if(a){Ext.draw.Animator.removeFrameCallback(a)}this.callParent()}},function(){if(location.search.match("svg")){Ext.draw.Container.prototype.engine="Ext.draw.engine.Svg"}else{if((Ext.os.is.BlackBerry&&Ext.os.version.getMajor()===10)||(Ext.browser.is.AndroidStock4&&(Ext.os.version.getMinor()===1||Ext.os.version.getMinor()===2||Ext.os.version.getMinor()===3))){Ext.draw.Container.prototype.engine="Ext.draw.engine.Svg"}}});Ext.define("Ext.chart.theme.Base",{mixins:{factoryable:"Ext.mixin.Factoryable"},requires:["Ext.draw.Color"],factoryConfig:{type:"chart.theme"},isTheme:true,config:{baseColor:null,colors:undefined,gradients:null,chart:{defaults:{background:"white"}},axis:{defaults:{label:{x:0,y:0,textBaseline:"middle",textAlign:"center",fontSize:"default",fontFamily:"default",fontWeight:"default",fillStyle:"black"},title:{fillStyle:"black",fontSize:"default*1.23",fontFamily:"default",fontWeight:"default"},style:{strokeStyle:"black"},grid:{strokeStyle:"rgb(221, 221, 221)"}},top:{style:{textPadding:5}},bottom:{style:{textPadding:5}}},series:{defaults:{label:{fillStyle:"black",strokeStyle:"none",fontFamily:"default",fontWeight:"default",fontSize:"default*1.077",textBaseline:"middle",textAlign:"center"},labelOverflowPadding:5}},sprites:{text:{fontSize:"default",fontWeight:"default",fontFamily:"default",fillStyle:"black"}},seriesThemes:undefined,markerThemes:{type:["circle","cross","plus","square","triangle","diamond"]},useGradients:false,background:null},colorDefaults:["#94ae0a","#115fa6","#a61120","#ff8809","#ffd13e","#a61187","#24ad9a","#7c7474","#a66111"],constructor:function(a){this.initConfig(a);this.resolveDefaults()},defaultRegEx:/^default([+\-/\*]\d+(?:\.\d+)?)?$/,defaultOperators:{"*":function(b,a){return b*a},"+":function(b,a){return b+a},"-":function(b,a){return b-a}},resolveDefaults:function(){var a=this;Ext.onReady(function(){var f=Ext.clone(a.getSprites()),e=Ext.clone(a.getAxis()),d=Ext.clone(a.getSeries()),g,c,b;if(!a.superclass.defaults){g=Ext.getBody().createChild({tag:"div",cls:"x-component"});a.superclass.defaults={fontFamily:g.getStyle("fontFamily"),fontWeight:g.getStyle("fontWeight"),fontSize:parseFloat(g.getStyle("fontSize")),fontVariant:g.getStyle("fontVariant"),fontStyle:g.getStyle("fontStyle")};g.destroy()}a.replaceDefaults(f.text);a.setSprites(f);for(c in e){b=e[c];a.replaceDefaults(b.label);a.replaceDefaults(b.title)}a.setAxis(e);for(c in d){b=d[c];a.replaceDefaults(b.label)}a.setSeries(d)})},replaceDefaults:function(h){var e=this,g=e.superclass.defaults,a=e.defaultRegEx,d,f,c,b;if(Ext.isObject(h)){for(d in g){c=a.exec(h[d]);if(c){f=g[d];c=c[1];if(c){b=e.defaultOperators[c.charAt(0)];f=Math.round(b(f,parseFloat(c.substr(1))))}h[d]=f}}}},applyBaseColor:function(c){var a,b;if(c){a=c.isColor?c:Ext.draw.Color.fromString(c);b=a.getHSL()[2];if(b<0.15){a=a.createLighter(0.3)}else{if(b<0.3){a=a.createLighter(0.15)}else{if(b>0.85){a=a.createDarker(0.3)}else{if(b>0.7){a=a.createDarker(0.15)}}}}this.setColors([a.createDarker(0.3).toString(),a.createDarker(0.15).toString(),a.toString(),a.createLighter(0.12).toString(),a.createLighter(0.24).toString(),a.createLighter(0.31).toString()])}return c},applyColors:function(a){return a||this.colorDefaults},updateUseGradients:function(a){if(a){this.updateGradients({type:"linear",degrees:90})}},updateBackground:function(a){if(a){var b=this.getChart();b.defaults.background=a;this.setChart(b)}},updateGradients:function(a){var c=this.getColors(),e=[],h,b,d,f,g;if(Ext.isObject(a)){for(f=0,g=c&&c.length||0;f<g;f++){b=Ext.draw.Color.fromString(c[f]);if(b){d=b.createLighter(0.15).toString();h=Ext.apply(Ext.Object.chain(a),{stops:[{offset:1,color:b.toString()},{offset:0,color:d.toString()}]});e.push(h)}}this.setColors(e)}},applySeriesThemes:function(a){this.getBaseColor();this.getUseGradients();this.getGradients();var b=this.getColors();if(!a){a={fillStyle:Ext.Array.clone(b),strokeStyle:Ext.Array.map(b,function(d){var c=Ext.draw.Color.fromString(d.stops?d.stops[0].color:d);return c.createDarker(0.15).toString()})}}return a}});Ext.define("Ext.chart.theme.Default",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.default","chart.theme.Base"]});Ext.define("Ext.chart.Markers",{extend:"Ext.draw.sprite.Instancing",isMarkers:true,defaultCategory:"default",constructor:function(){this.callParent(arguments);this.categories={};this.revisions={}},destroy:function(){this.categories=null;this.revisions=null;this.callParent()},getMarkerFor:function(b,a){if(b in this.categories){var c=this.categories[b];if(a in c){return this.get(c[a])}}},clear:function(a){a=a||this.defaultCategory;if(!(a in this.revisions)){this.revisions[a]=1}else{this.revisions[a]++}},putMarkerFor:function(e,b,c,h,f){e=e||this.defaultCategory;var d=this,g=d.categories[e]||(d.categories[e]={}),a;if(c in g){d.setAttributesFor(g[c],b,h)}else{g[c]=d.getCount();d.createInstance(b,h)}a=d.get(g[c]);if(a){a.category=e;if(!f){a.revision=d.revisions[e]||(d.revisions[e]=1)}}},getMarkerBBoxFor:function(c,a,b){if(c in this.categories){var d=this.categories[c];if(a in d){return this.getBBoxFor(d[a],b)}}},getBBox:function(){return null},render:function(a,l,b){var f=this,k=f.revisions,j=f.attr.matrix,h=f.getTemplate(),d=h.attr,g,c,e;j.toContext(l);h.preRender(a,l,b);h.useAttributes(l,b);for(c=0,e=f.instances.length;c<e;c++){g=f.get(c);if(g.hidden||g.revision!==k[g.category]){continue}l.save();h.attr=g;h.useAttributes(l,b);h.render(a,l,b);l.restore()}h.attr=d}});Ext.define("Ext.chart.label.Callout",{extend:"Ext.draw.modifier.Modifier",prepareAttributes:function(a){if(!a.hasOwnProperty("calloutOriginal")){a.calloutOriginal=Ext.Object.chain(a);a.calloutOriginal.prototype=a}if(this._previous){this._previous.prepareAttributes(a.calloutOriginal)}},setAttrs:function(e,h){var d=e.callout,i=e.calloutOriginal,l=e.bbox.plain,c=(l.width||0)+e.labelOverflowPadding,m=(l.height||0)+e.labelOverflowPadding,p,o;if("callout" in h){d=h.callout}if("callout" in h||"calloutPlaceX" in h||"calloutPlaceY" in h||"x" in h||"y" in h){var n="rotationRads" in h?i.rotationRads=h.rotationRads:i.rotationRads,g="x" in h?(i.x=h.x):i.x,f="y" in h?(i.y=h.y):i.y,b="calloutPlaceX" in h?h.calloutPlaceX:e.calloutPlaceX,a="calloutPlaceY" in h?h.calloutPlaceY:e.calloutPlaceY,k="calloutVertical" in h?h.calloutVertical:e.calloutVertical,j;n%=Math.PI*2;if(Math.cos(n)<0){n=(n+Math.PI)%(Math.PI*2)}if(n>Math.PI){n-=Math.PI*2}if(k){n=n*(1-d)-Math.PI/2*d;j=c;c=m;m=j}else{n=n*(1-d)}h.rotationRads=n;h.x=g*(1-d)+b*d;h.y=f*(1-d)+a*d;p=b-g;o=a-f;if(Math.abs(o*c)>Math.abs(p*m)){if(o>0){h.calloutEndX=h.x-(m/2)*(p/o)*d;h.calloutEndY=h.y-(m/2)*d}else{h.calloutEndX=h.x+(m/2)*(p/o)*d;h.calloutEndY=h.y+(m/2)*d}}else{if(p>0){h.calloutEndX=h.x-c/2;h.calloutEndY=h.y-(c/2)*(o/p)*d}else{h.calloutEndX=h.x+c/2;h.calloutEndY=h.y+(c/2)*(o/p)*d}}if(h.calloutStartX&&h.calloutStartY){h.calloutHasLine=(p>0&&h.calloutStartX<h.calloutEndX)||(p<=0&&h.calloutStartX>h.calloutEndX)||(o>0&&h.calloutStartY<h.calloutEndY)||(o<=0&&h.calloutStartY>h.calloutEndY)}else{h.calloutHasLine=true}}return h},pushDown:function(a,b){b=this.callParent([a.calloutOriginal,b]);return this.setAttrs(a,b)},popUp:function(a,b){a=a.prototype;b=this.setAttrs(a,b);if(this._next){return this._next.popUp(a,b)}else{return Ext.apply(a,b)}}});Ext.define("Ext.chart.label.Label",{extend:"Ext.draw.sprite.Text",requires:["Ext.chart.label.Callout"],inheritableStatics:{def:{processors:{callout:"limited01",calloutHasLine:"bool",calloutPlaceX:"number",calloutPlaceY:"number",calloutStartX:"number",calloutStartY:"number",calloutEndX:"number",calloutEndY:"number",calloutColor:"color",calloutWidth:"number",calloutVertical:"bool",labelOverflowPadding:"number",display:"enums(none,under,over,rotate,insideStart,insideEnd,inside,outside)",orientation:"enums(horizontal,vertical)",renderer:"default"},defaults:{callout:0,calloutHasLine:true,calloutPlaceX:0,calloutPlaceY:0,calloutStartX:0,calloutStartY:0,calloutEndX:0,calloutEndY:0,calloutWidth:1,calloutVertical:false,calloutColor:"black",labelOverflowPadding:5,display:"none",orientation:"",renderer:null},triggers:{callout:"transform",calloutPlaceX:"transform",calloutPlaceY:"transform",labelOverflowPadding:"transform",calloutRotation:"transform",display:"hidden"},updaters:{hidden:function(a){a.hidden=a.display==="none"}}}},config:{fx:{customDurations:{callout:200}},field:null,calloutLine:true},applyCalloutLine:function(a){if(a){return Ext.apply({},a)}},prepareModifiers:function(){this.callParent(arguments);this.calloutModifier=new Ext.chart.label.Callout({sprite:this});this.fx.setNext(this.calloutModifier);this.calloutModifier.setNext(this.topModifier)},render:function(b,c){var e=this,a=e.attr,d=a.calloutColor;c.save();c.globalAlpha*=a.callout;if(c.globalAlpha>0&&a.calloutHasLine){if(d&&d.isGradient){d=d.getStops()[0].color}c.strokeStyle=d;c.fillStyle=d;c.lineWidth=a.calloutWidth;c.beginPath();c.moveTo(e.attr.calloutStartX,e.attr.calloutStartY);c.lineTo(e.attr.calloutEndX,e.attr.calloutEndY);c.stroke();c.beginPath();c.arc(e.attr.calloutStartX,e.attr.calloutStartY,1*a.calloutWidth,0,2*Math.PI,true);c.fill();c.beginPath();c.arc(e.attr.calloutEndX,e.attr.calloutEndY,1*a.calloutWidth,0,2*Math.PI,true);c.fill()}c.restore();Ext.draw.sprite.Text.prototype.render.apply(e,arguments)}});Ext.define("Ext.chart.series.Series",{requires:["Ext.chart.Markers","Ext.chart.label.Label","Ext.tip.ToolTip"],mixins:["Ext.mixin.Observable","Ext.mixin.Bindable"],isSeries:true,defaultBindProperty:"store",type:null,seriesType:"sprite",identifiablePrefix:"ext-line-",observableType:"series",darkerStrokeRatio:0.15,config:{chart:null,title:null,renderer:null,showInLegend:true,triggerAfterDraw:false,style:{},subStyle:{},themeStyle:{},colors:null,useDarkerStrokeColor:true,store:null,label:{},labelOverflowPadding:null,showMarkers:true,marker:null,markerSubStyle:null,itemInstancing:null,background:null,highlightItem:null,surface:null,overlaySurface:null,hidden:false,highlight:false,highlightCfg:{merge:function(a){return a},$value:{fillStyle:"yellow",strokeStyle:"red"}},animation:null,tooltip:null},directions:[],sprites:null,themeColorCount:function(){return 1},isStoreDependantColorCount:false,themeMarkerCount:function(){return 0},getFields:function(f){var e=this,a=[],c,b,d;for(b=0,d=f.length;b<d;b++){c=e["get"+f[b]+"Field"]();if(Ext.isArray(c)){a.push.apply(a,c)}else{a.push(c)}}return a},applyAnimation:function(a,b){if(!a){a={duration:0}}else{if(a===true){a={easing:"easeInOut",duration:500}}}return b?Ext.apply({},a,b):a},getAnimation:function(){var a=this.getChart();if(a&&a.animationSuspendCount){return{duration:0}}else{return this.callParent()}},updateTitle:function(a){var j=this,g=j.getChart();if(!g||g.isInitializing){return}a=Ext.Array.from(a);var c=g.getSeries(),b=Ext.Array.indexOf(c,j),e=g.getLegendStore(),h=j.getYField(),d,l,k,f;if(e.getCount()&&b!==-1){f=h?Math.min(a.length,h.length):a.length;for(d=0;d<f;d++){k=a[d];l=e.getAt(b+d);if(k&&l){l.set("name",k)}}}},applyHighlight:function(a,b){if(Ext.isObject(a)){a=Ext.merge({},this.config.highlightCfg,a)}else{if(a===true){a=this.config.highlightCfg}}return Ext.apply(b||{},a)},updateHighlight:function(a){this.getStyle();if(!Ext.Object.isEmpty(a)){this.addItemHighlight()}},updateHighlightCfg:function(a){if(!Ext.Object.equals(a,this.defaultConfig.highlightCfg)){this.addItemHighlight()}},applyItemInstancing:function(a,b){return Ext.merge(b||{},a)},setAttributesForItem:function(c,d){var b=c&&c.sprite,a;if(b){if(b.itemsMarker&&c.category==="items"){b.putMarker(c.category,d,c.index,false,true)}if(b.isMarkerHolder&&c.category==="markers"){b.putMarker(c.category,d,c.index,false,true)}else{if(b.isInstancing){b.setAttributesFor(c.index,d)}else{if(Ext.isArray(b)){for(a=0;a<b.length;a++){b[a].setAttributes(d)}}else{b.setAttributes(d)}}}}},getBBoxForItem:function(a){if(a&&a.sprite){if(a.sprite.itemsMarker&&a.category==="items"){return a.sprite.getMarkerBBox(a.category,a.index)}else{if(a.sprite instanceof Ext.draw.sprite.Instancing){return a.sprite.getBBoxFor(a.index)}else{return a.sprite.getBBox()}}}return null},applyHighlightItem:function(d,a){if(d===a){return}if(Ext.isObject(d)&&Ext.isObject(a)){var c=d.sprite===a.sprite,b=d.index===a.index;if(c&&b){return}}return d},updateHighlightItem:function(b,a){this.setAttributesForItem(a,{highlighted:false});this.setAttributesForItem(b,{highlighted:true})},constructor:function(a){var b=this,c;a=a||{};if(a.tips){a=Ext.apply({tooltip:a.tips},a)}if(a.highlightCfg){a=Ext.apply({highlight:a.highlightCfg},a)}if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.sprites=[];b.dataRange=[];b.mixins.observable.constructor.call(b,a);b.initBindable()},lookupViewModel:function(a){var b=this.getChart();return b?b.lookupViewModel(a):null},applyTooltip:function(c,b){var a=Ext.apply({xtype:"tooltip",renderer:Ext.emptyFn,constrainPosition:true,shrinkWrapDock:true,autoHide:true,offsetX:10,offsetY:10},c);return Ext.create(a)},updateTooltip:function(){this.addItemHighlight()},addItemHighlight:function(){var d=this.getChart();if(!d){return}var e=d.getInteractions(),c,a,b;for(c=0;c<e.length;c++){a=e[c];if(a.isItemHighlight||a.isItemEdit){b=true;break}}if(!b){e.push("itemhighlight");d.setInteractions(e)}},showTooltip:function(l,m){var d=this,n=d.getTooltip(),j,a,i,f,h,k,g,e,b,c;if(!n){return}clearTimeout(d.tooltipTimeout);b=n.config;if(n.trackMouse){m[0]+=b.offsetX;m[1]+=b.offsetY}else{j=l.sprite;a=j.getSurface();i=Ext.get(a.getId());if(i){k=l.series.getBBoxForItem(l);g=k.x+k.width/2;e=k.y+k.height/2;h=a.matrix.transformPoint([g,e]);f=i.getXY();c=a.getInherited().rtl;g=c?f[0]+i.getWidth()-h[0]:f[0]+h[0];e=f[1]+h[1];m=[g,e]}}Ext.callback(n.renderer,n.scope,[n,l.record,l],0,d);n.show(m)},hideTooltip:function(b){var a=this,c=a.getTooltip();if(!c){return}clearTimeout(a.tooltipTimeout);a.tooltipTimeout=Ext.defer(function(){c.hide()},1)},applyStore:function(a){return a&&Ext.StoreManager.lookup(a)},getStore:function(){return this._store||this.getChart()&&this.getChart().getStore()},updateStore:function(b,a){var h=this,g=h.getChart(),c=g&&g.getStore(),f,j,e,d;a=a||c;if(a&&a!==b){a.un({datachanged:"onDataChanged",update:"onDataChanged",scope:h})}if(b){b.on({datachanged:"onDataChanged",update:"onDataChanged",scope:h});f=h.getSprites();for(d=0,e=f.length;d<e;d++){j=f[d];if(j.setStore){j.setStore(b)}}h.onDataChanged()}h.fireEvent("storechange",h,b,a)},onStoreChange:function(b,a,c){if(!this._store){this.updateStore(a,c)}},coordinate:function(o,m,e){var l=this,p=l.getStore(),h=l.getHidden(),k=p.getData().items,b=l["get"+o+"Axis"](),f={min:Infinity,max:-Infinity},q=l["fieldCategory"+o]||[o],g=l.getFields(q),d,n,c,a={},j=l.getSprites();if(j.length>0){if(!Ext.isBoolean(h)||!h){for(d=0;d<q.length;d++){n=g[d];c=l.coordinateData(k,n,b);l.getRangeOfData(c,f);a["data"+q[d]]=c}}l.dataRange[m]=f.min;l.dataRange[m+e]=f.max;a["dataMin"+o]=f.min;a["dataMax"+o]=f.max;if(b){b.range=null;a["range"+o]=b.getRange()}for(d=0;d<j.length;d++){j[d].setAttributes(a)}}},coordinateData:function(b,h,d){var g=[],f=b.length,e=d&&d.getLayout(),c,a;for(c=0;c<f;c++){a=b[c].data[h];if(!Ext.isEmpty(a,true)){if(e){g[c]=e.getCoordFor(a,h,c,b)}else{g[c]=+a}}else{g[c]=a}}return g},getRangeOfData:function(g,b){var e=g.length,d=b.min,a=b.max,c,f;for(c=0;c<e;c++){f=g[c];if(f<d){d=f}if(f>a){a=f}}b.min=d;b.max=a},updateLabelData:function(){var h=this,l=h.getStore(),g=l.getData().items,f=h.getSprites(),a=h.getLabel().getTemplate(),n=Ext.Array.from(a.getField()),c,b,e,d,m,k;if(!f.length||!n.length){return}for(c=0;c<f.length;c++){d=[];m=f[c];k=m.getField();if(Ext.Array.indexOf(n,k)<0){k=n[c]}for(b=0,e=g.length;b<e;b++){d.push(g[b].get(k))}m.setAttributes({labels:d})}},processData:function(){if(!this.getStore()){return}var d=this,f=this.directions,a,c=f.length,e,b;for(a=0;a<c;a++){e=f[a];b=d["get"+e+"Axis"]();if(b){b.processData(d);continue}if(d["coordinate"+e]){d["coordinate"+e]()}}d.updateLabelData()},applyBackground:function(a){if(this.getChart()){this.getSurface().setBackground(a);return this.getSurface().getBackground()}else{return a}},updateChart:function(d,a){var c=this,b=c._store;if(a){a.un("axeschange","onAxesChange",c);c.clearSprites();c.setSurface(null);c.setOverlaySurface(null);a.unregister(c);c.onChartDetached(a);if(!b){c.updateStore(null)}}if(d){c.setSurface(d.getSurface("series"));c.setOverlaySurface(d.getSurface("overlay"));d.on("axeschange","onAxesChange",c);if(d.getAxes()){c.onAxesChange(d)}c.onChartAttached(d);d.register(c);if(!b){c.updateStore(d.getStore())}}},onAxesChange:function(h){var k=this,g=h.getAxes(),c,a={},b={},e=false,j=this.directions,l,d,f;for(d=0,f=j.length;d<f;d++){l=j[d];b[l]=k.getFields(k["fieldCategory"+l])}for(d=0,f=g.length;d<f;d++){c=g[d];if(!a[c.getDirection()]){a[c.getDirection()]=[c]}else{a[c.getDirection()].push(c)}}for(d=0,f=j.length;d<f;d++){l=j[d];if(k["get"+l+"Axis"]()){continue}if(a[l]){c=k.findMatchingAxis(a[l],b[l]);if(c){k["set"+l+"Axis"](c);if(c.getNeedHighPrecision()){e=true}}}}this.getSurface().setHighPrecision(e)},findMatchingAxis:function(f,e){var d,c,b,a;for(b=0;b<f.length;b++){d=f[b];c=d.getFields();if(!c.length){return d}else{if(e){for(a=0;a<e.length;a++){if(Ext.Array.indexOf(c,e[a])>=0){return d}}}}}},onChartDetached:function(a){var b=this;b.fireEvent("chartdetached",a,b);a.un("storechange","onStoreChange",b)},onChartAttached:function(a){var b=this;b.setBackground(b.getBackground());b.fireEvent("chartattached",a,b);a.on("storechange","onStoreChange",b);b.processData()},updateOverlaySurface:function(a){var b=this;if(a){if(b.getLabel()){b.getOverlaySurface().add(b.getLabel())}}},applyLabel:function(a,b){if(!b){b=new Ext.chart.Markers({zIndex:10});b.setTemplate(new Ext.chart.label.Label(a))}else{b.getTemplate().setAttributes(a)}return b},createItemInstancingSprite:function(c,b){var e=this,f=new Ext.chart.Markers(),a,d;f.setAttributes({zIndex:Number.MAX_VALUE});a=Ext.apply({},b);if(e.getHighlight()){a.highlight=e.getHighlight();a.modifiers=["highlight"]}f.setTemplate(a);d=f.getTemplate();d.setAttributes(e.getStyle());d.fx.on("animationstart","onSpriteAnimationStart",this);d.fx.on("animationend","onSpriteAnimationEnd",this);c.bindMarker("items",f);e.getSurface().add(f);return f},getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer()}},updateRenderer:function(c){var b=this,a=b.getChart(),d;if(a&&a.isInitializing){return}d=b.getSprites();if(d.length){d[0].setAttributes({renderer:c||null});if(a&&!a.isInitializing){a.redraw()}}},updateShowMarkers:function(a){var d=this.getSprites(),b=d&&d[0],c=b&&b.getMarker("markers");if(c){c.getTemplate().setAttributes({hidden:!a})}},createSprite:function(){var f=this,a=f.getSurface(),e=f.getItemInstancing(),d=a.add(f.getDefaultSpriteConfig()),b=f.getMarker(),g,c;d.setAttributes(f.getStyle());d.setSeries(f);if(e){d.itemsMarker=f.createItemInstancingSprite(d,e)}if(d.bindMarker){if(b){g=new Ext.chart.Markers();c=Ext.Object.merge({},b);if(f.getHighlight()){c.highlight=f.getHighlight();c.modifiers=["highlight"]}g.setTemplate(c);g.getTemplate().fx.setCustomDurations({translationX:0,translationY:0});d.dataMarker=g;d.bindMarker("markers",g);f.getOverlaySurface().add(g)}if(f.getLabel().getTemplate().getField()){d.bindMarker("labels",f.getLabel())}}if(d.setStore){d.setStore(f.getStore())}d.fx.on("animationstart","onSpriteAnimationStart",f);d.fx.on("animationend","onSpriteAnimationEnd",f);f.sprites.push(d);return d},getSprites:Ext.emptyFn,onDataChanged:function(){var d=this,c=d.getChart(),b=c&&c.getStore(),a=d.getStore();if(a!==b){d.processData()}},isXType:function(a){return a==="series"},getItemId:function(){return this.getId()},applyThemeStyle:function(e,a){var b=this,d,c;d=e&&e.subStyle&&e.subStyle.fillStyle;c=d&&e.subStyle.strokeStyle;if(d&&!c){e.subStyle.strokeStyle=b.getStrokeColorsFromFillColors(d)}d=e&&e.markerSubStyle&&e.markerSubStyle.fillStyle;c=d&&e.markerSubStyle.strokeStyle;if(d&&!c){e.markerSubStyle.strokeStyle=b.getStrokeColorsFromFillColors(d)}return Ext.apply(a||{},e)},applyStyle:function(c,b){var a=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+this.seriesType));if(a&&a.def){c=a.def.normalize(c)}return Ext.apply({},c,b)},applySubStyle:function(b,c){var a=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+this.seriesType));if(a&&a.def){b=a.def.batchedNormalize(b,true)}return Ext.merge({},c,b)},applyMarker:function(c,a){var d=(c&&c.type)||(a&&a.type)||"circle",b=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+d));if(b&&b.def){c=b.def.normalize(Ext.isObject(c)?c:{},true);c.type=d}return Ext.merge(a||{},c)},applyMarkerSubStyle:function(c,a){var d=(c&&c.type)||(a&&a.type)||"circle",b=Ext.ClassManager.get(Ext.ClassManager.getNameByAlias("sprite."+d));if(b&&b.def){c=b.def.batchedNormalize(c,true)}return Ext.merge(a||{},c)},updateHidden:function(b){var a=this;a.getColors();a.getSubStyle();a.setSubStyle({hidden:b});a.processData();a.doUpdateStyles();if(!Ext.isArray(b)){a.updateLegendStore(b)}},updateLegendStore:function(f,b){var e=this,d=e.getChart(),c=d.getLegendStore(),g=e.getId(),a;if(c){if(arguments.length>1){a=c.findBy(function(h){return h.get("series")===g&&h.get("index")===b});if(a!==-1){a=c.getAt(a)}}else{a=c.findRecord("series",g)}if(a&&a.get("disabled")!==f){a.set("disabled",f)}}},setHiddenByIndex:function(a,c){var b=this;if(Ext.isArray(b.getHidden())){b.getHidden()[a]=c;b.updateHidden(b.getHidden());b.updateLegendStore(c,a)}else{b.setHidden(c)}},getStrokeColorsFromFillColors:function(a){var c=this,e=c.getUseDarkerStrokeColor(),b=(Ext.isNumber(e)?e:c.darkerStrokeRatio),d;if(e){d=Ext.Array.map(a,function(f){f=Ext.isString(f)?f:f.stops[0].color;f=Ext.draw.Color.fromString(f);return f.createDarker(b).toString()})}else{d=Ext.Array.clone(a)}return d},updateThemeColors:function(b){var c=this,d=c.getThemeStyle(),a=Ext.Array.clone(b),f=c.getStrokeColorsFromFillColors(b),e={fillStyle:a,strokeStyle:f};d.subStyle=Ext.apply(d.subStyle||{},e);d.markerSubStyle=Ext.apply(d.markerSubStyle||{},e);c.doUpdateStyles()},themeOnlyIfConfigured:{},updateTheme:function(d){var h=this,a=d.getSeries(),n=h.getInitialConfig(),c=h.defaultConfig,f=h.getConfigurator().configs,j=a.defaults,k=a[h.type],g=h.themeOnlyIfConfigured,l,i,o,b,m,e;a=Ext.merge({},j,k);for(l in a){i=a[l];e=f[l];if(i!==null&&i!==undefined&&e){m=n[l];o=Ext.isObject(i);b=m===c[l];if(o){if(b&&g[l]){continue}i=Ext.merge({},i,m)}if(b||o){h[e.names.set](i)}}}},updateChartColors:function(a){var b=this;if(!b.getColors()){b.updateThemeColors(a)}},updateColors:function(a){this.updateThemeColors(a)},updateStyle:function(){this.doUpdateStyles()},updateSubStyle:function(){this.doUpdateStyles()},updateThemeStyle:function(){this.doUpdateStyles()},doUpdateStyles:function(){var g=this,h=g.sprites,d=g.getItemInstancing(),c=0,f=h&&h.length,a=g.getConfig("showMarkers",true),b=g.getMarker(),e;for(;c<f;c++){e=g.getStyleByIndex(c);if(d){h[c].itemsMarker.getTemplate().setAttributes(e)}h[c].setAttributes(e);if(b&&h[c].dataMarker){h[c].dataMarker.getTemplate().setAttributes(g.getMarkerStyleByIndex(c))}}},getStyleWithTheme:function(){var b=this,c=b.getThemeStyle(),d=(c&&c.style)||{},a=Ext.applyIf(Ext.apply({},b.getStyle()),d);return a},getSubStyleWithTheme:function(){var c=this,d=c.getThemeStyle(),a=(d&&d.subStyle)||{},b=Ext.applyIf(Ext.apply({},c.getSubStyle()),a);return b},getStyleByIndex:function(b){var e=this,h=e.getThemeStyle(),d,g,c,f,a={};d=e.getStyle();g=(h&&h.style)||{};c=e.styleDataForIndex(e.getSubStyle(),b);f=e.styleDataForIndex((h&&h.subStyle),b);Ext.apply(a,g);Ext.apply(a,f);Ext.apply(a,d);Ext.apply(a,c);return a},getMarkerStyleByIndex:function(d){var g=this,c=g.getThemeStyle(),a,e,k,j,b,l,h,f,m={};a=g.getStyle();e=(c&&c.style)||{};k=g.styleDataForIndex(g.getSubStyle(),d);if(k.hasOwnProperty("hidden")){k.hidden=k.hidden||!this.getConfig("showMarkers",true)}j=g.styleDataForIndex((c&&c.subStyle),d);b=g.getMarker();l=(c&&c.marker)||{};h=g.getMarkerSubStyle();f=g.styleDataForIndex((c&&c.markerSubStyle),d);Ext.apply(m,e);Ext.apply(m,j);Ext.apply(m,l);Ext.apply(m,f);Ext.apply(m,a);Ext.apply(m,k);Ext.apply(m,b);Ext.apply(m,h);return m},styleDataForIndex:function(d,c){var e,b,a={};if(d){for(b in d){e=d[b];if(Ext.isArray(e)){a[b]=e[c%e.length]}else{a[b]=e}}}return a},getItemForPoint:Ext.emptyFn,getItemByIndex:function(a,e){var d=this,f=d.getSprites(),b=f&&f[0],c;if(!b){return}if(e===undefined&&b.isMarkerHolder){e=d.getItemInstancing()?"items":"markers"}else{if(!e||e===""||e==="sprites"){b=f[a]}}if(b){c={series:d,category:e,index:a,record:d.getStore().getData().items[a],field:d.getYField(),sprite:b};return c}},onSpriteAnimationStart:function(a){this.fireEvent("animationstart",this,a)},onSpriteAnimationEnd:function(a){this.fireEvent("animationend",this,a)},resolveListenerScope:function(e){var d=this,a=Ext._namedScopes[e],c=d.getChart(),b;if(!a){b=c?c.resolveListenerScope(e,false):(e||d)}else{if(a.isThis){b=d}else{if(a.isController){b=c?c.resolveListenerScope(e,false):d}else{if(a.isSelf){b=c?c.resolveListenerScope(e,false):d;if(b===c&&!c.getInheritedConfig("defaultListenerScope")){b=d}}}}}return b},provideLegendInfo:function(a){a.push({name:this.getTitle()||this.getId(),mark:"black",disabled:this.getHidden(),series:this.getId(),index:0})},clearSprites:function(){var d=this.sprites,b,a,c;for(a=0,c=d.length;a<c;a++){b=d[a];if(b&&b.isSprite){b.destroy()}}this.sprites=[]},destroy:function(){var b=this,a=b._store,c=b.getConfig("tooltip",true);if(a&&a.getAutoDestroy()){Ext.destroy(a)}b.setChart(null);b.clearListeners();if(c){Ext.destroy(c);clearTimeout(b.tooltipTimeout)}b.callParent()}});Ext.define("Ext.chart.interactions.Abstract",{xtype:"interaction",mixins:{observable:"Ext.mixin.Observable"},config:{gestures:{tap:"onGesture"},chart:null,enabled:true},throttleGap:0,stopAnimationBeforeSync:false,constructor:function(a){var b=this,c;a=a||{};if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.mixins.observable.constructor.call(b,a)},initialize:Ext.emptyFn,updateChart:function(c,a){var b=this;if(a===c){return}if(a){a.unregister(b);b.removeChartListener(a)}if(c){c.register(b);b.addChartListener()}},updateEnabled:function(a){var c=this,b=c.getChart();if(b){if(a){c.addChartListener()}else{c.removeChartListener(b)}}},onGesture:Ext.emptyFn,getItemForEvent:function(d){var b=this,a=b.getChart(),c=a.getEventXY(d);return a.getItemForPoint(c[0],c[1])},getItemsForEvent:function(d){var b=this,a=b.getChart(),c=a.getEventXY(d);return a.getItemsForPoint(c[0],c[1])},addChartListener:function(){var c=this,b=c.getChart(),e=c.getGestures(),a;if(!c.getEnabled()){return}function d(f,g){b.addElementListener(f,c.listeners[f]=function(j){var i=c.getLocks(),h;if(c.getEnabled()&&(!(f in i)||i[f]===c)){h=(Ext.isFunction(g)?g:c[g]).apply(this,arguments);if(h===false&&j&&j.stopPropagation){j.stopPropagation()}return h}},c)}c.listeners=c.listeners||{};for(a in e){d(a,e[a])}},removeChartListener:function(c){var d=this,e=d.getGestures(),b;function a(f){var g=d.listeners[f];if(g){c.removeElementListener(f,g);delete d.listeners[f]}}if(d.listeners){for(b in e){a(b)}}},lockEvents:function(){var d=this,c=d.getLocks(),a=Array.prototype.slice.call(arguments),b=a.length;while(b--){c[a[b]]=d}},unlockEvents:function(){var c=this.getLocks(),a=Array.prototype.slice.call(arguments),b=a.length;while(b--){delete c[a[b]]}},getLocks:function(){var a=this.getChart();return a.lockedEvents||(a.lockedEvents={})},isMultiTouch:function(){if(Ext.browser.is.IE10){return true}return !Ext.os.is.Desktop},initializeDefaults:Ext.emptyFn,doSync:function(){var b=this,a=b.getChart();if(b.syncTimer){clearTimeout(b.syncTimer);b.syncTimer=null}if(b.stopAnimationBeforeSync){a.animationSuspendCount++}a.redraw();if(b.stopAnimationBeforeSync){a.animationSuspendCount--}b.syncThrottle=Date.now()+b.throttleGap},sync:function(){var a=this;if(a.throttleGap&&Ext.frameStartTime<a.syncThrottle){if(a.syncTimer){return}a.syncTimer=Ext.defer(function(){a.doSync()},a.throttleGap)}else{a.doSync()}},getItemId:function(){return this.getId()},isXType:function(a){return a==="interaction"},destroy:function(){var a=this;a.setChart(null);delete a.listeners;a.callParent()}},function(){if(Ext.os.is.Android4){this.prototype.throttleGap=40}});Ext.define("Ext.chart.MarkerHolder",{extend:"Ext.Mixin",mixinConfig:{id:"markerHolder",after:{constructor:"constructor",preRender:"preRender"},before:{destroy:"destroy"}},isMarkerHolder:true,surfaceMatrix:null,inverseSurfaceMatrix:null,deprecated:{6:{methods:{getBoundMarker:{message:"Please use the 'getMarker' method instead.",fn:function(b){var a=this.boundMarkers[b];return a?[a]:a}}}}},constructor:function(){this.boundMarkers={};this.cleanRedraw=false},bindMarker:function(b,a){var c=this,d=c.boundMarkers;if(a&&a.isMarkers){c.releaseMarker(b);d[b]=a;a.on("destroy",c.onMarkerDestroy,c)}},onMarkerDestroy:function(a){this.releaseMarker(a)},releaseMarker:function(a){var c=this.boundMarkers,b;if(a&&a.isMarkers){for(b in c){if(c[b]===a){delete c[b];break}}}else{b=a;a=c[b];delete c[b]}return a||null},getMarker:function(a){return this.boundMarkers[a]||null},preRender:function(){var f=this,g=f.getId(),d=f.boundMarkers,e=f.getParent(),c,a,b;if(f.surfaceMatrix){b=f.surfaceMatrix.set(1,0,0,1,0,0)}else{b=f.surfaceMatrix=new Ext.draw.Matrix()}f.cleanRedraw=!f.attr.dirty;if(!f.cleanRedraw){for(c in d){a=d[c];if(a){a.clear(g)}}}while(e&&e.attr&&e.attr.matrix){b.prependMatrix(e.attr.matrix);e=e.getParent()}b.prependMatrix(e.matrix);f.surfaceMatrix=b;f.inverseSurfaceMatrix=b.inverse(f.inverseSurfaceMatrix)},putMarker:function(d,a,c,g,e){var b=this.boundMarkers[d],f=this.getId();if(b){b.putMarkerFor(f,a,c,g,e)}},getMarkerBBox:function(c,b,d){var a=this.boundMarkers[c],e=this.getId();if(a){return a.getMarkerBBoxFor(e,b,d)}},destroy:function(){var c=this.boundMarkers,b,a;for(b in c){a=c[b];a.destroy()}}});Ext.define("Ext.chart.axis.sprite.Axis",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.axis",type:"axis",mixins:{markerHolder:"Ext.chart.MarkerHolder"},requires:["Ext.draw.sprite.Text"],inheritableStatics:{def:{processors:{grid:"bool",axisLine:"bool",minorTicks:"bool",minorTickSize:"number",majorTicks:"bool",majorTickSize:"number",length:"number",startGap:"number",endGap:"number",dataMin:"number",dataMax:"number",visibleMin:"number",visibleMax:"number",position:"enums(left,right,top,bottom,angular,radial,gauge)",minStepSize:"number",estStepSize:"number",titleOffset:"number",textPadding:"number",min:"number",max:"number",centerX:"number",centerY:"number",radius:"number",totalAngle:"number",baseRotation:"number",data:"default",enlargeEstStepSizeByText:"bool"},defaults:{grid:false,axisLine:true,minorTicks:false,minorTickSize:3,majorTicks:true,majorTickSize:5,length:0,startGap:0,endGap:0,visibleMin:0,visibleMax:1,dataMin:0,dataMax:1,position:"",minStepSize:0,estStepSize:20,min:0,max:1,centerX:0,centerY:0,radius:1,baseRotation:0,data:null,titleOffset:0,textPadding:0,scalingCenterY:0,scalingCenterX:0,strokeStyle:"black",enlargeEstStepSizeByText:false},triggers:{minorTickSize:"bbox",majorTickSize:"bbox",position:"bbox,layout",axisLine:"bbox,layout",min:"layout",max:"layout",length:"layout",minStepSize:"layout",estStepSize:"layout",data:"layout",dataMin:"layout",dataMax:"layout",visibleMin:"layout",visibleMax:"layout",enlargeEstStepSizeByText:"layout"},updaters:{layout:"layoutUpdater"}}},config:{label:null,layout:null,segmenter:null,renderer:null,layoutContext:null,axis:null},thickness:0,stepSize:0,getBBox:function(){return null},defaultRenderer:function(a){return this.segmenter.renderer(a,this)},layoutUpdater:function(){var h=this,f=h.getAxis().getChart();if(f.isInitializing){return}var e=h.attr,d=h.getLayout(),g=f.getInherited().rtl,b=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMin,i=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMax,c=e.position,a={attr:e,segmenter:h.getSegmenter(),renderer:h.defaultRenderer};if(c==="left"||c==="right"){e.translationX=0;e.translationY=i*e.length/(i-b);e.scalingX=1;e.scalingY=-e.length/(i-b);e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}else{if(c==="top"||c==="bottom"){if(g){e.translationX=e.length+b*e.length/(i-b)+1}else{e.translationX=-b*e.length/(i-b)}e.translationY=0;e.scalingX=(g?-1:1)*e.length/(i-b);e.scalingY=1;e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}}if(d){d.calculateLayout(a);h.setLayoutContext(a)}},iterate:function(e,j){var c,g,a,b,h,d,k=Ext.Array.some,m=Math.abs,f;if(e.getLabel){if(e.min<e.from){j.call(this,e.min,e.getLabel(e.min),-1,e)}for(c=0;c<=e.steps;c++){j.call(this,e.get(c),e.getLabel(c),c,e)}if(e.max>e.to){j.call(this,e.max,e.getLabel(e.max),e.steps+1,e)}}else{b=this.getAxis();h=b.floatingAxes;d=[];f=(e.to-e.from)/(e.steps+1);if(b.getFloating()){for(a in h){d.push(h[a])}}function l(i){return !d.length||k(d,function(n){return m(n-i)>f})}if(e.min<e.from&&l(e.min)){j.call(this,e.min,e.min,-1,e)}for(c=0;c<=e.steps;c++){g=e.get(c);if(l(g)){j.call(this,g,g,c,e)}}if(e.max>e.to&&l(e.max)){j.call(this,e.max,e.max,e.steps+1,e)}}},renderTicks:function(l,m,s,p){var v=this,k=v.attr,u=k.position,n=k.matrix,e=0.5*k.lineWidth,f=n.getXX(),i=n.getDX(),j=n.getYY(),h=n.getDY(),o=s.majorTicks,d=k.majorTickSize,a=s.minorTicks,r=k.minorTickSize;if(o){switch(u){case"right":function q(w){return function(x,z,y){x=l.roundPixel(x*j+h)+e;m.moveTo(0,x);m.lineTo(w,x)}}v.iterate(o,q(d));a&&v.iterate(a,q(r));break;case"left":function t(w){return function(x,z,y){x=l.roundPixel(x*j+h)+e;m.moveTo(p[2]-w,x);m.lineTo(p[2],x)}}v.iterate(o,t(d));a&&v.iterate(a,t(r));break;case"bottom":function c(w){return function(x,z,y){x=l.roundPixel(x*f+i)-e;m.moveTo(x,0);m.lineTo(x,w)}}v.iterate(o,c(d));a&&v.iterate(a,c(r));break;case"top":function b(w){return function(x,z,y){x=l.roundPixel(x*f+i)-e;m.moveTo(x,p[3]);m.lineTo(x,p[3]-w)}}v.iterate(o,b(d));a&&v.iterate(a,b(r));break;case"angular":v.iterate(o,function(w,y,x){w=w/(k.max+1)*Math.PI*2+k.baseRotation;m.moveTo(k.centerX+(k.length)*Math.cos(w),k.centerY+(k.length)*Math.sin(w));m.lineTo(k.centerX+(k.length+d)*Math.cos(w),k.centerY+(k.length+d)*Math.sin(w))});break;case"gauge":var g=v.getGaugeAngles();v.iterate(o,function(w,y,x){w=(w-k.min)/(k.max-k.min+1)*k.totalAngle-k.totalAngle+g.start;m.moveTo(k.centerX+(k.length)*Math.cos(w),k.centerY+(k.length)*Math.sin(w));m.lineTo(k.centerX+(k.length+d)*Math.cos(w),k.centerY+(k.length+d)*Math.sin(w))});break}}},renderLabels:function(E,q,D,K){var o=this,k=o.attr,i=0.5*k.lineWidth,u=k.position,y=k.matrix,A=k.textPadding,x=y.getXX(),d=y.getDX(),g=y.getYY(),c=y.getDY(),n=0,I=D.majorTicks,G=Math.max(k.majorTickSize,k.minorTickSize)+k.lineWidth,f=Ext.draw.Draw.isBBoxIntersect,F=o.getLabel(),J,s,r=null,w=0,b=0,m=D.segmenter,B=o.getRenderer(),t=o.getAxis(),z=t.getTitle(),a=z&&z.attr.text!==""&&z.getBBox(),l,h=null,p,C,v,e,H;if(I&&F&&!F.attr.hidden){J=F.attr.font;if(q.font!==J){q.font=J}F.setAttributes({translationX:0,translationY:0},true);F.applyTransformations();l=F.attr.inverseMatrix.elements.slice(0);switch(u){case"left":e=a?a.x+a.width:0;switch(F.attr.textAlign){case"start":H=E.roundPixel(e+d)-i;break;case"end":H=E.roundPixel(K[2]-G+d)-i;break;default:H=E.roundPixel(e+(K[2]-e-G)/2+d)-i}F.setAttributes({translationX:H},true);break;case"right":e=a?K[2]-a.x:0;switch(F.attr.textAlign){case"start":H=E.roundPixel(G+d)+i;break;case"end":H=E.roundPixel(K[2]-e+d)+i;break;default:H=E.roundPixel(G+(K[2]-G-e)/2+d)+i}F.setAttributes({translationX:H},true);break;case"top":e=a?a.y+a.height:0;F.setAttributes({translationY:E.roundPixel(e+(K[3]-e-G)/2)-i},true);break;case"bottom":e=a?K[3]-a.y:0;F.setAttributes({translationY:E.roundPixel(G+(K[3]-G-e)/2)+i},true);break;case"radial":F.setAttributes({translationX:k.centerX},true);break;case"angular":F.setAttributes({translationY:k.centerY},true);break;case"gauge":F.setAttributes({translationY:k.centerY},true);break}if(u==="left"||u==="right"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;F.setAttributes({text:String(v),translationY:E.roundPixel(L*g+c)},true);F.applyTransformations();n=Math.max(n,F.getBBox().width+G);if(n<=o.thickness){C=Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));p=C.prepend.apply(C,l).transformBBox(F.getBBox(true));if(h&&!f(p,h,A)){return}E.renderSprite(F);h=p;w+=p.height;b++}})}else{if(u==="top"||u==="bottom"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;F.setAttributes({text:String(v),translationX:E.roundPixel(L*x+d)},true);F.applyTransformations();n=Math.max(n,F.getBBox().height+G);if(n<=o.thickness){C=Ext.draw.Matrix.fly(F.attr.matrix.elements.slice(0));p=C.prepend.apply(C,l).transformBBox(F.getBBox(true));if(h&&!f(p,h,A)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="radial"){o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;if(typeof v!=="undefined"){F.setAttributes({text:String(v),translationX:k.centerX-E.roundPixel(L)/k.max*k.length*Math.cos(k.baseRotation+Math.PI/2),translationY:k.centerY-E.roundPixel(L)/k.max*k.length*Math.sin(k.baseRotation+Math.PI/2)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="angular"){s=k.majorTickSize+k.lineWidth*0.5+(parseInt(F.attr.fontSize,10)||10)/2;o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;n=Math.max(n,Math.max(k.majorTickSize,k.minorTickSize)+(k.lineCap!=="butt"?k.lineWidth*0.5:0));if(typeof v!=="undefined"){var O=L/(k.max+1)*Math.PI*2+k.baseRotation;F.setAttributes({text:String(v),translationX:k.centerX+(k.length+s)*Math.cos(O),translationY:k.centerY+(k.length+s)*Math.sin(O)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}else{if(u==="gauge"){var j=o.getGaugeAngles();o.iterate(I,function(L,N,M){if(N===undefined){return}if(B){v=Ext.callback(B,null,[t,N,D,r],0,t)}else{v=m.renderer(N,D,r)}r=N;if(typeof v!=="undefined"){var O=(L-k.min)/(k.max-k.min+1)*k.totalAngle-k.totalAngle+j.start;F.setAttributes({text:String(v),translationX:k.centerX+(k.length+10)*Math.cos(O),translationY:k.centerY+(k.length+10)*Math.sin(O)},true);F.applyTransformations();p=F.attr.matrix.transformBBox(F.getBBox(true));if(h&&!f(p,h)){return}E.renderSprite(F);h=p;w+=p.width;b++}})}}}}}if(k.enlargeEstStepSizeByText&&b){w/=b;w+=G;w*=2;if(k.estStepSize<w){k.estStepSize=w}}if(Math.abs(o.thickness-(n))>1){o.thickness=n;k.bbox.plain.dirty=true;k.bbox.transform.dirty=true;o.doThicknessChanged();return false}}},renderAxisLine:function(a,i,e,c){var h=this,g=h.attr,b=g.lineWidth*0.5,j=g.position,d,f;if(g.axisLine&&g.length){switch(j){case"left":d=a.roundPixel(c[2])-b;i.moveTo(d,-g.endGap);i.lineTo(d,g.length+g.startGap+1);break;case"right":i.moveTo(b,-g.endGap);i.lineTo(b,g.length+g.startGap+1);break;case"bottom":i.moveTo(-g.startGap,b);i.lineTo(g.length+g.endGap,b);break;case"top":d=a.roundPixel(c[3])-b;i.moveTo(-g.startGap,d);i.lineTo(g.length+g.endGap,d);break;case"angular":i.moveTo(g.centerX+g.length,g.centerY);i.arc(g.centerX,g.centerY,g.length,0,Math.PI*2,true);break;case"gauge":f=h.getGaugeAngles();i.moveTo(g.centerX+Math.cos(f.start)*g.length,g.centerY+Math.sin(f.start)*g.length);i.arc(g.centerX,g.centerY,g.length,f.start,f.end,true);break}}},getGaugeAngles:function(){var a=this,c=a.attr.totalAngle,b;if(c<=Math.PI){b=(Math.PI-c)*0.5}else{b=-(Math.PI*2-c)*0.5}b=Math.PI*2-b;return{start:b,end:b-c}},renderGridLines:function(m,n,s,r){var t=this,b=t.getAxis(),l=t.attr,p=l.matrix,d=l.startGap,a=l.endGap,c=p.getXX(),k=p.getYY(),h=p.getDX(),g=p.getDY(),u=l.position,f=b.getGridAlignment(),q=s.majorTicks,e,o,i;if(l.grid){if(q){if(u==="left"||u==="right"){i=l.min*k+g+a+d;t.iterate(q,function(j,w,v){e=j*k+g+a;t.putMarker(f+"-"+(v%2?"odd":"even"),{y:e,height:i-e},o=v,true);i=e});o++;e=0;t.putMarker(f+"-"+(o%2?"odd":"even"),{y:e,height:i-e},o,true)}else{if(u==="top"||u==="bottom"){i=l.min*c+h+d;if(d){t.putMarker(f+"-even",{x:0,width:i},-1,true)}t.iterate(q,function(j,w,v){e=j*c+h+d;t.putMarker(f+"-"+(v%2?"odd":"even"),{x:e,width:i-e},o=v,true);i=e});o++;e=l.length+l.startGap+l.endGap;t.putMarker(f+"-"+(o%2?"odd":"even"),{x:e,width:i-e},o,true)}else{if(u==="radial"){t.iterate(q,function(j,w,v){if(!j){return}e=j/l.max*l.length;t.putMarker(f+"-"+(v%2?"odd":"even"),{scalingX:e,scalingY:e},v,true);i=e})}else{if(u==="angular"){t.iterate(q,function(j,w,v){if(!l.length){return}e=j/(l.max+1)*Math.PI*2+l.baseRotation;t.putMarker(f+"-"+(v%2?"odd":"even"),{rotationRads:e,rotationCenterX:0,rotationCenterY:0,scalingX:l.length,scalingY:l.length},v,true);i=e})}}}}}}},renderLimits:function(o){var t=this,a=t.getAxis(),h=a.getChart(),p=h.getInnerPadding(),d=Ext.Array.from(a.getLimits());if(!d.length){return}var r=a.limits.surface.getRect(),m=t.attr,n=m.matrix,u=m.position,k=Ext.Object.chain,v=a.limits.titles,c,j,b,s,l,q,f,g,e;v.instances=[];v.position=0;if(u==="left"||u==="right"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l*n.getYY()+n.getDY();s.line.y=l+p.top;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("horizontal-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);j=s.line.title.position||(u==="left"?"start":"end");switch(j){case"start":g=10;break;case"end":g=r[2]-10;break;case"middle":g=r[2]/2;break}v.setAttributesFor(v.position-1,{x:g,y:s.line.y-c.height/2,textAlign:j,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="top"||u==="bottom"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l*n.getXX()+n.getDX();s.line.x=l+p.left;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("vertical-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);j=s.line.title.position||(u==="top"?"end":"start");switch(j){case"start":e=r[3]-c.width/2-10;break;case"end":e=c.width/2+10;break;case"middle":e=r[3]/2;break}v.setAttributesFor(v.position-1,{x:s.line.x+c.height/2,y:e,fillStyle:s.line.title.fillStyle||s.line.strokeStyle,rotationRads:Math.PI/2})}}}else{if(u==="radial"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;if(l>m.max){continue}l=l/m.max*m.length;s.line.cx=m.centerX;s.line.cy=m.centerY;s.line.scalingX=l;s.line.scalingY=l;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("circular-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);v.setAttributesFor(v.position-1,{x:m.centerX,y:m.centerY-l-c.height/2,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="angular"){for(q=0,f=d.length;q<f;q++){s=k(d[q]);!s.line&&(s.line={});l=Ext.isString(s.value)?a.getCoordFor(s.value):s.value;l=l/(m.max+1)*Math.PI*2+m.baseRotation;s.line.translationX=m.centerX;s.line.translationY=m.centerY;s.line.rotationRads=l;s.line.rotationCenterX=0;s.line.rotationCenterY=0;s.line.scalingX=m.length;s.line.scalingY=m.length;s.line.strokeStyle=s.line.strokeStyle||m.strokeStyle;t.putMarker("radial-limit-lines",s.line,q,true);if(s.line.title){v.createInstance(s.line.title);c=v.getBBoxFor(v.position-1);b=((l>-0.5*Math.PI&&l<0.5*Math.PI)||(l>1.5*Math.PI&&l<2*Math.PI))?1:-1;v.setAttributesFor(v.position-1,{x:m.centerX+0.5*m.length*Math.cos(l)+b*c.height/2*Math.sin(l),y:m.centerY+0.5*m.length*Math.sin(l)-b*c.height/2*Math.cos(l),rotationRads:b===1?l:l-Math.PI,fillStyle:s.line.title.fillStyle||s.line.strokeStyle})}}}else{if(u==="gauge"){}}}}}},doThicknessChanged:function(){var a=this.getAxis();if(a){a.onThicknessChanged()}},render:function(a,c,d){var e=this,b=e.getLayoutContext();if(b){if(false===e.renderLabels(a,c,b,d)){return false}c.beginPath();e.renderTicks(a,c,b,d);e.renderAxisLine(a,c,b,d);e.renderGridLines(a,c,b,d);e.renderLimits(d);c.stroke()}}});Ext.define("Ext.chart.axis.segmenter.Segmenter",{config:{axis:null},constructor:function(a){this.initConfig(a)},renderer:function(b,a){return String(b)},from:function(a){return a},diff:Ext.emptyFn,align:Ext.emptyFn,add:Ext.emptyFn,preferredStep:Ext.emptyFn});Ext.define("Ext.chart.axis.segmenter.Names",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.names",renderer:function(b,a){return b},diff:function(b,a,c){return Math.floor(a-b)},align:function(c,b,a){return Math.floor(c)},add:function(c,b,a){return c+b},preferredStep:function(c,a,b,d){return{unit:1,step:1}}});Ext.define("Ext.chart.axis.segmenter.Numeric",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.numeric",isNumeric:true,renderer:function(b,a){return b.toFixed(Math.max(0,a.majorTicks.unit.fixes))},diff:function(b,a,c){return Math.floor((a-b)/c.scale)},align:function(c,b,a){return Math.floor(c/(a.scale*b))*a.scale*b},add:function(c,b,a){return c+b*a.scale},preferredStep:function(c,b){var a=Math.floor(Math.log(b)*Math.LOG10E),d=Math.pow(10,a);b/=d;if(b<2){b=2}else{if(b<5){b=5}else{if(b<10){b=10;a++}}}return{unit:{fixes:-a,scale:d},step:b}},exactStep:function(c,b){var a=Math.floor(Math.log(b)*Math.LOG10E),d=Math.pow(10,a);return{unit:{fixes:-a+(b%d===0?0:1),scale:1},step:b}},adjustByMajorUnit:function(e,g,c){var d=c[0],b=c[1],a=e*g,f=d%a;if(f!==0){c[0]=d-f+(d<0?-a:0)}f=b%a;if(f!==0){c[1]=b-f+(b>0?a:0)}}});Ext.define("Ext.chart.axis.segmenter.Time",{extend:"Ext.chart.axis.segmenter.Segmenter",alias:"segmenter.time",config:{step:null},renderer:function(c,b){var a=Ext.Date;switch(b.majorTicks.unit){case"y":return a.format(c,"Y");case"mo":return a.format(c,"Y-m");case"d":return a.format(c,"Y-m-d")}return a.format(c,"Y-m-d\nH:i:s")},from:function(a){return new Date(a)},diff:function(b,a,c){if(isFinite(b)){b=new Date(b)}if(isFinite(a)){a=new Date(a)}return Ext.Date.diff(b,a,c)},align:function(a,c,b){if(b==="d"&&c>=7){a=Ext.Date.align(a,"d",c);a.setDate(a.getDate()-a.getDay()+1);return a}else{return Ext.Date.align(a,b,c)}},add:function(c,b,a){return Ext.Date.add(new Date(c),a,b)},stepUnits:[[Ext.Date.YEAR,1,2,5,10,20,50,100,200,500],[Ext.Date.MONTH,1,3,6],[Ext.Date.DAY,1,7,14],[Ext.Date.HOUR,1,6,12],[Ext.Date.MINUTE,1,5,15,30],[Ext.Date.SECOND,1,5,15,30],[Ext.Date.MILLI,1,2,5,10,20,50,100,200,500]],preferredStep:function(b,e){if(this.getStep()){return this.getStep()}var f=new Date(+b),g=new Date(+b+Math.ceil(e)),d=this.stepUnits,l,k,h,c,a;for(c=0;c<d.length;c++){k=d[c][0];h=this.diff(f,g,k);if(h>0){for(a=1;a<d[c].length;a++){if(h<=d[c][a]){l={unit:k,step:d[c][a]};break}}if(!l){c--;l={unit:d[c][0],step:1}}break}}if(!l){l={unit:Ext.Date.DAY,step:1}}return l}});Ext.define("Ext.chart.axis.layout.Layout",{mixins:{observable:"Ext.mixin.Observable"},config:{axis:null},constructor:function(a){this.mixins.observable.constructor.call(this,a)},processData:function(b){var e=this,c=e.getAxis(),f=c.getDirection(),g=c.boundSeries,a,d;if(b){b["coordinate"+f]()}else{for(a=0,d=g.length;a<d;a++){g[a]["coordinate"+f]()}}},calculateMajorTicks:function(a){var f=this,e=a.attr,d=e.max-e.min,i=d/Math.max(1,e.length)*(e.visibleMax-e.visibleMin),h=e.min+d*e.visibleMin,b=e.min+d*e.visibleMax,g=e.estStepSize*i,c=f.snapEnds(a,e.min,e.max,g);if(c){f.trimByRange(a,c,h,b);a.majorTicks=c}},calculateMinorTicks:function(a){if(this.snapMinorEnds){a.minorTicks=this.snapMinorEnds(a)}},calculateLayout:function(b){var c=this,a=b.attr;if(a.length===0){return null}if(a.majorTicks){c.calculateMajorTicks(b);if(a.minorTicks){c.calculateMinorTicks(b)}}},snapEnds:Ext.emptyFn,trimByRange:function(b,f,i,a){var g=b.segmenter,j=f.unit,h=g.diff(f.from,i,j),d=g.diff(f.from,a,j),c=Math.max(0,Math.ceil(h/f.step)),e=Math.min(f.steps,Math.floor(d/f.step));if(e<f.steps){f.to=g.add(f.from,e*f.step,j)}if(f.max>a){f.max=f.to}if(f.from<i){f.from=g.add(f.from,c*f.step,j);while(f.from<i){c++;f.from=g.add(f.from,f.step,j)}}if(f.min<i){f.min=f.from}f.steps=e-c}});Ext.define("Ext.chart.axis.layout.Discrete",{extend:"Ext.chart.axis.layout.Layout",alias:"axisLayout.discrete",isDiscrete:true,processData:function(){var f=this,d=f.getAxis(),c=d.boundSeries,g=d.getDirection(),b,e,a;f.labels=[];f.labelMap={};for(b=0,e=c.length;b<e;b++){a=c[b];if(a["get"+g+"Axis"]()===d){a["coordinate"+g]()}}d.getSprites()[0].setAttributes({data:f.labels});f.fireEvent("datachange",f.labels)},calculateLayout:function(a){a.data=this.labels;this.callParent([a])},calculateMajorTicks:function(a){var g=this,f=a.attr,d=a.data,e=f.max-f.min,j=e/Math.max(1,f.length)*(f.visibleMax-f.visibleMin),i=f.min+e*f.visibleMin,b=f.min+e*f.visibleMax,h=f.estStepSize*j;var c=g.snapEnds(a,Math.max(0,f.min),Math.min(f.max,d.length-1),h);if(c){g.trimByRange(a,c,i,b);a.majorTicks=c}},snapEnds:function(e,d,a,b){b=Math.ceil(b);var c=Math.floor((a-d)/b),f=e.data;return{min:d,max:a,from:d,to:c*b+d,step:b,steps:c,unit:1,getLabel:function(g){return f[this.from+this.step*g]},get:function(g){return this.from+this.step*g}}},trimByRange:function(b,f,h,a){var i=f.unit,g=Math.ceil((h-f.from)/i)*i,d=Math.floor((a-f.from)/i)*i,c=Math.max(0,Math.ceil(g/f.step)),e=Math.min(f.steps,Math.floor(d/f.step));if(e<f.steps){f.to=e}if(f.max>a){f.max=f.to}if(f.from<h&&f.step>0){f.from=f.from+c*f.step*i;while(f.from<h){c++;f.from+=f.step*i}}if(f.min<h){f.min=f.from}f.steps=e-c},getCoordFor:function(c,d,a,b){this.labels.push(c);return this.labels.length-1}});Ext.define("Ext.chart.axis.layout.CombineDuplicate",{extend:"Ext.chart.axis.layout.Discrete",alias:"axisLayout.combineDuplicate",getCoordFor:function(d,e,b,c){if(!(d in this.labelMap)){var a=this.labelMap[d]=this.labels.length;this.labels.push(d);return a}return this.labelMap[d]}});Ext.define("Ext.chart.axis.layout.Continuous",{extend:"Ext.chart.axis.layout.Layout",alias:"axisLayout.continuous",isContinuous:true,config:{adjustMinimumByMajorUnit:false,adjustMaximumByMajorUnit:false},getCoordFor:function(c,d,a,b){return +c},snapEnds:function(a,d,i,h){var f=a.segmenter,c=this.getAxis(),l=c.getMajorTickSteps(),e=l&&f.exactStep?f.exactStep(d,(i-d)/l):f.preferredStep(d,h),k=e.unit,b=e.step,j=f.align(d,b,k),g=(l||f.diff(d,i,k))+1;return{min:f.from(d),max:f.from(i),from:j,to:f.add(j,g*b,k),step:b,steps:g,unit:k,get:function(m){return f.add(this.from,this.step*m,k)}}},snapMinorEnds:function(a){var e=a.majorTicks,m=this.getAxis().getMinorTickSteps(),f=a.segmenter,d=e.min,i=e.max,k=e.from,l=e.unit,b=e.step/m,n=b*l.scale,j=k-d,c=Math.floor(j/n),h=c+Math.floor((i-e.to)/n)+1,g=e.steps*m+h;return{min:d,max:i,from:d+j%n,to:f.add(k,g*b,l),step:b,steps:g,unit:l,get:function(o){return(o%m+c+1!==0)?f.add(this.from,this.step*o,l):null}}}});Ext.define("Ext.chart.axis.Axis",{xtype:"axis",mixins:{observable:"Ext.mixin.Observable"},requires:["Ext.chart.axis.sprite.Axis","Ext.chart.axis.segmenter.*","Ext.chart.axis.layout.*"],isAxis:true,config:{position:"bottom",fields:[],label:undefined,grid:false,limits:null,renderer:null,chart:null,style:null,margin:0,titleMargin:4,background:null,minimum:NaN,maximum:NaN,reconcileRange:false,minZoom:1,maxZoom:10000,layout:"continuous",segmenter:"numeric",hidden:false,majorTickSteps:0,minorTickSteps:0,adjustByMajorUnit:true,title:null,increment:0.5,length:0,center:null,radius:null,totalAngle:Math.PI,rotation:null,labelInSpan:null,visibleRange:[0,1],needHighPrecision:false,linkedTo:null,floating:null},titleOffset:0,spriteAnimationCount:0,prevMin:0,prevMax:1,boundSeries:[],sprites:null,surface:null,range:null,xValues:[],yValues:[],masterAxis:null,applyRotation:function(b){var a=Math.PI*2;return(b%a+Math.PI)%a-Math.PI},updateRotation:function(b){var c=this.getSprites(),a=this.getPosition();if(!this.getHidden()&&a==="angular"&&c[0]){c[0].setAttributes({baseRotation:b})}},applyTitle:function(c,b){var a;if(Ext.isString(c)){c={text:c}}if(!b){b=Ext.create("sprite.text",c);if((a=this.getSurface())){a.add(b)}}else{b.setAttributes(c)}return b},applyFloating:function(b,a){if(b===null){b={value:null,alongAxis:null}}else{if(Ext.isNumber(b)){b={value:b,alongAxis:null}}}if(Ext.isObject(b)){if(a&&a.alongAxis){delete this.getChart().getAxis(a.alongAxis).floatingAxes[this.getId()]}return b}return a},constructor:function(a){var b=this,c;b.sprites=[];b.labels=[];b.floatingAxes={};a=a||{};if(a.position==="angular"){a.style=a.style||{};a.style.estStepSize=1}if("id" in a){c=a.id}else{if("id" in b.config){c=b.config.id}else{c=b.getId()}}b.setId(c);b.mixins.observable.constructor.apply(b,arguments)},getAlignment:function(){switch(this.getPosition()){case"left":case"right":return"vertical";case"top":case"bottom":return"horizontal";case"radial":return"radial";case"angular":return"angular"}},getGridAlignment:function(){switch(this.getPosition()){case"left":case"right":return"horizontal";case"top":case"bottom":return"vertical";case"radial":return"circular";case"angular":return"radial"}},getSurface:function(){var e=this,d=e.getChart();if(d&&!e.surface){var b=e.surface=d.getSurface(e.getId(),"axis"),c=e.gridSurface=d.getSurface("main"),a=e.getSprites()[0],f=e.getGridAlignment();c.waitFor(b);e.getGrid();if(e.getLimits()&&f){f=f.replace("3d","");e.limits={surface:d.getSurface("overlay"),lines:new Ext.chart.Markers(),titles:new Ext.draw.sprite.Instancing()};e.limits.lines.setTemplate({xclass:"grid."+f});e.limits.lines.getTemplate().setAttributes({strokeStyle:"black"},true);e.limits.surface.add(e.limits.lines);a.bindMarker(f+"-limit-lines",e.limits.lines);e.limitTitleTpl=new Ext.draw.sprite.Text();e.limits.titles.setTemplate(e.limitTitleTpl);e.limits.surface.add(e.limits.titles);d.on("redraw",e.renderLimits,e)}}return e.surface},applyGrid:function(a){if(a===true){return{}}return a},updateGrid:function(b){var e=this,d=e.getChart();if(!d){e.on({chartattached:Ext.bind(e.updateGrid,e,[b]),single:true});return}var c=e.gridSurface,a=e.getSprites()[0],f=e.getGridAlignment(),g;if(b){g=e.gridSpriteEven;if(!g){g=e.gridSpriteEven=new Ext.chart.Markers();g.setTemplate({xclass:"grid."+f});c.add(g);a.bindMarker(f+"-even",g)}if(Ext.isObject(b)){g.getTemplate().setAttributes(b);if(Ext.isObject(b.even)){g.getTemplate().setAttributes(b.even)}}g=e.gridSpriteOdd;if(!g){g=e.gridSpriteOdd=new Ext.chart.Markers();g.setTemplate({xclass:"grid."+f});c.add(g);a.bindMarker(f+"-odd",g)}if(Ext.isObject(b)){g.getTemplate().setAttributes(b);if(Ext.isObject(b.odd)){g.getTemplate().setAttributes(b.odd)}}}},renderLimits:function(){this.getSprites()[0].renderLimits()},getCoordFor:function(c,d,a,b){return this.getLayout().getCoordFor(c,d,a,b)},applyPosition:function(a){return a.toLowerCase()},applyLength:function(b,a){return b>0?b:a},applyLabel:function(b,a){if(!a){a=new Ext.draw.sprite.Text({})}if(this.limitTitleTpl){this.limitTitleTpl.setAttributes(b)}a.setAttributes(b);return a},applyLayout:function(b,a){b=Ext.factory(b,null,a,"axisLayout");b.setAxis(this);return b},applySegmenter:function(a,b){a=Ext.factory(a,null,b,"segmenter");a.setAxis(this);return a},updateMinimum:function(){this.range=null},updateMaximum:function(){this.range=null},hideLabels:function(){this.getSprites()[0].setDirty(true);this.setLabel({hidden:true})},showLabels:function(){this.getSprites()[0].setDirty(true);this.setLabel({hidden:false})},renderFrame:function(){this.getSurface().renderFrame()},updateChart:function(d,b){var c=this,a;if(b){b.unregister(c);b.un("serieschange",c.onSeriesChange,c);b.un("redraw",c.renderLimits,c);c.linkAxis();c.fireEvent("chartdetached",b,c)}if(d){d.on("serieschange",c.onSeriesChange,c);c.surface=null;a=c.getSurface();c.getLabel().setSurface(a);a.add(c.getSprites());a.add(c.getTitle());d.register(c);c.fireEvent("chartattached",d,c)}},applyBackground:function(a){var b=Ext.ClassManager.getByAlias("sprite.rect");return b.def.normalize(a)},processData:function(){this.getLayout().processData();this.range=null},getDirection:function(){return this.getChart().getDirectionForAxis(this.getPosition())},isSide:function(){var a=this.getPosition();return a==="left"||a==="right"},applyFields:function(a){return Ext.Array.from(a)},applyVisibleRange:function(a,c){this.getChart();if(a[0]>a[1]){var b=a[0];a[0]=a[1];a[0]=b}if(a[1]===a[0]){a[1]+=1/this.getMaxZoom()}if(a[1]>a[0]+1){a[0]=0;a[1]=1}else{if(a[0]<0){a[1]-=a[0];a[0]=0}else{if(a[1]>1){a[0]-=a[1]-1;a[1]=1}}}if(c&&a[0]===c[0]&&a[1]===c[1]){return undefined}return a},updateVisibleRange:function(a){this.fireEvent("visiblerangechange",this,a)},onSeriesChange:function(e){var f=this,b=e.getSeries(),j="get"+f.getDirection()+"Axis",g=[],c,d=b.length,a,h;for(c=0;c<d;c++){if(this===b[c][j]()){g.push(b[c])}}f.boundSeries=g;a=f.getLinkedTo();h=!Ext.isEmpty(a)&&e.getAxis(a);if(h){f.linkAxis(h)}else{f.getLayout().processData()}},linkAxis:function(a){var c=this;function b(f,d,e){e.getLayout()[f]("datachange","onDataChange",d);e[f]("rangechange","onMasterAxisRangeChange",d)}if(c.masterAxis){b("un",c,c.masterAxis);c.masterAxis=null}if(a){if(a.type!==this.type){Ext.Error.raise("Linked axes must be of the same type.")}b("on",c,a);c.onDataChange(a.getLayout().labels);c.onMasterAxisRangeChange(a,a.range);c.setStyle(Ext.apply({},c.config.style,a.config.style));c.setTitle(Ext.apply({},c.config.title,a.config.title));c.setLabel(Ext.apply({},c.config.label,a.config.label));c.masterAxis=a}},onDataChange:function(a){this.getLayout().labels=a},onMasterAxisRangeChange:function(b,a){this.range=a},applyRange:function(a){if(!a){return this.dataRange.slice(0)}else{return[a[0]===null?this.dataRange[0]:a[0],a[1]===null?this.dataRange[1]:a[1]]}},getRange:function(){var m=this;if(m.range){return m.range}else{if(m.masterAxis){return m.masterAxis.range}}if(Ext.isNumber(m.getMinimum()+m.getMaximum())){return m.range=[m.getMinimum(),m.getMaximum()]}var d=Infinity,n=-Infinity,o=m.boundSeries,h=m.getLayout(),l=m.getSegmenter(),p=m.getVisibleRange(),b="get"+m.getDirection()+"Range",a,j,g,f,e,k;for(e=0,k=o.length;e<k;e++){f=o[e];var c=f[b]();if(c){if(c[0]<d){d=c[0]}if(c[1]>n){n=c[1]}}}if(!isFinite(n)){n=m.prevMax}if(!isFinite(d)){d=m.prevMin}if(m.getLabelInSpan()||d===n){n+=m.getIncrement();d-=m.getIncrement()}if(Ext.isNumber(m.getMinimum())){d=m.getMinimum()}else{m.prevMin=d}if(Ext.isNumber(m.getMaximum())){n=m.getMaximum()}else{m.prevMax=n}m.range=[Ext.Number.correctFloat(d),Ext.Number.correctFloat(n)];if(m.getReconcileRange()){m.reconcileRange()}if(m.getAdjustByMajorUnit()&&l.adjustByMajorUnit&&!m.getMajorTickSteps()){j=Ext.Object.chain(m.getSprites()[0].attr);j.min=m.range[0];j.max=m.range[1];j.visibleMin=p[0];j.visibleMax=p[1];a={attr:j,segmenter:l};h.calculateLayout(a);g=a.majorTicks;if(g){l.adjustByMajorUnit(g.step,g.unit.scale,m.range);j.min=m.range[0];j.max=m.range[1];delete a.majorTicks;h.calculateLayout(a);g=a.majorTicks;l.adjustByMajorUnit(g.step,g.unit.scale,m.range)}else{if(!m.hasClearRangePending){m.hasClearRangePending=true;m.getChart().on("layout","clearRange",m)}}}if(!Ext.Array.equals(m.range,m.oldRange||[])){m.fireEvent("rangechange",m,m.range);m.oldRange=m.range}return m.range},clearRange:function(){delete this.hasClearRangePending;this.range=null},reconcileRange:function(){var e=this,g=e.getChart().getAxes(),f=e.getDirection(),b,d,c,a;if(!g){return}for(b=0,d=g.length;b<d;b++){c=g[b];a=c.getRange();if(c===e||c.getDirection()!==f||!a||!c.getReconcileRange()){continue}if(a[0]<e.range[0]){e.range[0]=a[0]}if(a[1]>e.range[1]){e.range[1]=a[1]}}},applyStyle:function(c,b){var a=Ext.ClassManager.getByAlias("sprite."+this.seriesType);if(a&&a.def){c=a.def.normalize(c)}b=Ext.apply(b||{},c);return b},themeOnlyIfConfigured:{grid:true},updateTheme:function(d){var i=this,k=d.getAxis(),e=i.getPosition(),o=i.getInitialConfig(),c=i.defaultConfig,g=i.getConfigurator().configs,a=k.defaults,n=k[e],h=i.themeOnlyIfConfigured,l,j,p,b,m,f;k=Ext.merge({},a,n);for(l in k){j=k[l];f=g[l];if(j!==null&&j!==undefined&&f){m=o[l];p=Ext.isObject(j);b=m===c[l];if(p){if(b&&h[l]){continue}j=Ext.merge({},j,m)}if(b||p){i[f.names.set](j)}}}},updateCenter:function(b){var e=this.getSprites(),a=e[0],d=b[0],c=b[1];if(a){a.setAttributes({centerX:d,centerY:c})}if(this.gridSpriteEven){this.gridSpriteEven.getTemplate().setAttributes({translationX:d,translationY:c,rotationCenterX:d,rotationCenterY:c})}if(this.gridSpriteOdd){this.gridSpriteOdd.getTemplate().setAttributes({translationX:d,translationY:c,rotationCenterX:d,rotationCenterY:c})}},getSprites:function(){if(!this.getChart()){return}var i=this,e=i.getRange(),f=i.getPosition(),g=i.getChart(),c=g.getAnimation(),d,a,b=i.getLength(),h=i.superclass;if(c===false){c={duration:0}}if(e){a=Ext.applyIf({position:f,axis:i,min:e[0],max:e[1],length:b,grid:i.getGrid(),hidden:i.getHidden(),titleOffset:i.titleOffset,layout:i.getLayout(),segmenter:i.getSegmenter(),totalAngle:i.getTotalAngle(),label:i.getLabel()},i.getStyle());if(!i.sprites.length){while(!h.xtype){h=h.superclass}d=Ext.create("sprite."+h.xtype,a);d.fx.setCustomDurations({baseRotation:0});d.fx.on("animationstart","onAnimationStart",i);d.fx.on("animationend","onAnimationEnd",i);d.setLayout(i.getLayout());d.setSegmenter(i.getSegmenter());d.setLabel(i.getLabel());i.sprites.push(d);i.updateTitleSprite()}else{d=i.sprites[0];d.setAnimation(c);d.setAttributes(a)}if(i.getRenderer()){d.setRenderer(i.getRenderer())}}return i.sprites},updateTitleSprite:function(){var f=this,b=f.getLength();if(!f.sprites[0]||!Ext.isNumber(b)){return}var h=this.sprites[0].thickness,a=f.getSurface(),g=f.getTitle(),e=f.getPosition(),c=f.getMargin(),i=f.getTitleMargin(),d=a.roundPixel(b/2);if(g){switch(e){case"top":g.setAttributes({x:d,y:c+i/2,textBaseline:"top",textAlign:"center"},true);g.applyTransformations();f.titleOffset=g.getBBox().height+i;break;case"bottom":g.setAttributes({x:d,y:h+i/2,textBaseline:"top",textAlign:"center"},true);g.applyTransformations();f.titleOffset=g.getBBox().height+i;break;case"left":g.setAttributes({x:c+i/2,y:d,textBaseline:"top",textAlign:"center",rotationCenterX:c+i/2,rotationCenterY:d,rotationRads:-Math.PI/2},true);g.applyTransformations();f.titleOffset=g.getBBox().width+i;break;case"right":g.setAttributes({x:h-c+i/2,y:d,textBaseline:"bottom",textAlign:"center",rotationCenterX:h+i/2,rotationCenterY:d,rotationRads:Math.PI/2},true);g.applyTransformations();f.titleOffset=g.getBBox().width+i;break}}},onThicknessChanged:function(){this.getChart().onThicknessChanged()},getThickness:function(){if(this.getHidden()){return 0}return(this.sprites[0]&&this.sprites[0].thickness||1)+this.titleOffset+this.getMargin()},onAnimationStart:function(){this.spriteAnimationCount++;if(this.spriteAnimationCount===1){this.fireEvent("animationstart",this)}},onAnimationEnd:function(){this.spriteAnimationCount--;if(this.spriteAnimationCount===0){this.fireEvent("animationend",this)}},getItemId:function(){return this.getId()},getAncestorIds:function(){return[this.getChart().getId()]},isXType:function(a){return a==="axis"},resolveListenerScope:function(e){var d=this,a=Ext._namedScopes[e],c=d.getChart(),b;if(!a){b=c?c.resolveListenerScope(e,false):(e||d)}else{if(a.isThis){b=d}else{if(a.isController){b=c?c.resolveListenerScope(e,false):d}else{if(a.isSelf){b=c?c.resolveListenerScope(e,false):d;if(b===c&&!c.getInheritedConfig("defaultListenerScope")){b=d}}}}}return b},destroy:function(){var a=this;a.setChart(null);a.surface.destroy();a.surface=null;a.callParent()}});Ext.define("Ext.chart.LegendBase",{extend:"Ext.view.View",config:{tpl:['<div class="',Ext.baseCSSPrefix,'legend-container">','<tpl for=".">','<div class="',Ext.baseCSSPrefix,'legend-item">',"<span ",'class="',Ext.baseCSSPrefix,"legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + 'legend-inactive' : '' ]}\" ",'style="background:{mark};">',"</span>{name}","</div>","</tpl>","</div>"],nodeContainerSelector:"div."+Ext.baseCSSPrefix+"legend-container",itemSelector:"div."+Ext.baseCSSPrefix+"legend-item",docked:"bottom"},setDocked:function(d){var c=this,a=c.ownerCt,b;c.docked=d;switch(d){case"top":case"bottom":c.addCls(Ext.baseCSSPrefix+"horizontal");b="hbox";break;case"left":case"right":c.removeCls(Ext.baseCSSPrefix+"horizontal");b="vbox";break}if(a){a.setDocked(d)}},setStore:function(a){this.bindStore(a)},clearViewEl:function(){this.callParent(arguments);Ext.removeNode(this.getNodeContainer())},onItemClick:function(a,c,b,d){this.callParent(arguments);this.toggleItem(b)}});Ext.define("Ext.chart.Legend",{xtype:"legend",extend:"Ext.chart.LegendBase",config:{baseCls:Ext.baseCSSPrefix+"legend",padding:5,rect:null,disableSelection:true,toggleable:true},toggleItem:function(c){if(!this.getToggleable()){return}var b=this.getStore(),h=0,e,g=true,d,f,a;if(b){f=b.getCount();for(d=0;d<f;d++){a=b.getAt(d);if(a.get("disabled")){h++}}g=f-h>1;a=b.getAt(c);if(a){e=a.get("disabled");if(e||g){a.set("disabled",!e)}}}}});Ext.define("Ext.chart.AbstractChart",{extend:"Ext.draw.Container",requires:["Ext.chart.theme.Default","Ext.chart.series.Series","Ext.chart.interactions.Abstract","Ext.chart.axis.Axis","Ext.data.StoreManager","Ext.chart.Legend","Ext.data.Store"],isChart:true,defaultBindProperty:"store",config:{store:"ext-empty-store",theme:"default",style:null,animation:!Ext.isIE8,series:[],axes:[],legend:null,colors:null,insetPadding:{top:10,left:10,right:10,bottom:10},background:null,interactions:[],mainRect:null,resizeHandler:null,highlightItem:null},animationSuspendCount:0,chartLayoutSuspendCount:0,axisThicknessSuspendCount:0,isThicknessChanged:false,surfaceZIndexes:{background:0,main:1,grid:2,series:3,axis:4,chart:5,overlay:6,events:7},constructor:function(a){var b=this;b.itemListeners={};b.surfaceMap={};b.chartComponents={};b.isInitializing=true;b.suspendChartLayout();b.animationSuspendCount++;b.callParent(arguments);delete b.isInitializing;b.getSurface("main");b.getSurface("chart").setFlipRtlText(b.getInherited().rtl);b.getSurface("overlay").waitFor(b.getSurface("series"));b.animationSuspendCount--;b.resumeChartLayout()},applyAnimation:function(a,b){if(!a){a={duration:0}}else{if(a===true){a={easing:"easeInOut",duration:500}}}return b?Ext.apply({},a,b):a},getAnimation:function(){if(this.animationSuspendCount){return{duration:0}}else{return this.callParent()}},applyInsetPadding:function(b,a){if(!Ext.isObject(b)){return Ext.util.Format.parseBox(b)}else{if(!a){return b}else{return Ext.apply(a,b)}}},suspendAnimation:function(){var d=this,c=d.getSeries(),e=c.length,b=-1,a;d.animationSuspendCount++;if(d.animationSuspendCount===1){while(++b<e){a=c[b];a.setAnimation(a.getAnimation())}}},resumeAnimation:function(){var d=this,c=d.getSeries(),f=c.length,b=-1,a,e;d.animationSuspendCount--;if(d.animationSuspendCount===0){while(++b<f){a=c[b];e=a.getAnimation();a.setAnimation(e.duration&&e||d.getAnimation())}}},suspendChartLayout:function(){this.chartLayoutSuspendCount++;if(this.chartLayoutSuspendCount===1){if(this.scheduledLayoutId){this.layoutInSuspension=true;this.cancelChartLayout()}else{this.layoutInSuspension=false}}},resumeChartLayout:function(){this.chartLayoutSuspendCount--;if(this.chartLayoutSuspendCount===0){if(this.layoutInSuspension){this.scheduleLayout()}}},cancelChartLayout:function(){if(this.scheduledLayoutId){Ext.draw.Animator.cancel(this.scheduledLayoutId);this.scheduledLayoutId=null}},scheduleLayout:function(){var a=this;if(a.allowSchedule()&&!a.scheduledLayoutId){a.scheduledLayoutId=Ext.draw.Animator.schedule("doScheduleLayout",a)}},allowSchedule:function(){return true},doScheduleLayout:function(){if(this.chartLayoutSuspendCount){this.layoutInSuspension=true}else{this.performLayout()}},suspendThicknessChanged:function(){this.axisThicknessSuspendCount++},resumeThicknessChanged:function(){if(this.axisThicknessSuspendCount>0){this.axisThicknessSuspendCount--;if(this.axisThicknessSuspendCount===0&&this.isThicknessChanged){this.onThicknessChanged()}}},onThicknessChanged:function(){if(this.axisThicknessSuspendCount===0){this.isThicknessChanged=false;this.performLayout()}else{this.isThicknessChanged=true}},applySprites:function(b){var a=this.getSurface("chart");b=Ext.Array.from(b);a.removeAll(true);a.add(b);return b},initItems:function(){var a=this.items,b,d,c;if(a&&!a.isMixedCollection){this.items=[];a=Ext.Array.from(a);for(b=0,d=a.length;b<d;b++){c=a[b];if(c.type){Ext.raise("To add custom sprites to the chart use the 'sprites' config.")}else{this.items.push(c)}}}this.callParent()},applyBackground:function(c,e){var b=this.getSurface("background"),d,a,f;if(c){if(e){d=e.attr.width;a=e.attr.height;f=e.type===(c.type||"rect")}if(c.isSprite){e=c}else{if(c.type==="image"&&Ext.isString(c.src)){if(f){e.setAttributes({src:c.src})}else{b.remove(e,true);e=b.add(c)}}else{if(f){e.setAttributes({fillStyle:c})}else{b.remove(e,true);e=b.add({type:"rect",fillStyle:c,fx:{customDurations:{x:0,y:0,width:0,height:0}}})}}}}if(d&&a){e.setAttributes({width:d,height:a})}e.setAnimation(this.getAnimation());return e},getLegendStore:function(){return this.legendStore},refreshLegendStore:function(){if(this.getLegendStore()){var d,e,c=this.getSeries(),b,a=[];if(c){for(d=0,e=c.length;d<e;d++){b=c[d];if(b.getShowInLegend()){b.provideLegendInfo(a)}}}this.getLegendStore().setData(a)}},resetLegendStore:function(){var c=this.getLegendStore(),e,d,a,b;if(c){e=this.getLegendStore().getData().items;for(d=0,a=e.length;d<a;d++){b=e[d];b.beginEdit();b.set("disabled",false);b.commit()}}},onUpdateLegendStore:function(b,a){var d=this.getSeries(),c;if(a&&d){c=d.map[a.get("series")];if(c){c.setHiddenByIndex(a.get("index"),a.get("disabled"));this.redraw()}}},defaultResizeHandler:function(a){this.scheduleLayout();return false},applyMainRect:function(a,b){if(!b){return a}this.getSeries();this.getAxes();if(a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]){return b}else{return a}},register:function(a){var b=this.chartComponents,c=a.getId();b[c]=a},unregister:function(a){var b=this.chartComponents,c=a.getId();delete b[c]},get:function(a){return this.chartComponents[a]},getAxis:function(a){if(a instanceof Ext.chart.axis.Axis){return a}else{if(Ext.isNumber(a)){return this.getAxes()[a]}else{if(Ext.isString(a)){return this.get(a)}}}},getSurface:function(b,c){b=b||"main";c=c||b;var d=this,a=this.callParent([b]),f=d.surfaceZIndexes,e=d.surfaceMap;if(c in f){a.element.setStyle("zIndex",f[c])}if(!e[c]){e[c]=[]}if(Ext.Array.indexOf(e[c],a)<0){a.type=c;e[c].push(a);a.on("destroy",d.forgetSurface,d)}return a},forgetSurface:function(a){var d=this.surfaceMap;if(!d||this.isDestroying){return}var c=d[a.type],b=c?Ext.Array.indexOf(c,a):-1;if(b>=0){c.splice(b,1)}},applyAxes:function(b,k){var l=this,g={left:"right",right:"left"},m=[],c,d,e,a,f,h,j;l.animationSuspendCount++;l.getStore();if(!k){k=[];k.map={}}j=k.map;m.map={};b=Ext.Array.from(b,true);for(f=0,h=b.length;f<h;f++){c=b[f];if(!c){continue}if(c instanceof Ext.chart.axis.Axis){d=j[c.getId()];c.setChart(l)}else{c=Ext.Object.chain(c);e=c.linkedTo;a=c.id;if(Ext.isNumber(e)){c=Ext.merge({},b[e],c)}else{if(Ext.isString(e)){Ext.Array.each(b,function(i){if(i.id===c.linkedTo){c=Ext.merge({},i,c);return false}})}}c.id=a;c.chart=l;if(l.getInherited().rtl){c.position=g[c.position]||c.position}a=c.getId&&c.getId()||c.id;c=Ext.factory(c,null,d=j[a],"axis")}if(c){m.push(c);m.map[c.getId()]=c;if(!d){c.on("animationstart","onAnimationStart",l);c.on("animationend","onAnimationEnd",l)}}}for(f in j){if(!m.map[f]){j[f].destroy()}}l.animationSuspendCount--;return m},updateAxes:function(){if(!this.isDestroying){this.scheduleLayout()}},circularCopyArray:function(e,f,d){var c=[],b,a=e&&e.length;if(a){for(b=0;b<d;b++){c.push(e[(f+b)%a])}}return c},circularCopyObject:function(f,g,d){var c=this,b,e,a={};if(d){for(b in f){if(f.hasOwnProperty(b)){e=f[b];if(Ext.isArray(e)){a[b]=c.circularCopyArray(e,g,d)}else{a[b]=e}}}}return a},getColors:function(){var b=this,a=b.config.colors,c=b.getTheme();if(Ext.isArray(a)&&a.length>0){a=b.applyColors(a)}return a||(c&&c.getColors())},applyColors:function(a){a=Ext.Array.map(a,function(b){if(Ext.isString(b)){return b}else{return b.toString()}});return a},updateColors:function(c){var k=this,e=k.getTheme(),a=c||(e&&e.getColors()),l=0,f=k.getSeries(),d=f&&f.length,g,j,b,h;if(a.length){for(g=0;g<d;g++){j=f[g];h=j.themeColorCount();b=k.circularCopyArray(a,l,h);l+=h;j.updateChartColors(b)}}k.refreshLegendStore()},applyTheme:function(a){if(a&&a.isTheme){return a}return Ext.Factory.chartTheme(a)},updateTheme:function(g){var e=this,f=e.getAxes(),d=e.getSeries(),a=e.getColors(),c,b;e.updateChartTheme(g);for(b=0;b<f.length;b++){f[b].updateTheme(g)}for(b=0;b<d.length;b++){c=d[b];c.updateTheme(g)}e.updateSpriteTheme(g);e.updateColors(a);e.redraw()},themeOnlyIfConfigured:{},updateChartTheme:function(c){var i=this,k=c.getChart(),n=i.getInitialConfig(),b=i.defaultConfig,e=i.getConfigurator().configs,f=k.defaults,g=k[i.xtype],h=i.themeOnlyIfConfigured,l,j,o,a,m,d;k=Ext.merge({},f,g);for(l in k){j=k[l];d=e[l];if(j!==null&&j!==undefined&&d){m=n[l];o=Ext.isObject(j);a=m===b[l];if(o){if(a&&h[l]){continue}j=Ext.merge({},j,m)}if(a||o){i[d.names.set](j)}}}},updateSpriteTheme:function(c){this.getSprites();var j=this,e=j.getSurface("chart"),h=e.getItems(),m=c.getSprites(),k,a,l,f,d,b,g;for(b=0,g=h.length;b<g;b++){k=h[b];a=m[k.type];if(a){f={};d=k.type==="text";for(l in a){if(!(l in k.config)){if(!(d&&l.indexOf("font")===0&&k.config.font)){f[l]=a[l]}}}k.setAttributes(f)}}},addSeries:function(b){var a=this.getSeries();Ext.Array.push(a,b);this.setSeries(a)},removeSeries:function(d){d=Ext.Array.from(d);var b=this.getSeries(),f=[],a=d.length,g={},c,e;for(c=0;c<a;c++){e=d[c];if(typeof e!=="string"){e=e.getId()}g[e]=true}for(c=0,a=b.length;c<a;c++){if(!g[b[c].getId()]){f.push(b[c])}}this.setSeries(f)},applySeries:function(e,d){var g=this,j=[],h,a,c,f,b;g.animationSuspendCount++;g.getAxes();if(d){h=d.map}else{d=[];h=d.map={}}j.map={};e=Ext.Array.from(e,true);for(c=0,f=e.length;c<f;c++){b=e[c];if(!b){continue}a=h[b.getId&&b.getId()||b.id];if(b instanceof Ext.chart.series.Series){if(a&&a!==b){a.destroy()}b.setChart(g)}else{if(Ext.isObject(b)){if(a){a.setConfig(b);b=a}else{if(Ext.isString(b)){b={type:b}}b.chart=g;b=Ext.create(b.xclass||("series."+b.type),b);b.on("animationstart","onAnimationStart",g);b.on("animationend","onAnimationEnd",g)}}}j.push(b);j.map[b.getId()]=b}for(c in h){if(!j.map[h[c].getId()]){h[c].destroy()}}g.animationSuspendCount--;return j},applyLegend:function(b,a){return Ext.factory(b,Ext.chart.Legend,a)},updateLegend:function(b,a){if(a){a.destroy()}if(b){this.getItems();this.legendStore=new Ext.data.Store({autoDestroy:true,fields:["id","name","mark","disabled","series","index"]});b.setStore(this.legendStore);this.refreshLegendStore();this.legendStore.on("update","onUpdateLegendStore",this)}},updateSeries:function(b,a){var c=this;if(c.isDestroying){return}c.animationSuspendCount++;c.fireEvent("serieschange",c,b,a);c.refreshLegendStore();if(!Ext.isEmpty(b)){c.updateTheme(c.getTheme())}c.scheduleLayout();c.animationSuspendCount--},applyInteractions:function(h,d){if(!d){d=[];d.map={}}var g=this,a=[],c=d.map,e,f,b;a.map={};h=Ext.Array.from(h,true);for(e=0,f=h.length;e<f;e++){b=h[e];if(!b){continue}b=Ext.factory(b,null,c[b.getId&&b.getId()||b.id],"interaction");if(b){b.setChart(g);a.push(b);a.map[b.getId()]=b}}for(e in c){if(!a.map[e]){c[e].destroy()}}return a},getInteraction:function(e){var f=this.getInteractions(),a=f&&f.length,c=null,b,d;if(a){for(d=0;d<a;++d){b=f[d];if(b.type===e){c=b;break}}}return c},applyStore:function(a){return a&&Ext.StoreManager.lookup(a)},updateStore:function(a,c){var b=this;if(c){c.un({datachanged:"onDataChanged",update:"onDataChanged",scope:b,order:"after"});if(c.autoDestroy){c.destroy()}}if(a){a.on({datachanged:"onDataChanged",update:"onDataChanged",scope:b,order:"after"})}b.fireEvent("storechange",b,a,c);b.onDataChanged()},redraw:function(){this.fireEvent("redraw",this)},performLayout:function(){var d=this,b=d.getChartSize(true),c=[0,0,b.width,b.height],a=d.getBackground();d.hasFirstLayout=true;d.fireEvent("layout",d);d.cancelChartLayout();d.getSurface("background").setRect(c);d.getSurface("chart").setRect(c);a.setAttributes({width:b.width,height:b.height})},getChartSize:function(b){var a=this;if(b){a.chartSize=null}return a.chartSize||(a.chartSize=a.innerElement.getSize())},getEventXY:function(a){return this.getSurface().getEventXY(a)},getItemForPoint:function(h,g){var f=this,a=f.getSeries(),e=f.getMainRect(),d=a.length,b=f.hasFirstLayout?d-1:-1,c,j;if(!(e&&h>=0&&h<=e[2]&&g>=0&&g<=e[3])){return null}for(;b>=0;b--){c=a[b];j=c.getItemForPoint(h,g);if(j){return j}}return null},getItemsForPoint:function(h,g){var f=this,a=f.getSeries(),d=a.length,b=f.hasFirstLayout?d-1:-1,e=[],c,j;for(;b>=0;b--){c=a[b];j=c.getItemForPoint(h,g);if(j){e.push(j)}}return e},onAnimationStart:function(){this.fireEvent("animationstart",this)},onAnimationEnd:function(){this.fireEvent("animationend",this)},onDataChanged:function(){var d=this;if(d.isInitializing){return}var c=d.getMainRect(),a=d.getStore(),b=d.getSeries(),e=d.getAxes();if(!a||!e||!b){return}if(!c){d.on({redraw:d.onDataChanged,scope:d,single:true});return}d.processData();d.redraw()},recordCount:0,processData:function(){var g=this,e=g.getStore().getCount(),c=g.getSeries(),f=c.length,d=false,b=0,a;for(;b<f;b++){a=c[b];a.processData();if(!d&&a.isStoreDependantColorCount){d=true}}if(d&&e>g.recordCount){g.updateColors(g.getColors());g.recordCount=e}},bindStore:function(a){this.setStore(a)},applyHighlightItem:function(f,a){if(f===a){return}if(Ext.isObject(f)&&Ext.isObject(a)){var e=f,d=a,c=e.sprite&&(e.sprite[0]||e.sprite),b=d.sprite&&(d.sprite[0]||d.sprite);if(c===b&&e.index===d.index){return}}return f},updateHighlightItem:function(b,a){if(a){a.series.setAttributesForItem(a,{highlighted:false})}if(b){b.series.setAttributesForItem(b,{highlighted:true});this.fireEvent("itemhighlight",this,b,a)}this.fireEvent("itemhighlightchange",this,b,a)},destroyChart:function(){var f=this,d=f.getLegend(),g=f.getAxes(),c=f.getSeries(),h=f.getInteractions(),b=[],a,e;f.surfaceMap=null;for(a=0,e=h.length;a<e;a++){h[a].destroy()}for(a=0,e=g.length;a<e;a++){g[a].destroy()}for(a=0,e=c.length;a<e;a++){c[a].destroy()}f.setInteractions(b);f.setAxes(b);f.setSeries(b);if(d){d.destroy();f.setLegend(null)}f.legendStore=null;f.setStore(null);f.cancelChartLayout()},getRefItems:function(b){var g=this,e=g.getSeries(),h=g.getAxes(),a=g.getInteractions(),c=[],d,f;for(d=0,f=e.length;d<f;d++){c.push(e[d]);if(e[d].getRefItems){c.push.apply(c,e[d].getRefItems(b))}}for(d=0,f=h.length;d<f;d++){c.push(h[d]);if(h[d].getRefItems){c.push.apply(c,h[d].getRefItems(b))}}for(d=0,f=a.length;d<f;d++){c.push(a[d]);if(a[d].getRefItems){c.push.apply(c,a[d].getRefItems(b))}}return c}});Ext.define("Ext.chart.overrides.AbstractChart",{override:"Ext.chart.AbstractChart",updateLegend:function(b,a){var c;this.callParent([b,a]);if(b){c=b.docked;this.addDocked({dock:c,xtype:"panel",shrinkWrap:true,scrollable:true,layout:{type:c==="top"||c==="bottom"?"hbox":"vbox",pack:"center"},items:b,cls:Ext.baseCSSPrefix+"legend-panel"})}},performLayout:function(){if(this.isVisible(true)){return this.callParent()}this.cancelChartLayout();return false},afterComponentLayout:function(c,a,b,d){this.callParent([c,a,b,d]);this.scheduleLayout()},allowSchedule:function(){return this.rendered},onDestroy:function(){this.destroyChart();this.callParent(arguments)}});Ext.define("Ext.chart.grid.HorizontalGrid",{extend:"Ext.draw.sprite.Sprite",alias:"grid.horizontal",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number"},defaults:{x:0,y:0,width:1,height:1,strokeStyle:"#DDD"}}},render:function(b,c,e){var a=this.attr,f=b.roundPixel(a.y),d=c.lineWidth*0.5;c.beginPath();c.rect(e[0]-b.matrix.getDX(),f+d,+e[2],a.height);c.fill();c.beginPath();c.moveTo(e[0]-b.matrix.getDX(),f+d);c.lineTo(e[0]+e[2]-b.matrix.getDX(),f+d);c.stroke()}});Ext.define("Ext.chart.grid.VerticalGrid",{extend:"Ext.draw.sprite.Sprite",alias:"grid.vertical",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number"},defaults:{x:0,y:0,width:1,height:1,strokeStyle:"#DDD"}}},render:function(c,d,f){var b=this.attr,a=c.roundPixel(b.x),e=d.lineWidth*0.5;d.beginPath();d.rect(a-e,f[1]-c.matrix.getDY(),b.width,f[3]);d.fill();d.beginPath();d.moveTo(a-e,f[1]-c.matrix.getDY());d.lineTo(a-e,f[1]+f[3]-c.matrix.getDY());d.stroke()}});Ext.define("Ext.chart.CartesianChart",{extend:"Ext.chart.AbstractChart",alternateClassName:"Ext.chart.Chart",requires:["Ext.chart.grid.HorizontalGrid","Ext.chart.grid.VerticalGrid"],xtype:["cartesian","chart"],isCartesian:true,config:{flipXY:false,innerRect:[0,0,1,1],innerPadding:{top:0,left:0,right:0,bottom:0}},applyInnerPadding:function(b,a){if(!Ext.isObject(b)){return Ext.util.Format.parseBox(b)}else{if(!a){return b}else{return Ext.apply(a,b)}}},getDirectionForAxis:function(a){var b=this.getFlipXY();if(a==="left"||a==="right"){if(b){return"X"}else{return"Y"}}else{if(b){return"Y"}else{return"X"}}},performLayout:function(){var A=this;A.animationSuspendCount++;if(A.callParent()===false){--A.animationSuspendCount;return}A.suspendThicknessChanged();var d=A.getSurface("chart").getRect(),o=d[2],n=d[3],z=A.getAxes(),b,q=A.getSeries(),h,l,a,f=A.getInsetPadding(),v=A.getInnerPadding(),r,c,e=Ext.apply({},f),u,p,s,k,m,y,t,x,g,j=A.getInherited().rtl,w=A.getFlipXY();if(o<=0||n<=0){return}for(x=0;x<z.length;x++){b=z[x];l=b.getSurface();m=b.getFloating();y=m?m.value:null;a=b.getThickness();switch(b.getPosition()){case"top":l.setRect([0,e.top+1,o,a]);break;case"bottom":l.setRect([0,n-(e.bottom+a),o,a]);break;case"left":l.setRect([e.left,0,a,n]);break;case"right":l.setRect([o-(e.right+a),0,a,n]);break}if(y===null){e[b.getPosition()]+=a}}o-=e.left+e.right;n-=e.top+e.bottom;u=[e.left,e.top,o,n];e.left+=v.left;e.top+=v.top;e.right+=v.right;e.bottom+=v.bottom;p=o-v.left-v.right;s=n-v.top-v.bottom;A.setInnerRect([e.left,e.top,p,s]);if(p<=0||s<=0){return}A.setMainRect(u);A.getSurface().setRect(u);for(x=0,g=A.surfaceMap.grid&&A.surfaceMap.grid.length;x<g;x++){c=A.surfaceMap.grid[x];c.setRect(u);c.matrix.set(1,0,0,1,v.left,v.top);c.matrix.inverse(c.inverseMatrix)}for(x=0;x<z.length;x++){b=z[x];l=b.getSurface();t=l.matrix;k=t.elements;switch(b.getPosition()){case"top":case"bottom":k[4]=e.left;b.setLength(p);break;case"left":case"right":k[5]=e.top;b.setLength(s);break}b.updateTitleSprite();t.inverse(l.inverseMatrix)}for(x=0,g=q.length;x<g;x++){h=q[x];r=h.getSurface();r.setRect(u);if(w){if(j){r.matrix.set(0,-1,-1,0,v.left+p,v.top+s)}else{r.matrix.set(0,-1,1,0,v.left,v.top+s)}}else{r.matrix.set(1,0,0,-1,v.left,v.top+s)}r.matrix.inverse(r.inverseMatrix);h.getOverlaySurface().setRect(u)}A.redraw();A.animationSuspendCount--;A.resumeThicknessChanged()},refloatAxes:function(){var h=this,g=h.getAxes(),o=(g&&g.length)||0,c,d,n,f,l,b,k,r=h.getChartSize(),q=h.getInsetPadding(),p=h.getInnerPadding(),a=r.width-q.left-q.right,m=r.height-q.top-q.bottom,j,e;for(e=0;e<o;e++){c=g[e];f=c.getFloating();l=f?f.value:null;if(l===null){delete c.floatingAtCoord;continue}d=c.getSurface();n=d.getRect();if(!n){continue}n=n.slice();b=h.getAxis(f.alongAxis);if(b){j=b.getAlignment()==="horizontal";if(Ext.isString(l)){l=b.getCoordFor(l)}b.floatingAxes[c.getId()]=l;k=b.getSprites()[0].attr.matrix;if(j){l=l*k.getXX()+k.getDX();c.floatingAtCoord=l+p.left+p.right}else{l=l*k.getYY()+k.getDY();c.floatingAtCoord=l+p.top+p.bottom}}else{j=c.getAlignment()==="horizontal";if(j){c.floatingAtCoord=l+p.top+p.bottom}else{c.floatingAtCoord=l+p.left+p.right}l=d.roundPixel(0.01*l*(j?m:a))}switch(c.getPosition()){case"top":n[1]=q.top+p.top+l-n[3]+1;break;case"bottom":n[1]=q.top+p.top+(b?l:m-l);break;case"left":n[0]=q.left+p.left+l-n[2];break;case"right":n[0]=q.left+p.left+(b?l:a-l)-1;break}d.setRect(n)}},redraw:function(){var C=this,r=C.getSeries(),z=C.getAxes(),b=C.getMainRect(),p,t,w=C.getInnerPadding(),f,l,s,e,q,A,v,g,d,c,a,k,n,y=C.getFlipXY(),x=1000,m,u,h,o,B;if(!b){return}p=b[2]-w.left-w.right;t=b[3]-w.top-w.bottom;for(A=0;A<r.length;A++){h=r[A];if((c=h.getXAxis())){n=c.getVisibleRange();l=c.getRange();l=[l[0]+(l[1]-l[0])*n[0],l[0]+(l[1]-l[0])*n[1]]}else{l=h.getXRange()}if((a=h.getYAxis())){n=a.getVisibleRange();s=a.getRange();s=[s[0]+(s[1]-s[0])*n[0],s[0]+(s[1]-s[0])*n[1]]}else{s=h.getYRange()}q={visibleMinX:l[0],visibleMaxX:l[1],visibleMinY:s[0],visibleMaxY:s[1],innerWidth:p,innerHeight:t,flipXY:y};f=h.getSprites();for(v=0,g=f.length;v<g;v++){o=f[v];m=o.attr.zIndex;if(m<x){m+=(A+1)*100+x;o.attr.zIndex=m;B=o.getMarker("items");if(B){u=B.attr.zIndex;if(u===Number.MAX_VALUE){B.attr.zIndex=m}else{if(u<x){B.attr.zIndex=m+u}}}}o.setAttributes(q,true)}}for(A=0;A<z.length;A++){d=z[A];e=d.isSide();f=d.getSprites();k=d.getRange();n=d.getVisibleRange();q={dataMin:k[0],dataMax:k[1],visibleMin:n[0],visibleMax:n[1]};if(e){q.length=t;q.startGap=w.bottom;q.endGap=w.top}else{q.length=p;q.startGap=w.left;q.endGap=w.right}for(v=0,g=f.length;v<g;v++){f[v].setAttributes(q,true)}}C.renderFrame();C.callParent(arguments)},renderFrame:function(){this.refloatAxes();this.callParent()}});Ext.define("Ext.chart.grid.CircularGrid",{extend:"Ext.draw.sprite.Circle",alias:"grid.circular",inheritableStatics:{def:{defaults:{r:1,strokeStyle:"#DDD"}}}});Ext.define("Ext.chart.grid.RadialGrid",{extend:"Ext.draw.sprite.Path",alias:"grid.radial",inheritableStatics:{def:{processors:{startRadius:"number",endRadius:"number"},defaults:{startRadius:0,endRadius:1,scalingCenterX:0,scalingCenterY:0,strokeStyle:"#DDD"},triggers:{startRadius:"path,bbox",endRadius:"path,bbox"}}},render:function(){this.callParent(arguments)},updatePath:function(d,a){var b=a.startRadius,c=a.endRadius;d.moveTo(b,0);d.lineTo(c,0)}});Ext.define("Ext.chart.PolarChart",{extend:"Ext.chart.AbstractChart",requires:["Ext.chart.grid.CircularGrid","Ext.chart.grid.RadialGrid"],xtype:"polar",isPolar:true,config:{center:[0,0],radius:0,innerPadding:0},getDirectionForAxis:function(a){return a==="radial"?"Y":"X"},applyCenter:function(a,b){if(b&&a[0]===b[0]&&a[1]===b[1]){return}return[+a[0],+a[1]]},updateCenter:function(a){var g=this,h=g.getAxes(),d=g.getSeries(),c,f,e,b;for(c=0,f=h.length;c<f;c++){e=h[c];e.setCenter(a)}for(c=0,f=d.length;c<f;c++){b=d[c];b.setCenter(a)}},applyInnerPadding:function(b,a){return Ext.isNumber(b)?b:a},doSetSurfaceRect:function(b,c){var a=this.getMainRect();b.setRect(c);b.matrix.set(1,0,0,1,a[0]-c[0],a[1]-c[1]);b.inverseMatrix.set(1,0,0,1,c[0]-a[0],c[1]-a[1])},applyAxes:function(f,h){var e=this,g=Ext.Array.from(e.config.series)[0],b,d,c,a;if(g.type==="radar"&&f&&f.length){for(b=0,d=f.length;b<d;b++){c=f[b];if(c.position==="angular"){a=true;break}}if(!a){f.push({type:"category",position:"angular",fields:g.xField||g.angleField,style:{estStepSize:1},grid:true})}}return this.callParent(arguments)},performLayout:function(){var F=this,g=true;try{F.animationSuspendCount++;if(this.callParent()===false){g=false;return}F.suspendThicknessChanged();var h=F.getSurface("chart").getRect(),v=F.getInsetPadding(),G=F.getInnerPadding(),l=Ext.apply({},v),d,s=h[2]-v.left-v.right,r=h[3]-v.top-v.bottom,x=[v.left,v.top,s,r],u=F.getSeries(),p,t=s-G*2,w=r-G*2,D=[t*0.5+G,w*0.5+G],j=Math.min(t,w)*0.5,A=F.getAxes(),f,a,k,m=[],o=[],E=j-G,z,n,b,q,y,c,C;F.setMainRect(x);F.doSetSurfaceRect(F.getSurface(),x);for(z=0,n=F.surfaceMap.grid&&F.surfaceMap.grid.length;z<n;z++){F.doSetSurfaceRect(F.surfaceMap.grid[z],h)}for(z=0,n=A.length;z<n;z++){f=A[z];switch(f.getPosition()){case"angular":m.push(f);break;case"radial":o.push(f);break}}for(z=0,n=m.length;z<n;z++){f=m[z];q=f.getFloating();y=q?q.value:null;F.doSetSurfaceRect(f.getSurface(),h);a=f.getThickness();for(d in l){l[d]+=a}s=h[2]-l.left-l.right;r=h[3]-l.top-l.bottom;b=Math.min(s,r)*0.5;if(z===0){E=b-G}f.setMinimum(0);f.setLength(b);f.getSprites();k=f.sprites[0].attr.lineWidth*0.5;for(d in l){l[d]+=k}}for(z=0,n=o.length;z<n;z++){f=o[z];F.doSetSurfaceRect(f.getSurface(),h);f.setMinimum(0);f.setLength(E);f.getSprites()}for(z=0,n=u.length;z<n;z++){p=u[z];if(p.type==="gauge"&&!c){c=p}else{p.setRadius(E)}F.doSetSurfaceRect(p.getSurface(),x)}F.doSetSurfaceRect(F.getSurface("overlay"),h);if(c){c.setRect(x);C=c.getRadius()-G;F.setRadius(C);F.setCenter(c.getCenter());c.setRadius(C);if(A.length&&A[0].getPosition()==="gauge"){f=A[0];F.doSetSurfaceRect(f.getSurface(),h);f.setTotalAngle(c.getTotalAngle());f.setLength(C)}}else{F.setRadius(j);F.setCenter(D)}F.redraw()}catch(B){throw B}finally{F.animationSuspendCount--;if(g){F.resumeThicknessChanged()}}},refloatAxes:function(){var j=this,g=j.getAxes(),h=j.getMainRect(),f,k,b,d,a,c,e;if(!h){return}e=0.5*Math.min(h[2],h[3]);for(d=0,a=g.length;d<a;d++){c=g[d];f=c.getFloating();k=f?f.value:null;if(k!==null){b=j.getAxis(f.alongAxis);if(c.getPosition()==="angular"){if(b){k=b.getLength()*k/b.getRange()[1]}else{k=0.01*k*e}c.sprites[0].setAttributes({length:k},true)}else{if(b){if(Ext.isString(k)){k=b.getCoordFor(k)}k=k/(b.getRange()[1]+1)*Math.PI*2-Math.PI*1.5+c.getRotation()}else{k=Ext.draw.Draw.rad(k)}c.sprites[0].setAttributes({baseRotation:k},true)}}}},redraw:function(){var f=this,g=f.getAxes(),d,c=f.getSeries(),b,a,e;for(a=0,e=g.length;a<e;a++){d=g[a];d.getSprites()}for(a=0,e=c.length;a<e;a++){b=c[a];b.getSprites()}f.renderFrame();f.callParent(arguments)},renderFrame:function(){this.refloatAxes();this.callParent()}});Ext.define("Ext.chart.SpaceFillingChart",{extend:"Ext.chart.AbstractChart",xtype:"spacefilling",config:{},performLayout:function(){var j=this;try{j.animationSuspendCount++;if(j.callParent()===false){return}var k=j.getSurface("chart").getRect(),l=j.getInsetPadding(),a=k[2]-l.left-l.right,m=k[3]-l.top-l.bottom,h=[l.left,l.top,a,m],b=j.getSeries(),d,c,g;j.getSurface().setRect(h);j.setMainRect(h);for(c=0,g=b.length;c<g;c++){d=b[c];d.getSurface().setRect(h);if(d.setRect){d.setRect(h)}d.getOverlaySurface().setRect(k)}j.redraw()}catch(f){throw f}finally{j.animationSuspendCount--}},redraw:function(){var e=this,c=e.getSeries(),b,a,d;for(a=0,d=c.length;a<d;a++){b=c[a];b.getSprites()}e.renderFrame();e.callParent(arguments)}});Ext.define("Ext.chart.axis.sprite.Axis3D",{extend:"Ext.chart.axis.sprite.Axis",alias:"sprite.axis3d",type:"axis3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0},triggers:{depth:"layout"}}},config:{fx:{customDurations:{depth:0}}},layoutUpdater:function(){var h=this,f=h.getAxis().getChart();if(f.isInitializing){return}var e=h.attr,d=h.getLayout(),c=d.isDiscrete?0:e.depth,g=f.getInherited().rtl,b=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMin,i=e.dataMin+(e.dataMax-e.dataMin)*e.visibleMax,a={attr:e,segmenter:h.getSegmenter(),renderer:h.defaultRenderer};if(e.position==="left"||e.position==="right"){e.translationX=0;e.translationY=i*(e.length-c)/(i-b)+c;e.scalingX=1;e.scalingY=(-e.length+c)/(i-b);e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}else{if(e.position==="top"||e.position==="bottom"){if(g){e.translationX=e.length+b*e.length/(i-b)+1}else{e.translationX=-b*e.length/(i-b)}e.translationY=0;e.scalingX=(g?-1:1)*(e.length-c)/(i-b);e.scalingY=1;e.scalingCenterY=0;e.scalingCenterX=0;h.applyTransformations(true)}}if(d){d.calculateLayout(a);h.setLayoutContext(a)}},renderAxisLine:function(a,j,f,c){var i=this,h=i.attr,b=h.lineWidth*0.5,f=i.getLayout(),d=f.isDiscrete?0:h.depth,k=h.position,e,g;if(h.axisLine&&h.length){switch(k){case"left":e=a.roundPixel(c[2])-b;j.moveTo(e,-h.endGap+d);j.lineTo(e,h.length+h.startGap);break;case"right":j.moveTo(b,-h.endGap);j.lineTo(b,h.length+h.startGap);break;case"bottom":j.moveTo(-h.startGap,b);j.lineTo(h.length-d+h.endGap,b);break;case"top":e=a.roundPixel(c[3])-b;j.moveTo(-h.startGap,e);j.lineTo(h.length+h.endGap,e);break;case"angular":j.moveTo(h.centerX+h.length,h.centerY);j.arc(h.centerX,h.centerY,h.length,0,Math.PI*2,true);break;case"gauge":g=i.getGaugeAngles();j.moveTo(h.centerX+Math.cos(g.start)*h.length,h.centerY+Math.sin(g.start)*h.length);j.arc(h.centerX,h.centerY,h.length,g.start,g.end,true);break}}}});Ext.define("Ext.chart.axis.Axis3D",{extend:"Ext.chart.axis.Axis",xtype:"axis3d",requires:["Ext.chart.axis.sprite.Axis3D"],config:{depth:0},onSeriesChange:function(e){var g=this,b="depthchange",f="onSeriesDepthChange",d,c;function a(h){var i=g.boundSeries;for(d=0;d<i.length;d++){c=i[d];c[h](b,f,g)}}a("un");g.callParent(arguments);a("on")},onSeriesDepthChange:function(b,f){var d=this,g=f,e=d.boundSeries,a,c;if(f>d.getDepth()){g=f}else{for(a=0;a<e.length;a++){c=e[a];if(c!==b&&c.getDepth){f=c.getDepth();if(f>g){g=f}}}}d.setDepth(g)},updateDepth:function(d){var b=this,c=b.getSprites(),a={depth:d};if(c&&c.length){c[0].setAttributes(a)}if(b.gridSpriteEven&&b.gridSpriteOdd){b.gridSpriteEven.getTemplate().setAttributes(a);b.gridSpriteOdd.getTemplate().setAttributes(a)}},getGridAlignment:function(){switch(this.getPosition()){case"left":case"right":return"horizontal3d";case"top":case"bottom":return"vertical3d"}}});Ext.define("Ext.chart.axis.Category",{requires:["Ext.chart.axis.layout.CombineDuplicate","Ext.chart.axis.segmenter.Names"],extend:"Ext.chart.axis.Axis",alias:"axis.category",type:"category",config:{layout:"combineDuplicate",segmenter:"names"}});Ext.define("Ext.chart.axis.Category3D",{requires:["Ext.chart.axis.layout.CombineDuplicate","Ext.chart.axis.segmenter.Names"],extend:"Ext.chart.axis.Axis3D",alias:"axis.category3d",type:"category3d",config:{layout:"combineDuplicate",segmenter:"names"}});Ext.define("Ext.chart.axis.Numeric",{extend:"Ext.chart.axis.Axis",type:"numeric",alias:["axis.numeric","axis.radial"],requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Numeric"],config:{layout:"continuous",segmenter:"numeric",aggregator:"double"}});Ext.define("Ext.chart.axis.Numeric3D",{extend:"Ext.chart.axis.Axis3D",alias:["axis.numeric3d"],type:"numeric3d",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Numeric"],config:{layout:"continuous",segmenter:"numeric",aggregator:"double"}});Ext.define("Ext.chart.axis.Time",{extend:"Ext.chart.axis.Numeric",alias:"axis.time",type:"time",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Time"],config:{calculateByLabelSize:true,dateFormat:null,fromDate:null,toDate:null,step:[Ext.Date.DAY,1],layout:"continuous",segmenter:"time",aggregator:"time"},updateDateFormat:function(a){this.setRenderer(function(c,b){return Ext.Date.format(new Date(b),a)})},updateFromDate:function(a){this.setMinimum(+a)},updateToDate:function(a){this.setMaximum(+a)},getCoordFor:function(a){if(Ext.isString(a)){a=new Date(a)}return +a}});Ext.define("Ext.chart.axis.Time3D",{extend:"Ext.chart.axis.Numeric3D",alias:"axis.time3d",type:"time3d",requires:["Ext.chart.axis.layout.Continuous","Ext.chart.axis.segmenter.Time"],config:{calculateByLabelSize:true,dateFormat:null,fromDate:null,toDate:null,step:[Ext.Date.DAY,1],layout:"continuous",segmenter:"time",aggregator:"time"},updateDateFormat:function(a){this.setRenderer(function(c,b){return Ext.Date.format(new Date(b),a)})},updateFromDate:function(a){this.setMinimum(+a)},updateToDate:function(a){this.setMaximum(+a)},getCoordFor:function(a){if(Ext.isString(a)){a=new Date(a)}return +a}});Ext.define("Ext.chart.grid.HorizontalGrid3D",{extend:"Ext.chart.grid.HorizontalGrid",alias:"grid.horizontal3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0}}},render:function(a,k,d){var f=this.attr,i=a.roundPixel(f.x),h=a.roundPixel(f.y),l=a.matrix.getDX(),c=k.lineWidth*0.5,j=f.height,e=f.depth,b,g;if(h<=d[1]){return}b=d[0]+e-l;g=h+c-e;k.beginPath();k.rect(b,g,d[2],j);k.fill();k.beginPath();k.moveTo(b,g);k.lineTo(b+d[2],g);k.stroke();b=d[0]+i-l;g=h+c;k.beginPath();k.moveTo(b,g);k.lineTo(b+e,g-e);k.lineTo(b+e,g-e+j);k.lineTo(b,g+j);k.closePath();k.fill();k.beginPath();k.moveTo(b,g);k.lineTo(b+e,g-e);k.stroke()}});Ext.define("Ext.chart.grid.VerticalGrid3D",{extend:"Ext.chart.grid.VerticalGrid",alias:"grid.vertical3d",inheritableStatics:{def:{processors:{depth:"number"},defaults:{depth:0}}},render_:function(c,d,f){var b=this.attr,a=c.roundPixel(b.x),e=d.lineWidth*0.5;d.beginPath();d.rect(a-e,f[1]-c.matrix.getDY(),b.width,f[3]);d.fill();d.beginPath();d.moveTo(a-e,f[1]-c.matrix.getDY());d.lineTo(a-e,f[1]+f[3]-c.matrix.getDY());d.stroke()},render:function(b,j,e){var g=this.attr,i=b.roundPixel(g.x),k=b.matrix.getDY(),d=j.lineWidth*0.5,a=g.width,f=g.depth,c,h;if(i>=e[2]){return}c=i-d+f;h=e[1]-f-k;j.beginPath();j.rect(c,h,a,e[3]);j.fill();j.beginPath();j.moveTo(c,h);j.lineTo(c,h+e[3]);j.stroke();c=i-d;h=e[3];j.beginPath();j.moveTo(c,h);j.lineTo(c+f,h-f);j.lineTo(c+f+a,h-f);j.lineTo(c+a,h);j.closePath();j.fill();c=i-d;h=e[3];j.beginPath();j.moveTo(c,h);j.lineTo(c+f,h-f);j.stroke()}});Ext.define("Ext.chart.interactions.CrossZoom",{extend:"Ext.chart.interactions.Abstract",type:"crosszoom",alias:"interaction.crosszoom",isCrossZoom:true,config:{axes:true,gestures:{dragstart:"onGestureStart",drag:"onGesture",dragend:"onGestureEnd",dblclick:"onDoubleTap"},undoButton:{}},stopAnimationBeforeSync:false,zoomAnimationInProgress:false,constructor:function(){this.callParent(arguments);this.zoomHistory=[]},applyAxes:function(b){var a={};if(b===true){return{top:{},right:{},bottom:{},left:{}}}else{if(Ext.isArray(b)){a={};Ext.each(b,function(c){a[c]={}})}else{if(Ext.isObject(b)){Ext.iterate(b,function(c,d){if(d===true){a[c]={}}else{if(d!==false){a[c]=d}}})}}}return a},applyUndoButton:function(b,a){var c=this;if(a){a.destroy()}if(b){return Ext.create("Ext.Button",Ext.apply({cls:[],text:"Undo Zoom",disabled:true,handler:function(){c.undoZoom()}},b))}},getSurface:function(){return this.getChart()&&this.getChart().getSurface("main")},setSeriesOpacity:function(b){var a=this.getChart()&&this.getChart().getSurface("series");if(a){a.element.setStyle("opacity",b)}},onGestureStart:function(h){var j=this,i=j.getChart(),d=j.getSurface(),l=i.getInnerRect(),c=i.getInnerPadding(),g=c.left,b=g+l[2],f=c.top,a=f+l[3],n=i.getEventXY(h),m=n[0],k=n[1];if(j.zoomAnimationInProgress){return}if(m>g&&m<b&&k>f&&k<a){j.gestureEvent="drag";j.lockEvents(j.gestureEvent);j.startX=m;j.startY=k;j.selectionRect=d.add({type:"rect",globalAlpha:0.5,fillStyle:"rgba(80,80,140,0.5)",strokeStyle:"rgba(80,80,140,1)",lineWidth:2,x:m,y:k,width:0,height:0,zIndex:10000});j.setSeriesOpacity(0.8);return false}},onGesture:function(h){var j=this;if(j.zoomAnimationInProgress){return}if(j.getLocks()[j.gestureEvent]===j){var i=j.getChart(),d=j.getSurface(),l=i.getInnerRect(),c=i.getInnerPadding(),g=c.left,b=g+l[2],f=c.top,a=f+l[3],n=i.getEventXY(h),m=n[0],k=n[1];if(m<g){m=g}else{if(m>b){m=b}}if(k<f){k=f}else{if(k>a){k=a}}j.selectionRect.setAttributes({width:m-j.startX,height:k-j.startY});if(Math.abs(j.startX-m)<11||Math.abs(j.startY-k)<11){j.selectionRect.setAttributes({globalAlpha:0.5})}else{j.selectionRect.setAttributes({globalAlpha:1})}d.renderFrame();return false}},onGestureEnd:function(i){var l=this;if(l.zoomAnimationInProgress){return}if(l.getLocks()[l.gestureEvent]===l){var k=l.getChart(),d=l.getSurface(),n=k.getInnerRect(),c=k.getInnerPadding(),g=c.left,b=g+n[2],f=c.top,a=f+n[3],h=n[2],j=n[3],p=k.getEventXY(i),o=p[0],m=p[1];if(o<g){o=g}else{if(o>b){o=b}}if(m<f){m=f}else{if(m>a){m=a}}if(Math.abs(l.startX-o)<11||Math.abs(l.startY-m)<11){d.remove(l.selectionRect)}else{l.zoomBy([Math.min(l.startX,o)/h,1-Math.max(l.startY,m)/j,Math.max(l.startX,o)/h,1-Math.min(l.startY,m)/j]);l.selectionRect.setAttributes({x:Math.min(l.startX,o),y:Math.min(l.startY,m),width:Math.abs(l.startX-o),height:Math.abs(l.startY-m)});l.selectionRect.setAnimation(k.getAnimation()||{duration:0});l.selectionRect.setAttributes({globalAlpha:0,x:0,y:0,width:h,height:j});l.zoomAnimationInProgress=true;k.suspendThicknessChanged();l.selectionRect.fx.on("animationend",function(){k.resumeThicknessChanged();d.remove(l.selectionRect);l.selectionRect=null;l.zoomAnimationInProgress=false})}d.renderFrame();l.sync();l.unlockEvents(l.gestureEvent);l.setSeriesOpacity(1);if(!l.zoomAnimationInProgress){d.remove(l.selectionRect);l.selectionRect=null}}},zoomBy:function(o){var n=this,a=n.getAxes(),k=n.getChart(),j=k.getAxes(),l=k.getInherited().rtl,f,d={},c,b;if(l){o=o.slice();c=1-o[0];b=1-o[2];o[0]=Math.min(c,b);o[2]=Math.max(c,b)}for(var h=0;h<j.length;h++){var g=j[h];f=a[g.getPosition()];if(f&&f.allowZoom!==false){var e=g.isSide(),m=g.getVisibleRange();d[g.getId()]=m.slice(0);if(!e){g.setVisibleRange([(m[1]-m[0])*o[0]+m[0],(m[1]-m[0])*o[2]+m[0]])}else{g.setVisibleRange([(m[1]-m[0])*o[1]+m[0],(m[1]-m[0])*o[3]+m[0]])}}}n.zoomHistory.push(d);n.getUndoButton().setDisabled(false)},undoZoom:function(){var c=this.zoomHistory.pop(),d=this.getChart().getAxes();if(c){for(var a=0;a<d.length;a++){var b=d[a];if(c[b.getId()]){b.setVisibleRange(c[b.getId()])}}}this.getUndoButton().setDisabled(this.zoomHistory.length===0);this.sync()},onDoubleTap:function(a){this.undoZoom()},destroy:function(){this.setUndoButton(null);this.callParent(arguments)}});Ext.define("Ext.chart.interactions.Crosshair",{extend:"Ext.chart.interactions.Abstract",requires:["Ext.chart.grid.HorizontalGrid","Ext.chart.grid.VerticalGrid","Ext.chart.CartesianChart","Ext.chart.axis.layout.Discrete"],type:"crosshair",alias:"interaction.crosshair",config:{axes:{top:{label:{},rect:{}},right:{label:{},rect:{}},bottom:{label:{},rect:{}},left:{label:{},rect:{}}},lines:{horizontal:{strokeStyle:"black",lineDash:[5,5]},vertical:{strokeStyle:"black",lineDash:[5,5]}},gesture:"drag"},applyAxes:function(b,a){return Ext.merge(a||{},b)},applyLines:function(a,b){return Ext.merge(b||{},a)},updateChart:function(a){if(a&&!a.isCartesian){Ext.raise("Crosshair interaction can only be used on cartesian charts.")}this.callParent(arguments)},getGestures:function(){var a=this,b={};b[a.getGesture()]="onGesture";b[a.getGesture()+"start"]="onGestureStart";b[a.getGesture()+"end"]="onGestureEnd";return b},onGestureStart:function(N){var m=this,O=m.getChart(),B=O.getTheme().getAxis(),A,F=O.getSurface("overlay"),s=O.getInnerRect(),n=s[2],M=s[3],r=O.getEventXY(N),D=r[0],C=r[1],E=O.getAxes(),u=m.getAxes(),h=m.getLines(),q,v,b,d,k,z,G,L,J,o,I,w,l,f,p,j,t,a,g,H,c,K;if(D>0&&D<n&&C>0&&C<M){m.lockEvents(m.getGesture());H=Ext.apply({xclass:"Ext.chart.grid.HorizontalGrid",x:0,y:C,width:n},h.horizontal);c=Ext.apply({xclass:"Ext.chart.grid.VerticalGrid",x:D,y:0,height:M},h.vertical);m.axesLabels=m.axesLabels||{};for(K=0;K<E.length;K++){q=E[K];v=q.getSurface();b=v.getRect();w=q.getSprites()[0];d=b[2];k=b[3];z=q.getPosition();G=q.getAlignment();t=q.getTitle();a=t&&t.attr.text!==""&&t.getBBox();l=w.attr;f=w.thickness;p=l.axisLine?l.lineWidth:0;j=p/2;I=Math.max(l.majorTickSize,l.minorTickSize)+p;L=m.axesLabels[z]=v.add({type:"composite"});L.labelRect=L.add(Ext.apply({type:"rect",fillStyle:"white",x:z==="right"?p:0,y:z==="bottom"?p:0,width:d-p-(G==="vertical"&&a?a.width:0),height:k-p-(G==="horizontal"&&a?a.height:0),translationX:z==="left"&&a?a.width:0,translationY:z==="top"&&a?a.height:0},u.rect||u[z].rect));if(G==="vertical"&&!c.strokeStyle){c.strokeStyle=l.strokeStyle}if(G==="horizontal"&&!H.strokeStyle){H.strokeStyle=l.strokeStyle}A=Ext.merge({},B.defaults,B[z]);J=Ext.apply({},q.config.label,A.label);o=u.label||u[z].label;L.labelText=L.add(Ext.apply(J,o,{type:"text",x:(function(){switch(z){case"left":g=a?a.x+a.width:0;return g+(d-g-I)/2-j;case"right":g=a?d-a.x:0;return I+(d-I-g)/2+j;default:return 0}})(),y:(function(){switch(z){case"top":g=a?a.y+a.height:0;return g+(k-g-I)/2-j;case"bottom":g=a?k-a.y:0;return I+(k-I-g)/2+j;default:return 0}})()}))}m.horizontalLine=F.add(H);m.verticalLine=F.add(c);return false}},onGesture:function(G){var K=this;if(K.getLocks()[K.getGesture()]!==K){return}var u=K.getChart(),z=u.getSurface("overlay"),a=Ext.Array.slice(u.getInnerRect()),r=u.getInnerPadding(),t=r.left,q=r.top,E=a[2],f=a[3],d=u.getEventXY(G),k=d[0],j=d[1],D=u.getAxes(),c,h,m,p,J,w,I,H,s,b,C,g,v,n,l,A,F,o,B;if(k<0){k=0}else{if(k>E){k=E}}if(j<0){j=0}else{if(j>f){j=f}}k+=t;j+=q;for(B=0;B<D.length;B++){c=D[B];h=c.getPosition();m=c.getAlignment();p=c.getSurface();J=c.getSprites()[0];w=J.attr.matrix;C=J.attr.textPadding*2;s=K.axesLabels[h];I=J.getLayoutContext();H=c.getSegmenter();if(s){if(m==="vertical"){v=w.getYY();l=w.getDY();F=(j-l-q)/v;if(c.getLayout() instanceof Ext.chart.axis.layout.Discrete){j=Math.round(F)*v+l+q;F=H.from(Math.round(F));F=J.attr.data[F]}else{F=H.from(F)}o=H.renderer(F,I);s.setAttributes({translationY:j-q});s.labelText.setAttributes({text:o});b=s.labelText.getBBox();s.labelRect.setAttributes({height:b.height+C,y:-(b.height+C)/2});p.renderFrame()}else{g=w.getXX();n=w.getDX();A=(k-n-t)/g;if(c.getLayout() instanceof Ext.chart.axis.layout.Discrete){k=Math.round(A)*g+n+t;A=H.from(Math.round(A));A=J.attr.data[A]}else{A=H.from(A)}o=H.renderer(A,I);s.setAttributes({translationX:k-t});s.labelText.setAttributes({text:o});b=s.labelText.getBBox();s.labelRect.setAttributes({width:b.width+C,x:-(b.width+C)/2});p.renderFrame()}}}K.horizontalLine.setAttributes({y:j,strokeStyle:J.attr.strokeStyle});K.verticalLine.setAttributes({x:k,strokeStyle:J.attr.strokeStyle});z.renderFrame();return false},onGestureEnd:function(h){var l=this,k=l.getChart(),a=k.getSurface("overlay"),j=k.getAxes(),c,g,d,b,f;a.remove(l.verticalLine);a.remove(l.horizontalLine);for(f=0;f<j.length;f++){c=j[f];g=c.getPosition();d=c.getSurface();b=l.axesLabels[g];if(b){delete l.axesLabels[g];d.remove(b)}d.renderFrame()}a.renderFrame();l.unlockEvents(l.getGesture())}});Ext.define("Ext.chart.interactions.ItemHighlight",{extend:"Ext.chart.interactions.Abstract",type:"itemhighlight",alias:"interaction.itemhighlight",isItemHighlight:true,config:{gestures:{tap:"onTapGesture",mousemove:"onMouseMoveGesture",mousedown:"onMouseDownGesture",mouseup:"onMouseUpGesture",mouseleave:"onMouseUpGesture"},sticky:false},stickyHighlightItem:null,onMouseMoveGesture:function(g){var d=this,h=d.tipItem,a=g.pointerType==="mouse",c,f,b;if(d.getSticky()){return true}if(d.isDragging){if(h&&a){h.series.hideTooltip(h);d.tipItem=null}}else{if(!d.stickyHighlightItem){c=d.getItemForEvent(g);b=d.getChart();if(c!==b.getHighlightItem()){d.highlight(c);d.sync()}if(a){if(h&&(!c||h.field!==c.field||h.record!==c.record)){h.series.hideTooltip(h);d.tipItem=h=null}if(c&&(f=c.series.getTooltip())){if(f.trackMouse||!h){c.series.showTooltip(c,g.getXY())}d.tipItem=c}}return false}}},highlight:function(a){this.getChart().setHighlightItem(a)},showTooltip:function(b,a){a.series.showTooltip(a,b.getXY());this.tipItem=a},onMouseDownGesture:function(){this.isDragging=true},onMouseUpGesture:function(){this.isDragging=false},onTapGesture:function(c){var b=this;if(c.pointerType==="mouse"&&!b.getSticky()){return}var a=b.getItemForEvent(c);if(b.stickyHighlightItem&&a&&(b.stickyHighlightItem.index===a.index)){a=null}b.stickyHighlightItem=a;b.highlight(a)}});Ext.define("Ext.chart.interactions.ItemEdit",{extend:"Ext.chart.interactions.ItemHighlight",requires:["Ext.tip.ToolTip"],type:"itemedit",alias:"interaction.itemedit",isItemEdit:true,config:{style:null,renderer:null,tooltip:true,gestures:{dragstart:"onDragStart",drag:"onDrag",dragend:"onDragEnd"},cursors:{ewResize:"ew-resize",nsResize:"ns-resize",move:"move"}},item:null,applyTooltip:function(b){if(b){var a=Ext.apply({},b,{renderer:this.defaultTooltipRenderer,constrainPosition:true,shrinkWrapDock:true,autoHide:true,offsetX:10,offsetY:10});b=new Ext.tip.ToolTip(a)}return b},defaultTooltipRenderer:function(b,a,f,d){var c=[];if(f.xField){c.push(f.xField+": "+f.xValue)}if(f.yField){c.push(f.yField+": "+f.yValue)}b.setHtml(c.join("<br>"))},onDragStart:function(d){var c=this,a=c.getChart(),b=a.getHighlightItem();if(b){a.fireEvent("beginitemedit",a,c,c.item=b);return false}},onDrag:function(f){var d=this,b=d.getChart(),c=b.getHighlightItem(),a=c&&c.sprite.type;if(c){switch(a){case"barSeries":return d.onDragBar(f);break;case"scatterSeries":return d.onDragScatter(f);break}}},highlight:function(f){var e=this,d=e.getChart(),a=d.getFlipXY(),g=e.getCursors(),c=f&&f.sprite.type,b=d.el.dom.style;e.callParent([f]);if(f){switch(c){case"barSeries":if(a){b.cursor=g.ewResize}else{b.cursor=g.nsResize}break;case"scatterSeries":b.cursor=g.move;break}}else{d.el.dom.style.cursor="default"}},onDragBar:function(i){var m=this,k=m.getChart(),l=k.getInherited().rtl,f=k.isCartesian&&k.getFlipXY(),q=k.getHighlightItem(),g=q.sprite.getMarker("items"),p=g.getMarkerFor(q.sprite.getId(),q.index),b=q.sprite.getSurface(),c=b.getRect(),r=b.getEventXY(i),o=q.sprite.attr.matrix,j=m.getRenderer(),a,n,d,h;if(f){h=l?c[2]-r[0]:r[0]}else{h=c[3]-r[1]}a={x:p.x,y:h,width:p.width,height:p.height+(p.y-h),radius:p.radius,fillStyle:"none",lineDash:[4,4],zIndex:100};Ext.apply(a,m.getStyle());if(Ext.isArray(q.series.getYField())){h=h-p.y-p.height}m.target={index:q.index,yField:q.field,yValue:(h-o.getDY())/o.getYY()};d=[k,{target:m.target,style:a,item:q}];n=Ext.callback(j,null,d,0,k);if(n){Ext.apply(a,n)}q.sprite.putMarker("items",a,"itemedit");m.showTooltip(i,m.target,q);b.renderFrame()},onDragScatter:function(n){var t=this,g=t.getChart(),d=g.getInherited().rtl,l=g.isCartesian&&g.getFlipXY(),o=g.getHighlightItem(),b=o.sprite.getMarker("items"),p=b.getMarkerFor(o.sprite.getId(),o.index),j=o.sprite.getSurface(),h=j.getRect(),a=j.getEventXY(n),k=o.sprite.attr.matrix,c=o.series.getXAxis(),f=c&&c.getLayout().isContinuous,i=t.getRenderer(),m,u,q,s,r;if(l){r=d?h[2]-a[0]:a[0]}else{r=h[3]-a[1]}if(f){if(l){s=h[3]-a[1]}else{s=a[0]}}else{s=p.translationX}m={translationX:s,translationY:r,scalingX:p.scalingX,scalingY:p.scalingY,r:p.r,fillStyle:"none",lineDash:[4,4],zIndex:100};Ext.apply(m,t.getStyle());t.target={index:o.index,yField:o.field,yValue:(r-k.getDY())/k.getYY()};if(f){Ext.apply(t.target,{xField:o.series.getXField(),xValue:(s-k.getDX())/k.getXX()})}q=[g,{target:t.target,style:m,item:o}];u=Ext.callback(i,null,q,0,g);if(u){Ext.apply(m,u)}o.sprite.putMarker("items",m,"itemedit");t.showTooltip(n,t.target,o);j.renderFrame()},showTooltip:function(g,f,c){var d=this.getTooltip(),a,b;if(d&&Ext.toolkit!=="modern"){a=d.config;b=this.getChart();Ext.callback(a.renderer,null,[d,c,f,g],0,b);d.show([g.x+a.offsetX,g.y+a.offsetY])}},hideTooltip:function(){var a=this.getTooltip();if(a&&Ext.toolkit!=="modern"){a.hide()}},onDragEnd:function(g){var d=this,f=d.target,c=d.getChart(),b=c.getStore(),a;if(f){a=b.getAt(f.index);if(f.yField){a.set(f.yField,f.yValue,{convert:false})}if(f.xField){a.set(f.xField,f.xValue,{convert:false})}if(f.yField||f.xField){d.getChart().onDataChanged()}d.target=null}d.hideTooltip();if(d.item){c.fireEvent("enditemedit",c,d,d.item,f)}d.highlight(d.item=null)},destroy:function(){var a=this.getConfig("tooltip",true);Ext.destroy(a);this.callParent()}});Ext.define("Ext.chart.interactions.PanZoom",{extend:"Ext.chart.interactions.Abstract",type:"panzoom",alias:"interaction.panzoom",requires:["Ext.draw.Animator"],config:{axes:{top:{},right:{},bottom:{},left:{}},minZoom:null,maxZoom:null,showOverflowArrows:true,panGesture:"drag",zoomGesture:"pinch",zoomOnPanGesture:false,modeToggleButton:{xtype:"segmentedbutton",width:200,defaults:{ui:"default-toolbar"},cls:Ext.baseCSSPrefix+"panzoom-toggle",items:[{text:"Pan"},{text:"Zoom"}]},hideLabelInGesture:false},stopAnimationBeforeSync:true,applyAxes:function(b,a){return Ext.merge(a||{},b)},applyZoomOnPanGesture:function(a){this.getChart();if(this.isMultiTouch()){return false}return a},updateZoomOnPanGesture:function(b){var a=this.getModeToggleButton();if(!this.isMultiTouch()){a.show();a.setValue(b?1:0)}else{a.hide()}},toggleMode:function(){var a=this;if(!a.isMultiTouch()){a.setZoomOnPanGesture(!a.getZoomOnPanGesture())}},applyModeToggleButton:function(c,b){var d=this,a=Ext.factory(c,"Ext.button.Segmented",b);if(!a&&b){b.destroy()}if(a&&!b){a.addListener("toggle",function(e){d.setZoomOnPanGesture(e.getValue()===1)})}return a},getGestures:function(){var c=this,e={},d=c.getPanGesture(),b=c.getZoomGesture(),a=Ext.supports.Touch;e[b]="onZoomGestureMove";e[b+"start"]="onZoomGestureStart";e[b+"end"]="onZoomGestureEnd";e[d]="onPanGestureMove";e[d+"start"]="onPanGestureStart";e[d+"end"]="onPanGestureEnd";e.doubletap="onDoubleTap";return e},onDoubleTap:function(h){var f=this,c=f.getChart(),g=c.getAxes(),b,a,d;for(a=0,d=g.length;a<d;a++){b=g[a];b.setVisibleRange([0,1])}c.redraw()},onPanGestureStart:function(d){if(!d||!d.touches||d.touches.length<2){var b=this,a=b.getChart().getInnerRect(),c=b.getChart().element.getXY();b.startX=d.getX()-c[0]-a[0];b.startY=d.getY()-c[1]-a[1];b.oldVisibleRanges=null;b.hideLabels();b.getChart().suspendThicknessChanged();b.lockEvents(b.getPanGesture());return false}},onPanGestureMove:function(d){var b=this;if(b.getLocks()[b.getPanGesture()]===b){var a=b.getChart().getInnerRect(),c=b.getChart().element.getXY();if(b.getZoomOnPanGesture()){b.transformAxesBy(b.getZoomableAxes(d),0,0,(d.getX()-c[0]-a[0])/b.startX,b.startY/(d.getY()-c[1]-a[1]))}else{b.transformAxesBy(b.getPannableAxes(d),d.getX()-c[0]-a[0]-b.startX,d.getY()-c[1]-a[1]-b.startY,1,1)}b.sync();return false}},onPanGestureEnd:function(b){var a=this,c=a.getPanGesture();if(a.getLocks()[c]===a){a.getChart().resumeThicknessChanged();a.showLabels();a.sync();a.unlockEvents(c);return false}},onZoomGestureStart:function(b){if(b.touches&&b.touches.length===2){var c=this,i=c.getChart().element.getXY(),f=c.getChart().getInnerRect(),h=i[0]+f[0],d=i[1]+f[1],j=[b.touches[0].point.x-h,b.touches[0].point.y-d,b.touches[1].point.x-h,b.touches[1].point.y-d],g=Math.max(44,Math.abs(j[2]-j[0])),a=Math.max(44,Math.abs(j[3]-j[1]));c.getChart().suspendThicknessChanged();c.lastZoomDistances=[g,a];c.lastPoints=j;c.oldVisibleRanges=null;c.hideLabels();c.lockEvents(c.getZoomGesture());return false}},onZoomGestureMove:function(d){var f=this;if(f.getLocks()[f.getZoomGesture()]===f){var i=f.getChart().getInnerRect(),n=f.getChart().element.getXY(),k=n[0]+i[0],h=n[1]+i[1],o=Math.abs,c=f.lastPoints,m=[d.touches[0].point.x-k,d.touches[0].point.y-h,d.touches[1].point.x-k,d.touches[1].point.y-h],g=Math.max(44,o(m[2]-m[0])),b=Math.max(44,o(m[3]-m[1])),a=this.lastZoomDistances||[g,b],l=g/a[0],j=b/a[1];f.transformAxesBy(f.getZoomableAxes(d),i[2]*(l-1)/2+m[2]-c[2]*l,i[3]*(j-1)/2+m[3]-c[3]*j,l,j);f.sync();return false}},onZoomGestureEnd:function(c){var b=this,a=b.getZoomGesture();if(b.getLocks()[a]===b){b.getChart().resumeThicknessChanged();b.showLabels();b.sync();b.unlockEvents(a);return false}},hideLabels:function(){if(this.getHideLabelInGesture()){this.eachInteractiveAxes(function(a){a.hideLabels()})}},showLabels:function(){if(this.getHideLabelInGesture()){this.eachInteractiveAxes(function(a){a.showLabels()})}},isEventOnAxis:function(c,a){var b=a.getSurface().getRect();return b[0]<=c.getX()&&c.getX()<=b[0]+b[2]&&b[1]<=c.getY()&&c.getY()<=b[1]+b[3]},getPannableAxes:function(d){var h=this,a=h.getAxes(),f=h.getChart().getAxes(),c,g=f.length,k=[],j=false,b;if(d){for(c=0;c<g;c++){if(this.isEventOnAxis(d,f[c])){j=true;break}}}for(c=0;c<g;c++){b=a[f[c].getPosition()];if(b&&b.allowPan!==false&&(!j||this.isEventOnAxis(d,f[c]))){k.push(f[c])}}return k},getZoomableAxes:function(f){var j=this,a=j.getAxes(),g=j.getChart().getAxes(),l=[],d,h=g.length,c,k=false,b;if(f){for(d=0;d<h;d++){if(this.isEventOnAxis(f,g[d])){k=true;break}}}for(d=0;d<h;d++){c=g[d];b=a[c.getPosition()];if(b&&b.allowZoom!==false&&(!k||this.isEventOnAxis(f,c))){l.push(c)}}return l},eachInteractiveAxes:function(c){var d=this,b=d.getAxes(),e=d.getChart().getAxes();for(var a=0;a<e.length;a++){if(b[e[a].getPosition()]){if(false===c.call(this,e[a])){return}}}},transformAxesBy:function(d,j,g,h,e){var f=this.getChart().getInnerRect(),a=this.getAxes(),k,b=this.oldVisibleRanges,l=false;if(!b){this.oldVisibleRanges=b={};this.eachInteractiveAxes(function(i){b[i.getId()]=i.getVisibleRange()})}if(!f){return}for(var c=0;c<d.length;c++){k=a[d[c].getPosition()];l=this.transformAxisBy(d[c],b[d[c].getId()],j,g,h,e,this.minZoom||k.minZoom,this.maxZoom||k.maxZoom)||l}return l},transformAxisBy:function(c,o,r,q,k,i,h,m){var s=this,b=o[1]-o[0],l=c.getVisibleRange(),g=h||s.getMinZoom()||c.config.minZoom,j=m||s.getMaxZoom()||c.config.maxZoom,a=s.getChart().getInnerRect(),f,p;if(!a){return}var d=c.isSide(),e=d?a[3]:a[2],n=d?-q:r;b/=d?i:k;if(b<0){b=-b}if(b*g>1){b=1}if(b*j<1){b=1/j}f=o[0];p=o[1];l=l[1]-l[0];if(b===l&&l===1){return}c.setVisibleRange([(o[0]+o[1]-b)*0.5-n/e*b,(o[0]+o[1]+b)*0.5-n/e*b]);return(Math.abs(f-c.getVisibleRange()[0])>1e-10||Math.abs(p-c.getVisibleRange()[1])>1e-10)},destroy:function(){this.setModeToggleButton(null);this.callParent()}});Ext.define("Ext.chart.interactions.Rotate",{extend:"Ext.chart.interactions.Abstract",type:"rotate",alias:"interaction.rotate",config:{gesture:"rotate",gestures:{rotate:"onRotate",rotateend:"onRotate",dragstart:"onGestureStart",drag:"onGesture",dragend:"onGestureEnd"},rotation:0},oldRotations:null,getAngle:function(f){var c=this,b=c.getChart(),d=b.getEventXY(f),a=b.getCenter();return Math.atan2(d[1]-a[1],d[0]-a[0])},getRadius:function(a){return this.getChart().getRadius()},getEventRadius:function(h){var f=this,d=f.getChart(),g=d.getEventXY(h),a=d.getCenter(),c=g[0]-a[0],b=g[1]-a[1];return Math.sqrt(c*c+b*b)},onGestureStart:function(d){var c=this,b=c.getRadius(d),a=c.getEventRadius(d);if(b>=a){c.lockEvents("drag");c.angle=c.getAngle(d);c.oldRotations={};return false}},onGesture:function(b){var a=this,c=a.getAngle(b)-a.angle;if(a.getLocks().drag===a){a.doRotateTo(c,true);return false}},doRotateTo:function(d,a,b){var n=this,l=n.getChart(),k=l.getAxes(),f=l.getSeries(),m=n.oldRotations,c,j,g,e,h;if(!b){l.suspendAnimation()}for(e=0,h=k.length;e<h;e++){c=k[e];g=m[c.getId()]||(m[c.getId()]=c.getRotation());c.setRotation(d+(a?g:0))}for(e=0,h=f.length;e<h;e++){j=f[e];g=m[j.getId()]||(m[j.getId()]=j.getRotation());j.setRotation(d+(a?g:0))}n.setRotation(d+(a?g:0));n.fireEvent("rotate",n,n.getRotation());n.sync();if(!b){l.resumeAnimation()}},rotateTo:function(c,b,a){this.doRotateTo(c,b,a);this.oldRotations={}},onGestureEnd:function(b){var a=this;if(a.getLocks().drag===a){a.onGesture(b);a.unlockEvents("drag");a.fireEvent("rotationEnd",a,a.getRotation());return false}},onRotate:function(a){}});Ext.define("Ext.chart.interactions.RotatePie3D",{extend:"Ext.chart.interactions.Rotate",type:"rotatePie3d",alias:"interaction.rotatePie3d",getAngle:function(g){var a=this.getChart(),f=a.getInherited().rtl,d=f?-1:1,h=g.getXY(),c=a.element.getXY(),b=a.getMainRect();return d*Math.atan2(h[1]-c[1]-b[3]*0.5,h[0]-c[0]-b[2]*0.5)},getRadius:function(j){var f=this.getChart(),a=f.getRadius(),d=f.getSeries(),h=d.length,c=0,b,g;for(;c<h;c++){b=d[c];if(b.isPie3D){g=b.getRadius();if(g>a){a=g}}}return a}});Ext.define("Ext.chart.plugin.ItemEvents",{extend:"Ext.plugin.Abstract",alias:"plugin.chartitemevents",moveEvents:false,mouseMoveEvents:{mousemove:true,mouseover:true,mouseout:true},itemMouseMoveEvents:{itemmousemove:true,itemmouseover:true,itemmouseout:true},init:function(b){var a="handleEvent";this.chart=b;b.addElementListener({click:a,dblclick:a,mousedown:a,mousemove:a,mouseup:a,mouseover:a,mouseout:a,priority:1001,scope:this})},hasItemMouseMoveListeners:function(){var b=this.chart.hasListeners,a;for(a in this.itemMouseMoveEvents){if(a in b){return true}}return false},handleEvent:function(g){var d=this,a=d.chart,h=g.type in d.mouseMoveEvents,c=d.lastItem,f,b;if(h&&!d.hasItemMouseMoveListeners()&&!d.moveEvents){return}f=a.getEventXY(g);b=a.getItemForPoint(f[0],f[1]);if(h&&!Ext.Object.equals(b,c)){if(c){a.fireEvent("itemmouseout",a,c,g);c.series.fireEvent("itemmouseout",c.series,c,g)}if(b){a.fireEvent("itemmouseover",a,b,g);b.series.fireEvent("itemmouseover",b.series,b,g)}}if(b){a.fireEvent("item"+g.type,a,b,g);b.series.fireEvent("item"+g.type,b.series,b,g)}d.lastItem=b}});Ext.define("Ext.chart.series.Cartesian",{extend:"Ext.chart.series.Series",config:{xField:null,yField:null,xAxis:null,yAxis:null},directions:["X","Y"],fieldCategoryX:["X"],fieldCategoryY:["Y"],applyXAxis:function(a,b){return this.getChart().getAxis(a)||b},applyYAxis:function(a,b){return this.getChart().getAxis(a)||b},updateXAxis:function(a){a.processData(this)},updateYAxis:function(a){a.processData(this)},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},getItemForPoint:function(a,g){if(this.getSprites()){var f=this,d=f.getSprites()[0],b=f.getStore(),e,c;if(f.getHidden()){return null}if(d){c=d.getIndexNearPoint(a,g);if(c!==-1){e={series:f,category:f.getItemInstancing()?"items":"markers",index:c,record:b.getData().items[c],field:f.getYField(),sprite:d};return e}}}},createSprite:function(){var c=this,a=c.callParent(),b=c.getChart(),d=c.getXAxis();a.setAttributes({flipXY:b.getFlipXY(),xAxis:d});if(a.setAggregator&&d&&d.getAggregator){if(d.getAggregator){a.setAggregator({strategy:d.getAggregator()})}else{a.setAggregator({})}}return a},getSprites:function(){var d=this,c=this.getChart(),e=d.getAnimation()||c&&c.getAnimation(),b=d.getItemInstancing(),f=d.sprites,a;if(!c){return[]}if(!f.length){a=d.createSprite()}else{a=f[0]}if(e){if(b){a.itemsMarker.getTemplate().setAnimation(e)}a.setAnimation(e)}return f},provideLegendInfo:function(d){var b=this,a=b.getSubStyleWithTheme(),c=a.fillStyle;if(Ext.isArray(c)){c=c[0]}d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})},getXRange:function(){return[this.dataRange[0],this.dataRange[2]]},getYRange:function(){return[this.dataRange[1],this.dataRange[3]]}});Ext.define("Ext.chart.series.StackedCartesian",{extend:"Ext.chart.series.Cartesian",config:{stacked:true,splitStacks:true,fullStack:false,fullStackTotal:100,hidden:[]},spriteAnimationCount:0,themeColorCount:function(){var b=this,a=b.getYField();return Ext.isArray(a)?a.length:1},updateStacked:function(){this.processData()},updateSplitStacks:function(){this.processData()},coordinateY:function(){return this.coordinateStacked("Y",1,2)},coordinateStacked:function(D,e,m){var F=this,f=F.getStore(),r=f.getData().items,B=r.length,c=F["get"+D+"Axis"](),x=F.getHidden(),a=F.getSplitStacks(),z=F.getFullStack(),l=F.getFullStackTotal(),p={min:0,max:0},n=F["fieldCategory"+D],C=[],o=[],E=[],h,A=F.getStacked(),g=F.getSprites(),q=[],w,v,u,s,H,y,b,d,G,t;if(!g.length){return}for(w=0;w<n.length;w++){d=n[w];s=F.getFields([d]);H=s.length;for(v=0;v<B;v++){C[v]=0;o[v]=0;E[v]=0}for(v=0;v<H;v++){if(!x[v]){q[v]=F.coordinateData(r,s[v],c)}}if(A&&z){y=[];if(a){b=[]}for(v=0;v<B;v++){y[v]=0;if(a){b[v]=0}for(u=0;u<H;u++){G=q[u];if(!G){continue}G=G[v];if(G>=0||!a){y[v]+=G}else{if(G<0){b[v]+=G}}}}}for(v=0;v<H;v++){t={};if(x[v]){t["dataStart"+d]=C;t["data"+d]=C;g[v].setAttributes(t);continue}G=q[v];if(A){h=[];for(u=0;u<B;u++){if(!G[u]){G[u]=0}if(G[u]>=0||!a){if(z&&y[u]){G[u]*=l/y[u]}C[u]=o[u];o[u]+=G[u];h[u]=o[u]}else{if(z&&b[u]){G[u]*=l/b[u]}C[u]=E[u];E[u]+=G[u];h[u]=E[u]}}t["dataStart"+d]=C;t["data"+d]=h;F.getRangeOfData(C,p);F.getRangeOfData(h,p)}else{t["dataStart"+d]=C;t["data"+d]=G;F.getRangeOfData(G,p)}g[v].setAttributes(t)}}F.dataRange[e]=p.min;F.dataRange[e+m]=p.max;t={};t["dataMin"+D]=p.min;t["dataMax"+D]=p.max;for(w=0;w<g.length;w++){g[w].setAttributes(t)}},getFields:function(f){var e=this,a=[],c,b,d;for(b=0,d=f.length;b<d;b++){c=e["get"+f[b]+"Field"]();if(Ext.isArray(c)){a.push.apply(a,c)}else{a.push(c)}}return a},updateLabelOverflowPadding:function(a){this.getLabel().setAttributes({labelOverflowPadding:a})},getSprites:function(){var k=this,j=k.getChart(),c=k.getAnimation()||j&&j.getAnimation(),f=k.getFields(k.fieldCategoryY),b=k.getItemInstancing(),h=k.sprites,l,e=k.getHidden(),g=false,d,a=f.length;if(!j){return[]}for(d=0;d<a;d++){l=h[d];if(!l){l=k.createSprite();l.setAttributes({zIndex:-d});l.setField(f[d]);g=true;e.push(false);if(b){l.itemsMarker.getTemplate().setAttributes(k.getStyleByIndex(d))}else{l.setAttributes(k.getStyleByIndex(d))}}if(c){if(b){l.itemsMarker.getTemplate().setAnimation(c)}l.setAnimation(c)}}if(g){k.updateHidden(e)}return h},getItemForPoint:function(k,j){if(this.getSprites()){var h=this,b,g,m,a=h.getItemInstancing(),f=h.getSprites(),l=h.getStore(),c=h.getHidden(),n,d,e;for(b=0,g=f.length;b<g;b++){if(!c[b]){m=f[b];d=m.getIndexNearPoint(k,j);if(d!==-1){e=h.getYField();n={series:h,index:d,category:a?"items":"markers",record:l.getData().items[d],field:typeof e==="string"?e:e[b],sprite:m};return n}}}return null}},provideLegendInfo:function(e){var g=this,f=g.getSprites(),h=g.getTitle(),j=g.getYField(),d=g.getHidden(),k=f.length===1,b,l,c,a;for(c=0;c<f.length;c++){b=g.getStyleByIndex(c);l=b.fillStyle;if(h){if(Ext.isArray(h)){a=h[c]}else{if(k){a=h}}}else{if(Ext.isArray(j)){a=j[c]}else{a=g.getId()}}e.push({name:a,mark:(Ext.isObject(l)?l.stops&&l.stops[0].color:l)||b.strokeStyle||"black",disabled:d[c],series:g.getId(),index:c})}},onSpriteAnimationStart:function(a){this.spriteAnimationCount++;if(this.spriteAnimationCount===1){this.fireEvent("animationstart")}},onSpriteAnimationEnd:function(a){this.spriteAnimationCount--;if(this.spriteAnimationCount===0){this.fireEvent("animationend")}}});Ext.define("Ext.chart.series.sprite.Series",{extend:"Ext.draw.sprite.Sprite",mixins:{markerHolder:"Ext.chart.MarkerHolder"},inheritableStatics:{def:{processors:{dataMinX:"number",dataMaxX:"number",dataMinY:"number",dataMaxY:"number",rangeX:"data",rangeY:"data",dataX:"data",dataY:"data"},defaults:{dataMinX:0,dataMaxX:1,dataMinY:0,dataMaxY:1,rangeX:null,rangeY:null,dataX:null,dataY:null},triggers:{dataX:"bbox",dataY:"bbox",dataMinX:"bbox",dataMaxX:"bbox",dataMinY:"bbox",dataMaxY:"bbox"}}},config:{store:null,series:null,field:null}});Ext.define("Ext.chart.series.sprite.Cartesian",{extend:"Ext.chart.series.sprite.Series",inheritableStatics:{def:{processors:{labels:"default",labelOverflowPadding:"number",selectionTolerance:"number",flipXY:"bool",renderer:"default",visibleMinX:"number",visibleMinY:"number",visibleMaxX:"number",visibleMaxY:"number",innerWidth:"number",innerHeight:"number"},defaults:{labels:null,labelOverflowPadding:10,selectionTolerance:20,flipXY:false,renderer:null,transformFillStroke:false,visibleMinX:0,visibleMinY:0,visibleMaxX:1,visibleMaxY:1,innerWidth:1,innerHeight:1},triggers:{dataX:"dataX,bbox",dataY:"dataY,bbox",visibleMinX:"panzoom",visibleMinY:"panzoom",visibleMaxX:"panzoom",visibleMaxY:"panzoom",innerWidth:"panzoom",innerHeight:"panzoom"},updaters:{dataX:function(a){this.processDataX();this.scheduleUpdater(a,"dataY",["dataY"])},dataY:function(){this.processDataY()},panzoom:function(c){var e=c.visibleMaxX-c.visibleMinX,d=c.visibleMaxY-c.visibleMinY,b=c.flipXY?c.innerHeight:c.innerWidth,g=!c.flipXY?c.innerHeight:c.innerWidth,a=this.getSurface(),f=a?a.getInherited().rtl:false;if(f&&!c.flipXY){c.translationX=b+c.visibleMinX*b/e}else{c.translationX=-c.visibleMinX*b/e}c.translationY=-c.visibleMinY*g/d;c.scalingX=(f&&!c.flipXY?-1:1)*b/e;c.scalingY=g/d;c.scalingCenterX=0;c.scalingCenterY=0;this.applyTransformations(true)}}}},processDataY:Ext.emptyFn,processDataX:Ext.emptyFn,updatePlainBBox:function(b){var a=this.attr;b.x=a.dataMinX;b.y=a.dataMinY;b.width=a.dataMaxX-a.dataMinX;b.height=a.dataMaxY-a.dataMinY},binarySearch:function(d){var b=this.attr.dataX,f=0,a=b.length;if(d<=b[0]){return f}if(d>=b[a-1]){return a-1}while(f+1<a){var c=(f+a)>>1,e=b[c];if(e===d){return c}else{if(e<d){f=c}else{a=c}}}return f},render:function(b,c,g){var f=this,a=f.attr,e=a.inverseMatrix.clone();e.appendMatrix(b.inverseMatrix);if(a.dataX===null||a.dataX===undefined){return}if(a.dataY===null||a.dataY===undefined){return}if(e.getXX()*e.getYX()||e.getXY()*e.getYY()){console.log("Cartesian Series sprite does not support rotation/sheering");return}var d=e.transformList([[g[0]-1,g[3]+1],[g[0]+g[2]+1,-1]]);d=d[0].concat(d[1]);f.renderClipped(b,c,d,g)},renderClipped:Ext.emptyFn,getIndexNearPoint:function(f,e){var w=this,q=w.attr.matrix,h=w.attr.dataX,g=w.attr.dataY,k=w.attr.selectionTolerance,t,r,c=-1,j=q.clone().prependMatrix(w.surfaceMatrix).inverse(),u=j.transformPoint([f,e]),b=j.transformPoint([f-k,e-k]),n=j.transformPoint([f+k,e+k]),a=Math.min(b[0],n[0]),s=Math.max(b[0],n[0]),l=Math.min(b[1],n[1]),d=Math.max(b[1],n[1]),m,v,o,p;for(o=0,p=h.length;o<p;o++){m=h[o];v=g[o];if(m>a&&m<s&&v>l&&v<d){if(c===-1||(Math.abs(m-u[0])<t)&&(Math.abs(v-u[1])<r)){t=Math.abs(m-u[0]);r=Math.abs(v-u[1]);c=o}}}return c}});Ext.define("Ext.chart.series.sprite.StackedCartesian",{extend:"Ext.chart.series.sprite.Cartesian",inheritableStatics:{def:{processors:{groupCount:"number",groupOffset:"number",dataStartY:"data"},defaults:{selectionTolerance:20,groupCount:1,groupOffset:0,dataStartY:null},triggers:{dataStartY:"dataY,bbox"}}},getIndexNearPoint:function(e,d){var o=this,q=o.attr.matrix,h=o.attr.dataX,f=o.attr.dataY,u=o.attr.dataStartY,l=o.attr.selectionTolerance,s=0.5,r=Infinity,b=-1,k=q.clone().prependMatrix(this.surfaceMatrix).inverse(),t=k.transformPoint([e,d]),a=k.transformPoint([e-l,d-l]),n=k.transformPoint([e+l,d+l]),m=Math.min(a[1],n[1]),c=Math.max(a[1],n[1]),j,g;for(var p=0;p<h.length;p++){if(Math.min(u[p],f[p])<=c&&m<=Math.max(u[p],f[p])){j=Math.abs(h[p]-t[0]);g=Math.max(-Math.min(f[p]-t[1],t[1]-u[p]),0);if(j<s&&g<=r){s=j;r=g;b=p}}}return b}});Ext.define("Ext.chart.series.sprite.Area",{alias:"sprite.areaSeries",extend:"Ext.chart.series.sprite.StackedCartesian",inheritableStatics:{def:{processors:{step:"bool"},defaults:{step:false}}},renderClipped:function(q,s,A){var B=this,p=B.attr,l=p.dataX,j=p.dataY,C=p.dataStartY,t=p.matrix,h,g,v,f,d,z,w,e=t.elements[0],m=t.elements[4],o=t.elements[3],k=t.elements[5],c=B.surfaceMatrix,n={},r=Math.min(A[0],A[2]),u=Math.max(A[0],A[2]),b=Math.max(0,this.binarySearch(r)),a=Math.min(l.length-1,this.binarySearch(u)+1);s.beginPath();z=l[b]*e+m;w=j[b]*o+k;s.moveTo(z,w);if(p.step){d=w;for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,d);s.lineTo(h,d=g)}}else{for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,g)}}if(C){if(p.step){f=l[a]*e+m;for(v=a;v>=b;v--){h=l[v]*e+m;g=C[v]*o+k;s.lineTo(f,g);s.lineTo(f=h,g)}}else{for(v=a;v>=b;v--){h=l[v]*e+m;g=C[v]*o+k;s.lineTo(h,g)}}}else{s.lineTo(l[a]*e+m,g);s.lineTo(l[a]*e+m,k);s.lineTo(z,k);s.lineTo(z,j[v]*o+k)}if(p.transformFillStroke){p.matrix.toContext(s)}s.fill();if(p.transformFillStroke){p.inverseMatrix.toContext(s)}s.beginPath();s.moveTo(z,w);if(p.step){for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,d);s.lineTo(h,d=g);n.translationX=c.x(h,g);n.translationY=c.y(h,g);B.putMarker("markers",n,v,!p.renderer)}}else{for(v=b;v<=a;v++){h=l[v]*e+m;g=j[v]*o+k;s.lineTo(h,g);n.translationX=c.x(h,g);n.translationY=c.y(h,g);B.putMarker("markers",n,v,!p.renderer)}}if(p.transformFillStroke){p.matrix.toContext(s)}s.stroke()}});Ext.define("Ext.chart.series.Area",{extend:"Ext.chart.series.StackedCartesian",alias:"series.area",type:"area",seriesType:"areaSeries",requires:["Ext.chart.series.sprite.Area"],config:{splitStacks:false}});Ext.define("Ext.chart.series.sprite.Bar",{alias:"sprite.barSeries",extend:"Ext.chart.series.sprite.StackedCartesian",inheritableStatics:{def:{processors:{minBarWidth:"number",maxBarWidth:"number",minGapWidth:"number",radius:"number",inGroupGapWidth:"number"},defaults:{minBarWidth:2,maxBarWidth:100,minGapWidth:5,inGroupGapWidth:3,radius:0}}},drawLabel:function(k,i,s,h,o){var q=this,n=q.attr,f=q.getMarker("labels"),d=f.getTemplate(),l=q.labelCfg||(q.labelCfg={}),c=q.surfaceMatrix,j=n.labelOverflowPadding,b=d.attr.display,m=d.attr.orientation,g,e,a,r,t,p;l.x=c.x(i,h);l.y=c.y(i,h);if(!n.flipXY){l.rotationRads=-Math.PI*0.5}else{l.rotationRads=0}l.calloutVertical=!n.flipXY;switch(m){case"horizontal":l.rotationRads=0;l.calloutVertical=false;break;case"vertical":l.rotationRads=-Math.PI*0.5;l.calloutVertical=true;break}l.text=k;if(d.attr.renderer){p=[k,f,l,{store:q.getStore()},o];r=Ext.callback(d.attr.renderer,null,p,0,q.getSeries());if(typeof r==="string"){l.text=r}else{if(typeof r==="object"){if("text" in r){l.text=r.text}t=true}}}a=q.getMarkerBBox("labels",o,true);if(!a){q.putMarker("labels",l,o);a=q.getMarkerBBox("labels",o,true)}e=(a.width/2+j);if(s>h){e=-e}if((m==="horizontal"&&n.flipXY)||(m==="vertical"&&!n.flipXY)||!m){g=(b==="insideStart")?s+e:h-e}else{g=(b==="insideStart")?s+j*2:h-j*2}l.x=c.x(i,g);l.y=c.y(i,g);g=(b==="insideStart")?s-e:h+e;l.calloutPlaceX=c.x(i,g);l.calloutPlaceY=c.y(i,g);g=(b==="insideStart")?s:h;l.calloutStartX=c.x(i,g);l.calloutStartY=c.y(i,g);if(s>h){e=-e}if(Math.abs(h-s)<=e*2||b==="outside"){l.callout=1}else{l.callout=0}if(t){Ext.apply(l,r)}q.putMarker("labels",l,o)},drawBar:function(l,b,d,c,h,k,a,e){var g=this,j={},f=g.attr.renderer,i;j.x=c;j.y=h;j.width=k-c;j.height=a-h;j.radius=g.attr.radius;if(f){i=Ext.callback(f,null,[g,j,{store:g.getStore()},e],0,g.getSeries());Ext.apply(j,i)}g.putMarker("items",j,e,!f)},renderClipped:function(G,u,F,C){if(this.cleanRedraw){return}var q=this,o=q.attr,w=o.dataX,v=o.dataY,H=o.labels,n=o.dataStartY,m=o.groupCount,E=o.groupOffset-(m-1)*0.5,z=o.inGroupGapWidth,t=u.lineWidth,D=o.matrix,B=D.elements[0],j=D.elements[3],e=D.elements[4],d=G.roundPixel(D.elements[5])-1,J=(B<0?-1:1)*B-o.minGapWidth,k=(Math.min(J,o.maxBarWidth)-z*(m-1))/m,A=G.roundPixel(Math.max(o.minBarWidth,k)),c=q.surfaceMatrix,g,I,b,h,K,a,l=0.5*o.lineWidth,L=Math.min(F[0],F[2]),x=Math.max(F[0],F[2]),y=Math.max(0,Math.floor(L)),p=Math.min(w.length-1,Math.ceil(x)),f=H&&q.getMarker("labels"),s,r;for(K=y;K<=p;K++){s=n?n[K]:0;r=v[K];a=w[K]*B+e+E*(A+z);g=G.roundPixel(a-A/2)+l;h=G.roundPixel(r*j+d+t);I=G.roundPixel(a+A/2)-l;b=G.roundPixel(s*j+d+t);q.drawBar(u,G,F,g,h-l,I,b-l,K);if(f&&H[K]!=null){q.drawLabel(H[K],a,b,h,K)}q.putMarker("markers",{translationX:c.x(a,h),translationY:c.y(a,h)},K,true)}},getIndexNearPoint:function(l,k){var m=this,g=m.attr,h=g.dataX,a=m.getSurface(),b=a.getRect()||[0,0,0,0],j=b[3],e,d,c,n,f=-1;if(g.flipXY){e=j-k;if(a.getInherited().rtl){d=b[2]-l}else{d=l}}else{e=l;d=j-k}for(c=0;c<h.length;c++){n=m.getMarkerBBox("items",c);if(Ext.draw.Draw.isPointInBBox(e,d,n)){f=c;break}}return f}});Ext.define("Ext.chart.series.Bar",{extend:"Ext.chart.series.StackedCartesian",alias:"series.bar",type:"bar",seriesType:"barSeries",requires:["Ext.chart.series.sprite.Bar","Ext.draw.sprite.Rect"],config:{itemInstancing:{type:"rect",fx:{customDurations:{x:0,y:0,width:0,height:0,radius:0}}}},getItemForPoint:function(a,f){if(this.getSprites()){var d=this,c=d.getChart(),e=c.getInnerPadding(),b=c.getInherited().rtl;arguments[0]=a+(b?e.right:-e.left);arguments[1]=f+e.bottom;return d.callParent(arguments)}},updateXAxis:function(a){a.setLabelInSpan(true);this.callParent(arguments)},updateHidden:function(a){this.callParent(arguments);this.updateStacked()},updateStacked:function(c){var e=this,g=e.getSprites(),d=g.length,f=[],a={},b;for(b=0;b<d;b++){if(!g[b].attr.hidden){f.push(g[b])}}d=f.length;if(e.getStacked()){a.groupCount=1;a.groupOffset=0;for(b=0;b<d;b++){f[b].setAttributes(a)}}else{a.groupCount=f.length;for(b=0;b<d;b++){a.groupOffset=b;f[b].setAttributes(a)}}e.callParent(arguments)}});Ext.define("Ext.chart.series.sprite.Bar3D",{extend:"Ext.chart.series.sprite.Bar",alias:"sprite.bar3dSeries",requires:["Ext.draw.gradient.Linear"],inheritableStatics:{def:{processors:{depthWidthRatio:"number",saturationFactor:"number",brightnessFactor:"number",colorSpread:"number"},defaults:{depthWidthRatio:1/3,saturationFactor:1,brightnessFactor:1,colorSpread:1,transformFillStroke:true},triggers:{groupCount:"panzoom"},updaters:{panzoom:function(c){var g=this,e=c.visibleMaxX-c.visibleMinX,d=c.visibleMaxY-c.visibleMinY,b=c.flipXY?c.innerHeight:c.innerWidth,h=!c.flipXY?c.innerHeight:c.innerWidth,a=g.getSurface(),f=a?a.getInherited().rtl:false;if(f&&!c.flipXY){c.translationX=b+c.visibleMinX*b/e}else{c.translationX=-c.visibleMinX*b/e}c.translationY=-c.visibleMinY*(h-g.depth)/d;c.scalingX=(f&&!c.flipXY?-1:1)*b/e;c.scalingY=(h-g.depth)/d;c.scalingCenterX=0;c.scalingCenterY=0;g.applyTransformations(true)}}}},config:{showStroke:false},depth:0,drawBar:function(p,b,d,c,l,o,a,h){var k=this,i=k.attr,n={},j=i.renderer,m,g,f,e;n.x=(c+o)*0.5;n.y=l;n.width=(o-c)*0.75;n.height=a-l;n.depth=g=n.width*i.depthWidthRatio;n.orientation=i.flipXY?"horizontal":"vertical";n.saturationFactor=i.saturationFactor;n.brightnessFactor=i.brightnessFactor;n.colorSpread=i.colorSpread;if(g!==k.depth){k.depth=g;f=k.getSeries();f.fireEvent("depthchange",f,g)}if(j){e=[k,n,{store:k.getStore()},h];m=Ext.callback(j,null,e,0,k.getSeries());Ext.apply(n,m)}k.putMarker("items",n,h,!j)}});Ext.define("Ext.chart.series.sprite.Box",{extend:"Ext.draw.sprite.Sprite",alias:"sprite.box",type:"box",inheritableStatics:{def:{processors:{x:"number",y:"number",width:"number",height:"number",depth:"number",orientation:"enums(vertical,horizontal)",showStroke:"bool",saturationFactor:"number",brightnessFactor:"number",colorSpread:"number"},triggers:{x:"bbox",y:"bbox",width:"bbox",height:"bbox",depth:"bbox",orientation:"bbox"},defaults:{x:0,y:0,width:8,height:8,depth:8,orientation:"vertical",showStroke:false,saturationFactor:1,brightnessFactor:1,colorSpread:1,lineJoin:"bevel"}}},constructor:function(a){this.callParent([a]);this.topGradient=new Ext.draw.gradient.Linear({});this.rightGradient=new Ext.draw.gradient.Linear({});this.frontGradient=new Ext.draw.gradient.Linear({})},updatePlainBBox:function(d){var c=this.attr,b=c.x,g=c.y,e=c.width,a=c.height,f=c.depth;d.x=b-e*0.5;d.width=e+f;if(a>0){d.y=g;d.height=a+f}else{d.y=g+f;d.height=a-f}},render:function(l,m){var u=this,k=u.attr,r=k.x,j=k.y,f=j+k.height,i=j<f,e=k.width*0.5,v=k.depth,d=k.orientation==="horizontal",g=k.globalAlpha<1,c=k.fillStyle,n=Ext.draw.Color.create(c.isGradient?c.getStops()[0].color:c),h=k.saturationFactor,o=k.brightnessFactor,t=k.colorSpread,b=n.getHSV(),a={},s,q,p;if(!k.showStroke){m.strokeStyle=Ext.draw.Color.RGBA_NONE}if(i){p=j;j=f;f=p}u.topGradient.setDegrees(d?0:80);u.topGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5+t*0.1)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5-t*0.11)*o,0,1))}]);u.rightGradient.setDegrees(d?45:90);u.rightGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*h,0,1),Ext.Number.constrain((0.5-t*0.14)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1+t*0.4)*h,0,1),Ext.Number.constrain((0.5-t*0.32)*o,0,1))}]);if(d){u.frontGradient.setDegrees(0)}else{u.frontGradient.setRadians(Math.atan2(j-f,e*2))}u.frontGradient.setStops([{offset:0,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1-t*0.1)*h,0,1),Ext.Number.constrain((0.5+t*0.1)*o,0,1))},{offset:1,color:Ext.draw.Color.fromHSV(b[0],Ext.Number.constrain(b[1]*(1+t*0.1)*h,0,1),Ext.Number.constrain((0.5-t*0.23)*o,0,1))}]);if(g||i){m.beginPath();m.moveTo(r-e,f);m.lineTo(r-e+v,f+v);m.lineTo(r+e+v,f+v);m.lineTo(r+e,f);m.closePath();a.x=r-e;a.y=j;a.width=e+v;a.height=v;m.fillStyle=(d?u.rightGradient:u.topGradient).generateGradient(m,a);m.fillStroke(k)}if(g){m.beginPath();m.moveTo(r-e,j);m.lineTo(r-e+v,j+v);m.lineTo(r-e+v,f+v);m.lineTo(r-e,f);m.closePath();a.x=r+e;a.y=f;a.width=v;a.height=j+v-f;m.fillStyle=(d?u.topGradient:u.rightGradient).generateGradient(m,a);m.fillStroke(k)}q=l.roundPixel(j);m.beginPath();m.moveTo(r-e,q);m.lineTo(r-e+v,j+v);m.lineTo(r+e+v,j+v);m.lineTo(r+e,q);m.closePath();a.x=r-e;a.y=j;a.width=e+v;a.height=v;m.fillStyle=(d?u.rightGradient:u.topGradient).generateGradient(m,a);m.fillStroke(k);s=l.roundPixel(r+e);m.beginPath();m.moveTo(s,l.roundPixel(j));m.lineTo(r+e+v,j+v);m.lineTo(r+e+v,f+v);m.lineTo(s,f);m.closePath();a.x=r+e;a.y=f;a.width=v;a.height=j+v-f;m.fillStyle=(d?u.topGradient:u.rightGradient).generateGradient(m,a);m.fillStroke(k);s=l.roundPixel(r+e);q=l.roundPixel(j);m.beginPath();m.moveTo(r-e,f);m.lineTo(r-e,q);m.lineTo(s,q);m.lineTo(s,f);m.closePath();a.x=r-e;a.y=f;a.width=e*2;a.height=j-f;m.fillStyle=u.frontGradient.generateGradient(m,a);m.fillStroke(k)}});Ext.define("Ext.chart.series.Bar3D",{extend:"Ext.chart.series.Bar",requires:["Ext.chart.series.sprite.Bar3D","Ext.chart.series.sprite.Box"],alias:"series.bar3d",type:"bar3d",seriesType:"bar3dSeries",config:{itemInstancing:{type:"box",fx:{customDurations:{x:0,y:0,width:0,height:0,depth:0}}},highlightCfg:{opacity:0.8}},getSprites:function(){var c=this.callParent(arguments),b,d,a;for(a=0;a<c.length;a++){b=c[a];d=b.attr.zIndex;if(d<0){b.setAttributes({zIndex:-d})}if(b.setSeries){b.setSeries(this)}}return c},getDepth:function(){var a=this.getSprites()[0];return a?(a.depth||0):0},getItemForPoint:function(m,k){if(this.getSprites()){var j=this,b,o,a=j.getItemInstancing(),h=j.getSprites(),n=j.getStore(),c=j.getHidden(),g=j.getChart(),l=g.getInnerPadding(),f=g.getInherited().rtl,p,d,e;m=m+(f?l.right:-l.left);k=k+l.bottom;for(b=h.length-1;b>=0;b--){if(!c[b]){o=h[b];d=o.getIndexNearPoint(m,k);if(d!==-1){e=j.getYField();p={series:j,index:d,category:a?"items":"markers",record:n.getData().items[d],field:typeof e==="string"?e:e[b],sprite:o};return p}}}return null}}});Ext.define("Ext.draw.LimitedCache",{config:{limit:40,feeder:function(){return 0},scope:null},cache:null,constructor:function(a){this.cache={};this.cache.list=[];this.cache.tail=0;this.initConfig(a)},get:function(e){var c=this.cache,b=this.getLimit(),a=this.getFeeder(),d=this.getScope()||this;if(c[e]){return c[e].value}if(c.list[c.tail]){delete c[c.list[c.tail].cacheId]}c[e]=c.list[c.tail]={value:a.apply(d,Array.prototype.slice.call(arguments,1)),cacheId:e};c.tail++;if(c.tail===b){c.tail=0}return c[e].value},clear:function(){this.cache={};this.cache.list=[];this.cache.tail=0}});Ext.define("Ext.draw.SegmentTree",{config:{strategy:"double"},time:function(m,l,n,c,E,d,e){var f=0,o,A,s=new Date(n[m.startIdx[0]]),x=new Date(n[m.endIdx[l-1]]),D=Ext.Date,u=[[D.MILLI,1,"ms1",null],[D.MILLI,2,"ms2","ms1"],[D.MILLI,5,"ms5","ms1"],[D.MILLI,10,"ms10","ms5"],[D.MILLI,50,"ms50","ms10"],[D.MILLI,100,"ms100","ms50"],[D.MILLI,500,"ms500","ms100"],[D.SECOND,1,"s1","ms500"],[D.SECOND,10,"s10","s1"],[D.SECOND,30,"s30","s10"],[D.MINUTE,1,"mi1","s10"],[D.MINUTE,5,"mi5","mi1"],[D.MINUTE,10,"mi10","mi5"],[D.MINUTE,30,"mi30","mi10"],[D.HOUR,1,"h1","mi30"],[D.HOUR,6,"h6","h1"],[D.HOUR,12,"h12","h6"],[D.DAY,1,"d1","h12"],[D.DAY,7,"d7","d1"],[D.MONTH,1,"mo1","d1"],[D.MONTH,3,"mo3","mo1"],[D.MONTH,6,"mo6","mo3"],[D.YEAR,1,"y1","mo3"],[D.YEAR,5,"y5","y1"],[D.YEAR,10,"y10","y5"],[D.YEAR,100,"y100","y10"]],z,b,k=f,F=l,j=false,r=m.startIdx,h=m.endIdx,w=m.minIdx,C=m.maxIdx,a=m.open,y=m.close,g=m.minX,q=m.minY,p=m.maxX,B=m.maxY,v,t;for(z=0;l>f+1&&z<u.length;z++){s=new Date(n[r[0]]);b=u[z];s=D.align(s,b[0],b[1]);if(D.diff(s,x,b[0])>n.length*2*b[1]){continue}if(b[3]&&m.map["time_"+b[3]]){o=m.map["time_"+b[3]][0];A=m.map["time_"+b[3]][1]}else{o=k;A=F}f=l;t=s;j=true;r[l]=r[o];h[l]=h[o];w[l]=w[o];C[l]=C[o];a[l]=a[o];y[l]=y[o];g[l]=g[o];q[l]=q[o];p[l]=p[o];B[l]=B[o];t=Ext.Date.add(t,b[0],b[1]);for(v=o+1;v<A;v++){if(n[h[v]]<+t){h[l]=h[v];y[l]=y[v];if(B[v]>B[l]){B[l]=B[v];p[l]=p[v];C[l]=C[v]}if(q[v]<q[l]){q[l]=q[v];g[l]=g[v];w[l]=w[v]}}else{l++;r[l]=r[v];h[l]=h[v];w[l]=w[v];C[l]=C[v];a[l]=a[v];y[l]=y[v];g[l]=g[v];q[l]=q[v];p[l]=p[v];B[l]=B[v];t=Ext.Date.add(t,b[0],b[1])}}if(l>f){m.map["time_"+b[2]]=[f,l]}}},"double":function(h,u,j,a,t,b,c){var e=0,k,f=1,n,d,v,g,s,l,m,r,q,p,o;while(u>e+1){k=e;e=u;f+=f;for(n=k;n<e;n+=2){if(n===e-1){d=h.startIdx[n];v=h.endIdx[n];g=h.minIdx[n];s=h.maxIdx[n];l=h.open[n];m=h.close[n];r=h.minX[n];q=h.minY[n];p=h.maxX[n];o=h.maxY[n]}else{d=h.startIdx[n];v=h.endIdx[n+1];l=h.open[n];m=h.close[n];if(h.minY[n]<=h.minY[n+1]){g=h.minIdx[n];r=h.minX[n];q=h.minY[n]}else{g=h.minIdx[n+1];r=h.minX[n+1];q=h.minY[n+1]}if(h.maxY[n]>=h.maxY[n+1]){s=h.maxIdx[n];p=h.maxX[n];o=h.maxY[n]}else{s=h.maxIdx[n+1];p=h.maxX[n+1];o=h.maxY[n+1]}}h.startIdx[u]=d;h.endIdx[u]=v;h.minIdx[u]=g;h.maxIdx[u]=s;h.open[u]=l;h.close[u]=m;h.minX[u]=r;h.minY[u]=q;h.maxX[u]=p;h.maxY[u]=o;u++}h.map["double_"+f]=[e,u]}},none:Ext.emptyFn,aggregateData:function(h,a,r,c,d){var b=h.length,e=[],s=[],f=[],q=[],j=[],p=[],n=[],o=[],m=[],k=[],g={startIdx:e,endIdx:s,minIdx:f,maxIdx:q,open:j,minX:p,minY:n,maxX:o,maxY:m,close:k},l;for(l=0;l<b;l++){e[l]=l;s[l]=l;f[l]=l;q[l]=l;j[l]=a[l];p[l]=h[l];n[l]=c[l];o[l]=h[l];m[l]=r[l];k[l]=d[l]}g.map={original:[0,b]};if(b){this[this.getStrategy()](g,b,h,a,r,c,d)}return g},binarySearchMin:function(c,g,a,e){var b=this.dataX;if(e<=b[c.startIdx[0]]){return g}if(e>=b[c.startIdx[a-1]]){return a-1}while(g+1<a){var d=(g+a)>>1,f=b[c.startIdx[d]];if(f===e){return d}else{if(f<e){g=d}else{a=d}}}return g},binarySearchMax:function(c,g,a,e){var b=this.dataX;if(e<=b[c.endIdx[0]]){return g}if(e>=b[c.endIdx[a-1]]){return a-1}while(g+1<a){var d=(g+a)>>1,f=b[c.endIdx[d]];if(f===e){return d}else{if(f<e){g=d}else{a=d}}}return a},constructor:function(a){this.initConfig(a)},setData:function(d,a,b,c,e){if(!b){e=c=b=a}this.dataX=d;this.dataOpen=a;this.dataHigh=b;this.dataLow=c;this.dataClose=e;if(d.length===b.length&&d.length===c.length){this.cache=this.aggregateData(d,a,b,c,e)}},getAggregation:function(d,k,i){if(!this.cache){return null}var c=Infinity,g=this.dataX[this.dataX.length-1]-this.dataX[0],l=this.cache.map,m=l.original,a,e,j,b,f,h;for(a in l){e=l[a];j=e[1]-e[0]-1;b=g/j;if(i<=b&&b<c){m=e;c=b}}f=Math.max(this.binarySearchMin(this.cache,m[0],m[1],d),m[0]);h=Math.min(this.binarySearchMax(this.cache,m[0],m[1],k)+1,m[1]);return{data:this.cache,start:f,end:h}}});Ext.define("Ext.chart.series.sprite.Aggregative",{extend:"Ext.chart.series.sprite.Cartesian",requires:["Ext.draw.LimitedCache","Ext.draw.SegmentTree"],inheritableStatics:{def:{processors:{dataHigh:"data",dataLow:"data",dataClose:"data"},aliases:{dataOpen:"dataY"},defaults:{dataHigh:null,dataLow:null,dataClose:null}}},config:{aggregator:{}},applyAggregator:function(b,a){return Ext.factory(b,Ext.draw.SegmentTree,a)},constructor:function(){this.callParent(arguments)},processDataY:function(){var d=this,b=d.attr,e=b.dataHigh,a=b.dataLow,f=b.dataClose,c=b.dataY;d.callParent(arguments);if(b.dataX&&c&&c.length>0){if(e){d.getAggregator().setData(b.dataX,b.dataY,e,a,f)}else{d.getAggregator().setData(b.dataX,b.dataY)}}},getGapWidth:function(){return 1},renderClipped:function(b,c,g,f){var e=this,d=Math.min(g[0],g[2]),a=Math.max(g[0],g[2]),h=e.getAggregator()&&e.getAggregator().getAggregation(d,a,(a-d)/f[2]*e.getGapWidth());if(h){e.dataStart=h.data.startIdx[h.start];e.dataEnd=h.data.endIdx[h.end-1];e.renderAggregates(h.data,h.start,h.end,b,c,g,f)}}});Ext.define("Ext.chart.series.sprite.CandleStick",{alias:"sprite.candlestickSeries",extend:"Ext.chart.series.sprite.Aggregative",inheritableStatics:{def:{processors:{raiseStyle:function(b,a){return Ext.merge({},a||{},b)},dropStyle:function(b,a){return Ext.merge({},a||{},b)},barWidth:"number",padding:"number",ohlcType:"enums(candlestick,ohlc)"},defaults:{raiseStyle:{strokeStyle:"green",fillStyle:"green"},dropStyle:{strokeStyle:"red",fillStyle:"red"},planar:false,barWidth:15,padding:3,lineJoin:"miter",miterLimit:5,ohlcType:"candlestick"},triggers:{raiseStyle:"raiseStyle",dropStyle:"dropStyle"},updaters:{raiseStyle:function(){this.raiseTemplate&&this.raiseTemplate.setAttributes(this.attr.raiseStyle)},dropStyle:function(){this.dropTemplate&&this.dropTemplate.setAttributes(this.attr.dropStyle)}}}},candlestick:function(i,c,a,e,h,f,b){var d=Math.min(c,h),g=Math.max(c,h);i.moveTo(f,e);i.lineTo(f,g);i.moveTo(f+b,g);i.lineTo(f+b,d);i.lineTo(f-b,d);i.lineTo(f-b,g);i.closePath();i.moveTo(f,a);i.lineTo(f,d)},ohlc:function(b,d,e,a,f,c,g){b.moveTo(c,e);b.lineTo(c,a);b.moveTo(c,d);b.lineTo(c-g,d);b.moveTo(c,f);b.lineTo(c+g,f)},constructor:function(){this.callParent(arguments);this.raiseTemplate=new Ext.draw.sprite.Rect({parent:this});this.dropTemplate=new Ext.draw.sprite.Rect({parent:this})},getGapWidth:function(){var a=this.attr,b=a.barWidth,c=a.padding;return b+c},renderAggregates:function(d,c,b,t,u,z){var D=this,s=this.attr,j=s.dataX,v=s.matrix,e=v.getXX(),r=v.getYY(),l=v.getDX(),h=v.getDY(),o=s.barWidth/e,C,k=s.ohlcType,f=Math.round(o*0.5*e),a=d.open,y=d.close,B=d.maxY,p=d.minY,q=d.startIdx,m,g,E,n,A,x,w=s.lineWidth*t.devicePixelRatio/2;w-=Math.floor(w);u.save();C=this.raiseTemplate;C.useAttributes(u,z);u.beginPath();for(x=c;x<b;x++){if(a[x]<=y[x]){m=Math.round(a[x]*r+h)+w;g=Math.round(B[x]*r+h)+w;E=Math.round(p[x]*r+h)+w;n=Math.round(y[x]*r+h)+w;A=Math.round(j[q[x]]*e+l)+w;D[k](u,m,g,E,n,A,f)}}u.fillStroke(C.attr);u.restore();u.save();C=this.dropTemplate;C.useAttributes(u,z);u.beginPath();for(x=c;x<b;x++){if(a[x]>y[x]){m=Math.round(a[x]*r+h)+w;g=Math.round(B[x]*r+h)+w;E=Math.round(p[x]*r+h)+w;n=Math.round(y[x]*r+h)+w;A=Math.round(j[q[x]]*e+l)+w;D[k](u,m,g,E,n,A,f)}}u.fillStroke(C.attr);u.restore()}});Ext.define("Ext.chart.series.CandleStick",{extend:"Ext.chart.series.Cartesian",requires:["Ext.chart.series.sprite.CandleStick"],alias:"series.candlestick",type:"candlestick",seriesType:"candlestickSeries",config:{openField:null,highField:null,lowField:null,closeField:null},fieldCategoryY:["Open","High","Low","Close"],themeColorCount:function(){return 2}});Ext.define("Ext.chart.series.Polar",{extend:"Ext.chart.series.Series",config:{rotation:0,radius:null,center:[0,0],offsetX:0,offsetY:0,showInLegend:true,xField:null,yField:null,angleField:null,radiusField:null,xAxis:null,yAxis:null},directions:["X","Y"],fieldCategoryX:["X"],fieldCategoryY:["Y"],deprecatedConfigs:{field:"angleField",lengthField:"radiusField"},constructor:function(b){var c=this,a=c.getConfigurator(),e=a.configs,d;if(b){for(d in c.deprecatedConfigs){if(d in b&&!(b in e)){Ext.raise("'"+d+"' config has been deprecated. Please use the '"+c.deprecatedConfigs[d]+"' config instead.")}}}c.callParent([b])},getXField:function(){return this.getAngleField()},updateXField:function(a){this.setAngleField(a)},getYField:function(){return this.getRadiusField()},updateYField:function(a){this.setRadiusField(a)},applyXAxis:function(a,b){return this.getChart().getAxis(a)||b},applyYAxis:function(a,b){return this.getChart().getAxis(a)||b},getXRange:function(){return[this.dataRange[0],this.dataRange[2]]},getYRange:function(){return[this.dataRange[1],this.dataRange[3]]},themeColorCount:function(){var c=this,a=c.getStore(),b=a&&a.getCount()||0;return b},isStoreDependantColorCount:true,getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer(),centerX:0,centerY:0,rotationCenterX:0,rotationCenterY:0}},applyRotation:function(a){return Ext.draw.sprite.AttributeParser.angle(a)},updateRotation:function(a){var b=this.getSprites();if(b&&b[0]){b[0].setAttributes({baseRotation:a})}}});Ext.define("Ext.chart.series.Gauge",{alias:"series.gauge",extend:"Ext.chart.series.Polar",type:"gauge",seriesType:"pieslice",requires:["Ext.draw.sprite.Sector"],config:{needle:false,needleLength:90,needleWidth:4,donut:30,showInLegend:false,value:null,colors:null,sectors:null,minimum:0,maximum:100,rotation:0,totalAngle:Math.PI/2,rect:[0,0,1,1],center:[0.5,0.75],radius:0.5,wholeDisk:false},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},updateNeedle:function(b){var a=this,d=a.getSprites(),c=a.valueToAngle(a.getValue());if(d&&d.length){d[0].setAttributes({startAngle:(b?c:0),endAngle:c,strokeOpacity:(b?1:0),lineWidth:(b?a.getNeedleWidth():0)});a.doUpdateStyles()}},themeColorCount:function(){var c=this,a=c.getStore(),b=a&&a.getCount()||0;return b+(c.getNeedle()?0:1)},updateColors:function(a,b){var f=this,h=f.getSectors(),j=h&&h.length,e=f.getSprites(),c=Ext.Array.clone(a),g=a&&a.length,d;if(!g||!a[0]){return}for(d=0;d<j;d++){c[d+1]=h[d].color||c[d+1]||a[d%g]}if(e.length){e[0].setAttributes({strokeStyle:c[0]})}this.setSubStyle({fillStyle:c,strokeStyle:c});this.doUpdateStyles()},updateRect:function(f){var d=this.getWholeDisk(),c=d?Math.PI:this.getTotalAngle()/2,g=this.getDonut()/100,e,b,a;if(c<=Math.PI/2){e=2*Math.sin(c);b=1-g*Math.cos(c)}else{e=2;b=1-Math.cos(c)}a=Math.min(f[2]/e,f[3]/b);this.setRadius(a);this.setCenter([f[2]/2,a+(f[3]-b*a)/2])},updateCenter:function(a){this.setStyle({centerX:a[0],centerY:a[1],rotationCenterX:a[0],rotationCenterY:a[1]});this.doUpdateStyles()},updateRotation:function(a){this.setStyle({rotationRads:a-(this.getTotalAngle()+Math.PI)/2});this.doUpdateStyles()},doUpdateShape:function(b,f){var a,d=this.getSectors(),c=(d&&d.length)||0,e=this.getNeedleLength()/100;a=[b*e,b];while(c--){a.push(b)}this.setSubStyle({endRho:a,startRho:b/100*f});this.doUpdateStyles()},updateRadius:function(a){var b=this.getDonut();this.doUpdateShape(a,b)},updateDonut:function(b){var a=this.getRadius();this.doUpdateShape(a,b)},valueToAngle:function(a){a=this.applyValue(a);return this.getTotalAngle()*(a-this.getMinimum())/(this.getMaximum()-this.getMinimum())},applyValue:function(a){return Math.min(this.getMaximum(),Math.max(a,this.getMinimum()))},updateValue:function(b){var a=this,c=a.getNeedle(),e=a.valueToAngle(b),d=a.getSprites();d[0].rendererData.value=b;d[0].setAttributes({startAngle:(c?e:0),endAngle:e});a.doUpdateStyles()},processData:function(){var f=this,j=f.getStore(),a,d,h,b,g,e=j&&j.first(),c,i;if(e){c=f.getXField();if(c){i=e.get(c)}}if(a=f.getXAxis()){d=a.getMinimum();h=a.getMaximum();b=a.getSprites()[0].fx;g=b.getDuration();b.setDuration(0);if(Ext.isNumber(d)){f.setMinimum(d)}else{a.setMinimum(f.getMinimum())}if(Ext.isNumber(h)){f.setMaximum(h)}else{a.setMaximum(f.getMaximum())}b.setDuration(g)}if(!Ext.isNumber(i)){i=f.getMinimum()}f.setValue(i)},getDefaultSpriteConfig:function(){return{type:this.seriesType,renderer:this.getRenderer(),fx:{customDurations:{translationX:0,translationY:0,rotationCenterX:0,rotationCenterY:0,centerX:0,centerY:0,startRho:0,endRho:0,baseRotation:0}}}},normalizeSectors:function(f){var d=this,c=(f&&f.length)||0,b,e,g,a;if(c){for(b=0;b<c;b++){e=f[b];if(typeof e==="number"){f[b]={start:(b>0?f[b-1].end:d.getMinimum()),end:Math.min(e,d.getMaximum())};if(b==(c-1)&&f[b].end<d.getMaximum()){f[b+1]={start:f[b].end,end:d.getMaximum()}}}else{if(typeof e.start==="number"){g=Math.max(e.start,d.getMinimum())}else{g=(b>0?f[b-1].end:d.getMinimum())}if(typeof e.end==="number"){a=Math.min(e.end,d.getMaximum())}else{a=d.getMaximum()}f[b].start=g;f[b].end=a}}}else{f=[{start:d.getMinimum(),end:d.getMaximum()}]}return f},getSprites:function(){var j=this,m=j.getStore(),l=j.getValue(),c,g;if(!m&&!Ext.isNumber(l)){return[]}var h=j.getChart(),b=j.getAnimation()||h&&h.getAnimation(),f=j.sprites,k=0,o,n,e,d,a=[];if(f&&f.length){f[0].setAnimation(b);return f}d={store:m,field:j.getXField(),angleField:j.getXField(),value:l,series:j};o=j.createSprite();o.setAttributes({zIndex:10},true);o.rendererData=d;o.rendererIndex=k++;a.push(j.getNeedleWidth());j.getLabel().getTemplate().setField(true);n=j.normalizeSectors(j.getSectors());for(c=0,g=n.length;c<g;c++){e={startAngle:j.valueToAngle(n[c].start),endAngle:j.valueToAngle(n[c].end),label:n[c].label,fillStyle:n[c].color,strokeOpacity:0,doCallout:false,labelOverflowPadding:-1};Ext.apply(e,n[c].style);o=j.createSprite();o.rendererData=d;o.rendererIndex=k++;o.setAttributes(e,true);a.push(e.lineWidth)}j.setSubStyle({lineWidth:a});j.doUpdateStyles();return f}});Ext.define("Ext.chart.series.sprite.Line",{alias:"sprite.lineSeries",extend:"Ext.chart.series.sprite.Aggregative",inheritableStatics:{def:{processors:{smooth:"bool",fillArea:"bool",step:"bool",preciseStroke:"bool",xAxis:"default",yCap:"default"},defaults:{smooth:false,fillArea:false,step:false,preciseStroke:true,xAxis:null,yCap:Math.pow(2,20),yJump:50},triggers:{dataX:"dataX,bbox,smooth",dataY:"dataY,bbox,smooth",smooth:"smooth"},updaters:{smooth:function(a){var c=a.dataX,b=a.dataY;if(a.smooth&&c&&b&&c.length>2&&b.length>2){this.smoothX=Ext.draw.Draw.spline(c);this.smoothY=Ext.draw.Draw.spline(b)}else{delete this.smoothX;delete this.smoothY}}}}},list:null,updatePlainBBox:function(d){var b=this.attr,c=Math.min(0,b.dataMinY),a=Math.max(0,b.dataMaxY);d.x=b.dataMinX;d.y=c;d.width=b.dataMaxX-b.dataMinX;d.height=a-c},drawStrip:function(a,c){a.moveTo(c[0],c[1]);for(var b=2,d=c.length;b<d;b+=2){a.lineTo(c[b],c[b+1])}},drawStraightStroke:function(p,q,e,d,u,h){var w=this,o=w.attr,n=o.renderer,g=o.step,a=true,l={type:"line",smooth:false,step:g},m=[],l,z,v,f,k,j,t,c,s,b,r;for(r=3;r<u.length;r+=3){t=u[r-3];c=u[r-2];k=u[r];j=u[r+1];s=u[r+3];b=u[r+4];if(n){l.x=k;l.y=j;l.x0=t;l.y0=c;v=[w,l,w.rendererData,e+r/3];z=Ext.callback(n,null,v,0,w.getSeries())}if(Ext.isNumber(k+j+t+c)){if(a){q.beginPath();q.moveTo(t,c);m.push(t,c);f=t;a=false}}else{continue}if(g){q.lineTo(k,c);m.push(k,c)}q.lineTo(k,j);m.push(k,j);if(z||!(Ext.isNumber(s+b))){q.save();Ext.apply(q,z);if(o.fillArea){q.lineTo(k,h);q.lineTo(f,h);q.closePath();q.fill()}q.beginPath();w.drawStrip(q,m);m=[];q.stroke();q.restore();q.beginPath();a=true}}},calculateScale:function(c,a){var b=0,d=c;while(d<a&&c>0){b++;d+=c>>b}return Math.pow(2,b>0?b-1:b)},drawSmoothStroke:function(u,v,c,b,C,f){var G=this,t=G.attr,d=t.step,z=t.matrix,s=t.renderer,e=z.getXX(),p=z.getYY(),m=z.getDX(),k=z.getDY(),r=G.smoothX,q=G.smoothY,I=G.calculateScale(t.dataX.length,b),o,F,n,E,h,g,B,a,A,w,H,D,l={type:"line",smooth:true,step:d};v.beginPath();v.moveTo(r[c*3]*e+m,q[c*3]*p+k);for(A=0,w=c*3+1;A<C.length-3;A+=3,w+=3*I){o=r[w]*e+m;F=q[w]*p+k;n=r[w+1]*e+m;E=q[w+1]*p+k;h=u.roundPixel(C[A+3]);g=C[A+4];B=u.roundPixel(C[A]);a=C[A+1];if(s){l.x0=B;l.y0=a;l.cx1=o;l.cy1=F;l.cx2=n;l.cy2=E;l.x=h;l.y=g;D=[G,l,G.rendererData,c+A/3+1];H=Ext.callback(s,null,D,0,G.getSeries());v.save();Ext.apply(v,H)}if(t.fillArea){v.moveTo(B,a);v.bezierCurveTo(o,F,n,E,h,g);v.lineTo(h,f);v.lineTo(B,f);v.lineTo(B,a);v.closePath();v.fill();v.beginPath()}v.moveTo(B,a);v.bezierCurveTo(o,F,n,E,h,g);v.stroke();v.moveTo(B,a);v.closePath();if(s){v.restore()}v.beginPath();v.moveTo(h,g)}v.beginPath()},drawLabel:function(k,i,h,o,a){var q=this,n=q.attr,e=q.getMarker("labels"),d=e.getTemplate(),m=q.labelCfg||(q.labelCfg={}),c=q.surfaceMatrix,g,f,j=n.labelOverflowPadding,l,b,r,p,s;m.x=c.x(i,h);m.y=c.y(i,h);if(n.flipXY){m.rotationRads=Math.PI*0.5}else{m.rotationRads=0}m.text=k;if(d.attr.renderer){p=[k,e,m,q.rendererData,o];r=Ext.callback(d.attr.renderer,null,p,0,q.getSeries());if(typeof r==="string"){m.text=r}else{if(typeof r==="object"){if("text" in r){m.text=r.text}s=true}}}b=q.getMarkerBBox("labels",o,true);if(!b){q.putMarker("labels",m,o);b=q.getMarkerBBox("labels",o,true)}l=b.height/2;g=i;switch(d.attr.display){case"under":f=h-l-j;break;case"rotate":g+=j;f=h-j;m.rotationRads=-Math.PI/4;break;default:f=h+l+j}m.x=c.x(g,f);m.y=c.y(g,f);if(s){Ext.apply(m,r)}q.putMarker("labels",m,o)},drawMarker:function(j,h,d){var g=this,e=g.attr,f=e.renderer,c=g.surfaceMatrix,b={},i,a;if(f&&g.getMarker("markers")){b.type="marker";b.x=j;b.y=h;a=[g,b,g.rendererData,d];i=Ext.callback(f,null,a,0,g.getSeries());if(i){Ext.apply(b,i)}}b.translationX=c.x(j,h);b.translationY=c.y(j,h);delete b.x;delete b.y;g.putMarker("markers",b,d,!f)},drawStroke:function(a,c,h,b,f,e){var d=this,g=d.attr.smooth&&d.smoothX&&d.smoothY;if(g){d.drawSmoothStroke(a,c,h,b,f,e)}else{d.drawStraightStroke(a,c,h,b,f,e)}},renderAggregates:function(B,w,l,N,o,I,D){var m=this,k=m.attr,s=k.dataX,r=k.dataY,h=k.labels,v=k.xAxis,a=k.yCap,g=k.smooth&&m.smoothX&&m.smoothY,d=h&&m.getMarker("labels"),t=m.getMarker("markers"),E=k.matrix,u=N.devicePixelRatio,C=E.getXX(),f=E.getYY(),c=E.getDX(),b=E.getDY(),q=m.list||(m.list=[]),F=B.minX,e=B.maxX,j=B.minY,P=B.maxY,U=B.startIdx,S=true,Q,T,L,K,R,G;m.rendererData={store:m.getStore()};q.length=0;for(R=w;R<l;R++){var O=F[R],p=e[R],M=j[R],n=P[R];if(O<p){q.push(O*C+c,M*f+b,U[R]);q.push(p*C+c,n*f+b,U[R])}else{if(O>p){q.push(p*C+c,n*f+b,U[R]);q.push(O*C+c,M*f+b,U[R])}else{q.push(p*C+c,n*f+b,U[R])}}}if(q.length){for(R=0;R<q.length;R+=3){L=q[R];K=q[R+1];if(Ext.isNumber(L+K)){if(K>a){K=a}else{if(K<-a){K=-a}}q[R+1]=K}else{S=false;continue}G=q[R+2];if(t){m.drawMarker(L,K,G)}if(d&&h[G]){m.drawLabel(h[G],L,K,G,D)}}m.isContinuousLine=S;if(g&&!S){Ext.raise("Line smoothing in only supported for gapless data, where all data points are finite numbers.")}if(v){T=v.getAlignment()==="vertical";if(Ext.isNumber(v.floatingAtCoord)){Q=(T?D[2]:D[3])-v.floatingAtCoord}else{Q=T?D[0]:D[1]}}else{Q=k.flipXY?D[0]:D[1]}if(k.preciseStroke){if(k.fillArea){o.fill()}if(k.transformFillStroke){k.inverseMatrix.toContext(o)}m.drawStroke(N,o,w,l,q,Q);if(k.transformFillStroke){k.matrix.toContext(o)}o.stroke()}else{m.drawStroke(N,o,w,l,q,Q);if(S&&g&&k.fillArea&&!k.renderer){var A=s[s.length-1]*C+c+u,z=r[r.length-1]*f+b,J=s[0]*C+c-u,H=r[0]*f+b;o.lineTo(A,z);o.lineTo(A,Q-k.lineWidth);o.lineTo(J,Q-k.lineWidth);o.lineTo(J,H)}if(k.transformFillStroke){k.matrix.toContext(o)}if(k.fillArea){o.fillStroke(k,true)}else{o.stroke(true)}}}}});Ext.define("Ext.chart.series.Line",{extend:"Ext.chart.series.Cartesian",alias:"series.line",type:"line",seriesType:"lineSeries",requires:["Ext.chart.series.sprite.Line"],config:{selectionTolerance:20,smooth:false,step:false,fill:undefined,aggregator:{strategy:"double"}},defaultSmoothness:3,overflowBuffer:1,themeMarkerCount:function(){return 1},getDefaultSpriteConfig:function(){var d=this,e=d.callParent(arguments),c=Ext.apply({},d.getStyle()),b,a=false;if(typeof d.config.fill!="undefined"){if(d.config.fill){a=true;if(typeof c.fillStyle=="undefined"){if(typeof c.strokeStyle=="undefined"){b=d.getStyleWithTheme();c.fillStyle=b.fillStyle;c.strokeStyle=b.strokeStyle}else{c.fillStyle=c.strokeStyle}}}}else{if(c.fillStyle){a=true}}if(!a){delete c.fillStyle}c=Ext.apply(e||{},c);return Ext.apply(c,{fillArea:a,step:d.config.step,smooth:d.config.smooth,selectionTolerance:d.config.selectionTolerance})},updateStep:function(b){var a=this.getSprites()[0];if(a&&a.attr.step!==b){a.setAttributes({step:b})}},updateFill:function(b){var a=this.getSprites()[0];if(a&&a.attr.fillArea!==b){a.setAttributes({fillArea:b})}},updateSmooth:function(a){var b=this.getSprites()[0];if(b&&b.attr.smooth!==a){b.setAttributes({smooth:a})}}});Ext.define("Ext.chart.series.sprite.PieSlice",{extend:"Ext.draw.sprite.Sector",mixins:{markerHolder:"Ext.chart.MarkerHolder"},alias:"sprite.pieslice",inheritableStatics:{def:{processors:{doCallout:"bool",label:"string",rotateLabels:"bool",labelOverflowPadding:"number",renderer:"default"},defaults:{doCallout:true,rotateLabels:true,label:"",labelOverflowPadding:10,renderer:null}}},config:{rendererData:null,rendererIndex:0,series:null},setGradientBBox:function(q,k){var j=this,i=j.attr,g=(i.fillStyle&&i.fillStyle.isGradient)||(i.strokeStyle&&i.strokeStyle.isGradient);if(g&&!i.constrainGradients){var b=j.getMidAngle(),d=i.margin,e=i.centerX,c=i.centerY,a=i.endRho,l=i.matrix,o=l.getScaleX(),n=l.getScaleY(),m=o*a,f=n*a,p={width:m+m,height:f+f};if(d){e+=d*Math.cos(b);c+=d*Math.sin(b)}p.x=l.x(e,c)-m;p.y=l.y(e,c)-f;q.setGradientBBox(p)}else{j.callParent([q,k])}},render:function(b,c,g,f){var e=this,a=e.attr,h={},d;if(a.renderer){h={type:"sector",text:a.text,centerX:a.centerX,centerY:a.centerY,margin:a.margin,startAngle:Math.min(a.startAngle,a.endAngle),endAngle:Math.max(a.startAngle,a.endAngle),startRho:Math.min(a.startRho,a.endRho),endRho:Math.max(a.startRho,a.endRho)};d=Ext.callback(a.renderer,null,[e,h,e.rendererData,e.rendererIndex],0,e.getSeries());e.setAttributes(d);e.useAttributes(c,g)}e.callParent([b,c,g,f]);if(a.label&&e.getMarker("labels")){e.placeLabel()}},placeLabel:function(){var z=this,s=z.attr,r=s.attributeId,t=Math.min(s.startAngle,s.endAngle),p=Math.max(s.startAngle,s.endAngle),k=(t+p)*0.5,n=s.margin,h=s.centerX,g=s.centerY,f=Math.sin(k),c=Math.cos(k),v=Math.min(s.startRho,s.endRho)+n,m=Math.max(s.startRho,s.endRho)+n,l=(v+m)*0.5,b=z.surfaceMatrix,o=z.labelCfg||(z.labelCfg={}),e=z.getMarker("labels"),d=e.getTemplate(),a=d.getCalloutLine(),q=a&&a.length||40,u,j,i,A,w;b.appendMatrix(s.matrix);o.text=s.label;j=h+c*l;i=g+f*l;o.x=b.x(j,i);o.y=b.y(j,i);j=h+c*m;i=g+f*m;o.calloutStartX=b.x(j,i);o.calloutStartY=b.y(j,i);j=h+c*(m+q);i=g+f*(m+q);o.calloutPlaceX=b.x(j,i);o.calloutPlaceY=b.y(j,i);if(!s.rotateLabels){o.rotationRads=0}else{switch(d.attr.orientation){case"horizontal":o.rotationRads=k+Math.atan2(b.y(1,0)-b.y(0,0),b.x(1,0)-b.x(0,0))+Math.PI/2;break;case"vertical":o.rotationRads=k+Math.atan2(b.y(1,0)-b.y(0,0),b.x(1,0)-b.x(0,0));break}}o.calloutColor=(a&&a.color)||z.attr.fillStyle;if(a){if(a.width){o.calloutWidth=a.width}}else{o.calloutHasLine=false}o.globalAlpha=s.globalAlpha*s.fillOpacity;o.hidden=(s.startAngle==s.endAngle);if(d.attr.renderer){w=[z.attr.label,e,o,z.rendererData,z.rendererIndex];A=Ext.callback(d.attr.renderer,null,w,0,z.getSeries());if(typeof A==="string"){o.text=A}else{Ext.apply(o,A)}}z.putMarker("labels",o,r);u=z.getMarkerBBox("labels",r,true);if(u){if(s.doCallout){if(d.attr.display==="outside"){z.putMarker("labels",{callout:1},r)}else{if(d.attr.display==="inside"){z.putMarker("labels",{callout:0},r)}else{z.putMarker("labels",{callout:1-z.sliceContainsLabel(s,u)},r)}}}else{z.putMarker("labels",{globalAlpha:z.sliceContainsLabel(s,u)},r)}}},sliceContainsLabel:function(d,f){var e=d.labelOverflowPadding,h=(d.endRho+d.startRho)/2,g=h+(f.width+e)/2,i=h-(f.width+e)/2,j,c,b,a;if(e<0){return 1}if(f.width+e*2>(d.endRho-d.startRho)){return 0}c=Math.sqrt(d.endRho*d.endRho-g*g);b=Math.sqrt(d.endRho*d.endRho-i*i);j=Math.abs(d.endAngle-d.startAngle);a=(j>Math.PI/2?i:Math.abs(Math.tan(j/2))*i);if(f.height+e*2>Math.min(c,b,a)*2){return 0}return 1}});Ext.define("Ext.chart.series.Pie",{extend:"Ext.chart.series.Polar",requires:["Ext.chart.series.sprite.PieSlice"],type:"pie",alias:"series.pie",seriesType:"pieslice",config:{donut:0,rotation:0,clockwise:true,totalAngle:2*Math.PI,hidden:[],radiusFactor:100,highlightCfg:{margin:20},style:{}},directions:["X"],applyLabel:function(a,b){if(Ext.isObject(a)&&!Ext.isString(a.orientation)){Ext.apply(a=Ext.Object.chain(a),{orientation:"vertical"})}return this.callParent([a,b])},updateLabelData:function(){var h=this,j=h.getStore(),g=j.getData().items,e=h.getSprites(),a=h.getLabel().getTemplate().getField(),d=h.getHidden(),b,f,c,k;if(e.length&&a){c=[];for(b=0,f=g.length;b<f;b++){c.push(g[b].get(a))}for(b=0,f=e.length;b<f;b++){k=e[b];k.setAttributes({label:c[b]});k.putMarker("labels",{hidden:d[b]},k.attr.attributeId)}}},coordinateX:function(){var t=this,f=t.getStore(),q=f.getData().items,c=q.length,b=t.getXField(),e=t.getYField(),l,a=0,m,k,s=0,o=t.getHidden(),d=[],p,g=0,h=t.getTotalAngle(),r=t.getClockwise()?1:-1,j=t.getSprites(),n;if(!j){return}for(p=0;p<c;p++){l=Math.abs(Number(q[p].get(b)))||0;k=e&&Math.abs(Number(q[p].get(e)))||0;if(!o[p]){a+=l;if(k>s){s=k}}d[p]=a;if(p>=o.length){o[p]=false}}o.length=c;t.maxY=s;if(a!==0){m=h/a}for(p=0;p<c;p++){j[p].setAttributes({startAngle:g,endAngle:g=(m?r*d[p]*m:0),globalAlpha:1})}if(c<t.sprites.length){for(p=c;p<t.sprites.length;p++){n=t.sprites[p];n.getMarker("labels").clear(n.getId());n.releaseMarker("labels");n.destroy()}t.sprites.length=c}for(p=c;p<t.sprites.length;p++){j[p].setAttributes({startAngle:h,endAngle:h,globalAlpha:0})}t.getChart().refreshLegendStore()},updateCenter:function(a){this.setStyle({translationX:a[0]+this.getOffsetX(),translationY:a[1]+this.getOffsetY()});this.doUpdateStyles()},updateRadius:function(a){this.setStyle({startRho:a*this.getDonut()*0.01,endRho:a*this.getRadiusFactor()*0.01});this.doUpdateStyles()},getStyleByIndex:function(c){var g=this,j=g.getStore(),k=j.getAt(c),f=g.getYField(),d=g.getRadius(),a={},e,b,h;if(k){h=f&&Math.abs(Number(k.get(f)))||0;e=d*g.getDonut()*0.01;b=d*g.getRadiusFactor()*0.01;a=g.callParent([c]);a.startRho=e;a.endRho=g.maxY?(e+(b-e)*h/g.maxY):b}return a},updateDonut:function(b){var a=this.getRadius();this.setStyle({startRho:a*b*0.01,endRho:a*this.getRadiusFactor()*0.01});this.doUpdateStyles()},rotationOffset:-Math.PI/2,updateRotation:function(a){this.setStyle({rotationRads:a+this.rotationOffset});this.doUpdateStyles()},updateTotalAngle:function(a){this.processData()},getSprites:function(){var k=this,h=k.getChart(),n=k.getStore();if(!h||!n){return[]}k.getColors();k.getSubStyle();var j=n.getData().items,b=j.length,d=k.getAnimation()||h&&h.getAnimation(),g=k.sprites,o,l=0,f,e,c=false,m=k.getLabel(),a=m.getTemplate();f={store:n,field:k.getXField(),angleField:k.getXField(),radiusField:k.getYField(),series:k};for(e=0;e<b;e++){o=g[e];if(!o){o=k.createSprite();if(k.getHighlight()){o.config.highlight=k.getHighlight();o.addModifier("highlight",true)}if(a.getField()){a.setAttributes({labelOverflowPadding:k.getLabelOverflowPadding()});a.fx.setCustomDurations({callout:200})}o.setAttributes(k.getStyleByIndex(e));o.rendererData=f;o.rendererIndex=l++;c=true}o.setAnimation(d)}if(c){k.doUpdateStyles()}return k.sprites},betweenAngle:function(d,f,c){var e=Math.PI*2,g=this.rotationOffset;if(!this.getClockwise()){d*=-1;f*=-1;c*=-1;f-=g;c-=g}else{f+=g;c+=g}d-=f;c-=f;d%=e;c%=e;d+=e;c+=e;d%=e;c%=e;return d<c||c===0},getItemForAngle:function(a){var h=this,f=h.getSprites(),d;a%=Math.PI*2;while(a<0){a+=Math.PI*2}if(f){var j=h.getStore(),g=j.getData().items,c=h.getHidden(),b=0,e=j.getCount();for(;b<e;b++){if(!c[b]){d=f[b].attr;if(d.startAngle<=a&&d.endAngle>=a){return{series:h,sprite:f[b],index:b,record:g[b],field:h.getXField()}}}}}return null},getItemForPoint:function(f,e){var t=this,c=t.getSprites();if(c){var s=t.getCenter(),q=t.getOffsetX(),p=t.getOffsetY(),j=f-s[0]+q,h=e-s[1]+p,b=t.getStore(),g=t.getDonut(),o=b.getData().items,r=Math.atan2(h,j)-t.getRotation(),a=Math.sqrt(j*j+h*h),l=t.getRadius()*g*0.01,m=t.getHidden(),n,d,k;for(n=0,d=o.length;n<d;n++){if(!m[n]){k=c[n].attr;if(a>=l+k.margin&&a<=k.endRho+k.margin){if(t.betweenAngle(r,k.startAngle,k.endAngle)){return{series:t,sprite:c[n],index:n,record:o[n],field:t.getXField()}}}}}return null}},provideLegendInfo:function(f){var h=this,j=h.getStore();if(j){var g=j.getData().items,b=h.getLabel().getTemplate().getField(),c=h.getXField(),e=h.getHidden(),d,a,k;for(d=0;d<g.length;d++){a=h.getStyleByIndex(d);k=a.fillStyle;if(Ext.isObject(k)){k=k.stops&&k.stops[0].color}f.push({name:b?String(g[d].get(b)):c+" "+d,mark:k||a.strokeStyle||"black",disabled:e[d],series:h.getId(),index:d})}}}});Ext.define("Ext.chart.series.sprite.Pie3DPart",{extend:"Ext.draw.sprite.Path",mixins:{markerHolder:"Ext.chart.MarkerHolder"},alias:"sprite.pie3dPart",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",margin:"number",thickness:"number",bevelWidth:"number",distortion:"number",baseColor:"color",colorSpread:"number",baseRotation:"number",part:"enums(top,bottom,start,end,innerFront,innerBack,outerFront,outerBack)",label:"string"},aliases:{rho:"endRho"},triggers:{centerX:"path,bbox",centerY:"path,bbox",startAngle:"path,partZIndex",endAngle:"path,partZIndex",startRho:"path",endRho:"path,bbox",margin:"path,bbox",thickness:"path",distortion:"path",baseRotation:"path,partZIndex",baseColor:"partZIndex,partColor",colorSpread:"partColor",part:"path,partZIndex",globalAlpha:"canvas,alpha"},defaults:{centerX:0,centerY:0,startAngle:Math.PI*2,endAngle:Math.PI*2,startRho:0,endRho:150,margin:0,thickness:35,distortion:0.5,baseRotation:0,baseColor:"white",colorSpread:1,miterLimit:1,bevelWidth:5,strokeOpacity:0,part:"top",label:""},updaters:{alpha:"alphaUpdater",partColor:"partColorUpdater",partZIndex:"partZIndexUpdater"}}},bevelParams:[],constructor:function(a){this.callParent([a]);this.bevelGradient=new Ext.draw.gradient.Linear({stops:[{offset:0,color:"rgba(255,255,255,0)"},{offset:0.7,color:"rgba(255,255,255,0.6)"},{offset:1,color:"rgba(255,255,255,0)"}]})},alphaUpdater:function(a){var d=this,c=a.globalAlpha,b=d.oldOpacity;if(c!==b&&(c===1||b===1)){d.scheduleUpdater(a,"path",["globalAlpha"]);d.oldOpacity=c}},partColorUpdater:function(a){var d=Ext.draw.Color.fly(a.baseColor),b=d.toString(),e=a.colorSpread,c;switch(a.part){case"top":c=new Ext.draw.gradient.Radial({start:{x:0,y:0,r:0},end:{x:0,y:0,r:1},stops:[{offset:0,color:d.createLighter(0.1*e)},{offset:1,color:d.createDarker(0.1*e)}]});break;case"bottom":c=new Ext.draw.gradient.Radial({start:{x:0,y:0,r:0},end:{x:0,y:0,r:1},stops:[{offset:0,color:d.createDarker(0.2*e)},{offset:1,color:d.toString()}]});break;case"outerFront":case"outerBack":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.15*e).toString()},{offset:0.3,color:b},{offset:0.8,color:d.createLighter(0.2*e).toString()},{offset:1,color:d.createDarker(0.25*e).toString()}]});break;case"start":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:1,color:d.createLighter(0.2*e).toString()}]});break;case"end":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:1,color:d.createLighter(0.2*e).toString()}]});break;case"innerFront":case"innerBack":c=new Ext.draw.gradient.Linear({stops:[{offset:0,color:d.createDarker(0.1*e).toString()},{offset:0.2,color:d.createLighter(0.2*e).toString()},{offset:0.7,color:b},{offset:1,color:d.createDarker(0.1*e).toString()}]});break}a.fillStyle=c;a.canvasAttributes.fillStyle=c},partZIndexUpdater:function(a){var c=Ext.draw.sprite.AttributeParser.angle,e=a.baseRotation,d=a.startAngle,b=a.endAngle,f;switch(a.part){case"top":a.zIndex=5;break;case"outerFront":d=c(d+e);b=c(b+e);if(d>=0&&b<0){f=Math.sin(d)}else{if(d<=0&&b>0){f=Math.sin(b)}else{if(d>=0&&b>0){if(d>b){f=0}else{f=Math.max(Math.sin(d),Math.sin(b))}}else{f=1}}}a.zIndex=4+f;break;case"outerBack":a.zIndex=1;break;case"start":a.zIndex=4+Math.sin(c(d+e));break;case"end":a.zIndex=4+Math.sin(c(b+e));break;case"innerFront":a.zIndex=2;break;case"innerBack":a.zIndex=4+Math.sin(c((d+b)/2+e));break;case"bottom":a.zIndex=0;break}a.dirtyZIndex=true},updatePlainBBox:function(k){var f=this.attr,a=f.part,b=f.baseRotation,e=f.centerX,d=f.centerY,j,c,i,h,g,l;if(a==="start"){c=f.startAngle+b}else{if(a==="end"){c=f.endAngle+b}}if(Ext.isNumber(c)){g=Math.sin(c);l=Math.cos(c);i=Math.min(e+l*f.startRho,e+l*f.endRho);h=d+g*f.startRho*f.distortion;k.x=i;k.y=h;k.width=l*(f.endRho-f.startRho);k.height=f.thickness+g*(f.endRho-f.startRho)*2;return}if(a==="innerFront"||a==="innerBack"){j=f.startRho}else{j=f.endRho}k.width=j*2;k.height=j*f.distortion*2+f.thickness;k.x=f.centerX-j;k.y=f.centerY-j*f.distortion},updateTransformedBBox:function(a){if(this.attr.part==="start"||this.attr.part==="end"){return this.callParent(arguments)}return this.updatePlainBBox(a)},updatePath:function(a){if(!this.attr.globalAlpha){return}if(this.attr.endAngle<this.attr.startAngle){return}this[this.attr.part+"Renderer"](a)},render:function(b,c){var d=this,a=d.attr;if(!a.globalAlpha){return}d.callParent([b,c]);d.bevelRenderer(b,c);if(a.label&&d.getMarker("labels")){d.placeLabel()}},placeLabel:function(){var z=this,u=z.attr,t=u.attributeId,p=u.margin,c=u.distortion,i=u.centerX,h=u.centerY,j=u.baseRotation,v=u.startAngle+j,r=u.endAngle+j,m=(v+r)/2,w=u.startRho+p,o=u.endRho+p,n=(w+o)/2,a=Math.sin(m),b=Math.cos(m),e=z.surfaceMatrix,g=z.getMarker("labels"),f=g.getTemplate(),d=f.getCalloutLine(),s=d&&d.length||40,q={},l,k;e.appendMatrix(u.matrix);q.text=u.label;l=i+b*n;k=h+a*n*c;q.x=e.x(l,k);q.y=e.y(l,k);l=i+b*o;k=h+a*o*c;q.calloutStartX=e.x(l,k);q.calloutStartY=e.y(l,k);l=i+b*(o+s);k=h+a*(o+s)*c;q.calloutPlaceX=e.x(l,k);q.calloutPlaceY=e.y(l,k);q.calloutWidth=2;z.putMarker("labels",q,t);z.putMarker("labels",{callout:1},t)},bevelRenderer:function(b,c){var f=this,a=f.attr,e=a.bevelWidth,g=f.bevelParams,d;for(d=0;d<g.length;d++){c.beginPath();c.ellipse.apply(c,g[d]);c.save();c.lineWidth=e;c.strokeOpacity=e?1:0;c.strokeGradient=f.bevelGradient;c.stroke(a);c.restore()}},lidRenderer:function(o,m){var k=this.attr,g=k.margin,c=k.distortion,i=k.centerX,h=k.centerY,f=k.baseRotation,j=k.startAngle+f,e=k.endAngle+f,d=(j+e)/2,l=k.startRho,b=k.endRho,n=Math.sin(e),a=Math.cos(e);i+=Math.cos(d)*g;h+=Math.sin(d)*g*c;o.ellipse(i,h+m,l,l*c,0,j,e,false);o.lineTo(i+a*b,h+m+n*b*c);o.ellipse(i,h+m,b,b*c,0,e,j,true);o.closePath()},topRenderer:function(a){this.lidRenderer(a,0)},bottomRenderer:function(b){var a=this.attr;if(a.globalAlpha<1||a.shadowColor!==Ext.draw.Color.RGBA_NONE){this.lidRenderer(b,a.thickness)}},sideRenderer:function(l,s){var o=this.attr,k=o.margin,g=o.centerX,f=o.centerY,e=o.distortion,h=o.baseRotation,p=o.startAngle+h,m=o.endAngle+h,a=o.thickness,q=o.startRho,j=o.endRho,r=(s==="start"&&p)||(s==="end"&&m),b=Math.sin(r),d=Math.cos(r),c=o.globalAlpha<1,n=s==="start"&&d<0||s==="end"&&d>0||c,i;if(n){i=(p+m)/2;g+=Math.cos(i)*k;f+=Math.sin(i)*k*e;l.moveTo(g+d*q,f+b*q*e);l.lineTo(g+d*j,f+b*j*e);l.lineTo(g+d*j,f+b*j*e+a);l.lineTo(g+d*q,f+b*q*e+a);l.closePath()}},startRenderer:function(a){this.sideRenderer(a,"start")},endRenderer:function(a){this.sideRenderer(a,"end")},rimRenderer:function(q,e,o,j){var w=this,s=w.attr,p=s.margin,h=s.centerX,g=s.centerY,d=s.distortion,i=s.baseRotation,t=Ext.draw.sprite.AttributeParser.angle,u=s.startAngle+i,r=s.endAngle+i,k=t((u+r)/2),a=s.thickness,b=s.globalAlpha<1,c,n,v;w.bevelParams=[];u=t(u);r=t(r);h+=Math.cos(k)*p;g+=Math.sin(k)*p*d;c=u>=0&&r>=0;n=u<=0&&r<=0;function l(){q.ellipse(h,g+a,e,e*d,0,Math.PI,u,true);q.lineTo(h+Math.cos(u)*e,g+Math.sin(u)*e*d);v=[h,g,e,e*d,0,u,Math.PI,false];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function f(){q.ellipse(h,g+a,e,e*d,0,0,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,0,true];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function x(){q.ellipse(h,g+a,e,e*d,0,Math.PI,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,Math.PI,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}function m(){q.ellipse(h,g+a,e,e*d,0,u,0,false);q.lineTo(h+e,g);v=[h,g,e,e*d,0,0,u,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}if(j){if(!o||b){if(u>=0&&r<0){l()}else{if(u<=0&&r>0){f()}else{if(u<=0&&r<0){if(u>r){q.ellipse(h,g+a,e,e*d,0,0,Math.PI,false);q.lineTo(h-e,g);v=[h,g,e,e*d,0,Math.PI,0,true];if(!o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}else{if(u>r){l();f()}else{v=[h,g,e,e*d,0,u,r,false];if(c&&!o||n&&o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d+a);q.ellipse(h,g+a,e,e*d,0,r,u,true);q.closePath()}}}}}}else{if(o||b){if(u>=0&&r<0){x()}else{if(u<=0&&r>0){m()}else{if(u<=0&&r<0){if(u>r){x();m()}else{q.ellipse(h,g+a,e,e*d,0,u,r,false);q.lineTo(h+Math.cos(r)*e,g+Math.sin(r)*e*d);v=[h,g,e,e*d,0,r,u,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}else{if(u>r){q.ellipse(h,g+a,e,e*d,0,-Math.PI,0,false);q.lineTo(h+e,g);v=[h,g,e,e*d,0,0,-Math.PI,true];if(o){w.bevelParams.push(v)}q.ellipse.apply(q,v);q.closePath()}}}}}}},innerFrontRenderer:function(a){this.rimRenderer(a,this.attr.startRho,true,true)},innerBackRenderer:function(a){this.rimRenderer(a,this.attr.startRho,true,false)},outerFrontRenderer:function(a){this.rimRenderer(a,this.attr.endRho,false,true)},outerBackRenderer:function(a){this.rimRenderer(a,this.attr.endRho,false,false)}});Ext.define("Ext.draw.PathUtil",function(){var a=Math.abs,c=Math.pow,e=Math.cos,b=Math.acos,d=Math.sqrt,f=Math.PI;return{singleton:true,requires:["Ext.draw.overrides.Path","Ext.draw.overrides.sprite.Path","Ext.draw.overrides.sprite.Instancing","Ext.draw.overrides.Surface"],cubicRoots:function(m){var z=m[0],x=m[1],w=m[2],v=m[3];if(z===0){return this.quadraticRoots(x,w,v)}var s=x/z,r=w/z,q=v/z,k=(3*r-c(s,2))/9,j=(9*s*r-27*q-2*c(s,3))/54,p=c(k,3)+c(j,2),n=[],h,g,o,l,u,y=Ext.Number.sign;if(p>=0){h=y(j+d(p))*c(a(j+d(p)),1/3);g=y(j-d(p))*c(a(j-d(p)),1/3);n[0]=-s/3+(h+g);n[1]=-s/3-(h+g)/2;n[2]=n[1];o=a(d(3)*(h-g)/2);if(o!==0){n[1]=-1;n[2]=-1}}else{l=b(j/d(-c(k,3)));n[0]=2*d(-k)*e(l/3)-s/3;n[1]=2*d(-k)*e((l+2*f)/3)-s/3;n[2]=2*d(-k)*e((l+4*f)/3)-s/3}for(u=0;u<3;u++){if(n[u]<0||n[u]>1){n[u]=-1}}return n},quadraticRoots:function(h,g,n){var m,l,k,j;if(h===0){return this.linearRoot(g,n)}m=g*g-4*h*n;if(m===0){k=[-g/(2*h)]}else{if(m>0){l=d(m);k=[(-g-l)/(2*h),(-g+l)/(2*h)]}else{return[]}}for(j=0;j<k.length;j++){if(k[j]<0||k[j]>1){k[j]=-1}}return k},linearRoot:function(h,g){var i=-g/h;if(h===0||i<0||i>1){return[]}return[i]},bezierCoeffs:function(h,g,k,j){var i=[];i[0]=-h+3*g-3*k+j;i[1]=3*h-6*g+3*k;i[2]=-3*h+3*g;i[3]=h;return i},cubicLineIntersections:function(I,G,F,E,l,k,j,h,M,p,K,n){var u=[],N=[],D=p-n,z=K-M,y=M*(n-p)-p*(K-M),L=this.bezierCoeffs(I,G,F,E),J=this.bezierCoeffs(l,k,j,h),H,x,w,v,g,q,o,m;u[0]=D*L[0]+z*J[0];u[1]=D*L[1]+z*J[1];u[2]=D*L[2]+z*J[2];u[3]=D*L[3]+z*J[3]+y;x=this.cubicRoots(u);for(H=0;H<x.length;H++){v=x[H];if(v<0||v>1){continue}g=v*v;q=g*v;o=L[0]*q+L[1]*g+L[2]*v+L[3];m=J[0]*q+J[1]*g+J[2]*v+J[3];if((K-M)!==0){w=(o-M)/(K-M)}else{w=(m-p)/(n-p)}if(!(w<0||w>1)){N.push([o,m])}}return N},splitCubic:function(g,q,p,o,m){var j=m*m,n=m*j,i=m-1,h=i*i,k=i*h,l=n*o-3*j*i*p+3*m*h*q-k*g;return[[g,m*q-i*g,j*p-2*m*i*q+h*g,l],[l,j*o-2*m*i*p+h*q,m*o-i*p,o]]},cubicDimension:function(p,o,l,k){var j=3*(-p+3*(o-l)+k),i=6*(p-2*o+l),h=-3*(p-o),q,n,g=Math.min(p,k),m=Math.max(p,k),r;if(j===0){if(i===0){return[g,m]}else{q=-h/i;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}}}else{r=i*i-4*j*h;if(r>=0){r=d(r);q=(r-i)/2/j;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}if(r>0){q-=r/j;if(0<q&&q<1){n=this.interpolateCubic(p,o,l,k,q);g=Math.min(g,n);m=Math.max(m,n)}}}}return[g,m]},interpolateCubic:function(h,g,l,k,i){if(i===0){return h}if(i===1){return k}var j=(1-i)/i;return i*i*i*(k+j*(3*l+j*(3*g+j*h)))},cubicsIntersections:function(r,q,p,o,A,z,y,v,g,F,E,D,m,l,k,i){var C=this,x=C.cubicDimension(r,q,p,o),B=C.cubicDimension(A,z,y,v),n=C.cubicDimension(g,F,E,D),s=C.cubicDimension(m,l,k,i),j,h,u,t,w=[];if(x[0]>n[1]||x[1]<n[0]||B[0]>s[1]||B[1]<s[0]){return[]}if(a(A-z)<1&&a(y-v)<1&&a(r-o)<1&&a(q-p)<1&&a(m-l)<1&&a(k-i)<1&&a(g-D)<1&&a(F-E)<1){return[[(r+o)*0.5,(A+z)*0.5]]}j=C.splitCubic(r,q,p,o,0.5);h=C.splitCubic(A,z,y,v,0.5);u=C.splitCubic(g,F,E,D,0.5);t=C.splitCubic(m,l,k,i,0.5);w.push.apply(w,C.cubicsIntersections.apply(C,j[0].concat(h[0],u[0],t[0])));w.push.apply(w,C.cubicsIntersections.apply(C,j[0].concat(h[0],u[1],t[1])));w.push.apply(w,C.cubicsIntersections.apply(C,j[1].concat(h[1],u[0],t[0])));w.push.apply(w,C.cubicsIntersections.apply(C,j[1].concat(h[1],u[1],t[1])));return w},linesIntersection:function(k,p,j,o,h,n,q,m){var l=(j-k)*(m-n)-(o-p)*(q-h),i,g;if(l===0){return null}i=((q-h)*(p-n)-(k-h)*(m-n))/l;g=((j-k)*(p-n)-(o-p)*(k-h))/l;if(i>=0&&i<=1&&g>=0&&g<=1){return[k+i*(j-k),p+i*(o-p)]}return null},pointOnLine:function(j,m,h,l,g,n){var k,i;if(a(h-j)<a(l-m)){i=j;j=m;m=i;i=h;h=l;l=i;i=g;g=n;n=i}k=(g-j)/(h-j);if(k<0||k>1){return false}return a(m+k*(l-m)-n)<4},pointOnCubic:function(w,u,s,r,l,k,h,g,p,o){var C=this,B=C.bezierCoeffs(w,u,s,r),A=C.bezierCoeffs(l,k,h,g),z,v,n,m,q;B[3]-=p;A[3]-=o;n=C.cubicRoots(B);m=C.cubicRoots(A);for(z=0;z<n.length;z++){q=n[z];for(v=0;v<m.length;v++){if(q>=0&&q<=1&&a(q-m[v])<0.05){return true}}}return false}}});Ext.define("Ext.chart.series.Pie3D",{extend:"Ext.chart.series.Polar",requires:["Ext.chart.series.sprite.Pie3DPart","Ext.draw.PathUtil"],type:"pie3d",seriesType:"pie3d",alias:"series.pie3d",isPie3D:true,config:{rect:[0,0,0,0],thickness:35,distortion:0.5,donut:false,hidden:[],highlightCfg:{margin:20},shadow:false},rotationOffset:-Math.PI/2,setField:function(a){return this.setXField(a)},getField:function(){return this.getXField()},updateRotation:function(a){this.setStyle({baseRotation:a+this.rotationOffset});this.doUpdateStyles()},updateDistortion:function(){this.setRadius()},updateThickness:function(){this.setRadius()},updateColors:function(a){this.setSubStyle({baseColor:a})},applyShadow:function(a){if(a===true){a={shadowColor:"rgba(0,0,0,0.8)",shadowBlur:30}}else{if(!Ext.isObject(a)){a={shadowColor:Ext.draw.Color.RGBA_NONE}}}return a},updateShadow:function(g){var e=this,f=e.getSprites(),d=e.spritesPerSlice,c=f&&f.length,b,a;for(b=1;b<c;b+=d){a=f[b];if(a.attr.part="bottom"){a.setAttributes(g)}}},getStyleByIndex:function(b){var d=this.callParent([b]),c=this.getStyle(),a=d.fillStyle||d.fill||d.color,e=c.strokeStyle||c.stroke;if(a){d.baseColor=a;delete d.fillStyle;delete d.fill;delete d.color}if(e){d.strokeStyle=e}return d},doUpdateStyles:function(){var g=this,h=g.getSprites(),f=g.spritesPerSlice,e=h&&h.length,c=0,b=0,a,d;for(;c<e;c+=f,b++){d=g.getStyleByIndex(b);for(a=0;a<f;a++){h[c+a].setAttributes(d)}}},coordinateX:function(){var w=this,m=w.getChart(),u=m&&m.getAnimation(),f=w.getStore(),t=f.getData().items,d=t.length,b=w.getXField(),p=w.getRotation(),s=w.getHidden(),n,c=0,h,e=[],k=w.getSprites(),a=k.length,l=w.spritesPerSlice,g=0,o=Math.PI*2,v=1e-10,r,q;for(r=0;r<d;r++){n=Math.abs(Number(t[r].get(b)))||0;if(!s[r]){c+=n}e[r]=c;if(r>=s.length){s[r]=false}}s.length=d;if(c===0){return}h=2*Math.PI/c;for(r=0;r<d;r++){e[r]*=h}for(r=0;r<a;r++){k[r].setAnimation(u)}for(r=0;r<d;r++){for(q=0;q<l;q++){k[r*l+q].setAttributes({startAngle:g,endAngle:e[r]-v,globalAlpha:1,baseRotation:p})}g=e[r]}for(r*=l;r<a;r++){k[r].setAnimation(u);k[r].setAttributes({startAngle:o,endAngle:o,globalAlpha:0,baseRotation:p})}},updateLabelData:function(){var l=this,m=l.getStore(),k=m.getData().items,h=l.getSprites(),b=l.getLabel().getTemplate().getField(),f=l.getHidden(),a=l.spritesPerSlice,d,c,g,e,n;if(h.length&&b){e=[];for(d=0,g=k.length;d<g;d++){e.push(k[d].get(b))}for(d=0,c=0,g=h.length;d<g;d+=a,c++){n=h[d];n.setAttributes({label:e[c]});n.putMarker("labels",{hidden:f[c]},n.attr.attributeId)}}},applyRadius:function(){var f=this,d=f.getChart(),h=d.getInnerPadding(),e=d.getMainRect()||[0,0,1,1],c=e[2]-h*2,a=e[3]-h*2-f.getThickness(),g=c/2,b=g*f.getDistortion();if(b>a/2){return a/(f.getDistortion()*2)}else{return g}},getSprites:function(){var y=this,e=y.getStore();if(!e){return[]}var n=y.getChart(),p=y.getSurface(),t=e.getData().items,l=y.spritesPerSlice,a=t.length,v=y.getAnimation()||n&&n.getAnimation(),x=y.getCenter(),w=y.getOffsetX(),u=y.getOffsetY(),b=y.getRadius(),q=y.getRotation(),d=y.getHighlight(),c={centerX:x[0]+w,centerY:x[1]+u-y.getThickness()/2,endRho:b,startRho:b*y.getDonut()/100,thickness:y.getThickness(),distortion:y.getDistortion()},k=y.sprites,h=y.getLabel(),f=h.getTemplate(),m,g,o,s,r;for(s=0;s<a;s++){g=Ext.apply({},this.getStyleByIndex(s),c);if(!k[s*l]){for(r=0;r<y.partNames.length;r++){o=p.add({type:"pie3dPart",part:y.partNames[r]});if(r===0&&f.getField()){o.bindMarker("labels",h)}o.fx.setDurationOn("baseRotation",q);if(d){o.config.highlight=d;o.addModifier("highlight",true)}o.setAttributes(g);k.push(o)}}else{m=k.slice(s*l,(s+1)*l);for(r=0;r<m.length;r++){o=m[r];if(v){o.setAnimation(v)}o.setAttributes(g)}}}return k},betweenAngle:function(d,f,c){var e=Math.PI*2,g=this.rotationOffset;f+=g;c+=g;d-=f;c-=f;d%=e;c%=e;d+=e;c+=e;d%=e;c%=e;return d<c||c===0},getItemForPoint:function(k,j){var h=this,g=h.getSprites();if(g){var l=h.getStore(),b=l.getData().items,a=h.spritesPerSlice,e=h.getHidden(),c,f,m,d;for(c=0,f=b.length;c<f;c++){if(!e[c]){d=c*a;m=g[d];if(m.hitTest([k,j])){return{series:h,sprite:g.slice(d,d+a),index:c,record:b[c],category:"sprites",field:h.getXField()}}}}return null}},provideLegendInfo:function(f){var h=this,k=h.getStore();if(k){var g=k.getData().items,b=h.getLabel().getTemplate().getField(),j=h.getField(),e=h.getHidden(),d,a,c;for(d=0;d<g.length;d++){a=h.getStyleByIndex(d);c=a.baseColor;f.push({name:b?String(g[d].get(b)):j+" "+d,mark:c||"black",disabled:e[d],series:h.getId(),index:d})}}}},function(){var b=this.prototype,a=Ext.chart.series.sprite.Pie3DPart.def.getInitialConfig().processors.part;b.partNames=a.replace(/^enums\(|\)/g,"").split(",");b.spritesPerSlice=b.partNames.length});Ext.define("Ext.chart.series.sprite.Polar",{extend:"Ext.chart.series.sprite.Series",inheritableStatics:{def:{processors:{centerX:"number",centerY:"number",startAngle:"number",endAngle:"number",startRho:"number",endRho:"number",baseRotation:"number",labels:"default",labelOverflowPadding:"number"},defaults:{centerX:0,centerY:0,startAngle:0,endAngle:Math.PI,startRho:0,endRho:150,baseRotation:0,labels:null,labelOverflowPadding:10},triggers:{centerX:"bbox",centerY:"bbox",startAngle:"bbox",endAngle:"bbox",startRho:"bbox",endRho:"bbox",baseRotation:"bbox"}}},updatePlainBBox:function(b){var a=this.attr;b.x=a.centerX-a.endRho;b.y=a.centerY+a.endRho;b.width=a.endRho*2;b.height=a.endRho*2}});Ext.define("Ext.chart.series.sprite.Radar",{alias:"sprite.radar",extend:"Ext.chart.series.sprite.Polar",getDataPointXY:function(d){var u=this,n=u.attr,f=n.centerX,e=n.centerY,o=n.matrix,t=n.dataMinX,s=n.dataMaxX,k=n.dataX,j=n.dataY,l=n.endRho,p=n.startRho,g=n.baseRotation,i,h,m,c,b,a,q;if(n.rangeY){q=n.rangeY[1]}else{q=n.dataMaxY}c=(k[d]-t)/(s-t+1)*2*Math.PI+g;m=j[d]/q*(l-p)+p;b=f+Math.cos(c)*m;a=e+Math.sin(c)*m;i=o.x(b,a);h=o.y(b,a);return[i,h]},render:function(a,l){var h=this,f=h.attr,g=f.dataX,b=g.length,e=h.surfaceMatrix,d={},c,k,j,m;l.beginPath();for(c=0;c<b;c++){m=h.getDataPointXY(c);k=m[0];j=m[1];if(c===0){l.moveTo(k,j)}l.lineTo(k,j);d.translationX=e.x(k,j);d.translationY=e.y(k,j);h.putMarker("markers",d,c,true)}l.closePath();l.fillStroke(f)}});Ext.define("Ext.chart.series.Radar",{extend:"Ext.chart.series.Polar",type:"radar",seriesType:"radar",alias:"series.radar",requires:["Ext.chart.series.sprite.Radar"],themeColorCount:function(){return 1},isStoreDependantColorCount:false,themeMarkerCount:function(){return 1},updateAngularAxis:function(a){a.processData(this)},updateRadialAxis:function(a){a.processData(this)},coordinateX:function(){return this.coordinate("X",0,2)},coordinateY:function(){return this.coordinate("Y",1,2)},updateCenter:function(a){this.setStyle({translationX:a[0]+this.getOffsetX(),translationY:a[1]+this.getOffsetY()});this.doUpdateStyles()},updateRadius:function(a){this.setStyle({endRho:a});this.doUpdateStyles()},updateRotation:function(a){this.setStyle({rotationRads:a});this.doUpdateStyles()},updateTotalAngle:function(a){this.processData()},getItemForPoint:function(k,j){var h=this,m=h.sprites&&h.sprites[0],f=m.attr,g=f.dataX,a=g.length,l=h.getStore(),e=h.getMarker(),b,o,p,d,n,c;if(h.getHidden()){return null}if(m&&e){c=m.getMarker("markers");for(d=0;d<a;d++){n=c.getBBoxFor(d);b=(n.width+n.height)*0.25;p=m.getDataPointXY(d);if(Math.abs(p[0]-k)<b&&Math.abs(p[1]-j)<b){o={series:h,sprite:m,index:d,category:"markers",record:l.getData().items[d],field:h.getYField()};return o}}}return h.callParent(arguments)},getDefaultSpriteConfig:function(){var a=this.callParent(),b={customDurations:{translationX:0,translationY:0,rotationRads:0,dataMinX:0,dataMaxX:0}};if(a.fx){Ext.apply(a.fx,b)}else{a.fx=b}return a},getSprites:function(){var d=this,c=d.getChart(),e=d.getAnimation()||c&&c.getAnimation(),b=d.sprites[0],a;if(!c){return[]}if(!b){b=d.createSprite()}if(e){a=b.getMarker("markers");if(a){a.getTemplate().setAnimation(e)}b.setAnimation(e)}return d.sprites},provideLegendInfo:function(d){var b=this,a=b.getSubStyleWithTheme(),c=a.fillStyle;if(Ext.isArray(c)){c=c[0]}d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})}});Ext.define("Ext.chart.series.sprite.Scatter",{alias:"sprite.scatterSeries",extend:"Ext.chart.series.sprite.Cartesian",renderClipped:function(r,s,w,u){if(this.cleanRedraw){return}var C=this,q=C.attr,l=q.dataX,h=q.dataY,z=q.labels,j=C.getSeries(),b=z&&C.getMarker("labels"),t=C.attr.matrix,c=t.getXX(),p=t.getYY(),m=t.getDX(),k=t.getDY(),n={},D,B,d=r.getInherited().rtl&&!q.flipXY?-1:1,a,A,o,e,g,f,v;if(q.flipXY){a=u[1]-c*d;A=u[1]+u[3]+c*d;o=u[0]-p;e=u[0]+u[2]+p}else{a=u[0]-c*d;A=u[0]+u[2]+c*d;o=u[1]-p;e=u[1]+u[3]+p}for(v=0;v<l.length;v++){g=l[v];f=h[v];g=g*c+m;f=f*p+k;if(a<=g&&g<=A&&o<=f&&f<=e){if(q.renderer){n={type:"items",translationX:g,translationY:f};B=[C,n,{store:C.getStore()},v];D=Ext.callback(q.renderer,null,B,0,j);n=Ext.apply(n,D)}else{n.translationX=g;n.translationY=f}C.putMarker("items",n,v,!q.renderer);if(b&&z[v]){C.drawLabel(z[v],g,f,v,u)}}}},drawLabel:function(j,h,g,p,a){var r=this,m=r.attr,d=r.getMarker("labels"),c=d.getTemplate(),l=r.labelCfg||(r.labelCfg={}),b=r.surfaceMatrix,f,e,i=m.labelOverflowPadding,o=m.flipXY,k,n,s,q;l.text=j;n=r.getMarkerBBox("labels",p,true);if(!n){r.putMarker("labels",l,p);n=r.getMarkerBBox("labels",p,true)}if(o){l.rotationRads=Math.PI*0.5}else{l.rotationRads=0}k=n.height/2;f=h;switch(c.attr.display){case"under":e=g-k-i;break;case"rotate":f+=i;e=g-i;l.rotationRads=-Math.PI/4;break;default:e=g+k+i}l.x=b.x(f,e);l.y=b.y(f,e);if(c.attr.renderer){q=[j,d,l,{store:r.getStore()},p];s=Ext.callback(c.attr.renderer,null,q,0,r.getSeries());if(typeof s==="string"){l.text=s}else{Ext.apply(l,s)}}r.putMarker("labels",l,p)}});Ext.define("Ext.chart.series.Scatter",{extend:"Ext.chart.series.Cartesian",alias:"series.scatter",type:"scatter",seriesType:"scatterSeries",requires:["Ext.chart.series.sprite.Scatter"],config:{itemInstancing:{fx:{customDurations:{translationX:0,translationY:0}}}},themeMarkerCount:function(){return 1},applyMarker:function(b,a){this.getItemInstancing();this.setItemInstancing(b);return this.callParent(arguments)},provideLegendInfo:function(d){var b=this,a=b.getMarkerStyleByIndex(0),c=a.fillStyle;d.push({name:b.getTitle()||b.getYField()||b.getId(),mark:(Ext.isObject(c)?c.stops&&c.stops[0].color:c)||a.strokeStyle||"black",disabled:b.getHidden(),series:b.getId(),index:0})}});Ext.define("Ext.chart.theme.Blue",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.blue","chart.theme.Blue"],config:{baseColor:"#4d7fe6"}});Ext.define("Ext.chart.theme.BlueGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.blue-gradients","chart.theme.Blue:gradients"],config:{baseColor:"#4d7fe6",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category1",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category1","chart.theme.Category1"],config:{colors:["#f0a50a","#c20024","#2044ba","#810065","#7eae29"]}});Ext.define("Ext.chart.theme.Category1Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category1-gradients","chart.theme.Category1:gradients"],config:{colors:["#f0a50a","#c20024","#2044ba","#810065","#7eae29"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category2",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category2","chart.theme.Category2"],config:{colors:["#6d9824","#87146e","#2a9196","#d39006","#1e40ac"]}});Ext.define("Ext.chart.theme.Category2Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category2-gradients","chart.theme.Category2:gradients"],config:{colors:["#6d9824","#87146e","#2a9196","#d39006","#1e40ac"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category3",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category3","chart.theme.Category3"],config:{colors:["#fbbc29","#ce2e4e","#7e0062","#158b90","#57880e"]}});Ext.define("Ext.chart.theme.Category3Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category3-gradients","chart.theme.Category3:gradients"],config:{colors:["#fbbc29","#ce2e4e","#7e0062","#158b90","#57880e"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category4",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category4","chart.theme.Category4"],config:{colors:["#ef5773","#fcbd2a","#4f770d","#1d3eaa","#9b001f"]}});Ext.define("Ext.chart.theme.Category4Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category4-gradients","chart.theme.Category4:gradients"],config:{colors:["#ef5773","#fcbd2a","#4f770d","#1d3eaa","#9b001f"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category5",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category5","chart.theme.Category5"],config:{colors:["#7eae29","#fdbe2a","#910019","#27b4bc","#d74dbc"]}});Ext.define("Ext.chart.theme.Category5Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category5-gradients","chart.theme.Category5:gradients"],config:{colors:["#7eae29","#fdbe2a","#910019","#27b4bc","#d74dbc"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Category6",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category6","chart.theme.Category6"],config:{colors:["#44dce1","#0b2592","#996e05","#7fb325","#b821a1"]}});Ext.define("Ext.chart.theme.Category6Gradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.category6-gradients","chart.theme.Category6:gradients"],config:{colors:["#44dce1","#0b2592","#996e05","#7fb325","#b821a1"],gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.DefaultGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.default-gradients","chart.theme.Base:gradients"],config:{gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Green",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.green","chart.theme.Green"],config:{baseColor:"#b1da5a"}});Ext.define("Ext.chart.theme.GreenGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.green-gradients","chart.theme.Green:gradients"],config:{baseColor:"#b1da5a",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Midnight",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.midnight","chart.theme.Midnight"],config:{colors:["#A837FF","#4AC0F2","#FF4D35","#FF8809","#61C102","#FF37EA"],chart:{defaults:{background:"rgb(52, 52, 53)"}},axis:{defaults:{style:{strokeStyle:"rgb(224, 224, 227)"},label:{fillStyle:"rgb(224, 224, 227)"},title:{fillStyle:"rgb(224, 224, 227)"},grid:{strokeStyle:"rgb(112, 112, 115)"}}},series:{defaults:{label:{fillStyle:"rgb(224, 224, 227)"}}},sprites:{text:{fillStyle:"rgb(224, 224, 227)"}}}});Ext.define("Ext.chart.theme.Muted",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.muted","chart.theme.Muted"],config:{colors:["#8ca640","#974144","#4091ba","#8e658e","#3b8d8b","#b86465","#d2af69","#6e8852","#3dcc7e","#a6bed1","#cbaa4b","#998baa"]}});Ext.define("Ext.chart.theme.Purple",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.purple","chart.theme.Purple"],config:{baseColor:"#da5abd"}});Ext.define("Ext.chart.theme.PurpleGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.purple-gradients","chart.theme.Purple:gradients"],config:{baseColor:"#da5abd",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Red",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.red","chart.theme.Red"],config:{baseColor:"#e84b67"}});Ext.define("Ext.chart.theme.RedGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.red-gradients","chart.theme.Red:gradients"],config:{baseColor:"#e84b67",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Sky",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.sky","chart.theme.Sky"],config:{baseColor:"#4ce0e7"}});Ext.define("Ext.chart.theme.SkyGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.sky-gradients","chart.theme.Sky:gradients"],config:{baseColor:"#4ce0e7",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.chart.theme.Yellow",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.yellow","chart.theme.Yellow"],config:{baseColor:"#fec935"}});Ext.define("Ext.chart.theme.YellowGradients",{extend:"Ext.chart.theme.Base",singleton:true,alias:["chart.theme.yellow-gradients","chart.theme.Yellow:gradients"],config:{baseColor:"#fec935",gradients:{type:"linear",degrees:90}}});Ext.define("Ext.draw.Point",{requires:["Ext.draw.Draw","Ext.draw.Matrix"],isPoint:true,x:0,y:0,length:0,angle:0,angleUnits:"degrees",statics:{fly:(function(){var a=null;return function(b,c){if(!a){a=new Ext.draw.Point()}a.constructor(b,c);return a}})()},constructor:function(a,c){var b=this;if(typeof a==="number"){b.x=a;if(typeof c==="number"){b.y=c}else{b.y=a}}else{if(Ext.isArray(a)){b.x=a[0];b.y=a[1]}else{if(a){b.x=a.x;b.y=a.y}}}b.calculatePolar()},calculateCartesian:function(){var b=this,a=b.length,c=b.angle;if(b.angleUnits==="degrees"){c=Ext.draw.Draw.rad(c)}b.x=Math.cos(c)*a;b.y=Math.sin(c)*a},calculatePolar:function(){var b=this,a=b.x,c=b.y;b.length=Math.sqrt(a*a+c*c);b.angle=Math.atan2(c,a);if(b.angleUnits==="degrees"){b.angle=Ext.draw.Draw.degrees(b.angle)}},setX:function(a){this.x=a;this.calculatePolar()},setY:function(a){this.y=a;this.calculatePolar()},set:function(a,b){this.constructor(a,b)},setAngle:function(a){this.angle=a;this.calculateCartesian()},setLength:function(a){this.length=a;this.calculateCartesian()},setPolar:function(b,a){this.angle=b;this.length=a;this.calculateCartesian()},clone:function(){return new Ext.draw.Point(this.x,this.y)},add:function(a,c){var b=Ext.draw.Point.fly(a,c);return new Ext.draw.Point(this.x+b.x,this.y+b.y)},sub:function(a,c){var b=Ext.draw.Point.fly(a,c);return new Ext.draw.Point(this.x-b.x,this.y-b.y)},mul:function(a){return new Ext.draw.Point(this.x*a,this.y*a)},div:function(a){return new Ext.draw.Point(this.x/a,this.y/a)},dot:function(a,c){var b=Ext.draw.Point.fly(a,c);return this.x*b.x+this.y*b.y},equals:function(a,c){var b=Ext.draw.Point.fly(a,c);return this.x===b.x&&this.y===b.y},rotate:function(f,c){var d,e,b,g,a;if(this.angleUnits==="degrees"){f=Ext.draw.Draw.rad(f);d=Math.sin(f);e=Math.cos(f)}if(c){b=c.x;g=c.y}else{b=0;g=0}a=Ext.draw.Matrix.fly([e,d,-d,e,b-e*b+g*d,g-e*g+b*-d]).transformPoint(this);return new Ext.draw.Point(a)},transform:function(a){if(a&&a.isMatrix){return new Ext.draw.Point(a.transformPoint(this))}else{if(arguments.length===6){return new Ext.draw.Point(Ext.draw.Matrix.fly(arguments).transformPoint(this))}else{Ext.raise("Invalid parameters.")}}},round:function(){return new Ext.draw.Point(Math.round(this.x),Math.round(this.y))},ceil:function(){return new Ext.draw.Point(Math.ceil(this.x),Math.ceil(this.y))},floor:function(){return new Ext.draw.Point(Math.floor(this.x),Math.floor(this.y))},abs:function(a,b){return new Ext.draw.Point(Math.abs(this.x),Math.abs(this.y))},normalize:function(c){var b=this.x,f=this.y,a,e,d;c=c||1;if(b===0){a=0;e=c*Ext.Number.sign(f)}else{d=f/b;a=c/Math.sqrt(1+d*d);e=a*d}return new Ext.draw.Point(a,e)},getDistanceToLine:function(c,b){if(arguments.length===4){c=new Ext.draw.Point(arguments[0],arguments[1]);b=new Ext.draw.Point(arguments[2],arguments[3])}var d=b.sub(c).normalize(),a=c.sub(this);return a.sub(d.mul(a.dot(d)))},isZero:function(){return this.x===0&&this.y===0},isNumber:function(){return Ext.isNumber(this.x+this.y)}});Ext.define("Ext.draw.plugin.SpriteEvents",{extend:"Ext.plugin.Abstract",alias:"plugin.spriteevents",requires:["Ext.draw.PathUtil"],mouseMoveEvents:{mousemove:true,mouseover:true,mouseout:true},spriteMouseMoveEvents:{spritemousemove:true,spritemouseover:true,spritemouseout:true},init:function(a){var b="handleEvent";this.drawContainer=a;a.addElementListener({click:b,dblclick:b,mousedown:b,mousemove:b,mouseup:b,mouseover:b,mouseout:b,priority:1001,scope:this})},hasSpriteMouseMoveListeners:function(){var b=this.drawContainer.hasListeners,a;for(a in this.spriteMouseMoveEvents){if(a in b){return true}}return false},hitTestEvent:function(f){var b=this.drawContainer.getItems(),a,d,c;for(c=b.length-1;c>=0;c--){a=b.get(c);d=a.hitTestEvent(f);if(d){return d}}return null},handleEvent:function(f){var d=this,b=d.drawContainer,g=f.type in d.mouseMoveEvents,a=d.lastSprite,c;if(g&&!d.hasSpriteMouseMoveListeners()){return}c=d.hitTestEvent(f);if(g&&!Ext.Object.equals(c,a)){if(a){b.fireEvent("spritemouseout",a,f)}if(c){b.fireEvent("spritemouseover",c,f)}}if(c){b.fireEvent("sprite"+f.type,c,f)}d.lastSprite=c}});Ext.define("Ext.chart.TipSurface",{extend:"Ext.draw.Container",spriteArray:false,renderFirst:true,constructor:function(a){this.callParent([a]);if(a.sprites){this.spriteArray=[].concat(a.sprites);delete a.sprites}},onRender:function(){var c=this,b=0,a=0,d,e;this.callParent(arguments);e=c.spriteArray;if(c.renderFirst&&e){c.renderFirst=false;for(a=e.length;b<a;b++){d=c.surface.add(e[b]);d.setAttributes({hidden:false},true)}}}});Ext.define("Ext.chart.interactions.ItemInfo",{extend:"Ext.chart.interactions.Abstract",type:"iteminfo",alias:"interaction.iteminfo",config:{extjsGestures:{start:{event:"click",handler:"onInfoGesture"},move:{event:"mousemove",handler:"onInfoGesture"},end:{event:"mouseleave",handler:"onInfoGesture"}}},item:null,onInfoGesture:function(f,a){var c=this,b=c.getItemForEvent(f),d=b&&b.series.tooltip;if(d){d.onMouseMove.call(d,f)}if(b!==c.item){if(b){b.series.showTip(b)}else{c.item.series.hideTip(c.item)}c.item=b}return false}});
\ No newline at end of file
diff --git a/serverside/jsmod/6.1-3/proxmoxlib.js.original b/serverside/jsmod/6.1-3/proxmoxlib.js.original
deleted file mode 100644
index 9cb4842b9ad71ac098b7e819473fb46bfe8a70fc..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.1-3/proxmoxlib.js.original
+++ /dev/null
@@ -1,7639 +0,0 @@
-// 2.1-3
-Ext.ns('Proxmox');
-Ext.ns('Proxmox.Setup');
-
-if (!Ext.isDefined(Proxmox.Setup.auth_cookie_name)) {
-    throw "Proxmox library not initialized";
-}
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	dir: function() {},
-	log: function() {}
-    };
-}
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-Ext.Ajax.on('beforerequest', function(conn, options) {
-    if (Proxmox.CSRFPreventionToken) {
-	if (!options.headers) {
-	    options.headers = {};
-	}
-	options.headers.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-    }
-});
-
-Ext.define('Proxmox.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    yesText: gettext('Yes'),
-    noText: gettext('No'),
-    enabledText: gettext('Enabled'),
-    disabledText: gettext('Disabled'),
-    noneText: gettext('none'),
-    errorText: gettext('Error'),
-    unknownText: gettext('Unknown'),
-    defaultText: gettext('Default'),
-    daysText: gettext('days'),
-    dayText: gettext('day'),
-    runningText: gettext('running'),
-    stoppedText: gettext('stopped'),
-    neverText: gettext('never'),
-    totalText: gettext('Total'),
-    usedText: gettext('Used'),
-    directoryText: gettext('Directory'),
-    stateText: gettext('State'),
-    groupText: gettext('Group'),
-
-    language_map: {
-	ca: 'Catalan',
-	da: 'Danish',
-	de: 'German',
-	en: 'English',
-	es: 'Spanish',
-	eu: 'Euskera (Basque)',
-	fa: 'Persian (Farsi)',
-	fr: 'French',
-	he: 'Hebrew',
-	it: 'Italian',
-	ja: 'Japanese',
-	nb: 'Norwegian (Bokmal)',
-	nn: 'Norwegian (Nynorsk)',
-	pl: 'Polish',
-	pt_BR: 'Portuguese (Brazil)',
-	ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	tr: 'Turkish',
-	zh_CN: 'Chinese (Simplified)',
-	zh_TW: 'Chinese (Traditional)',
-    },
-
-    render_language: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (English)';
-	}
-	var text = Proxmox.Utils.language_map[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    language_array: function() {
-	var data = [['__default__', Proxmox.Utils.render_language('')]];
-	Ext.Object.each(Proxmox.Utils.language_map, function(key, value) {
-	    data.push([key, Proxmox.Utils.render_language(value)]);
-	});
-
-	return data;
-    },
-
-    bond_mode_gettext_map: {
-	'802.3ad': 'LACP (802.3ad)',
-	'lacp-balance-slb': 'LACP (balance-slb)',
-	'lacp-balance-tcp': 'LACP (balance-tcp)',
-    },
-
-    render_bond_mode: value => Proxmox.Utils.bond_mode_gettext_map[value] || value || '',
-
-    bond_mode_array: function(modes) {
-	return modes.map(mode => [mode, Proxmox.Utils.render_bond_mode(mode)]);
-    },
-
-    getNoSubKeyHtml: function(url) {
-	// url http://www.proxmox.com/products/proxmox-ve/subscription-service-plans
-	return Ext.String.format('You do not have a valid subscription for this server. Please visit <a target="_blank" href="{0}">www.proxmox.com</a> to get a list of available options.', url || 'https://www.proxmox.com');
-    },
-
-    format_boolean_with_default: function(value) {
-	if (Ext.isDefined(value) && value !== '__default__') {
-	    return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-	}
-	return Proxmox.Utils.defaultText;
-    },
-
-    format_boolean: function(value) {
-	return value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_neg_boolean: function(value) {
-	return !value ? Proxmox.Utils.yesText : Proxmox.Utils.noText;
-    },
-
-    format_enabled_toggle: function(value) {
-	return value ? Proxmox.Utils.enabledText : Proxmox.Utils.disabledText;
-    },
-
-    format_expire: function(date) {
-	if (!date) {
-	    return Proxmox.Utils.neverText;
-	}
-	return Ext.Date.format(date, "Y-m-d");
-    },
-
-    format_duration_long: function(ut) {
-
-	var days = Math.floor(ut / 86400);
-	ut -= days*86400;
-	var hours = Math.floor(ut / 3600);
-	ut -= hours*3600;
-	var mins = Math.floor(ut / 60);
-	ut -= mins*60;
-
-	var hours_str = '00' + hours.toString();
-	hours_str = hours_str.substr(hours_str.length - 2);
-	var mins_str = "00" + mins.toString();
-	mins_str = mins_str.substr(mins_str.length - 2);
-	var ut_str = "00" + ut.toString();
-	ut_str = ut_str.substr(ut_str.length - 2);
-
-	if (days) {
-	    var ds = days > 1 ? Proxmox.Utils.daysText : Proxmox.Utils.dayText;
-	    return days.toString() + ' ' + ds + ' ' +
-		hours_str + ':' + mins_str + ':' + ut_str;
-	} else {
-	    return hours_str + ':' + mins_str + ':' + ut_str;
-	}
-    },
-
-    format_subscription_level: function(level) {
-	if (level === 'c') {
-	    return 'Community';
-	} else if (level === 'b') {
-	    return 'Basic';
-	} else if (level === 's') {
-	    return 'Standard';
-	} else if (level === 'p') {
-	    return 'Premium';
-	} else {
-	    return Proxmox.Utils.noneText;
-	}
-    },
-
-    compute_min_label_width: function(text, width) {
-
-	if (width === undefined) { width = 100; }
-
-	var tm = new Ext.util.TextMetrics();
-	var min = tm.getWidth(text + ':');
-
-	return min < width ? width : min;
-    },
-
-    setAuthData: function(data) {
-	Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
-	Proxmox.UserName = data.username;
-	Proxmox.LoggedOut = data.LoggedOut;
-	// creates a session cookie (expire = null)
-	// that way the cookie gets deleted after the browser window is closed
-	Ext.util.Cookies.set(Proxmox.Setup.auth_cookie_name, data.ticket, null, '/', null, true);
-    },
-
-    authOK: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	return (Proxmox.UserName !== '') && Ext.util.Cookies.get(Proxmox.Setup.auth_cookie_name);
-    },
-
-    authClear: function() {
-	if (Proxmox.LoggedOut) {
-	    return undefined;
-	}
-	Ext.util.Cookies.clear(Proxmox.Setup.auth_cookie_name);
-    },
-
-    // comp.setLoading() is buggy in ExtJS 4.0.7, so we
-    // use el.mask() instead
-    setErrorMask: function(comp, msg) {
-	var el = comp.el;
-	if (!el) {
-	    return;
-	}
-	if (!msg) {
-	    el.unmask();
-	} else {
-	    if (msg === true) {
-		el.mask(gettext("Loading..."));
-	    } else {
-		el.mask(msg);
-	    }
-	}
-    },
-
-    monStoreErrors: function(me, store, clearMaskBeforeLoad) {
-	if (clearMaskBeforeLoad) {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		Proxmox.Utils.setErrorMask(me, false);
-	    });
-	} else {
-	    me.mon(store, 'beforeload', function(s, operation, eOpts) {
-		if (!me.loadCount) {
-		    me.loadCount = 0; // make sure it is numeric
-		    Proxmox.Utils.setErrorMask(me, true);
-		}
-	    });
-	}
-
-	// only works with 'proxmox' proxy
-	me.mon(store.proxy, 'afterload', function(proxy, request, success) {
-	    me.loadCount++;
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-
-	    var msg;
-	    /*jslint nomen: true */
-	    var operation = request._operation;
-	    var error = operation.getError();
-	    if (error.statusText) {
-		msg = error.statusText + ' (' + error.status + ')';
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    extractRequestError: function(result, verbose) {
-	var msg = gettext('Successful');
-
-	if (!result.success) {
-	    msg = gettext("Unknown error");
-	    if (result.message) {
-		msg = result.message;
-		if (result.status) {
-		    msg += ' (' + result.status + ')';
-		}
-	    }
-	    if (verbose && Ext.isObject(result.errors)) {
-		msg += "<br>";
-		Ext.Object.each(result.errors, function(prop, desc) {
-		    msg += "<br><b>" + Ext.htmlEncode(prop) + "</b>: " +
-			Ext.htmlEncode(desc);
-		});
-	    }
-	}
-
-	return msg;
-    },
-
-    // Ext.Ajax.request
-    API2Request: function(reqOpts) {
-
-	var newopts = Ext.apply({
-	    waitMsg: gettext('Please wait...')
-	}, reqOpts);
-
-	if (!newopts.url.match(/^\/api2/)) {
-	    newopts.url = '/api2/extjs' + newopts.url;
-	}
-	delete newopts.callback;
-
-	var createWrapper = function(successFn, callbackFn, failureFn) {
-	    Ext.apply(newopts, {
-		success: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    var result = Ext.decode(response.responseText);
-		    response.result = result;
-		    if (!result.success) {
-			response.htmlStatus = Proxmox.Utils.extractRequestError(result, true);
-			Ext.callback(callbackFn, options.scope, [options, false, response]);
-			Ext.callback(failureFn, options.scope, [response, options]);
-			return;
-		    }
-		    Ext.callback(callbackFn, options.scope, [options, true, response]);
-		    Ext.callback(successFn, options.scope, [response, options]);
-		},
-		failure: function(response, options) {
-		    if (options.waitMsgTarget) {
-			if (Proxmox.Utils.toolkit === 'touch') {
-			    options.waitMsgTarget.setMasked(false);
-			} else {
-			    options.waitMsgTarget.setLoading(false);
-			}
-		    }
-		    response.result = {};
-		    try {
-			response.result = Ext.decode(response.responseText);
-		    } catch(e) {}
-		    var msg = gettext('Connection error') + ' - server offline?';
-		    if (response.aborted) {
-			msg = gettext('Connection error') + ' - aborted.';
-		    } else if (response.timedout) {
-			msg = gettext('Connection error') + ' - Timeout.';
-		    } else if (response.status && response.statusText) {
-			msg = gettext('Connection error') + ' ' + response.status + ': ' + response.statusText;
-		    }
-		    response.htmlStatus = msg;
-		    Ext.callback(callbackFn, options.scope, [options, false, response]);
-		    Ext.callback(failureFn, options.scope, [response, options]);
-		}
-	    });
-	};
-
-	createWrapper(reqOpts.success, reqOpts.callback, reqOpts.failure);
-
-	var target = newopts.waitMsgTarget;
-	if (target) {
-	    if (Proxmox.Utils.toolkit === 'touch') {
-		target.setMasked({ xtype: 'loadmask', message: newopts.waitMsg} );
-	    } else {
-		// Note: ExtJS bug - this does not work when component is not rendered
-		target.setLoading(newopts.waitMsg);
-	    }
-	}
-	Ext.Ajax.request(newopts);
-    },
-
-    checked_command: function(orig_cmd) {
-	Proxmox.Utils.API2Request({
-	    url: '/nodes/localhost/subscription',
-	    method: 'GET',
-	    //waitMsgTarget: me,
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-
-		if (data.status !== 'Active') {
-		    Ext.Msg.show({
-			title: gettext('No valid subscription'),
-			icon: Ext.Msg.WARNING,
-			message: Proxmox.Utils.getNoSubKeyHtml(data.url),
-			buttons: Ext.Msg.OK,
-			callback: function(btn) {
-			    if (btn !== 'ok') {
-				return;
-			    }
-			    orig_cmd();
-			}
-		    });
-		} else {
-		    orig_cmd();
-		}
-	    }
-	});
-    },
-
-    assemble_field_data: function(values, data) {
-        if (Ext.isObject(data)) {
-	    Ext.Object.each(data, function(name, val) {
-		if (values.hasOwnProperty(name)) {
-                    var bucket = values[name];
-                    if (!Ext.isArray(bucket)) {
-                        bucket = values[name] = [bucket];
-                    }
-                    if (Ext.isArray(val)) {
-                        values[name] = bucket.concat(val);
-                    } else {
-                        bucket.push(val);
-                    }
-                } else {
-		    values[name] = val;
-                }
-            });
-	}
-    },
-
-    dialog_title: function(subject, create, isAdd) {
-	if (create) {
-	    if (isAdd) {
-		return gettext('Add') + ': ' + subject;
-	    } else {
-		return gettext('Create') + ': ' + subject;
-	    }
-	} else {
-	    return gettext('Edit') + ': ' + subject;
-	}
-    },
-
-    network_iface_types: {
-	eth: gettext("Network Device"),
-	bridge: 'Linux Bridge',
-	bond: 'Linux Bond',
-	vlan: 'Linux VLAN',
-	OVSBridge: 'OVS Bridge',
-	OVSBond: 'OVS Bond',
-	OVSPort: 'OVS Port',
-	OVSIntPort: 'OVS IntPort'
-    },
-
-    render_network_iface_type: function(value) {
-	return Proxmox.Utils.network_iface_types[value] ||
-	    Proxmox.Utils.unknownText;
-    },
-
-    task_desc_table: {
-	acmenewcert: [ 'SRV', gettext('Order Certificate') ],
-	acmeregister: [ 'ACME Account', gettext('Register') ],
-	acmedeactivate: [ 'ACME Account', gettext('Deactivate') ],
-	acmeupdate: [ 'ACME Account', gettext('Update') ],
-	acmerefresh: [ 'ACME Account', gettext('Refresh') ],
-	acmerenew: [ 'SRV', gettext('Renew Certificate') ],
-	acmerevoke: [ 'SRV', gettext('Revoke Certificate') ],
-	'move_volume': [ 'CT', gettext('Move Volume') ],
-	clustercreate: [ '', gettext('Create Cluster') ],
-	clusterjoin: [ '', gettext('Join Cluster') ],
-	diskinit: [ 'Disk', gettext('Initialize Disk with GPT') ],
-	vncproxy: [ 'VM/CT', gettext('Console') ],
-	spiceproxy: [ 'VM/CT', gettext('Console') + ' (Spice)' ],
-	vncshell: [ '', gettext('Shell') ],
-	spiceshell: [ '', gettext('Shell')  + ' (Spice)' ],
-	qmsnapshot: [ 'VM', gettext('Snapshot') ],
-	qmrollback: [ 'VM', gettext('Rollback') ],
-	qmdelsnapshot: [ 'VM', gettext('Delete Snapshot') ],
-	qmcreate: [ 'VM', gettext('Create') ],
-	qmrestore: [ 'VM', gettext('Restore') ],
-	qmdestroy: [ 'VM', gettext('Destroy') ],
-	qmigrate: [ 'VM', gettext('Migrate') ],
-	qmclone: [ 'VM', gettext('Clone') ],
-	qmmove: [ 'VM', gettext('Move disk') ],
-	qmtemplate: [ 'VM', gettext('Convert to template') ],
-	qmstart: [ 'VM', gettext('Start') ],
-	qmstop: [ 'VM', gettext('Stop') ],
-	qmreset: [ 'VM', gettext('Reset') ],
-	qmshutdown: [ 'VM', gettext('Shutdown') ],
-	qmreboot: [ 'VM', gettext('Reboot') ],
-	qmsuspend: [ 'VM', gettext('Hibernate') ],
-	qmpause: [ 'VM', gettext('Pause') ],
-	qmresume: [ 'VM', gettext('Resume') ],
-	qmconfig: [ 'VM', gettext('Configure') ],
-	vzsnapshot: [ 'CT', gettext('Snapshot') ],
-	vzrollback: [ 'CT', gettext('Rollback') ],
-	vzdelsnapshot: [ 'CT', gettext('Delete Snapshot') ],
-	vzcreate: ['CT', gettext('Create') ],
-	vzrestore: ['CT', gettext('Restore') ],
-	vzdestroy: ['CT', gettext('Destroy') ],
-	vzmigrate: [ 'CT', gettext('Migrate') ],
-	vzclone: [ 'CT', gettext('Clone') ],
-	vztemplate: [ 'CT', gettext('Convert to template') ],
-	vzstart: ['CT', gettext('Start') ],
-	vzstop: ['CT', gettext('Stop') ],
-	vzmount: ['CT', gettext('Mount') ],
-	vzumount: ['CT', gettext('Unmount') ],
-	vzshutdown: ['CT', gettext('Shutdown') ],
-	vzreboot: ['CT', gettext('Reboot') ],
-	vzsuspend: [ 'CT', gettext('Suspend') ],
-	vzresume: [ 'CT', gettext('Resume') ],
-	push_file: ['CT', gettext('Push file')],
-	pull_file: ['CT', gettext('Pull file')],
-	hamigrate: [ 'HA', gettext('Migrate') ],
-	hastart: [ 'HA', gettext('Start') ],
-	hastop: [ 'HA', gettext('Stop') ],
-	hashutdown: [ 'HA', gettext('Shutdown') ],
-	srvstart: ['SRV', gettext('Start') ],
-	srvstop: ['SRV', gettext('Stop') ],
-	srvrestart: ['SRV', gettext('Restart') ],
-	srvreload: ['SRV', gettext('Reload') ],
-	cephcreatemgr: ['Ceph Manager', gettext('Create') ],
-	cephdestroymgr: ['Ceph Manager', gettext('Destroy') ],
-	cephcreatemon: ['Ceph Monitor', gettext('Create') ],
-	cephdestroymon: ['Ceph Monitor', gettext('Destroy') ],
-	cephcreateosd: ['Ceph OSD', gettext('Create') ],
-	cephdestroyosd: ['Ceph OSD', gettext('Destroy') ],
-	cephcreatepool: ['Ceph Pool', gettext('Create') ],
-	cephdestroypool: ['Ceph Pool', gettext('Destroy') ],
-	cephfscreate: ['CephFS', gettext('Create') ],
-	cephcreatemds: ['Ceph Metadata Server', gettext('Create') ],
-	cephdestroymds: ['Ceph Metadata Server', gettext('Destroy') ],
-	imgcopy: ['', gettext('Copy data') ],
-	imgdel: ['', gettext('Erase data') ],
-	unknownimgdel: ['', gettext('Destroy image from unknown guest') ],
-	download: ['', gettext('Download') ],
-	vzdump: ['VM/CT', gettext('Backup') ],
-	aptupdate: ['', gettext('Update package database') ],
-	startall: [ '', gettext('Start all VMs and Containers') ],
-	stopall: [ '', gettext('Stop all VMs and Containers') ],
-	migrateall: [ '', gettext('Migrate all VMs and Containers') ],
-	dircreate: [ gettext('Directory Storage'), gettext('Create') ],
-	lvmcreate: [ gettext('LVM Storage'), gettext('Create') ],
-	lvmthincreate: [ gettext('LVM-Thin Storage'), gettext('Create') ],
-	zfscreate: [ gettext('ZFS Storage'), gettext('Create') ]
-    },
-
-    format_task_description: function(type, id) {
-	var farray = Proxmox.Utils.task_desc_table[type];
-	var text;
-	if (!farray) {
-	    text = type;
-	    if (id) {
-		type += ' ' + id;
-	    }
-	    return text;
-	}
-	var prefix = farray[0];
-	text = farray[1];
-	if (prefix) {
-	    return prefix + ' ' + id + ' - ' + text;
-	}
-	return text;
-    },
-
-    format_size: function(size) {
-	/*jslint confusion: true */
-
-	var units = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
-	var num = 0;
-
-	while (size >= 1024 && ((num++)+1) < units.length) {
-	    size = size / 1024;
-	}
-
-	return size.toFixed((num > 0)?2:0) + " " + units[num] + "B";
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    render_uptime: function(value) {
-
-	var uptime = value;
-
-	if (uptime === undefined) {
-	    return '';
-	}
-
-	if (uptime <= 0) {
-	    return '-';
-	}
-
-	return Proxmox.Utils.format_duration_long(uptime);
-    },
-
-    parse_task_upid: function(upid) {
-	var task = {};
-
-	var res = upid.match(/^UPID:([^\s:]+):([0-9A-Fa-f]{8}):([0-9A-Fa-f]{8,9}):(([0-9A-Fa-f]{8,16}):)?([0-9A-Fa-f]{8}):([^:\s]+):([^:\s]*):([^:\s]+):$/);
-	if (!res) {
-	    throw "unable to parse upid '" + upid + "'";
-	}
-	task.node = res[1];
-	task.pid = parseInt(res[2], 16);
-	task.pstart = parseInt(res[3], 16);
-	if (res[5] !== undefined) {
-	    task.task_id = parseInt(res[5], 16);
-	}
-	task.starttime = parseInt(res[6], 16);
-	task.type = res[7];
-	task.id = res[8];
-	task.user = res[9];
-
-	task.desc = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	return task;
-    },
-
-    render_timestamp: function(value, metaData, record, rowIndex, colIndex, store) {
-	var servertime = new Date(value * 1000);
-	return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-    },
-
-    get_help_info: function(section) {
-	var helpMap;
-	if (typeof proxmoxOnlineHelpInfo !== 'undefined') {
-	    helpMap = proxmoxOnlineHelpInfo;
-	} else if (typeof pveOnlineHelpInfo !== 'undefined') {
-	    // be backward compatible with older pve-doc-generators
-	    helpMap = pveOnlineHelpInfo;
-	} else {
-	    throw "no global OnlineHelpInfo map declared";
-	}
-
-	return helpMap[section];
-    },
-
-    get_help_link: function(section) {
-	var info = Proxmox.Utils.get_help_info(section);
-	if (!info) {
-	    return;
-	}
-
-	return window.location.origin + info.link;
-    },
-
-    openXtermJsViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    xtermjs: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    cmd: cmd,
-
-	});
-	var nw = window.open("?" + url, '_blank', 'toolbar=no,location=no,status=no,menubar=no,resizable=yes,width=800,height=420');
-	if (nw) {
-	    nw.focus();
-	}
-    }
-
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-
-	var IPV4_OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])";
-	var IPV4_REGEXP = "(?:(?:" + IPV4_OCTET + "\\.){3}" + IPV4_OCTET + ")";
-	var IPV6_H16 = "(?:[0-9a-fA-F]{1,4})";
-	var IPV6_LS32 = "(?:(?:" + IPV6_H16 + ":" + IPV6_H16 + ")|" + IPV4_REGEXP + ")";
-	var IPV4_CIDR_MASK = "([0-9]{1,2})";
-	var IPV6_CIDR_MASK = "([0-9]{1,3})";
-
-
-	me.IP4_match = new RegExp("^(?:" + IPV4_REGEXP + ")$");
-	me.IP4_cidr_match = new RegExp("^(?:" + IPV4_REGEXP + ")\/" + IPV4_CIDR_MASK + "$");
-
-	var IPV6_REGEXP = "(?:" +
-	    "(?:(?:"                                                  + "(?:" + IPV6_H16 + ":){6})" + IPV6_LS32 + ")|" +
-	    "(?:(?:"                                         +   "::" + "(?:" + IPV6_H16 + ":){5})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:"                           + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){4})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,1}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){3})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,2}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){2})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,3}" + IPV6_H16 + ")?::" + "(?:" + IPV6_H16 + ":){1})" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,4}" + IPV6_H16 + ")?::" +                         ")" + IPV6_LS32 + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,5}" + IPV6_H16 + ")?::" +                         ")" + IPV6_H16  + ")|" +
-	    "(?:(?:(?:(?:" + IPV6_H16 + ":){0,7}" + IPV6_H16 + ")?::" +                         ")"             + ")"  +
-	    ")";
-
-	me.IP6_match = new RegExp("^(?:" + IPV6_REGEXP + ")$");
-	me.IP6_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + ")\/" + IPV6_CIDR_MASK + "$");
-	me.IP6_bracket_match = new RegExp("^\\[(" + IPV6_REGEXP + ")\\]");
-
-	me.IP64_match = new RegExp("^(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + ")$");
-	me.IP64_cidr_match = new RegExp("^(?:" + IPV6_REGEXP + "\/" + IPV6_CIDR_MASK + ")|(?:" + IPV4_REGEXP + "\/" + IPV4_CIDR_MASK + ")$");
-
-	var DnsName_REGEXP = "(?:(([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?)\\.)*([A-Za-z0-9]([A-Za-z0-9\\-]*[A-Za-z0-9])?))";
-	me.DnsName_match = new RegExp("^" + DnsName_REGEXP + "$");
-
-	me.HostPort_match = new RegExp("^(" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")(:\\d+)?$");
-	me.HostPortBrackets_match = new RegExp("^\\[(?:" + IPV6_REGEXP + "|" + IPV4_REGEXP + "|" + DnsName_REGEXP + ")\\](:\\d+)?$");
-	me.IP6_dotnotation_match = new RegExp("^" + IPV6_REGEXP + "(\\.\\d+)?$");
-        me.Vlan_match = new RegExp('^vlan(\\d+)');
-        me.VlanInterface_match = new RegExp('(\\w+)\\.(\\d+)');
-    }
-});
-// ExtJS related things
-
- // do not send '_dc' parameter
-Ext.Ajax.disableCaching = false;
-
-// FIXME: HACK! Makes scrolling in number spinner work again. fixed in ExtJS >= 6.1
-if (Ext.isFirefox) {
-    Ext.$eventNameMap.DOMMouseScroll = 'DOMMouseScroll';
-}
-
-// custom Vtypes
-Ext.apply(Ext.form.field.VTypes, {
-    IPAddress:  function(v) {
-	return Proxmox.Utils.IP4_match.test(v);
-    },
-    IPAddressText:  gettext('Example') + ': 192.168.1.1',
-    IPAddressMask: /[\d\.]/i,
-
-    IPCIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP4_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 32);
-    },
-    IPCIDRAddressText:  gettext('Example') + ': 192.168.1.1/24' + "<br>" + gettext('Valid CIDR Range') + ': 8-32',
-    IPCIDRAddressMask: /[\d\.\/]/i,
-
-    IP6Address:  function(v) {
-        return Proxmox.Utils.IP6_match.test(v);
-    },
-    IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
-    IP6AddressMask: /[A-Fa-f0-9:]/,
-
-    IP6CIDRAddress:  function(v) {
-	var result = Proxmox.Utils.IP6_cidr_match.exec(v);
-	// limits according to JSON Schema see
-	// pve-common/src/PVE/JSONSchema.pm
-	return (result !== null && result[1] >= 8 && result[1] <= 128);
-    },
-    IP6CIDRAddressText:  gettext('Example') + ': 2001:DB8::42/64' + "<br>" + gettext('Valid CIDR Range') + ': 8-128',
-    IP6CIDRAddressMask:  /[A-Fa-f0-9:\/]/,
-
-    IP6PrefixLength:  function(v) {
-	return v >= 0 && v <= 128;
-    },
-    IP6PrefixLengthText:  gettext('Example') + ': X, where 0 <= X <= 128',
-    IP6PrefixLengthMask:  /[0-9]/,
-
-    IP64Address:  function(v) {
-        return Proxmox.Utils.IP64_match.test(v);
-    },
-    IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
-    IP64AddressMask: /[A-Fa-f0-9\.:]/,
-
-    IP64CIDRAddress: function(v) {
-	var result = Proxmox.Utils.IP64_cidr_match.exec(v);
-	if (result === null) {
-	    return false;
-	}
-	if (result[1] !== undefined) {
-	    return result[1] >= 8 && result[1] <= 128;
-	} else if (result[2] !== undefined) {
-	    return result[2] >= 8 && result[2] <= 32;
-	} else {
-	    return false;
-	}
-    },
-    IP64CIDRAddressText: gettext('Example') + ': 192.168.1.1/24 2001:DB8::42/64',
-    IP64CIDRAddressMask: /[A-Fa-f0-9\.:\/]/,
-
-    MacAddress: function(v) {
-	return (/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/).test(v);
-    },
-    MacAddressMask: /[a-fA-F0-9:]/,
-    MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
-
-    MacPrefix:  function(v) {
-	return (/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i).test(v);
-    },
-    MacPrefixMask: /[a-fA-F0-9:]/,
-    MacPrefixText: gettext('Example') + ': 02:8f - ' + gettext('only unicast addresses are allowed'),
-
-    BridgeName: function(v) {
-        return (/^vmbr\d{1,4}$/).test(v);
-    },
-    VlanName: function(v) {
-       if (Proxmox.Utils.VlanInterface_match.test(v)) {
-         return true;
-       } else if (Proxmox.Utils.Vlan_match.test(v)) {
-         return true;
-       }
-       return true;
-    },
-    BridgeNameText: gettext('Format') + ': vmbr<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    BondName: function(v) {
-        return (/^bond\d{1,4}$/).test(v);
-    },
-    BondNameText: gettext('Format') + ': bond<b>N</b>, where 0 <= <b>N</b> <= 9999',
-
-    InterfaceName: function(v) {
-        return (/^[a-z][a-z0-9_]{1,20}$/).test(v);
-    },
-    InterfaceNameText: gettext("Allowed characters") + ": 'a-z', '0-9', '_'" + "<br />" +
-		       gettext("Minimum characters") + ": 2" + "<br />" +
-		       gettext("Maximum characters") + ": 21" + "<br />" +
-		       gettext("Must start with") + ": 'a-z'",
-
-    StorageId:  function(v) {
-        return (/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i).test(v);
-    },
-    StorageIdText: gettext("Allowed characters") + ":  'A-Z', 'a-z', '0-9', '-', '_', '.'" + "<br />" +
-		   gettext("Minimum characters") + ": 2" + "<br />" +
-		   gettext("Must start with") + ": 'A-Z', 'a-z'<br />" +
-		   gettext("Must end with") + ": 'A-Z', 'a-z', '0-9'<br />",
-
-    ConfigId:  function(v) {
-        return (/^[a-z][a-z0-9\_]+$/i).test(v);
-    },
-    ConfigIdText: gettext("Allowed characters") + ": 'A-Z', 'a-z', '0-9', '_'" + "<br />" +
-		  gettext("Minimum characters") + ": 2" + "<br />" +
-		  gettext("Must start with") + ": " + gettext("letter"),
-
-    HttpProxy:  function(v) {
-        return (/^http:\/\/.*$/).test(v);
-    },
-    HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
-
-    DnsName: function(v) {
-	return Proxmox.Utils.DnsName_match.test(v);
-    },
-    DnsNameText: gettext('This is not a valid DNS name'),
-
-    // workaround for https://www.sencha.com/forum/showthread.php?302150
-    proxmoxMail: function(v) {
-        return (/^(\w+)([\-+.][\w]+)*@(\w[\-\w]*\.){1,5}([A-Za-z]){2,63}$/).test(v);
-    },
-    proxmoxMailText: gettext('Example') + ": user@example.com",
-
-    DnsOrIp: function(v) {
-	if (!Proxmox.Utils.DnsName_match.test(v) &&
-	    !Proxmox.Utils.IP64_match.test(v)) {
-	    return false;
-	}
-
-	return true;
-    },
-    DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
-
-    HostList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == "") {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
-		!Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
-		!Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    HostListText: gettext('Not a valid list of hosts'),
-
-    password: function(val, field) {
-        if (field.initialPassField) {
-            var pwd = field.up('form').down(
-		'[name=' + field.initialPassField + ']');
-            return (val == pwd.getValue());
-        }
-        return true;
-    },
-
-    passwordText: gettext('Passwords do not match')
-});
-
-// Firefox 52+ Touchscreen bug
-// see https://www.sencha.com/forum/showthread.php?336762-Examples-don-t-work-in-Firefox-52-touchscreen/page2
-// and https://bugzilla.proxmox.com/show_bug.cgi?id=1223
-Ext.define('EXTJS_23846.Element', {
-    override: 'Ext.dom.Element'
-}, function(Element) {
-    var supports = Ext.supports,
-        proto = Element.prototype,
-        eventMap = proto.eventMap,
-        additiveEvents = proto.additiveEvents;
-
-    if (Ext.os.is.Desktop && supports.TouchEvents && !supports.PointerEvents) {
-        eventMap.touchstart = 'mousedown';
-        eventMap.touchmove = 'mousemove';
-        eventMap.touchend = 'mouseup';
-        eventMap.touchcancel = 'mouseup';
-
-        additiveEvents.mousedown = 'mousedown';
-        additiveEvents.mousemove = 'mousemove';
-        additiveEvents.mouseup = 'mouseup';
-        additiveEvents.touchstart = 'touchstart';
-        additiveEvents.touchmove = 'touchmove';
-        additiveEvents.touchend = 'touchend';
-        additiveEvents.touchcancel = 'touchcancel';
-
-        additiveEvents.pointerdown = 'mousedown';
-        additiveEvents.pointermove = 'mousemove';
-        additiveEvents.pointerup = 'mouseup';
-        additiveEvents.pointercancel = 'mouseup';
-    }
-});
-
-Ext.define('EXTJS_23846.Gesture', {
-    override: 'Ext.event.publisher.Gesture'
-}, function(Gesture) {
-    var me = Gesture.instance;
-
-    if (Ext.supports.TouchEvents && !Ext.isWebKit && Ext.os.is.Desktop) {
-        me.handledDomEvents.push('mousedown', 'mousemove', 'mouseup');
-        me.registerEvents();
-    }
-});
-
-Ext.define('EXTJS_18900.Pie', {
-    override: 'Ext.chart.series.Pie',
-
-    // from 6.0.2
-    betweenAngle: function (x, a, b) {
-        var pp = Math.PI * 2,
-            offset = this.rotationOffset;
-
-        if (a === b) {
-            return false;
-        }
-
-        if (!this.getClockwise()) {
-            x *= -1;
-            a *= -1;
-            b *= -1;
-            a -= offset;
-            b -= offset;
-        } else {
-            a += offset;
-            b += offset;
-        }
-
-        x -= a;
-        b -= a;
-
-        // Normalize, so that both x and b are in the [0,360) interval.
-        x %= pp;
-        b %= pp;
-        x += pp;
-        b += pp;
-        x %= pp;
-        b %= pp;
-
-        // Because 360 * n angles will be normalized to 0,
-        // we need to treat b === 0 as a special case.
-        return x < b || b === 0;
-    },
-});
-
-// we always want the number in x.y format and never in, e.g., x,y
-Ext.define('PVE.form.field.Number', {
-    override: 'Ext.form.field.Number',
-    submitLocaleSeparator: false
-});
-
-// ExtJs 5-6 has an issue with caching
-// see https://www.sencha.com/forum/showthread.php?308989
-Ext.define('Proxmox.UnderlayPool', {
-    override: 'Ext.dom.UnderlayPool',
-
-    checkOut: function () {
-        var cache = this.cache,
-            len = cache.length,
-            el;
-
-        // do cleanup because some of the objects might have been destroyed
-	while (len--) {
-            if (cache[len].destroyed) {
-                cache.splice(len, 1);
-            }
-        }
-        // end do cleanup
-
-	el = cache.shift();
-
-        if (!el) {
-            el = Ext.Element.create(this.elementConfig);
-            el.setVisibilityMode(2);
-            //<debug>
-            // tell the spec runner to ignore this element when checking if the dom is clean
-	    el.dom.setAttribute('data-sticky', true);
-            //</debug>
-	}
-
-        return el;
-    }
-});
-
-// 'Enter' in Textareas and aria multiline fields should not activate the
-// defaultbutton, fixed in extjs 6.0.2
-Ext.define('PVE.panel.Panel', {
-    override: 'Ext.panel.Panel',
-
-    fireDefaultButton: function(e) {
-	if (e.target.getAttribute('aria-multiline') === 'true' ||
-	    e.target.tagName === "TEXTAREA") {
-	    return true;
-	}
-	return this.callParent(arguments);
-    }
-});
-
-// if the order of the values are not the same in originalValue and value
-// extjs will not overwrite value, but marks the field dirty and thus
-// the reset button will be enabled (but clicking it changes nothing)
-// so if the arrays are not the same after resetting, we
-// clear and set it
-Ext.define('Proxmox.form.ComboBox', {
-    override: 'Ext.form.field.ComboBox',
-
-    reset: function() {
-	// copied from combobox
-	var me = this;
-	me.callParent();
-
-	// clear and set when not the same
-	var value = me.getValue();
-	if (Ext.isArray(me.originalValue) && Ext.isArray(value) && !Ext.Array.equals(value, me.originalValue)) {
-	    me.clearValue();
-	    me.setValue(me.originalValue);
-	}
-    }
-});
-
-// when refreshing a grid/tree view, restoring the focus moves the view back to
-// the previously focused item. Save scroll position before refocusing.
-Ext.define(null, {
-    override: 'Ext.view.Table',
-
-    jumpToFocus: false,
-
-    saveFocusState: function() {
-        var me = this,
-            store = me.dataSource,
-            actionableMode = me.actionableMode,
-            navModel = me.getNavigationModel(),
-            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
-            refocusRow, refocusCol;
-
-        if (focusPosition) {
-            // Separate this from the instance that the nav model is using.
-            focusPosition = focusPosition.clone();
-
-            // Exit actionable mode.
-            // We must inform any Actionables that they must relinquish control.
-            // Tabbability must be reset.
-            if (actionableMode) {
-                me.ownerGrid.setActionableMode(false);
-            }
-
-            // Blur the focused descendant, but do not trigger focusLeave.
-            me.el.dom.focus();
-
-            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
-            // clear the navigation position
-            navModel.setPosition();
-
-            // The following function will attempt to refocus back in the same mode to the same cell
-            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
-            return function() {
-                // If we still have data, attempt to refocus in the same mode.
-                if (store.getCount()) {
-
-                    // Adjust expectations of where we are able to refocus according to what kind of destruction
-                    // might have been wrought on this view's DOM during focus save.
-                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
-                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
-                    focusPosition = new Ext.grid.CellContext(me).setPosition(
-                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
-
-                    if (actionableMode) {
-                        me.ownerGrid.setActionableMode(true, focusPosition);
-                    } else {
-                        me.cellFocused = true;
-
-			// we sometimes want to scroll back to where we were
-			var x = me.getScrollX();
-			var y = me.getScrollY();
-
-                        // Pass "preventNavigation" as true so that that does not cause selection.
-                        navModel.setPosition(focusPosition, null, null, null, true);
-
-			if (!me.jumpToFocus) {
-			    me.scrollTo(x,y);
-			}
-                    }
-                }
-                // No rows - focus associated column header
-                else {
-                    focusPosition.column.focus();
-                }
-            };
-        }
-        return Ext.emptyFn;
-    }
-});
-
-// should be fixed with ExtJS 6.0.2, see:
-// https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
-Ext.define('Proxmox.Datepicker', {
-    override: 'Ext.picker.Date',
-    hideMode: 'visibility'
-});
-
-// ExtJS 6.0.1 has no setSubmitValue() (although you find it in the docs).
-// Note: this.submitValue is a boolean flag, whereas getSubmitValue() returns
-// data to be submitted.
-Ext.define('Proxmox.form.field.Text', {
-    override: 'Ext.form.field.Text',
-
-    setSubmitValue: function(v) {
-	this.submitValue = v;
-    },
-});
-
-// this should be fixed with ExtJS 6.0.2
-// make mousescrolling work in firefox in the containers overflowhandler
-Ext.define(null, {
-    override: 'Ext.layout.container.boxOverflow.Scroller',
-
-    createWheelListener: function() {
-	var me = this;
-	if (Ext.isFirefox) {
-	    me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
-	} else {
-	    me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
-	}
-    },
-
-    // special wheel handler for firefox. differs from the default onMouseWheel
-    // handler by using deltaY instead of wheelDeltaY and no normalizing,
-    // because it is already
-    onMouseWheelFirefox: function(e) {
-	e.stopEvent();
-	var delta = e.browserEvent.deltaY || 0;
-	this.scrollBy(delta * this.wheelIncrement, false);
-    }
-
-});
-
-// add '@' to the valid id
-Ext.define('Proxmox.validIdReOverride', {
-    override: 'Ext.Component',
-    validIdRe: /^[a-z_][a-z0-9\-_\@]*$/i,
-});
-
-// force alert boxes to be rendered with an Error Icon
-// since Ext.Msg is an object and not a prototype, we need to override it
-// after the framework has been initiated
-Ext.onReady(function() {
-/*jslint confusion: true */
-    Ext.override(Ext.Msg, {
-	alert: function(title, message, fn, scope) {
-	    if (Ext.isString(title)) {
-		var config = {
-		    title: title,
-		    message: message,
-		    icon: this.ERROR,
-		    buttons: this.OK,
-		    fn: fn,
-		    scope : scope,
-		    minWidth: this.minWidth
-		};
-	    return this.show(config);
-	    }
-	}
-    });
-/*jslint confusion: false */
-});
-Ext.define('Ext.ux.IFrame', {
-    extend: 'Ext.Component',
-
-    alias: 'widget.uxiframe',
-
-    loadMask: 'Loading...',
-
-    src: 'about:blank',
-
-    renderTpl: [
-        '<iframe src="{src}" id="{id}-iframeEl" data-ref="iframeEl" name="{frameName}" width="100%" height="100%" frameborder="0" allowfullscreen="true"></iframe>'
-    ],
-    childEls: ['iframeEl'],
-
-    initComponent: function () {
-        this.callParent();
-
-        this.frameName = this.frameName || this.id + '-frame';
-    },
-
-    initEvents : function() {
-        var me = this;
-        me.callParent();
-        me.iframeEl.on('load', me.onLoad, me);
-    },
-
-    initRenderData: function() {
-        return Ext.apply(this.callParent(), {
-            src: this.src,
-            frameName: this.frameName
-        });
-    },
-
-    getBody: function() {
-        var doc = this.getDoc();
-        return doc.body || doc.documentElement;
-    },
-
-    getDoc: function() {
-        try {
-            return this.getWin().document;
-        } catch (ex) {
-            return null;
-        }
-    },
-
-    getWin: function() {
-        var me = this,
-            name = me.frameName,
-            win = Ext.isIE
-                ? me.iframeEl.dom.contentWindow
-                : window.frames[name];
-        return win;
-    },
-
-    getFrame: function() {
-        var me = this;
-        return me.iframeEl.dom;
-    },
-
-    beforeDestroy: function () {
-        this.cleanupListeners(true);
-        this.callParent();
-    },
-
-    cleanupListeners: function(destroying){
-        var doc, prop;
-
-        if (this.rendered) {
-            try {
-                doc = this.getDoc();
-                if (doc) {
-		    /*jslint nomen: true*/
-                    Ext.get(doc).un(this._docListeners);
-		    /*jslint nomen: false*/
-                    if (destroying && doc.hasOwnProperty) {
-                        for (prop in doc) {
-                            if (doc.hasOwnProperty(prop)) {
-                                delete doc[prop];
-                            }
-                        }
-                    }
-                }
-            } catch(e) { }
-        }
-    },
-
-    onLoad: function() {
-        var me = this,
-            doc = me.getDoc(),
-            fn = me.onRelayedEvent;
-
-        if (doc) {
-            try {
-                // These events need to be relayed from the inner document (where they stop
-                // bubbling) up to the outer document. This has to be done at the DOM level so
-                // the event reaches listeners on elements like the document body. The effected
-                // mechanisms that depend on this bubbling behavior are listed to the right
-                // of the event.
-		/*jslint nomen: true*/
-                Ext.get(doc).on(
-                    me._docListeners = {
-                        mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
-                        mousemove: fn, // window resize drag detection
-                        mouseup: fn,   // window resize termination
-                        click: fn,     // not sure, but just to be safe
-                        dblclick: fn,  // not sure again
-                        scope: me
-                    }
-                );
-		/*jslint nomen: false*/
-            } catch(e) {
-                // cannot do this xss
-            }
-
-            // We need to be sure we remove all our events from the iframe on unload or we're going to LEAK!
-            Ext.get(this.getWin()).on('beforeunload', me.cleanupListeners, me);
-
-            this.el.unmask();
-            this.fireEvent('load', this);
-
-        } else if (me.src) {
-
-            this.el.unmask();
-            this.fireEvent('error', this);
-        }
-
-
-    },
-
-    onRelayedEvent: function (event) {
-        // relay event from the iframe's document to the document that owns the iframe...
-
-        var iframeEl = this.iframeEl,
-
-            // Get the left-based iframe position
-            iframeXY = iframeEl.getTrueXY(),
-            originalEventXY = event.getXY(),
-
-            // Get the left-based XY position.
-            // This is because the consumer of the injected event will
-            // perform its own RTL normalization.
-            eventXY = event.getTrueXY();
-
-        // the event from the inner document has XY relative to that document's origin,
-        // so adjust it to use the origin of the iframe in the outer document:
-        event.xy = [iframeXY[0] + eventXY[0], iframeXY[1] + eventXY[1]];
-
-        event.injectEvent(iframeEl); // blame the iframe for the event...
-
-        event.xy = originalEventXY; // restore the original XY (just for safety)
-    },
-
-    load: function (src) {
-        var me = this,
-            text = me.loadMask,
-            frame = me.getFrame();
-
-        if (me.fireEvent('beforeload', me, src) !== false) {
-            if (text && me.el) {
-                me.el.mask(text);
-            }
-
-            frame.src = me.src = (src || me.src);
-        }
-    }
-});
-Ext.define('Proxmox.Mixin.CBind', {
-    extend: 'Ext.Mixin',
-
-    mixinConfig: {
-        before: {
-            initComponent: 'cloneTemplates'
-        }
-    },
-
-    cloneTemplates: function() {
-	var me = this;
-
- 	if (typeof(me.cbindData) == "function") {
-	    me.cbindData = me.cbindData(me.initialConfig);
-	}
-	me.cbindData = me.cbindData || {};
-
-	var getConfigValue = function(cname) {
-
-	    if (cname in me.initialConfig) {
-		return me.initialConfig[cname];
-	    }
-	    if (cname in me.cbindData) {
-		return me.cbindData[cname];
-	    }
-	    if (cname in me) {
-		return me[cname];
-	    }
-	    throw "unable to get cbind data for '" + cname + "'";
-	};
-
-	var applyCBind = function(obj) {
-	    var cbind = obj.cbind, prop, cdata, cvalue, match, found;
-	    if (!cbind) return;
-
-	    for (prop in cbind) {
-		cdata = cbind[prop];
-
-		found = false;
-		if (typeof cdata === 'function') {
-		    obj[prop] = cdata(getConfigValue, prop);
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*)\}$/i.exec(cdata)) {
-		    var cvalue = getConfigValue(match[2]);
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else if (match = /^\{(!)?([a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)+)\}$/i.exec(cdata)) {
-		    var keys = match[2].split('.');
-		    var cvalue = getConfigValue(keys.shift());
-		    keys.forEach(function(k) {
-			if (k in cvalue) {
-			    cvalue = cvalue[k];
-			} else {
-			    throw "unable to get cbind data for '" + match[2] + "'";
-			}
-		    });
-		    if (match[1]) cvalue = !cvalue;
-		    obj[prop] = cvalue;
-		    found = true;
-		} else {
-		    obj[prop] = cdata.replace(/{([a-z_][a-z0-9_]*)\}/ig, function(match, cname) {
-			var cvalue = getConfigValue(cname);
-			found = true;
-			return cvalue;
-		    });
-		}
-		if (!found) {
-		    throw "unable to parse cbind template '" + cdata + "'";
-		}
-
-	    }
-	};
-
-	if (me.cbind) {
-	    applyCBind(me);
-	}
-
-	var cloneTemplateArray = function(org) {
-	    var copy, i, found, el, elcopy, arrayLength;
-
-	    arrayLength = org.length;
-	    found = false;
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    found = true;
-		    break;
-		}
-	    }
-
-	    if (!found) return org; // no need to copy
-
-	    copy = [];
-	    for (i = 0; i < arrayLength; i++) {
-		el = org[i];
-		if (el.constructor == Object && el.xtype) {
-		    elcopy = cloneTemplateObject(el);
-		    if (elcopy.cbind) {
-			applyCBind(elcopy);
-		    }
-		    copy.push(elcopy);
-		} else if (el.constructor == Array) {
-		    elcopy = cloneTemplateArray(el);
-		    copy.push(elcopy);
-		} else {
-		    copy.push(el);
-		}
-	    }
-	    return copy;
-	};
-
-	var cloneTemplateObject = function(org) {
-	    var res = {}, prop, el, copy;
-	    for (prop in org) {
-		el = org[prop];
-		if (el === undefined || el === null) {
-		    res[prop] = el;
-		    continue;
-		}
-		if (el.constructor == Object && el.xtype) {
-		    copy = cloneTemplateObject(el);
-		    if (copy.cbind) {
-			applyCBind(copy);
-		    }
-		    res[prop] = copy;
-		} else if (el.constructor == Array) {
-		    copy = cloneTemplateArray(el);
-		    res[prop] = copy;
-		} else {
-		    res[prop] = el;
-		}
-	    }
-	    return res;
-	};
-
-	var condCloneProperties = function() {
-	    var prop, el, i, tmp;
-
-	    for (prop in me) {
-		el = me[prop];
-		if (el === undefined || el === null) continue;
-		if (typeof(el) === 'object' && el.constructor == Object) {
-		    if (el.xtype && prop != 'config') {
-			me[prop] = cloneTemplateObject(el);
-		    }
-		} else if (el.constructor == Array) {
-		    tmp = cloneTemplateArray(el);
-		    me[prop] = tmp;
-		}
-	    }
-	};
-
-	condCloneProperties();
-    }
-});
-/* A reader to store a single JSON Object (hash) into a storage.
- * Also accepts an array containing a single hash.
- *
- * So it can read:
- *
- * example1: {data1: "xyz", data2: "abc"}
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * example2: [ {data1: "xyz", data2: "abc"} ]
- * returns [{key: "data1", value: "xyz"}, {key: "data2", value: "abc"}]
- *
- * If you set 'readArray', the reader expexts the object as array:
- *
- * example3: [ { key: "data1", value: "xyz", p2: "cde" },  { key: "data2", value: "abc", p2: "efg" }]
- * returns [{key: "data1", value: "xyz", p2: "cde}, {key: "data2", value: "abc", p2: "efg"}]
- *
- * Note: The records can contain additional properties (like 'p2' above) when you use 'readArray'
- *
- * Additional feature: specify allowed properties with default values with 'rows' object
- *
- * var rows = {
- *   memory: {
- *     required: true,
- *     defaultValue: 512
- *   }
- * }
- *
- */
-
-Ext.define('Proxmox.data.reader.JsonObject', {
-    extend: 'Ext.data.reader.Json',
-    alias : 'reader.jsonobject',
-
-    readArray: false,
-
-    rows: undefined,
-
-    constructor: function(config) {
-        var me = this;
-
-        Ext.apply(me, config || {});
-
-	me.callParent([config]);
-    },
-
-    getResponseData: function(response) {
-	var me = this;
-
-	var data = [];
-        try {
-        var result = Ext.decode(response.responseText);
-        // get our data items inside the server response
-        var root = result[me.getRootProperty()];
-
-	    if (me.readArray) {
-
-		var rec_hash = {};
-		Ext.Array.each(root, function(rec) {
-		    if (Ext.isDefined(rec.key)) {
-			rec_hash[rec.key] = rec;
-		    }
-		});
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			var rec = rec_hash[key];
-			if (Ext.isDefined(rec)) {
-			    if (!Ext.isDefined(rec.value)) {
-				rec.value = rowdef.defaultValue;
-			    }
-			    data.push(rec);
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue} );
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined });
-			}
-		    });
-		} else {
-		    Ext.Array.each(root, function(rec) {
-			if (Ext.isDefined(rec.key)) {
-			    data.push(rec);
-			}
-		    });
-		}
-
-	    } else {
-
-		var org_root = root;
-
-		if (Ext.isArray(org_root)) {
-		    if (root.length == 1) {
-			root = org_root[0];
-		    } else {
-			root = {};
-		    }
-		}
-
-		if (me.rows) {
-		    Ext.Object.each(me.rows, function(key, rowdef) {
-			if (Ext.isDefined(root[key])) {
-			    data.push({key: key, value: root[key]});
-			} else if (Ext.isDefined(rowdef.defaultValue)) {
-			    data.push({key: key, value: rowdef.defaultValue});
-			} else if (rowdef.required) {
-			    data.push({key: key, value: undefined});
-			}
-		    });
-		} else {
-		    Ext.Object.each(root, function(key, value) {
-			data.push({key: key, value: value });
-		    });
-		}
-	    }
-	}
-        catch (ex) {
-            Ext.Error.raise({
-                response: response,
-                json: response.responseText,
-                parseError: ex,
-                msg: 'Unable to parse the JSON returned by the server: ' + ex.toString()
-            });
-        }
-
-	return data;
-    }
-});
-
-Ext.define('Proxmox.RestProxy', {
-    extend: 'Ext.data.RestProxy',
-    alias : 'proxy.proxmox',
-
-    pageParam : null,
-    startParam: null,
-    limitParam: null,
-    groupParam: null,
-    sortParam: null,
-    filterParam: null,
-    noCache : false,
-
-    afterRequest: function(request, success) {
-	this.fireEvent('afterload', this, request, success);
-	return;
-    },
-
-    constructor: function(config) {
-
-	Ext.applyIf(config, {
-	    reader: {
-		type: 'json',
-		rootProperty: config.root || 'data'
-	    }
-	});
-
-	this.callParent([config]);
-    }
-}, function() {
-
-    Ext.define('KeyValue', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('KeyValuePendingDelete', {
-	extend: "Ext.data.Model",
-	fields: [ 'key', 'value', 'pending', 'delete' ],
-	idProperty: 'key'
-    });
-
-    Ext.define('proxmox-tasks', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'starttime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'endtime', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'upid', 'user', 'status', 'type', 'id'
-	],
-	idProperty: 'upid'
-    });
-
-    Ext.define('proxmox-cluster-log', {
-	extend: 'Ext.data.Model',
-	fields:  [
-	    { name: 'uid' , type: 'int' },
-	    { name: 'time', type : 'date', dateFormat: 'timestamp' },
-	    { name: 'pri', type: 'int' },
-	    { name: 'pid', type: 'int' },
-	    'node', 'user', 'tag', 'msg',
-	    {
-		name: 'id',
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-		    // compute unique ID
-		    return info.uid + ':' + info.node;
-		}
-	    }
-	],
-	idProperty: 'id'
-    });
-
-});
-/* Extends the Ext.data.Store type
- * with  startUpdate() and stopUpdate() methods
- * to refresh the store data in the background
- * Components using this store directly will flicker
- * due to the redisplay of the element ater 'config.interval' ms
- *
- * Note that you have to call yourself startUpdate() for the background load
- * to begin
- */
-Ext.define('Proxmox.data.UpdateStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.update',
-
-    isStopped: true,
-
-    autoStart: false,
-
-    destroy: function() {
-	var me = this;
-	me.stopUpdate();
-	me.callParent();
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.interval) {
-	    config.interval = 3000;
-	}
-
-	if (!config.storeid) {
-	    throw "no storeid specified";
-	}
-
-	var load_task = new Ext.util.DelayedTask();
-
-	var run_load_task = function() {
-	    if (me.isStopped) {
-		return;
-	    }
-
-	    if (Proxmox.Utils.authOK()) {
-		var start = new Date();
-		me.load(function() {
-		    var runtime = (new Date()) - start;
-		    var interval = config.interval + runtime*2;
-		    load_task.delay(interval, run_load_task);
-		});
-	    } else {
-		load_task.delay(200, run_load_task);
-	    }
-	};
-
-	Ext.apply(config, {
-	    startUpdate: function() {
-		me.isStopped = false;
-		// run_load_task(); this makes problems with chrome
-		load_task.delay(1, run_load_task);
-	    },
-	    stopUpdate: function() {
-		me.isStopped = true;
-		load_task.cancel();
-	    }
-	});
-
-	me.callParent([config]);
-
-	me.load_task = load_task;
-
-	if (me.autoStart) {
-	    me.startUpdate();
-	}
-    }
-});
-/*
- * The DiffStore is a in-memory store acting as proxy between a real store
- * instance and a component.
- * Its purpose is to redisplay the component *only* if the data has been changed
- * inside the real store, to avoid the annoying visual flickering of using
- * the real store directly.
- *
- * Implementation:
- * The DiffStore monitors via mon() the 'load' events sent by the real store.
- * On each 'load' event, the DiffStore compares its own content with the target
- * store (call to cond_add_item()) and then fires a 'refresh' event.
- * The 'refresh' event will automatically trigger a view refresh on the component
- * who binds to this store.
- */
-
-/* Config properties:
- * rstore: the realstore which will autorefresh its content from the API
- * Only works if rstore has a model and use 'idProperty'
- * sortAfterUpdate: sort the diffstore before rendering the view
- */
-Ext.define('Proxmox.data.DiffStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.diff',
-
-    sortAfterUpdate: false,
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	if (!config.rstore) {
-	    throw "no rstore specified";
-	}
-
-	if (!config.rstore.model) {
-	    throw "no rstore model specified";
-	}
-
-	var rstore = config.rstore;
-
-	Ext.apply(config, {
-	    model: rstore.model,
-	    proxy: { type: 'memory' }
-	});
-
-	me.callParent([config]);
-
-	var first_load = true;
-
-	var cond_add_item = function(data, id) {
-	    var olditem = me.getById(id);
-	    if (olditem) {
-		olditem.beginEdit();
-		Ext.Array.each(me.model.prototype.fields, function(field) {
-		    if (olditem.data[field.name] !== data[field.name]) {
-			olditem.set(field.name, data[field.name]);
-		    }
-		});
-		olditem.endEdit(true);
-		olditem.commit();
-	    } else {
-		var newrec = Ext.create(me.model, data);
-		var pos = (me.appendAtStart && !first_load) ? 0 : me.data.length;
-		me.insert(pos, newrec);
-	    }
-	};
-
-	var loadFn = function(s, records, success) {
-
-	    if (!success) {
-		return;
-	    }
-
-	    me.suspendEvents();
-
-	    // getSource returns null if data is not filtered
-	    // if it is filtered it returns all records
-	    var allItems = me.getData().getSource() || me.getData();
-
-	    // remove vanished items
-	    allItems.each(function(olditem) {
-		var item = rstore.getById(olditem.getId());
-		if (!item) {
-		    me.remove(olditem);
-		}
-	    });
-
-	    rstore.each(function(item) {
-		cond_add_item(item.data, item.getId());
-	    });
-
-	    me.filter();
-
-	    if (me.sortAfterUpdate) {
-		me.sort();
-	    }
-
-	    first_load = false;
-
-	    me.resumeEvents();
-	    me.fireEvent('refresh', me);
-	    me.fireEvent('datachanged', me);
-	};
-
-	if (rstore.isLoaded()) {
-	    // if store is already loaded,
-	    // insert items instantly
-	    loadFn(rstore, [], true);
-	}
-
-	me.mon(rstore, 'load', loadFn);
-    }
-});
-/* This store encapsulates data items which are organized as an Array of key-values Objects
- * ie data[0] contains something like {key: "keyboard", value: "da"}
-*
-* Designed to work with the KeyValue model and the JsonObject data reader
-*/
-Ext.define('Proxmox.data.ObjectStore',  {
-    extend: 'Proxmox.data.UpdateStore',
-
-    getRecord: function() {
-	var me = this;
-	var record = Ext.create('Ext.data.Model');
-	me.getData().each(function(item) {
-	    record.set(item.data.key, item.data.value);
-	});
-	record.commit(true);
-	return record;
-    },
-
-    constructor: function(config) {
-	var me = this;
-
-        config = config || {};
-
-	if (!config.storeid) {
-	    config.storeid =  'proxmox-store-' + (++Ext.idSeed);
-	}
-
-        Ext.applyIf(config, {
-	    model: 'KeyValue',
-            proxy: {
-                type: 'proxmox',
-		url: config.url,
-		extraParams: config.extraParams,
-                reader: {
-		    type: 'jsonobject',
-		    rows: config.rows,
-		    readArray: config.readArray,
-		    rootProperty: config.root || 'data'
-		}
-            }
-        });
-
-        me.callParent([config]);
-    }
-});
-/* Extends the Proxmox.data.UpdateStore type
- *
- *
- */
-Ext.define('Proxmox.data.RRDStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    alias: 'store.proxmoxRRDStore',
-
-    setRRDUrl: function(timeframe, cf) {
-	var me = this;
-	if (!timeframe) {
-	    timeframe = me.timeframe;
-	}
-
-	if (!cf) {
-	    cf = me.cf;
-	}
-
-	me.proxy.url = me.rrdurl + "?timeframe=" + timeframe + "&cf=" + cf;
-    },
-
-    proxy: {
-	type: 'proxmox'
-    },
-
-    timeframe: 'hour',
-
-    cf: 'AVERAGE',
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	// set default interval to 30seconds
-	if (!config.interval) {
-	    config.interval = 30000;
-	}
-
-	// set a new storeid
-	if (!config.storeid) {
-	    config.storeid = 'rrdstore-' + (++Ext.idSeed);
-	}
-
-	// rrdurl is required
-	if (!config.rrdurl) {
-	    throw "no rrdurl specified";
-	}
-
-	var stateid = 'proxmoxRRDTypeSelection';
-	var sp = Ext.state.Manager.getProvider();
-	var stateinit = sp.get(stateid);
-
-        if (stateinit) {
-	    if(stateinit.timeframe !== me.timeframe || stateinit.cf !== me.rrdcffn){
-		me.timeframe = stateinit.timeframe;
-		me.rrdcffn = stateinit.cf;
-	    }
-	}
-
-	me.callParent([config]);
-
-	me.setRRDUrl();
-	me.mon(sp, 'statechange', function(prov, key, state){
-	    if (key === stateid) {
-		if (state && state.id) {
-		    if (state.timeframe !== me.timeframe || state.cf !== me.cf) {
-		        me.timeframe = state.timeframe;
-		        me.cf = state.cf;
-			me.setRRDUrl();
-			me.reload();
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Timezone', {
-    extend: 'Ext.data.Model',
-    fields: ['zone']
-});
-
-Ext.define('Proxmox.data.TimezoneStore', {
-    extend: 'Ext.data.Store',
-    model: 'Timezone',
-    data: [
-	    ['Africa/Abidjan'],
-	    ['Africa/Accra'],
-	    ['Africa/Addis_Ababa'],
-	    ['Africa/Algiers'],
-	    ['Africa/Asmara'],
-	    ['Africa/Bamako'],
-	    ['Africa/Bangui'],
-	    ['Africa/Banjul'],
-	    ['Africa/Bissau'],
-	    ['Africa/Blantyre'],
-	    ['Africa/Brazzaville'],
-	    ['Africa/Bujumbura'],
-	    ['Africa/Cairo'],
-	    ['Africa/Casablanca'],
-	    ['Africa/Ceuta'],
-	    ['Africa/Conakry'],
-	    ['Africa/Dakar'],
-	    ['Africa/Dar_es_Salaam'],
-	    ['Africa/Djibouti'],
-	    ['Africa/Douala'],
-	    ['Africa/El_Aaiun'],
-	    ['Africa/Freetown'],
-	    ['Africa/Gaborone'],
-	    ['Africa/Harare'],
-	    ['Africa/Johannesburg'],
-	    ['Africa/Kampala'],
-	    ['Africa/Khartoum'],
-	    ['Africa/Kigali'],
-	    ['Africa/Kinshasa'],
-	    ['Africa/Lagos'],
-	    ['Africa/Libreville'],
-	    ['Africa/Lome'],
-	    ['Africa/Luanda'],
-	    ['Africa/Lubumbashi'],
-	    ['Africa/Lusaka'],
-	    ['Africa/Malabo'],
-	    ['Africa/Maputo'],
-	    ['Africa/Maseru'],
-	    ['Africa/Mbabane'],
-	    ['Africa/Mogadishu'],
-	    ['Africa/Monrovia'],
-	    ['Africa/Nairobi'],
-	    ['Africa/Ndjamena'],
-	    ['Africa/Niamey'],
-	    ['Africa/Nouakchott'],
-	    ['Africa/Ouagadougou'],
-	    ['Africa/Porto-Novo'],
-	    ['Africa/Sao_Tome'],
-	    ['Africa/Tripoli'],
-	    ['Africa/Tunis'],
-	    ['Africa/Windhoek'],
-	    ['America/Adak'],
-	    ['America/Anchorage'],
-	    ['America/Anguilla'],
-	    ['America/Antigua'],
-	    ['America/Araguaina'],
-	    ['America/Argentina/Buenos_Aires'],
-	    ['America/Argentina/Catamarca'],
-	    ['America/Argentina/Cordoba'],
-	    ['America/Argentina/Jujuy'],
-	    ['America/Argentina/La_Rioja'],
-	    ['America/Argentina/Mendoza'],
-	    ['America/Argentina/Rio_Gallegos'],
-	    ['America/Argentina/Salta'],
-	    ['America/Argentina/San_Juan'],
-	    ['America/Argentina/San_Luis'],
-	    ['America/Argentina/Tucuman'],
-	    ['America/Argentina/Ushuaia'],
-	    ['America/Aruba'],
-	    ['America/Asuncion'],
-	    ['America/Atikokan'],
-	    ['America/Bahia'],
-	    ['America/Bahia_Banderas'],
-	    ['America/Barbados'],
-	    ['America/Belem'],
-	    ['America/Belize'],
-	    ['America/Blanc-Sablon'],
-	    ['America/Boa_Vista'],
-	    ['America/Bogota'],
-	    ['America/Boise'],
-	    ['America/Cambridge_Bay'],
-	    ['America/Campo_Grande'],
-	    ['America/Cancun'],
-	    ['America/Caracas'],
-	    ['America/Cayenne'],
-	    ['America/Cayman'],
-	    ['America/Chicago'],
-	    ['America/Chihuahua'],
-	    ['America/Costa_Rica'],
-	    ['America/Cuiaba'],
-	    ['America/Curacao'],
-	    ['America/Danmarkshavn'],
-	    ['America/Dawson'],
-	    ['America/Dawson_Creek'],
-	    ['America/Denver'],
-	    ['America/Detroit'],
-	    ['America/Dominica'],
-	    ['America/Edmonton'],
-	    ['America/Eirunepe'],
-	    ['America/El_Salvador'],
-	    ['America/Fortaleza'],
-	    ['America/Glace_Bay'],
-	    ['America/Godthab'],
-	    ['America/Goose_Bay'],
-	    ['America/Grand_Turk'],
-	    ['America/Grenada'],
-	    ['America/Guadeloupe'],
-	    ['America/Guatemala'],
-	    ['America/Guayaquil'],
-	    ['America/Guyana'],
-	    ['America/Halifax'],
-	    ['America/Havana'],
-	    ['America/Hermosillo'],
-	    ['America/Indiana/Indianapolis'],
-	    ['America/Indiana/Knox'],
-	    ['America/Indiana/Marengo'],
-	    ['America/Indiana/Petersburg'],
-	    ['America/Indiana/Tell_City'],
-	    ['America/Indiana/Vevay'],
-	    ['America/Indiana/Vincennes'],
-	    ['America/Indiana/Winamac'],
-	    ['America/Inuvik'],
-	    ['America/Iqaluit'],
-	    ['America/Jamaica'],
-	    ['America/Juneau'],
-	    ['America/Kentucky/Louisville'],
-	    ['America/Kentucky/Monticello'],
-	    ['America/La_Paz'],
-	    ['America/Lima'],
-	    ['America/Los_Angeles'],
-	    ['America/Maceio'],
-	    ['America/Managua'],
-	    ['America/Manaus'],
-	    ['America/Marigot'],
-	    ['America/Martinique'],
-	    ['America/Matamoros'],
-	    ['America/Mazatlan'],
-	    ['America/Menominee'],
-	    ['America/Merida'],
-	    ['America/Mexico_City'],
-	    ['America/Miquelon'],
-	    ['America/Moncton'],
-	    ['America/Monterrey'],
-	    ['America/Montevideo'],
-	    ['America/Montreal'],
-	    ['America/Montserrat'],
-	    ['America/Nassau'],
-	    ['America/New_York'],
-	    ['America/Nipigon'],
-	    ['America/Nome'],
-	    ['America/Noronha'],
-	    ['America/North_Dakota/Center'],
-	    ['America/North_Dakota/New_Salem'],
-	    ['America/Ojinaga'],
-	    ['America/Panama'],
-	    ['America/Pangnirtung'],
-	    ['America/Paramaribo'],
-	    ['America/Phoenix'],
-	    ['America/Port-au-Prince'],
-	    ['America/Port_of_Spain'],
-	    ['America/Porto_Velho'],
-	    ['America/Puerto_Rico'],
-	    ['America/Rainy_River'],
-	    ['America/Rankin_Inlet'],
-	    ['America/Recife'],
-	    ['America/Regina'],
-	    ['America/Resolute'],
-	    ['America/Rio_Branco'],
-	    ['America/Santa_Isabel'],
-	    ['America/Santarem'],
-	    ['America/Santiago'],
-	    ['America/Santo_Domingo'],
-	    ['America/Sao_Paulo'],
-	    ['America/Scoresbysund'],
-	    ['America/Shiprock'],
-	    ['America/St_Barthelemy'],
-	    ['America/St_Johns'],
-	    ['America/St_Kitts'],
-	    ['America/St_Lucia'],
-	    ['America/St_Thomas'],
-	    ['America/St_Vincent'],
-	    ['America/Swift_Current'],
-	    ['America/Tegucigalpa'],
-	    ['America/Thule'],
-	    ['America/Thunder_Bay'],
-	    ['America/Tijuana'],
-	    ['America/Toronto'],
-	    ['America/Tortola'],
-	    ['America/Vancouver'],
-	    ['America/Whitehorse'],
-	    ['America/Winnipeg'],
-	    ['America/Yakutat'],
-	    ['America/Yellowknife'],
-	    ['Antarctica/Casey'],
-	    ['Antarctica/Davis'],
-	    ['Antarctica/DumontDUrville'],
-	    ['Antarctica/Macquarie'],
-	    ['Antarctica/Mawson'],
-	    ['Antarctica/McMurdo'],
-	    ['Antarctica/Palmer'],
-	    ['Antarctica/Rothera'],
-	    ['Antarctica/South_Pole'],
-	    ['Antarctica/Syowa'],
-	    ['Antarctica/Vostok'],
-	    ['Arctic/Longyearbyen'],
-	    ['Asia/Aden'],
-	    ['Asia/Almaty'],
-	    ['Asia/Amman'],
-	    ['Asia/Anadyr'],
-	    ['Asia/Aqtau'],
-	    ['Asia/Aqtobe'],
-	    ['Asia/Ashgabat'],
-	    ['Asia/Baghdad'],
-	    ['Asia/Bahrain'],
-	    ['Asia/Baku'],
-	    ['Asia/Bangkok'],
-	    ['Asia/Beirut'],
-	    ['Asia/Bishkek'],
-	    ['Asia/Brunei'],
-	    ['Asia/Choibalsan'],
-	    ['Asia/Chongqing'],
-	    ['Asia/Colombo'],
-	    ['Asia/Damascus'],
-	    ['Asia/Dhaka'],
-	    ['Asia/Dili'],
-	    ['Asia/Dubai'],
-	    ['Asia/Dushanbe'],
-	    ['Asia/Gaza'],
-	    ['Asia/Harbin'],
-	    ['Asia/Ho_Chi_Minh'],
-	    ['Asia/Hong_Kong'],
-	    ['Asia/Hovd'],
-	    ['Asia/Irkutsk'],
-	    ['Asia/Jakarta'],
-	    ['Asia/Jayapura'],
-	    ['Asia/Jerusalem'],
-	    ['Asia/Kabul'],
-	    ['Asia/Kamchatka'],
-	    ['Asia/Karachi'],
-	    ['Asia/Kashgar'],
-	    ['Asia/Kathmandu'],
-	    ['Asia/Kolkata'],
-	    ['Asia/Krasnoyarsk'],
-	    ['Asia/Kuala_Lumpur'],
-	    ['Asia/Kuching'],
-	    ['Asia/Kuwait'],
-	    ['Asia/Macau'],
-	    ['Asia/Magadan'],
-	    ['Asia/Makassar'],
-	    ['Asia/Manila'],
-	    ['Asia/Muscat'],
-	    ['Asia/Nicosia'],
-	    ['Asia/Novokuznetsk'],
-	    ['Asia/Novosibirsk'],
-	    ['Asia/Omsk'],
-	    ['Asia/Oral'],
-	    ['Asia/Phnom_Penh'],
-	    ['Asia/Pontianak'],
-	    ['Asia/Pyongyang'],
-	    ['Asia/Qatar'],
-	    ['Asia/Qyzylorda'],
-	    ['Asia/Rangoon'],
-	    ['Asia/Riyadh'],
-	    ['Asia/Sakhalin'],
-	    ['Asia/Samarkand'],
-	    ['Asia/Seoul'],
-	    ['Asia/Shanghai'],
-	    ['Asia/Singapore'],
-	    ['Asia/Taipei'],
-	    ['Asia/Tashkent'],
-	    ['Asia/Tbilisi'],
-	    ['Asia/Tehran'],
-	    ['Asia/Thimphu'],
-	    ['Asia/Tokyo'],
-	    ['Asia/Ulaanbaatar'],
-	    ['Asia/Urumqi'],
-	    ['Asia/Vientiane'],
-	    ['Asia/Vladivostok'],
-	    ['Asia/Yakutsk'],
-	    ['Asia/Yekaterinburg'],
-	    ['Asia/Yerevan'],
-	    ['Atlantic/Azores'],
-	    ['Atlantic/Bermuda'],
-	    ['Atlantic/Canary'],
-	    ['Atlantic/Cape_Verde'],
-	    ['Atlantic/Faroe'],
-	    ['Atlantic/Madeira'],
-	    ['Atlantic/Reykjavik'],
-	    ['Atlantic/South_Georgia'],
-	    ['Atlantic/St_Helena'],
-	    ['Atlantic/Stanley'],
-	    ['Australia/Adelaide'],
-	    ['Australia/Brisbane'],
-	    ['Australia/Broken_Hill'],
-	    ['Australia/Currie'],
-	    ['Australia/Darwin'],
-	    ['Australia/Eucla'],
-	    ['Australia/Hobart'],
-	    ['Australia/Lindeman'],
-	    ['Australia/Lord_Howe'],
-	    ['Australia/Melbourne'],
-	    ['Australia/Perth'],
-	    ['Australia/Sydney'],
-	    ['Europe/Amsterdam'],
-	    ['Europe/Andorra'],
-	    ['Europe/Athens'],
-	    ['Europe/Belgrade'],
-	    ['Europe/Berlin'],
-	    ['Europe/Bratislava'],
-	    ['Europe/Brussels'],
-	    ['Europe/Bucharest'],
-	    ['Europe/Budapest'],
-	    ['Europe/Chisinau'],
-	    ['Europe/Copenhagen'],
-	    ['Europe/Dublin'],
-	    ['Europe/Gibraltar'],
-	    ['Europe/Guernsey'],
-	    ['Europe/Helsinki'],
-	    ['Europe/Isle_of_Man'],
-	    ['Europe/Istanbul'],
-	    ['Europe/Jersey'],
-	    ['Europe/Kaliningrad'],
-	    ['Europe/Kiev'],
-	    ['Europe/Lisbon'],
-	    ['Europe/Ljubljana'],
-	    ['Europe/London'],
-	    ['Europe/Luxembourg'],
-	    ['Europe/Madrid'],
-	    ['Europe/Malta'],
-	    ['Europe/Mariehamn'],
-	    ['Europe/Minsk'],
-	    ['Europe/Monaco'],
-	    ['Europe/Moscow'],
-	    ['Europe/Oslo'],
-	    ['Europe/Paris'],
-	    ['Europe/Podgorica'],
-	    ['Europe/Prague'],
-	    ['Europe/Riga'],
-	    ['Europe/Rome'],
-	    ['Europe/Samara'],
-	    ['Europe/San_Marino'],
-	    ['Europe/Sarajevo'],
-	    ['Europe/Simferopol'],
-	    ['Europe/Skopje'],
-	    ['Europe/Sofia'],
-	    ['Europe/Stockholm'],
-	    ['Europe/Tallinn'],
-	    ['Europe/Tirane'],
-	    ['Europe/Uzhgorod'],
-	    ['Europe/Vaduz'],
-	    ['Europe/Vatican'],
-	    ['Europe/Vienna'],
-	    ['Europe/Vilnius'],
-	    ['Europe/Volgograd'],
-	    ['Europe/Warsaw'],
-	    ['Europe/Zagreb'],
-	    ['Europe/Zaporozhye'],
-	    ['Europe/Zurich'],
-	    ['Indian/Antananarivo'],
-	    ['Indian/Chagos'],
-	    ['Indian/Christmas'],
-	    ['Indian/Cocos'],
-	    ['Indian/Comoro'],
-	    ['Indian/Kerguelen'],
-	    ['Indian/Mahe'],
-	    ['Indian/Maldives'],
-	    ['Indian/Mauritius'],
-	    ['Indian/Mayotte'],
-	    ['Indian/Reunion'],
-	    ['Pacific/Apia'],
-	    ['Pacific/Auckland'],
-	    ['Pacific/Chatham'],
-	    ['Pacific/Chuuk'],
-	    ['Pacific/Easter'],
-	    ['Pacific/Efate'],
-	    ['Pacific/Enderbury'],
-	    ['Pacific/Fakaofo'],
-	    ['Pacific/Fiji'],
-	    ['Pacific/Funafuti'],
-	    ['Pacific/Galapagos'],
-	    ['Pacific/Gambier'],
-	    ['Pacific/Guadalcanal'],
-	    ['Pacific/Guam'],
-	    ['Pacific/Honolulu'],
-	    ['Pacific/Johnston'],
-	    ['Pacific/Kiritimati'],
-	    ['Pacific/Kosrae'],
-	    ['Pacific/Kwajalein'],
-	    ['Pacific/Majuro'],
-	    ['Pacific/Marquesas'],
-	    ['Pacific/Midway'],
-	    ['Pacific/Nauru'],
-	    ['Pacific/Niue'],
-	    ['Pacific/Norfolk'],
-	    ['Pacific/Noumea'],
-	    ['Pacific/Pago_Pago'],
-	    ['Pacific/Palau'],
-	    ['Pacific/Pitcairn'],
-	    ['Pacific/Pohnpei'],
-	    ['Pacific/Port_Moresby'],
-	    ['Pacific/Rarotonga'],
-	    ['Pacific/Saipan'],
-	    ['Pacific/Tahiti'],
-	    ['Pacific/Tarawa'],
-	    ['Pacific/Tongatapu'],
-	    ['Pacific/Wake'],
-	    ['Pacific/Wallis'],
-	    ['UTC']
-	]
-});
-Ext.define('Proxmox.form.field.Integer',{
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.proxmoxintegerfield',
-
-    config: {
-	deleteEmpty: false
-    },
-
-    allowDecimals: false,
-    allowExponential: false,
-    step: 1,
-
-   getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== undefined && val !== null && val !== '') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    }
-
-});
-Ext.define('Proxmox.form.field.Textfield', {
-    extend: 'Ext.form.field.Text',
-    alias: ['widget.proxmoxtextfield'],
-
-    config: {
-	skipEmptyText: true,
-
-	deleteEmpty: false,
-    },
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue && !me.isFileUpload()) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    getSubmitValue: function() {
-	var me = this;
-
-        var value = this.processRawValue(this.getRawValue());
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    }
-});
-Ext.define('Proxmox.DateTimeField', {
-    extend: 'Ext.form.FieldContainer',
-    xtype: 'promxoxDateTimeField',
-
-    layout: 'hbox',
-
-    referenceHolder: true,
-
-    submitFormat: 'U',
-
-    getValue: function() {
-	var me = this;
-	var d = me.lookupReference('dateentry').getValue();
-
-	if (d === undefined || d === null) { return null; }
-
-	var t = me.lookupReference('timeentry').getValue();
-
-	if (t === undefined || t === null) { return null; }
-
-	var offset = (t.getHours()*3600+t.getMinutes()*60)*1000;
-
-	return new Date(d.getTime() + offset);
-    },
-
-    getSubmitValue: function() {
-        var me = this;
-        var format = me.submitFormat;
-        var value = me.getValue();
-
-        return value ? Ext.Date.format(value, format) : null;
-    },
-
-    items: [
-	{
-	    xtype: 'datefield',
-	    editable: false,
-	    reference: 'dateentry',
-	    flex: 1,
-	    format: 'Y-m-d'
-	},
-	{
-	    xtype: 'timefield',
-	    reference: 'timeentry',
-	    format: 'H:i',
-	    width: 80,
-	    value: '00:00',
-	    increment: 60
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	var value = me.value || new Date();
-
-	me.lookupReference('dateentry').setValue(value);
-	me.lookupReference('timeentry').setValue(value);
-
-	me.relayEvents(me.lookupReference('dateentry'), ['change']);
-	me.relayEvents(me.lookupReference('timeentry'), ['change']);
-    }
-});
-Ext.define('Proxmox.form.Checkbox', {
-    extend: 'Ext.form.field.Checkbox',
-    alias: ['widget.proxmoxcheckbox'],
-
-    config: {
-	defaultValue: undefined,
-	deleteDefaultValue: false,
-	deleteEmpty: false
-    },
-
-    inputValue: '1',
-
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null) {
-                data = {};
-		if ((val == me.getDefaultValue()) && me.getDeleteDefaultValue()) {
-		    data['delete'] = me.getName();
-		} else {
-                    data[me.getName()] = val;
-		}
-            } else if (me.getDeleteEmpty()) {
-               data = {};
-               data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    // also accept integer 1 as true
-    setRawValue: function(value) {
-	var me = this;
-
-	if (value === 1) {
-            me.callParent([true]);
-	} else {
-            me.callParent([value]);
-	}
-    }
-
-});
-/* Key-Value ComboBox
- *
- * config properties:
- * comboItems: an array of Key - Value pairs
- * deleteEmpty: if set to true (default), an empty value received from the
- * comboBox will reset the property to its default value
- */
-Ext.define('Proxmox.form.KVComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.proxmoxKVComboBox',
-
-    config: {
-	deleteEmpty: true
-    },
-
-    comboItems: undefined,
-    displayField: 'value',
-    valueField: 'key',
-    queryMode: 'local',
-
-    // overide framework function to implement deleteEmpty behaviour
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val !== null && val !== '' && val !== '__default__') {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.getDeleteEmpty()) {
-                data = {};
-                data['delete'] = me.getName();
-            }
-        }
-        return data;
-    },
-
-    validator: function(val) {
-	var me = this;
-
-	if (me.editable || val === null || val === '') {
-	    return true;
-	}
-
-	if (me.store.getCount() > 0) {
-	    var values = me.multiSelect ? val.split(me.delimiter) : [val];
-	    var items = me.store.getData().collect('value', 'data');
-	    if (Ext.Array.every(values, function(value) {
-		return Ext.Array.contains(items, value);
-	    })) {
-		return true;
-	    }
-	}
-
-	// returns a boolean or string
-	/*jslint confusion: true */
-	return "value '" + val + "' not allowed!";
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.store = Ext.create('Ext.data.ArrayStore', {
-	    model: 'KeyValue',
-	    data : me.comboItems
-	});
-
-	if (me.initialConfig.editable === undefined) {
-	    me.editable = false;
-	}
-
-	me.callParent();
-    },
-
-    setComboItems: function(items) {
-	var me = this;
-
-	me.getStore().setData(items);
-    }
-
-});
-Ext.define('Proxmox.form.LanguageSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'proxmoxLanguageSelector',
-
-    comboItems: Proxmox.Utils.language_array()
-});
-/*
- * ComboGrid component: a ComboBox where the dropdown menu (the
- * "Picker") is a Grid with Rows and Columns expects a listConfig
- * object with a columns property roughly based on the GridPicker from
- * https://www.sencha.com/forum/showthread.php?299909
- *
-*/
-
-Ext.define('Proxmox.form.ComboGrid', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxComboGrid'],
-
-    // this value is used as default value after load()
-    preferredValue: undefined,
-
-    // hack: allow to select empty value
-    // seems extjs does not allow that when 'editable == false'
-    onKeyUp: function(e, t) {
-        var me = this;
-        var key = e.getKey();
-
-        if (!me.editable && me.allowBlank && !me.multiSelect &&
-	    (key == e.BACKSPACE || key == e.DELETE)) {
-	    me.setValue('');
-	}
-
-        me.callParent(arguments);
-    },
-
-    config: {
-	skipEmptyText: false,
-	notFoundIsValid: false,
-	deleteEmpty: false,
-    },
-
-    // needed to trigger onKeyUp etc.
-    enableKeyEvents: true,
-
-    editable: false,
-
-    triggers: {
-	clear: {
-	    cls: 'pmx-clear-trigger',
-	    weight: -1,
-	    hidden: true,
-	    handler: function() {
-		var me = this;
-		me.setValue('');
-	    }
-	}
-    },
-
-    setValue: function(value) {
-	var me = this;
-	let empty = Ext.isArray(value) ? !value.length : !value;
-	me.triggers.clear.setVisible(!empty && me.allowBlank);
-	return me.callParent([value]);
-    },
-
-    // override ExtJS method
-    // if the field has multiSelect enabled, the store is not loaded, and
-    // the displayfield == valuefield, it saves the rawvalue as an array
-    // but the getRawValue method is only defined in the textfield class
-    // (which has not to deal with arrays) an returns the string in the
-    // field (not an array)
-    //
-    // so if we have multiselect enabled, return the rawValue (which
-    // should be an array) and else we do callParent so
-    // it should not impact any other use of the class
-    getRawValue: function() {
-	var me = this;
-	if (me.multiSelect) {
-	    return me.rawValue;
-	} else {
-	    return me.callParent();
-	}
-    },
-
-    getSubmitData: function() {
-	var me = this;
-
-	let data = null;
-	if (!me.disabled && me.submitValue) {
-	    let val = me.getSubmitValue();
-	    if (val !== null) {
-		data = {};
-		data[me.getName()] = val;
-	    } else if (me.getDeleteEmpty()) {
-		data = {};
-		data['delete'] = me.getName();
-	    }
-	}
-	return data;
-   },
-
-    getSubmitValue: function() {
-	var me = this;
-
-	var value = me.callParent();
-	if (value !== '') {
-	    return value;
-	}
-
-	return me.getSkipEmptyText() ? null: value;
-    },
-
-    setAllowBlank: function(allowBlank) {
-	this.allowBlank = allowBlank;
-	this.validate();
-    },
-
-// override ExtJS protected method
-    onBindStore: function(store, initial) {
-        var me = this,
-            picker = me.picker,
-            extraKeySpec,
-            valueCollectionConfig;
-
-        // We're being bound, not unbound...
-        if (store) {
-            // If store was created from a 2 dimensional array with generated field names 'field1' and 'field2'
-            if (store.autoCreated) {
-                me.queryMode = 'local';
-                me.valueField = me.displayField = 'field1';
-                if (!store.expanded) {
-                    me.displayField = 'field2';
-                }
-
-                // displayTpl config will need regenerating with the autogenerated displayField name 'field1'
-                me.setDisplayTpl(null);
-            }
-            if (!Ext.isDefined(me.valueField)) {
-                me.valueField = me.displayField;
-            }
-
-            // Add a byValue index to the store so that we can efficiently look up records by the value field
-            // when setValue passes string value(s).
-            // The two indices (Ext.util.CollectionKeys) are configured unique: false, so that if duplicate keys
-            // are found, they are all returned by the get call.
-            // This is so that findByText and findByValue are able to return the *FIRST* matching value. By default,
-            // if unique is true, CollectionKey keeps the *last* matching value.
-            extraKeySpec = {
-                byValue: {
-                    rootProperty: 'data',
-                    unique: false
-                }
-            };
-            extraKeySpec.byValue.property = me.valueField;
-            store.setExtraKeys(extraKeySpec);
-
-            if (me.displayField === me.valueField) {
-                store.byText = store.byValue;
-            } else {
-                extraKeySpec.byText = {
-                    rootProperty: 'data',
-                    unique: false
-                };
-                extraKeySpec.byText.property = me.displayField;
-                store.setExtraKeys(extraKeySpec);
-            }
-
-            // We hold a collection of the values which have been selected, keyed by this field's valueField.
-            // This collection also functions as the selected items collection for the BoundList's selection model
-            valueCollectionConfig = {
-                rootProperty: 'data',
-                extraKeys: {
-                    byInternalId: {
-                        property: 'internalId'
-                    },
-                    byValue: {
-                        property: me.valueField,
-                        rootProperty: 'data'
-                    }
-                },
-                // Whenever this collection is changed by anyone, whether by this field adding to it,
-                // or the BoundList operating, we must refresh our value.
-                listeners: {
-                    beginupdate: me.onValueCollectionBeginUpdate,
-                    endupdate: me.onValueCollectionEndUpdate,
-                    scope: me
-                }
-            };
-
-            // This becomes our collection of selected records for the Field.
-            me.valueCollection = new Ext.util.Collection(valueCollectionConfig);
-
-            // We use the selected Collection as our value collection and the basis
-            // for rendering the tag list.
-
-            //proxmox override: since the picker is represented by a grid panel,
-            // we changed here the selection to RowModel
-            me.pickerSelectionModel = new Ext.selection.RowModel({
-                mode: me.multiSelect ? 'SIMPLE' : 'SINGLE',
-                // There are situations when a row is selected on mousedown but then the mouse is dragged to another row
-                // and released.  In these situations, the event target for the click event won't be the row where the mouse
-                // was released but the boundview.  The view will then determine that it should fire a container click, and
-                // the DataViewModel will then deselect all prior selections. Setting `deselectOnContainerClick` here will
-                // prevent the model from deselecting.
-                deselectOnContainerClick: false,
-                enableInitialSelection: false,
-                pruneRemoved: false,
-                selected: me.valueCollection,
-                store: store,
-                listeners: {
-                    scope: me,
-                    lastselectedchanged: me.updateBindSelection
-                }
-            });
-
-            if (!initial) {
-                me.resetToDefault();
-            }
-
-            if (picker) {
-                picker.setSelectionModel(me.pickerSelectionModel);
-                if (picker.getStore() !== store) {
-                    picker.bindStore(store);
-                }
-            }
-        }
-    },
-
-    // copied from ComboBox
-    createPicker: function() {
-        var me = this;
-        var picker;
-
-        var pickerCfg = Ext.apply({
-                // proxmox overrides: display a grid for selection
-                xtype: 'gridpanel',
-                id: me.pickerId,
-                pickerField: me,
-                floating: true,
-                hidden: true,
-                store: me.store,
-                displayField: me.displayField,
-                preserveScrollOnRefresh: true,
-                pageSize: me.pageSize,
-                tpl: me.tpl,
-                selModel: me.pickerSelectionModel,
-                focusOnToFront: false
-            }, me.listConfig, me.defaultListConfig);
-
-        picker = me.picker || Ext.widget(pickerCfg);
-
-        if (picker.getStore() !== me.store) {
-            picker.bindStore(me.store);
-        }
-
-        if (me.pageSize) {
-            picker.pagingToolbar.on('beforechange', me.onPageChange, me);
-        }
-
-        // proxmox overrides: pass missing method in gridPanel to its view
-        picker.refresh = function() {
-            picker.getSelectionModel().select(me.valueCollection.getRange());
-            picker.getView().refresh();
-        };
-        picker.getNodeByRecord = function() {
-            picker.getView().getNodeByRecord(arguments);
-        };
-
-        // We limit the height of the picker to fit in the space above
-        // or below this field unless the picker has its own ideas about that.
-        if (!picker.initialConfig.maxHeight) {
-            picker.on({
-                beforeshow: me.onBeforePickerShow,
-                scope: me
-            });
-        }
-        picker.getSelectionModel().on({
-            beforeselect: me.onBeforeSelect,
-            beforedeselect: me.onBeforeDeselect,
-            focuschange: me.onFocusChange,
-            selectionChange: function (sm, selectedRecords) {
-                var me = this;
-                if (selectedRecords.length) {
-                    me.setValue(selectedRecords);
-                    me.fireEvent('select', me, selectedRecords);
-                }
-            },
-            scope: me
-        });
-
-	// hack for extjs6
-	// when the clicked item is the same as the previously selected,
-	// it does not select the item
-	// instead we hide the picker
-	if (!me.multiSelect) {
-	    picker.on('itemclick', function (sm,record) {
-		if (picker.getSelection()[0] === record) {
-		    picker.hide();
-		}
-	    });
-	}
-
-	// when our store is not yet loaded, we increase
-	// the height of the gridpanel, so that we can see
-	// the loading mask
-	//
-	// we save the minheight to reset it after the load
-	picker.on('show', function() {
-	    if (me.enableLoadMask) {
-		me.savedMinHeight = picker.getMinHeight();
-		picker.setMinHeight(100);
-	    }
-	});
-
-        picker.getNavigationModel().navigateOnSpace = false;
-
-        return picker;
-    },
-
-    clearLocalFilter: function() {
-        var me = this,
-            filter = me.queryFilter;
-
-        if (filter) {
-            me.queryFilter = null;
-            me.changingFilters = true;
-            me.store.removeFilter(filter, true);
-            me.changingFilters = false;
-        }
-    },
-
-    isValueInStore: function(value) {
-	var me = this;
-	var store = me.store;
-	var found = false;
-
-	if (!store) {
-	    return found;
-	}
-
-	// Make sure the current filter is removed before checking the store
-	// to prevent false negative results when iterating over a filtered store.
-	// All store.find*() method's operate on the filtered store.
-	if (me.queryFilter && me.queryMode === 'local' && me.clearFilterOnBlur) {
-	    me.clearLocalFilter();
-	}
-
-	if (Ext.isArray(value)) {
-	    Ext.Array.each(value, function(v) {
-		if (store.findRecord(me.valueField, v)) {
-		    found = true;
-		    return false; // break
-		}
-	    });
-	} else {
-	    found = !!store.findRecord(me.valueField, value);
-	}
-
-	return found;
-    },
-
-    validator: function (value) {
-	var me = this;
-
-	if (!value) {
-	    return true; // handled later by allowEmpty in the getErrors call chain
-	}
-
-	// we normally get here the displayField as value, but if a valueField
-	// is configured we need to get the "actual" value, to ensure it is in
-	// the store. Below check is copied from ExtJS 6.0.2 ComboBox source
-	//
-	// we also have to get the 'real' value if the we have a mulitSelect
-	// Field but got a non array value
-	if ((me.valueField && me.valueField !== me.displayField) ||
-	    (me.multiSelect && !Ext.isArray(value))) {
-	    value = me.getValue();
-	}
-
-	if (!(me.notFoundIsValid || me.isValueInStore(value))) {
-	    return gettext('Invalid Value');
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    queryMode: 'local',
-	    matchFieldWidth: false
-	});
-
-	Ext.applyIf(me, { value: ''}); // hack: avoid ExtJS validate() bug
-
-	Ext.applyIf(me.listConfig, { width: 400 });
-
-        me.callParent();
-
-        // Create the picker at an early stage, so it is available to store the previous selection
-        if (!me.picker) {
-            me.createPicker();
-        }
-
-	if (me.editable) {
-	    // The trigger.picker causes first a focus event on the field then
-	    // toggles the selection picker. Thus skip expanding in this case,
-	    // else our focus listner expands and the picker.trigger then
-	    // collapses it directly afterwards.
-	    Ext.override(me.triggers.picker, {
-		onMouseDown : function (e) {
-		    // copied "should we focus" check from Ext.form.trigger.Trigger
-		    if (e.pointerType !== 'touch' && !this.field.owns(Ext.Element.getActiveElement())) {
-			me.skip_expand_on_focus = true;
-		    }
-		    this.callParent(arguments);
-		}
-	    });
-
-	    me.on("focus", function(me) {
-		if (!me.isExpanded && !me.skip_expand_on_focus) {
-		    me.expand();
-		}
-		me.skip_expand_on_focus = false;
-	    });
-	}
-
-	me.mon(me.store, 'beforeload', function() {
-	    if (!me.isDisabled()) {
-		me.enableLoadMask = true;
-	    }
-	});
-
-	// hack: autoSelect does not work
-	me.mon(me.store, 'load', function(store, r, success, o) {
-	    if (success) {
-		me.clearInvalid();
-
-		if (me.enableLoadMask) {
-		    delete me.enableLoadMask;
-
-		    // if the picker exists,
-		    // we reset its minheight to the saved var/0
-		    // we have to update the layout, otherwise the height
-		    // gets not recalculated
-		    if (me.picker) {
-			me.picker.setMinHeight(me.savedMinHeight || 0);
-			delete me.savedMinHeight;
-			me.picker.updateLayout();
-		    }
-		}
-
-		var def = me.getValue() || me.preferredValue;
-		if (def) {
-		    me.setValue(def, true); // sync with grid
-		}
-		var found = false;
-		if (def) {
-		    found = me.isValueInStore(def);
-		}
-
-		if (!found) {
-		    var rec = me.store.first();
-		    if (me.autoSelect && rec && rec.data) {
-			def = rec.data[me.valueField];
-			me.setValue(def, true);
-		    } else if (!me.allowBlank && !(Ext.isArray(def) ? def.length : def)) {
-			me.setValue(def);
-			if (!me.notFoundIsValid) {
-			    me.markInvalid(me.blankText);
-			}
-		    }
-		}
-	    }
-	});
-    }
-});
-Ext.define('Proxmox.form.RRDTypeSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.proxmoxRRDTypeSelector'],
-
-    displayField: 'text',
-    valueField: 'id',
-    editable: false,
-    queryMode: 'local',
-    value: 'hour',
-    stateEvents: [ 'select' ],
-    stateful: true,
-    stateId: 'proxmoxRRDTypeSelection',
-    store: {
-	type: 'array',
-	fields: [ 'id', 'timeframe', 'cf', 'text' ],
-	data : [
-	    [ 'hour', 'hour', 'AVERAGE',
-	      gettext('Hour') + ' (' + gettext('average') +')' ],
-	    [ 'hourmax', 'hour', 'MAX',
-	      gettext('Hour') + ' (' + gettext('maximum') + ')' ],
-	    [ 'day', 'day', 'AVERAGE',
-	      gettext('Day') + ' (' + gettext('average') + ')' ],
-	    [ 'daymax', 'day', 'MAX',
-	      gettext('Day') + ' (' + gettext('maximum') + ')' ],
-	    [ 'week', 'week', 'AVERAGE',
-	      gettext('Week') + ' (' + gettext('average') + ')' ],
-	    [ 'weekmax', 'week', 'MAX',
-	      gettext('Week') + ' (' + gettext('maximum') + ')' ],
-	    [ 'month', 'month', 'AVERAGE',
-	      gettext('Month') + ' (' + gettext('average') + ')' ],
-	    [ 'monthmax', 'month', 'MAX',
-	      gettext('Month') + ' (' + gettext('maximum') + ')' ],
-	    [ 'year', 'year', 'AVERAGE',
-	      gettext('Year') + ' (' + gettext('average') + ')' ],
-	    [ 'yearmax', 'year', 'MAX',
-	      gettext('Year') + ' (' + gettext('maximum') + ')' ]
-	]
-    },
-    // save current selection in the state Provider so RRDView can read it
-    getState: function() {
-	var ind = this.getStore().findExact('id', this.getValue());
-	var rec = this.getStore().getAt(ind);
-	if (!rec) {
-	    return;
-	}
-	return {
-	    id: rec.data.id,
-	    timeframe: rec.data.timeframe,
-	    cf: rec.data.cf
-	};
-    },
-    // set selection based on last saved state
-    applyState : function(state) {
-	if (state && state.id) {
-	    this.setValue(state.id);
-	}
-    }
-});
-Ext.define('Proxmox.form.BondModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondModeSelector'],
-
-    openvswitch: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.openvswitch) {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-	       'active-backup',
-	       'balance-slb',
-	       'lacp-balance-slb',
-	       'lacp-balance-tcp',
-	    ]);
-	} else {
-	    me.comboItems = Proxmox.Utils.bond_mode_array([
-		'balance-rr',
-		'active-backup',
-		'balance-xor',
-		'broadcast',
-		'802.3ad',
-		'balance-tlb',
-		'balance-alb',
-	    ]);
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('Proxmox.form.BondPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.bondPolicySelector'],
-    comboItems: [
-	    ['layer2', 'layer2'],
-	    ['layer2+3', 'layer2+3'],
-	    ['layer3+4', 'layer3+4']
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelectorController', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.proxmoxNetworkSelectorController',
-
-    init: function(view) {
-	var me = this;
-
-	if (!view.nodename) {
-	    throw "missing custom view config: nodename";
-	}
-	view.getStore().getProxy().setUrl('/api2/json/nodes/'+ view.nodename + '/network');
-    }
-});
-
-Ext.define('Proxmox.data.NetworkSelector', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{name: 'active'},
-	{name: 'cidr'},
-	{name: 'cidr6'},
-	{name: 'address'},
-	{name: 'address6'},
-	{name: 'comments'},
-	{name: 'iface'},
-	{name: 'slaves'},
-	{name: 'type'}
-    ]
-});
-
-Ext.define('Proxmox.form.NetworkSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.proxmoxNetworkSelector',
-
-    controller: 'proxmoxNetworkSelectorController',
-
-    nodename: 'localhost',
-    setNodename: function(nodename) {
-	this.nodename = nodename;
-	var networkSelectorStore = this.getStore();
-	networkSelectorStore.removeAll();
-	// because of manual local copy of data for ip4/6
-	this.getPicker().refresh();
-	if (networkSelectorStore && typeof networkSelectorStore.getProxy === 'function') {
-	    networkSelectorStore.getProxy().setUrl('/api2/json/nodes/'+ nodename + '/network');
-	    networkSelectorStore.load();
-	}
-    },
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'cidr',
-    displayField: 'cidr',
-    store: {
-	autoLoad: true,
-	model: 'Proxmox.data.NetworkSelector',
-	proxy: {
-	    type: 'proxmox'
-	},
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	],
-	filters: [
-	    function(item) {
-		return item.data.cidr;
-	    }
-	],
-	listeners: {
-	    load: function(store, records, successfull) {
-
-		if (successfull) {
-		    records.forEach(function(record) {
-			if (record.data.cidr6) {
-			    let dest = (record.data.cidr) ? record.copy(null) : record;
-			    dest.data.cidr = record.data.cidr6;
-			    dest.data.address = record.data.address6;
-			    delete record.data.cidr6;
-			    dest.data.comments = record.data.comments6;
-			    delete record.data.comments6;
-			    store.add(dest);
-			}
-		    });
-		}
-	    }
-	}
-    },
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-
-		header: gettext('CIDR'),
-		dataIndex: 'cidr',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-
-		header: gettext('IP'),
-		dataIndex: 'address',
-		hidden: true,
-	    },
-	    {
-		header: gettext('Interface'),
-		width: 90,
-		dataIndex: 'iface'
-	    },
-	    {
-		header: gettext('Active'),
-		renderer: Proxmox.Utils.format_boolean,
-		width: 60,
-		dataIndex: 'active'
-	    },
-	    {
-		header: gettext('Type'),
-		width: 80,
-		hidden: true,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 2,
-		dataIndex: 'comments'
-	    }
-	]
-    }
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- */
-Ext.define('Proxmox.button.Button', {
-    extend: 'Ext.button.Button',
-    alias: 'widget.proxmoxButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-
-	    // Note: me.realHandler may be a string (see named scopes)
-	    var realHandler = me.handler;
-
-	    me.handler = function(button, event) {
-		var rec, msg;
-		if (me.selModel) {
-		    rec = me.selModel.getSelection()[0];
-		    if (!rec || (me.enableFn(rec) === false)) {
-			return;
-		    }
-		}
-
-		if (me.confirmMsg) {
-		    msg = me.confirmMsg;
-		    if (Ext.isFunction(me.confirmMsg)) {
-			msg = me.confirmMsg(rec);
-		    }
-		    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		    Ext.Msg.show({
-			title: gettext('Confirm'),
-			icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-			message: msg,
-			buttons: Ext.Msg.YESNO,
-			defaultFocus: me.dangerous ? 'no' : 'yes',
-			callback: function(btn) {
-			    if (btn !== 'yes') {
-				return;
-			    }
-			    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-			}
-		    });
-		} else {
-		    Ext.callback(realHandler, me.scope, [button, event, rec], 0, me);
-		}
-	    };
-	}
-
-	me.callParent();
-
-	var grid;
-	if (!me.selModel && me.selModel !== null) {
-	    grid = me.up('grid');
-	    if (grid && grid.selModel) {
-		me.selModel = grid.selModel;
-	    }
-	}
-
-	if (me.waitMsgTarget === true) {
-	    grid = me.up('grid');
-	    if (grid) {
-		me.waitMsgTarget = grid;
-	    } else {
-		throw "unable to find waitMsgTarget";
-	    }
-	}
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else  {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-
-
-Ext.define('Proxmox.button.StdRemoveButton', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.proxmoxStdRemoveButton',
-
-    text: gettext('Remove'),
-
-    disabled: true,
-
-    // time to wait for removal task to finish
-    delay: undefined,
-
-    config: {
-	baseurl: undefined
-    },
-
-    getUrl: function(rec) {
-	var me = this;
-
-	return me.baseurl + '/' + rec.getId();
-    },
-
-    // also works with names scopes
-    callback: function(options, success, response) {},
-
-    getRecordName: function(rec) { return rec.getId() },
-
-    confirmMsg: function (rec) {
-	var me = this;
-
-	var name = me.getRecordName(rec);
-	return Ext.String.format(
-	    gettext('Are you sure you want to remove entry {0}'),
-	    "'" + name + "'");
-    },
-
-    handler: function(btn, event, rec) {
-	var me = this;
-
-	var url = me.getUrl(rec);
-
-	if (typeof me.delay !== 'undefined' && me .delay >= 0) {
-	    url += "?delay=" + me.delay;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    method: 'DELETE',
-	    waitMsgTarget: me.waitMsgTarget,
-	    callback: function(options, success, response) {
-		Ext.callback(me.callback, me.scope, [options, success, response], 0, me);
-	    },
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-/* help button pointing to an online documentation
-   for components contained in a modal window
-*/
-/*global
-  proxmoxOnlineHelpInfo
-*/
-Ext.define('Proxmox.button.Help', {
-    extend: 'Ext.button.Button',
-    xtype: 'proxmoxHelpButton',
-
-    text: gettext('Help'),
-
-    // make help button less flashy by styling it like toolbar buttons
-    iconCls: ' x-btn-icon-el-default-toolbar-small fa fa-question-circle',
-    cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-
-    hidden: true,
-
-    listenToGlobalEvent: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	listen: {
-	    global: {
-		proxmoxShowHelp: 'onProxmoxShowHelp',
-		proxmoxHideHelp: 'onProxmoxHideHelp'
-	    }
-	},
-	onProxmoxShowHelp: function(helpLink) {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.setOnlineHelp(helpLink);
-		me.show();
-	    }
-	},
-	onProxmoxHideHelp: function() {
-	    var me = this.getView();
-	    if (me.listenToGlobalEvent === true) {
-		me.hide();
-	    }
-	}
-    },
-
-    // this sets the link and the tooltip text
-    setOnlineHelp:function(blockid) {
-	var me = this;
-
-	var info = Proxmox.Utils.get_help_info(blockid);
-	if (info) {
-	    me.onlineHelp = blockid;
-	    var title = info.title;
-	    if (info.subtitle) {
-		title += ' - ' + info.subtitle;
-	    }
-	    me.setTooltip(title);
-	}
-    },
-
-    // helper to set the onlineHelp via a config object
-    setHelpConfig: function(config) {
-	var me = this;
-	me.setOnlineHelp(config.onlineHelp);
-    },
-
-    handler: function() {
-	var me = this;
-	var docsURI;
-
-	if (me.onlineHelp) {
-	    docsURI = Proxmox.Utils.get_help_link(me.onlineHelp);
-	}
-
-	if (docsURI) {
-	    window.open(docsURI);
-	} else {
-	    Ext.Msg.alert(gettext('Help'), gettext('No Help available'));
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-	var me = this;
-
-	me.callParent();
-
-	if  (me.onlineHelp) {
-	    me.setOnlineHelp(me.onlineHelp); // set tooltip
-	}
-    }
-});
-/* Renders a list of key values objets
-
-mandatory config parameters:
-rows: an object container where each propery is a key-value object we want to render
-       var rows = {
-           keyboard: {
-               header: gettext('Keyboard Layout'),
-               editor: 'Your.KeyboardEdit',
-               required: true
-           },
-
-optional:
-disabled: setting this parameter to true will disable selection and focus on the
-proxmoxObjectGrid as well as greying out input elements.
-Useful for a readonly tabular display
-
-*/
-
-Ext.define('Proxmox.grid.ObjectGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.proxmoxObjectGrid'],
-    disabled: false,
-    hideHeaders: true,
-
-    monStoreErrors: false,
-
-    add_combobox_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxKVComboBox',
-		    name: name,
-		    comboItems: opts.comboItems,
-		    value: opts.defaultValue,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_text_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxtextfield',
-		    name: name,
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    emptyText: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    vtype: opts.vtype,
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_boolean_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue || 0,
-	    header: text,
-	    renderer: opts.renderer || Proxmox.Utils.format_boolean,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxcheckbox',
-		    name: name,
-		    uncheckedValue: 0,
-		    defaultValue: opts.defaultValue  || 0,
-		    checked: opts.defaultValue ? true : false,
-		    deleteDefaultValue: opts.deleteDefaultValue ? true : false,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    add_integer_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {}
-	me.rows = me.rows || {};
-
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: {
-		xtype: 'proxmoxWindowEdit',
-		subject: text,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		items: {
-		    xtype: 'proxmoxintegerfield',
-		    name: name,
-		    minValue: opts.minValue,
-		    maxValue: opts.maxValue,
-		    emptyText: gettext('Default'),
-		    deleteEmpty: opts.deleteEmpty ? true : false,
-		    value: opts.defaultValue,
-		    labelWidth: Proxmox.Utils.compute_min_label_width(
-			text, opts.labelWidth),
-		    fieldLabel: text
-		}
-	    }
-	};
-    },
-
-    editorConfig: {}, // default config passed to editor
-
-    run_editor: function() {
-	var me = this;
-
-	var sm = me.getSelectionModel();
-	var rec = sm.getSelection()[0];
-	if (!rec) {
-	    return;
-	}
-
-	var rows = me.rows;
-	var rowdef = rows[rec.data.key];
-	if (!rowdef.editor) {
-	    return;
-	}
-
-	var win;
-	var config;
-	if (Ext.isString(rowdef.editor)) {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    win = Ext.create(rowdef.editor, config);
-	} else {
-	    config = Ext.apply({
-		confid: rec.data.key,
-	    },  me.editorConfig);
-	    Ext.apply(config, rowdef.editor);
-	    win = Ext.createWidget(rowdef.editor.xtype, config);
-	    win.load();
-	}
-
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    getObjectValue: function(key, defaultValue) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-	return defaultValue;
-    },
-
-    renderKey: function(key, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	return rowdef.header || key;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-
-	var renderer = rowdef.renderer;
-	if (renderer) {
-	    return renderer(value, metaData, record, rowIndex, colIndex, store);
-	}
-
-	return value;
-    },
-
-    listeners: {
-	itemkeydown: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER) {
-		this.pressedIndex = index;
-	    }
-	},
-	itemkeyup: function(view, record, item, index, e) {
-	    if (e.getKey() === e.ENTER && index == this.pressedIndex) {
-		this.run_editor();
-	    }
-
-	    this.pressedIndex = undefined;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	var rstore = me.rstore;
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore,
-	    sorters: [],
-	    filters: []
-	});
-
-	if (rows) {
-	    Ext.Object.each(rows, function(key, rowdef) {
-		if (Ext.isDefined(rowdef.defaultValue)) {
-		    store.add({ key: key, value: rowdef.defaultValue });
-		} else if (rowdef.required) {
-		    store.add({ key: key, value: undefined });
-		}
-	    });
-	}
-
-	if (me.sorterFn) {
-	    store.sorters.add(Ext.create('Ext.util.Sorter', {
-		sorterFn: me.sorterFn
-	    }));
-	}
-
-	store.filters.add(Ext.create('Ext.util.Filter', {
-	    filterFn: function(item) {
-		if (rows) {
-		    var rowdef = rows[item.data.key];
-		    if (!rowdef || (rowdef.visible === false)) {
-			return false;
-		    }
-		}
-		return true;
-	    }
-	}));
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.applyIf(me, {
-	    store: store,
-	    stateful: false,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: me.cwidth1 || 200,
-		    dataIndex: 'key',
-		    renderer: me.renderKey
-		},
-		{
-		    flex: 1,
-		    header: gettext('Value'),
-		    dataIndex: 'value',
-		    renderer: me.renderValue
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.monStoreErrors) {
-	    Proxmox.Utils.monStoreErrors(me, me.store);
-	}
-   }
-});
-Ext.define('Proxmox.grid.PendingObjectGrid', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxPendingObjectGrid'],
-
-    getObjectValue: function(key, defaultValue, pending) {
-	var me = this;
-	var rec = me.store.getById(key);
-	if (rec) {
-	    var value = rec.data.value;
-	    if (pending) {
-		if (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') {
-		    value = rec.data.pending;
-		} else if (rec.data['delete'] === 1) {
-		    value = defaultValue;
-		}
-	    }
-
-            if (Ext.isDefined(value) && (value !== '')) {
-		return value;
-            } else {
-		return defaultValue;
-            }
-	}
-	return defaultValue;
-    },
-
-    hasPendingChanges: function(key) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var keys = rowdef.multiKey ||  [ key ];
-	var pending = false;
-
-	Ext.Array.each(keys, function(k) {
-	    var rec = me.store.getById(k);
-	    if (rec && rec.data && (
-		    (Ext.isDefined(rec.data.pending) && rec.data.pending !== '') ||
-		    rec.data['delete'] === 1
-	    )) {
-		pending = true;
-		return false; // break
-	    }
-	});
-
-	return pending;
-    },
-
-    renderValue: function(value, metaData, record, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var key = record.data.key;
-	var rowdef = (rows && rows[key]) ?  rows[key] : {};
-	var renderer = rowdef.renderer;
-	var current = '';
-	var pendingdelete = '';
-	var pending = '';
-
-	if (renderer) {
-	    current = renderer(value, metaData, record, rowIndex, colIndex, store, false);
-	    if (me.hasPendingChanges(key)) {
-		pending = renderer(record.data.pending, metaData, record, rowIndex, colIndex, store, true);
-	    }
-	    if (pending == current) {
-		pending = undefined;
-	    }
-	} else {
-	    current = value || '';
-	    pending = record.data.pending;
-	}
-
-	if (record.data['delete']) {
-	    var delete_all = true;
-	    if (rowdef.multiKey) {
-		Ext.Array.each(rowdef.multiKey, function(k) {
-		    var rec = me.store.getById(k);
-		    if (rec && rec.data && rec.data['delete'] !== 1) {
-			delete_all = false;
-			return false; // break
-		    }
-		});
-	    }
-	    if (delete_all) {
-		pending = '<div style="text-decoration: line-through;">'+ current +'</div>';
-	    }
-	}
-
-	if (pending) {
-	    return current + '<div style="color:red">' + pending + '</div>';
-	} else {
-	    return current;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rows = me.rows;
-
-	if (!me.rstore) {
-	    if (!me.url) {
-		throw "no url specified";
-	    }
-
-	    me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-		model: 'KeyValuePendingDelete',
-		readArray: true,
-		url: me.url,
-		interval: me.interval,
-		extraParams: me.extraParams,
-		rows: me.rows
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('Proxmox.panel.InputPanel', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.inputpanel'],
-    listeners: {
-	activate: function() {
-	    // notify owning container that it should display a help button
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-	    }
-	},
-	deactivate: function() {
-	    if (this.onlineHelp) {
-		Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-	    }
-	}
-    },
-    border: false,
-
-    // override this with an URL to a relevant chapter of the pve manual
-    // setting this will display a help button in our parent panel
-    onlineHelp: undefined,
-
-    // will be set if the inputpanel has advanced items
-    hasAdvanced: false,
-
-    // if the panel has advanced items,
-    // this will determine if they are shown by default
-    showAdvanced: false,
-
-    // overwrite this to modify submit data
-    onGetValues: function(values) {
-	return values;
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-	if (Ext.isFunction(me.onGetValues)) {
-	    dirtyOnly = false;
-	}
-
-	var values = {};
-
-	Ext.Array.each(me.query('[isFormField]'), function(field) {
-	    if (!dirtyOnly || field.isDirty()) {
-		Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-	    }
-	});
-
-	return me.onGetValues(values);
-    },
-
-    setAdvancedVisible: function(visible) {
-	var me = this;
-	var advItems = me.getComponent('advancedContainer');
-	if (advItems) {
-	    advItems.setVisible(visible);
-	}
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.up('form');
-
-        Ext.iterate(values, function(fieldId, val) {
-	    var field = me.query('[isFormField][name=' + fieldId + ']')[0];
-            if (field) {
-		field.setValue(val);
-		if (form.trackResetOnLoad) {
-		    field.resetOriginalValue();
-		}
-	    }
-	});
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var items;
-
-	if (me.items) {
-	    me.columns = 1;
-	    items = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.items
-		}
-	    ];
-	    me.items = undefined;
-	} else if (me.column4) {
-	    me.columns = 4;
-	    items = [
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column2
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column3
-		},
-		{
-		    columnWidth: 0.25,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column4
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else if (me.column1) {
-	    me.columns = 2;
-	    items = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.column1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.column2 || [] // allow empty column
-		}
-	    ];
-	    if (me.columnB) {
-		items.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.columnB
-		});
-	    }
-	} else {
-	    throw "unsupported config";
-	}
-
-	var advItems;
-	if (me.advancedItems) {
-	    advItems = [
-		{
-		    columnWidth: 1,
-		    layout: 'anchor',
-		    items: me.advancedItems
-		}
-	    ];
-	    me.advancedItems = undefined;
-	} else if (me.advancedColumn1) {
-	    advItems = [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumn1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: me.advancedColumn2 || [] // allow empty column
-		}
-	    ];
-
-	    me.advancedColumn1 = undefined;
-	    me.advancedColumn2 = undefined;
-
-	    if (me.advancedColumnB) {
-		advItems.push({
-		    columnWidth: 1,
-		    padding: '10 0 0 0',
-		    layout: 'anchor',
-		    items: me.advancedColumnB
-		});
-		me.advancedColumnB = undefined;
-	    }
-	}
-
-	if (advItems) {
-	    me.hasAdvanced = true;
-	    advItems.unshift({
-		columnWidth: 1,
-		xtype: 'box',
-		hidden: false,
-		border: true,
-		autoEl: {
-		    tag: 'hr'
-		}
-	    });
-	    items.push({
-		columnWidth: 1,
-		xtype: 'container',
-		itemId: 'advancedContainer',
-		hidden: !me.showAdvanced,
-		layout: 'column',
-		defaults: {
-		    border: false
-		},
-		items: advItems
-	    });
-	}
-
-	if (me.useFieldContainer) {
-	    Ext.apply(me, {
-		layout: 'fit',
-		items: Ext.apply(me.useFieldContainer, {
-		    layout: 'column',
-		    defaultType: 'container',
-		    items: items
-		})
-	    });
-	} else {
-	    Ext.apply(me, {
-		layout: 'column',
-		defaultType: 'container',
-		items: items
-	    });
-	}
-
-	me.callParent();
-    }
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.LogView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxLogView',
-
-    pageSize: 500,
-    viewBuffer: 50,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    // callback for load failure, used for ceph
-    failCallback: undefined,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-	    if (viewModel.get('hide_timespan')) {
-		return;
-	    }
-
-	    if (since > until) {
-		Ext.Msg.alert('Error', 'Since date must be less equal than Until date.');
-		return;
-	    }
-
-	    viewModel.set('params.since', Ext.Date.format(since, 'Y-m-d'));
-	    viewModel.set('params.until', Ext.Date.format(until, 'Y-m-d') + ' 23:59:59');
-	    me.getView().loadTask.delay(200);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	updateView: function(text, first, total) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    var content = me.lookup('content');
-	    var data = viewModel.get('data');
-
-	    if (first === data.first && total === data.total && text.length === data.textlen) {
-		return; // same content, skip setting and scrolling
-	    }
-	    viewModel.set('data', {
-		first: first,
-		total: total,
-		textlen: text.length
-	    });
-
-	    var scrollPos = me.scrollPosBottom();
-
-	    content.update(text);
-
-	    if (view.scrollToEnd && scrollPos <= 0) {
-		// we use setTimeout to work around scroll handling on touchscreens
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    }
-	},
-
-	doLoad: function() {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-	    Proxmox.Utils.API2Request({
-		url: me.getView().url,
-		params: viewModel.get('params'),
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var total = response.result.total;
-		    var lines = new Array();
-		    var first = Infinity;
-
-		    Ext.Array.each(response.result.data, function(line) {
-			if (first > line.n) {
-			    first = line.n;
-			}
-			lines[line.n - 1] = Ext.htmlEncode(line.t);
-		    });
-
-		    lines.length = total;
-		    me.updateView(lines.join('<br>'), first - 1, total);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    if (view.failCallback) {
-			view.failCallback(response);
-		    } else {
-			var msg = response.htmlStatus;
-			Proxmox.Utils.setErrorMask(me, msg);
-		    }
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewModel = me.getViewModel();
-
-	    var lineHeight = view.lineHeight;
-	    var line = view.getScrollY()/lineHeight;
-	    var start = viewModel.get('params.start');
-	    var limit = viewModel.get('params.limit');
-	    var viewLines = view.getHeight()/lineHeight;
-
-	    var viewStart = Math.max(parseInt(line - 1 - view.viewBuffer, 10), 0);
-	    var viewEnd = parseInt(line + viewLines + 1 + view.viewBuffer, 10);
-
-	    if (viewStart < start || viewEnd > (start+limit)) {
-		viewModel.set('params.start',
-		    Math.max(parseInt(line - limit/2 + 10, 10), 0));
-		view.loadTask.delay(200);
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    viewModel.set('params.limit', view.pageSize);
-	    viewModel.set('hide_timespan', !view.log_select_timespan);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200);
-		    }
-		},
-		interval: 1000
-	    });
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    until: null,
-	    since: null,
-	    hide_timespan: false,
-	    data: {
-		start: 0,
-		total: 0,
-		textlen: 0
-	    },
-	    params: {
-		start: 0,
-		limit: 500,
-	    }
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-	bind: {
-	    hidden: '{hide_timespan}'
-	},
-	items: [
-	    '->',
-	    'Since: ',
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    'Until: ',
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		handler: 'updateParams'
-	    }
-	],
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-/*
- * Display log entries in a panel with scrollbar
- * The log entries are automatically refreshed via a background task,
- * with newest entries comming at the bottom
- */
-Ext.define('Proxmox.panel.JournalView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxJournalView',
-
-    numEntries: 500,
-    lineHeight: 16,
-
-    scrollToEnd: true,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateParams: function() {
-	    var me = this;
-	    var viewModel = me.getViewModel();
-	    var since = viewModel.get('since');
-	    var until = viewModel.get('until');
-
-	    since.setHours(0, 0, 0, 0);
-	    until.setHours(0, 0, 0, 0);
-	    until.setDate(until.getDate()+1);
-
-	    me.getView().loadTask.delay(200, undefined, undefined, [
-		false,
-		false,
-		Ext.Date.format(since, "U"),
-		Ext.Date.format(until, "U")
-	    ]);
-	},
-
-	scrollPosBottom: function() {
-	    var view = this.getView();
-	    var pos = view.getScrollY();
-	    var maxPos = view.getScrollable().getMaxPosition().y;
-	    return maxPos - pos;
-	},
-
-	scrollPosTop: function() {
-	    var view = this.getView();
-	    return view.getScrollY();
-	},
-
-	updateScroll: function(livemode, num, scrollPos, scrollPosTop) {
-	    var me = this;
-	    var view = me.getView();
-
-	    if (!livemode) {
-		setTimeout(function() { view.scrollTo(0, 0); }, 10);
-	    } else if (view.scrollToEnd && scrollPos <= 0) {
-		setTimeout(function() { view.scrollTo(0, Infinity); }, 10);
-	    } else if (!view.scrollToEnd && scrollPosTop < 20*view.lineHeight) {
-		setTimeout(function() { view.scrollTo(0, num*view.lineHeight + scrollPosTop); }, 10);
-	    }
-	},
-
-	updateView: function(lines, livemode, top) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    if (viewmodel.get('livemode') !== livemode) {
-		return; // we switched mode, do not update the content
-	    }
-	    var contentEl = me.lookup('content');
-
-	    // save old scrollpositions
-	    var scrollPos = me.scrollPosBottom();
-	    var scrollPosTop = me.scrollPosTop();
-
-	    var newend = lines.shift();
-	    var newstart = lines.pop();
-
-	    var num = lines.length;
-	    var text = lines.map(Ext.htmlEncode).join('<br>');
-
-	    if (!livemode) {
-		if (num) {
-		    view.content = text;
-		} else {
-		    view.content = 'nothing logged or no timespan selected';
-		}
-	    } else {
-		// update content
-		if (top && num) {
-		    view.content = view.content ? text + '<br>' + view.content : text;
-		} else if (!top && num) {
-		    view.content = view.content ? view.content + '<br>' + text : text;
-		}
-
-		// update cursors
-		if (!top || !view.startcursor) {
-		    view.startcursor = newstart;
-		}
-
-		if (top || !view.endcursor) {
-		    view.endcursor = newend;
-		}
-	    }
-
-	    contentEl.update(view.content);
-
-	    me.updateScroll(livemode, num, scrollPos, scrollPosTop);
-	},
-
-	doLoad: function(livemode, top, since, until) {
-	    var me = this;
-	    if (me.running) {
-		me.requested = true;
-		return;
-	    }
-	    me.running = true;
-	    var view = me.getView();
-	    var params = {
-		lastentries: view.numEntries || 500,
-	    };
-	    if (livemode) {
-		if (!top && view.startcursor) {
-		    params = {
-			startcursor: view.startcursor
-		    };
-		} else if (view.endcursor) {
-		    params.endcursor = view.endcursor;
-		}
-	    } else {
-		params = {
-		    since: since,
-		    until: until
-		};
-	    }
-	    Proxmox.Utils.API2Request({
-		url: view.url,
-		params: params,
-		waitMsgTarget: (!livemode) ? view : undefined,
-		method: 'GET',
-		success: function(response) {
-		    Proxmox.Utils.setErrorMask(me, false);
-		    var lines = response.result.data;
-		    me.updateView(lines, livemode, top);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		},
-		failure: function(response) {
-		    var msg = response.htmlStatus;
-		    Proxmox.Utils.setErrorMask(me, msg);
-		    me.running = false;
-		    if (me.requested) {
-			me.requested = false;
-			view.loadTask.delay(200);
-		    }
-		}
-	    });
-	},
-
-	onScroll: function(x, y) {
-	    var me = this;
-	    var view = me.getView();
-	    var viewmodel = me.getViewModel();
-	    var livemode = viewmodel.get('livemode');
-	    if (!livemode) {
-		return;
-	    }
-
-	    if (me.scrollPosTop() < 20*view.lineHeight) {
-		view.scrollToEnd = false;
-		view.loadTask.delay(200, undefined, undefined, [true, true]);
-	    } else if (me.scrollPosBottom() <= 1) {
-		view.scrollToEnd = true;
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-
-	    if (!view.url) {
-		throw "no url specified";
-	    }
-
-	    var viewmodel = me.getViewModel();
-	    var viewModel = this.getViewModel();
-	    var since = new Date();
-	    since.setDate(since.getDate() - 3);
-	    viewModel.set('until', new Date());
-	    viewModel.set('since', since);
-	    me.lookup('content').setStyle('line-height', view.lineHeight + 'px');
-
-	    view.loadTask = new Ext.util.DelayedTask(me.doLoad, me, [true, false]);
-
-	    me.updateParams();
-	    view.task = Ext.TaskManager.start({
-		run: function() {
-		    if (!view.isVisible() || !view.scrollToEnd || !viewmodel.get('livemode')) {
-			return;
-		    }
-
-		    if (me.scrollPosBottom() <= 1) {
-			view.loadTask.delay(200, undefined, undefined, [true, false]);
-		    }
-		},
-		interval: 1000
-	    });
-	},
-
-	onLiveMode: function() {
-	    var me = this;
-	    var view = me.getView();
-	    delete view.startcursor;
-	    delete view.endcursor;
-	    delete view.content;
-	    me.getViewModel().set('livemode', true);
-	    view.scrollToEnd = true;
-	    me.updateView([], true, false);
-	},
-
-	onTimespan: function() {
-	    var me = this;
-	    me.getViewModel().set('livemode', false);
-	    me.updateView([], false);
-	}
-    },
-
-    onDestroy: function() {
-	var me = this;
-	me.loadTask.cancel();
-	Ext.TaskManager.stop(me.task);
-	delete me.content;
-    },
-
-    // for user to initiate a load from outside
-    requestUpdate: function() {
-	var me = this;
-	me.loadTask.delay(200);
-    },
-
-    viewModel: {
-	data: {
-	    livemode: true,
-	    until: null,
-	    since: null
-	}
-    },
-
-    layout: 'auto',
-    bodyPadding: 5,
-    scrollable: {
-	x: 'auto',
-	y: 'auto',
-	listeners: {
-	    // we have to have this here, since we cannot listen to events
-	    // of the scroller in the viewcontroller (extjs bug?), nor does
-	    // the panel have a 'scroll' event'
-	    scroll: {
-		fn: function(scroller, x, y) {
-		    var controller = this.component.getController();
-		    if (controller) { // on destroy, controller can be gone
-			controller.onScroll(x,y);
-		    }
-		},
-		buffer: 200
-	    },
-	}
-    },
-
-    tbar: {
-
-	items: [
-	    '->',
-	    {
-		xtype: 'segmentedbutton',
-		items: [
-		    {
-			text: gettext('Live Mode'),
-			bind: {
-			    pressed: '{livemode}'
-			},
-			handler: 'onLiveMode',
-		    },
-		    {
-			text: gettext('Select Timespan'),
-			bind: {
-			    pressed: '{!livemode}'
-			},
-			handler: 'onTimespan',
-		    }
-		]
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Since') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'since_date',
-		reference: 'since',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{since}',
-		    maxValue: '{until}'
-		}
-	    },
-	    {
-		xtype: 'box',
-		bind: { disabled: '{livemode}' },
-		autoEl: { cn: gettext('Until') + ':' }
-	    },
-	    {
-		xtype: 'datefield',
-		name: 'until_date',
-		reference: 'until',
-		format: 'Y-m-d',
-		bind: {
-		    disabled: '{livemode}',
-		    value: '{until}',
-		    minValue: '{since}'
-		}
-	    },
-	    {
-		xtype: 'button',
-		text: 'Update',
-		reference: 'updateBtn',
-		handler: 'updateParams',
-		bind: {
-		    disabled: '{livemode}'
-		}
-	    }
-	]
-    },
-
-    items: [
-	{
-	    xtype: 'box',
-	    reference: 'content',
-	    style: {
-		font: 'normal 11px tahoma, arial, verdana, sans-serif',
-		'white-space': 'pre'
-	    },
-	}
-    ]
-});
-Ext.define('Proxmox.widget.RRDChart', {
-    extend: 'Ext.chart.CartesianChart',
-    alias: 'widget.proxmoxRRDChart',
-
-    unit: undefined, // bytes, bytespersecond, percent
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	convertToUnits: function(value) {
-	    var units = ['', 'k','M','G','T', 'P'];
-	    var si = 0;
-	    while(value >= 1000  && si < (units.length -1)){
-		value = value / 1000;
-		si++;
-	    }
-
-	    // javascript floating point weirdness
-	    value = Ext.Number.correctFloat(value);
-
-	    // limit to 2 decimal points
-	    value = Ext.util.Format.number(value, "0.##");
-
-	    return value.toString() + " " + units[si];
-	},
-
-	leftAxisRenderer: function(axis, label, layoutContext) {
-	    var me = this;
-
-	    return me.convertToUnits(label);
-	},
-
-	onSeriesTooltipRender: function(tooltip, record, item) {
-	    var me = this.getView();
-
-	    var suffix = '';
-
-	    if (me.unit === 'percent') {
-		suffix = '%';
-	    } else if (me.unit === 'bytes') {
-		suffix = 'B';
-	    } else if (me.unit === 'bytespersecond') {
-		suffix = 'B/s';
-	    }
-
-	    var prefix = item.field;
-	    if (me.fieldTitles && me.fieldTitles[me.fields.indexOf(item.field)]) {
-		prefix = me.fieldTitles[me.fields.indexOf(item.field)];
-	    }
-            tooltip.setHtml(prefix + ': ' + this.convertToUnits(record.get(item.field)) + suffix +
-			    '<br>' + new Date(record.get('time')));
-	},
-
-	onAfterAnimation: function(chart, eopts) {
-	    // if the undobuton is disabled,
-	    // disable our tool
-
-	    var ourUndoZoomButton = chart.tools[0];
-	    var undoButton = chart.interactions[0].getUndoButton();
-	    ourUndoZoomButton.setDisabled(undoButton.isDisabled());
-	}
-    },
-
-    width: 770,
-    height: 300,
-    animation: false,
-    interactions: [{
-	type: 'crosszoom'
-    }],
-    axes: [{
-	type: 'numeric',
-	position: 'left',
-	grid: true,
-	renderer: 'leftAxisRenderer',
-	//renderer: function(axis, label) { return label; },
-	minimum: 0
-    }, {
-	type: 'time',
-	position: 'bottom',
-	grid: true,
-	fields: ['time']
-    }],
-    legend: {
-	docked: 'bottom'
-    },
-    listeners: {
-	animationend: 'onAfterAnimation'
-    },
-
-
-    initComponent: function() {
-	var me = this;
-	var series = {};
-
-	if (!me.store) {
-	    throw "cannot work without store";
-	}
-
-	if (!me.fields) {
-	    throw "cannot work without fields";
-	}
-
-	me.callParent();
-
-	// add correct label for left axis
-	var axisTitle = "";
-	if (me.unit === 'percent') {
-	    axisTitle = "%";
-	} else if (me.unit === 'bytes') {
-	    axisTitle = "Bytes";
-	} else if (me.unit === 'bytespersecond') {
-	    axisTitle = "Bytes/s";
-	} else if (me.fieldTitles && me.fieldTitles.length === 1) {
-	    axisTitle = me.fieldTitles[0];
-	} else if (me.fields.length === 1) {
-	    axisTitle = me.fields[0];
-	}
-
-	me.axes[0].setTitle(axisTitle);
-
-	if (!me.noTool) {
-	    me.addTool([{
-		type: 'minus',
-		disabled: true,
-		tooltip: gettext('Undo Zoom'),
-		handler: function(){
-		    var undoButton = me.interactions[0].getUndoButton();
-		    if (undoButton.handler) {
-			undoButton.handler();
-		    }
-		}
-	    },{
-		type: 'restore',
-		tooltip: gettext('Toggle Legend'),
-		handler: function(){
-		    if (me.legend) {
-			me.legend.setVisible(!me.legend.isVisible());
-		    }
-		}
-	    }]);
-	}
-
-	// add a series for each field we get
-	me.fields.forEach(function(item, index){
-	    var title = item;
-	    if (me.fieldTitles && me.fieldTitles[index]) {
-		title = me.fieldTitles[index];
-	    }
-	    me.addSeries(Ext.apply(
-		{
-		    type: 'line',
-		    xField: 'time',
-		    yField: item,
-		    title: title,
-		    fill: true,
-		    style: {
-			lineWidth: 1.5,
-			opacity: 0.60
-		    },
-		    marker: {
-			opacity: 0,
-			scaling: 0.01,
-			fx: {
-			    duration: 200,
-			    easing: 'easeOut'
-			}
-		    },
-		    highlightCfg: {
-			opacity: 1,
-			scaling: 1.5
-		    },
-		    tooltip: {
-			trackMouse: true,
-			renderer: 'onSeriesTooltipRender'
-		    }
-		},
-		me.seriesConfig
-	    ));
-	});
-
-	// enable animation after the store is loaded
-	me.store.onAfter('load', function() {
-	    me.setAnimation(true);
-	}, this, {single: true});
-    }
-});
-Ext.define('Proxmox.panel.GaugeWidget', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.proxmoxGauge',
-
-    defaults: {
-	style: {
-	    'text-align':'center'
-	}
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	},
-	{
-	    xtype: 'polar',
-	    height: 120,
-	    border: false,
-	    itemId: 'chart',
-	    series: [{
-		type: 'gauge',
-		value: 0,
-		colors: ['#f5f5f5'],
-		sectors: [0],
-		donut: 90,
-		needleLength: 100,
-		totalAngle: Math.PI
-	    }],
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '',
-		textAlign: 'center',
-		textBaseline: 'bottom',
-		x: 125,
-		y: 110,
-		fontSize: 30
-	    }]
-	},
-	{
-	    xtype: 'box',
-	    itemId: 'text'
-	}
-    ],
-
-    header: false,
-    border: false,
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-    warningColor: '#fc0',
-    criticalColor: '#FF6C59',
-    defaultColor: '#c2ddf2',
-    backgroundColor: '#f5f5f5',
-
-    initialValue: 0,
-
-
-    updateValue: function(value, text) {
-	var me = this;
-	var color = me.defaultColor;
-	var attr = {};
-
-	if (value >= me.criticalThreshold) {
-	    color = me.criticalColor;
-	} else if (value >= me.warningThreshold) {
-	    color = me.warningColor;
-	}
-
-	me.chart.series[0].setColors([color, me.backgroundColor]);
-	me.chart.series[0].setValue(value*100);
-
-	me.valueSprite.setText(' '+(value*100).toFixed(0) + '%');
-	attr.x = me.chart.getWidth()/2;
-	attr.y = me.chart.getHeight()-20;
-	if (me.spriteFontSize) {
-	    attr.fontSize = me.spriteFontSize;
-	}
-	me.valueSprite.setAttributes(attr, true);
-
-	if (text !== undefined) {
-	    me.text.setHtml(text);
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.text = me.getComponent('text');
-	me.chart = me.getComponent('chart');
-	me.valueSprite = me.chart.getSurface('chart').get('valueSprite');
-    }
-});
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-Ext.define('Proxmox.window.Edit', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxWindowEdit',
-
-    // autoLoad trigger a load() after component creation
-    autoLoad: false,
-
-    resizable: false,
-
-    // use this tio atimatically generate a title like
-    // Create: <subject>
-    subject: undefined,
-
-    // set isCreate to true if you want a Create button (instead
-    // OK and RESET)
-    isCreate: false,
-
-    // set to true if you want an Add button (instead of Create)
-    isAdd: false,
-
-    // set to true if you want an Remove button (instead of Create)
-    isRemove: false,
-
-    // custom submitText
-    submitText: undefined,
-
-    backgroundDelay: 0,
-
-    // needed for finding the reference to submitbutton
-    // because we do not have a controller
-    referenceHolder: true,
-    defaultButton: 'submitbutton',
-
-    // finds the first form field
-    defaultFocus: 'field[disabled=false][hidden=false]',
-
-    showProgress: false,
-
-    showTaskViewer: false,
-
-    // gets called if we have a progress bar or taskview and it detected that
-    // the task finished. function(success)
-    taskDone: Ext.emptyFn,
-
-    // gets called when the api call is finished, right at the beginning
-    // function(success, response, options)
-    apiCallDone: Ext.emptyFn,
-
-    // assign a reference from docs, to add a help button docked to the
-    // bottom of the window. If undefined we magically fall back to the
-    // onlineHelp of our first item, if set.
-    onlineHelp: undefined,
-
-    isValid: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-	return form.isValid();
-    },
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.formPanel.getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	Ext.iterate(values, function(fieldId, val) {
-	    var field = form.findField(fieldId);
-	    if (field && !field.up('inputpanel')) {
-	        field.setValue(val);
-		if (form.trackResetOnLoad) {
-		    field.resetOriginalValue();
-		}
-	    }
-	});
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setValues(values);
-	});
-    },
-
-    setSubmitText: function(text) {
-	this.lookup('submitbutton').setText(text);
-    },
-
-    submit: function() {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	var values = me.getValues();
-	Ext.Object.each(values, function(name, val) {
-	    if (values.hasOwnProperty(name)) {
-                if (Ext.isArray(val) && !val.length) {
-		    values[name] = '';
-		}
-	    }
-	});
-
-	if (me.digest) {
-	    values.digest = me.digest;
-	}
-
-	if (me.backgroundDelay) {
-	    values.background_delay = me.backgroundDelay;
-	}
-
-	var url =  me.url;
-	if (me.method === 'DELETE') {
-	    url = url + "?" + Ext.Object.toQueryString(values);
-	    values = undefined;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    waitMsgTarget: me,
-	    method: me.method || (me.backgroundDelay ? 'POST' : 'PUT'),
-	    params: values,
-	    failure: function(response, options) {
-		me.apiCallDone(false, response, options);
-
-		if (response.result && response.result.errors) {
-		    form.markInvalid(response.result.errors);
-		}
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var hasProgressBar = (me.backgroundDelay || me.showProgress || me.showTaskViewer) &&
-		    response.result.data ? true : false;
-
-		me.apiCallDone(true, response, options);
-
-		if (hasProgressBar) {
-		    // stay around so we can trigger our close events
-		    // when background action is completed
-		    me.hide();
-
-		    var upid = response.result.data;
-		    var viewerClass = me.showTaskViewer ? 'Viewer' : 'Progress';
-		    var win = Ext.create('Proxmox.window.Task' + viewerClass, {
-			upid: upid,
-			taskDone: me.taskDone,
-			listeners: {
-			    destroy: function () {
-				me.close();
-			    }
-			}
-		    });
-		    win.show();
-		} else {
-		    me.close();
-		}
-	    }
-	});
-    },
-
-    load: function(options) {
-	var me = this;
-
-	var form = me.formPanel.getForm();
-
-	options = options || {};
-
-	var newopts = Ext.apply({
-	    waitMsgTarget: me
-	}, options);
-
-	var createWrapper = function(successFn) {
-	    Ext.apply(newopts, {
-		url: me.url,
-		method: 'GET',
-		success: function(response, opts) {
-		    form.clearInvalid();
-		    me.digest = response.result.data.digest;
-		    if (successFn) {
-			successFn(response, opts);
-		    } else {
-			me.setValues(response.result.data);
-		    }
-		    // hack: fix ExtJS bug
-		    Ext.Array.each(me.query('radiofield'), function(f) {
-			f.resetOriginalValue();
-		    });
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus, function() {
-			me.close();
-		    });
-		}
-	    });
-	};
-
-	createWrapper(options.success);
-
-	Proxmox.Utils.API2Request(newopts);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.url) {
-	    throw "no url specified";
-	}
-
-	if (me.create) {throw "deprecated parameter, use isCreate";}
-
-	var items = Ext.isArray(me.items) ? me.items : [ me.items ];
-
-	me.items = undefined;
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    url: me.url,
-	    method: me.method || 'PUT',
-	    trackResetOnLoad: true,
-	    bodyPadding: 10,
-	    border: false,
-	    defaults: Ext.apply({}, me.defaults, {
-		border: false
-	    }),
-	    fieldDefaults: Ext.apply({}, me.fieldDefaults, {
-		labelWidth: 100,
-		anchor: '100%'
-            }),
-	    items: items
-	});
-
-	var inputPanel = me.formPanel.down('inputpanel');
-
-	var form = me.formPanel.getForm();
-
-	var submitText;
-	if (me.isCreate) {
-	    if (me.submitText) {
-		submitText = me.submitText;
-	    } else if (me.isAdd) {
-		submitText = gettext('Add');
-	    } else if (me.isRemove) {
-		submitText = gettext('Remove');
-	    } else {
-		submitText = gettext('Create');
-	    }
-	} else {
-	    submitText = me.submitText || gettext('OK');
-	}
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    reference: 'submitbutton',
-	    text: submitText,
-	    disabled: !me.isCreate,
-	    handler: function() {
-		me.submit();
-	    }
-	});
-
-	var resetBtn = Ext.create('Ext.Button', {
-	    text: 'Reset',
-	    disabled: true,
-	    handler: function(){
-		form.reset();
-	    }
-	});
-
-	var set_button_status = function() {
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-	    submitBtn.setDisabled(!valid || !(dirty || me.isCreate));
-	    resetBtn.setDisabled(!dirty);
-
-	    if (inputPanel && inputPanel.hasAdvanced) {
-		// we want to show the advanced options
-		// as soon as some of it is not valid
-		var advancedItems = me.down('#advancedContainer').query('field');
-		var valid = true;
-		advancedItems.forEach(function(field) {
-		    if (!field.isValid()) {
-			valid = false;
-		    }
-		});
-
-		if (!valid) {
-		    inputPanel.setAdvancedVisible(true);
-		    me.down('#advancedcb').setValue(true);
-		}
-	    }
-	};
-
-	form.on('dirtychange', set_button_status);
-	form.on('validitychange', set_button_status);
-
-	var colwidth = 300;
-	if (me.fieldDefaults && me.fieldDefaults.labelWidth) {
-	    colwidth += me.fieldDefaults.labelWidth - 100;
-	}
-
-	var twoColumn = inputPanel &&
-	    (inputPanel.column1 || inputPanel.column2);
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, me.isCreate, me.isAdd);
-	}
-
-	if (me.isCreate) {
-		me.buttons = [ submitBtn ] ;
-	} else {
-		me.buttons = [ submitBtn, resetBtn ];
-	}
-
-	if (inputPanel && inputPanel.hasAdvanced) {
-	    var sp = Ext.state.Manager.getProvider();
-	    var advchecked = sp.get('proxmox-advanced-cb');
-	    inputPanel.setAdvancedVisible(advchecked);
-	    me.buttons.unshift(
-	       {
-		   xtype: 'proxmoxcheckbox',
-		   itemId: 'advancedcb',
-		   boxLabelAlign: 'before',
-		   boxLabel: gettext('Advanced'),
-		   stateId: 'proxmox-advanced-cb',
-		   value: advchecked,
-		   listeners: {
-		       change: function(cb, val) {
-			   inputPanel.setAdvancedVisible(val);
-			   sp.set('proxmox-advanced-cb', val);
-		       }
-		   }
-	       }
-	    );
-	}
-
-	var onlineHelp = me.onlineHelp;
-	if (!onlineHelp && inputPanel && inputPanel.onlineHelp) {
-	    onlineHelp = inputPanel.onlineHelp;
-	}
-
-	if (onlineHelp) {
-	    var helpButton = Ext.create('Proxmox.button.Help');
-	    me.buttons.unshift(helpButton, '->');
-	    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', onlineHelp);
-	}
-
-	Ext.applyIf(me, {
-	    modal: true,
-	    width: twoColumn ? colwidth*2 : colwidth,
-	    border: false,
-	    items: [ me.formPanel ]
-	});
-
-	me.callParent();
-
-	// always mark invalid fields
-	me.on('afterlayout', function() {
-	    // on touch devices, the isValid function
-	    // triggers a layout, which triggers an isValid
-	    // and so on
-	    // to prevent this we disable the layouting here
-	    // and enable it afterwards
-	    me.suspendLayout = true;
-	    me.isValid();
-	    me.suspendLayout = false;
-	});
-
-	if (me.autoLoad) {
-	    me.load();
-	}
-    }
-});
-Ext.define('Proxmox.window.PasswordEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'proxmoxWindowPasswordEdit',
-
-    subject: gettext('Password'),
-
-    url: '/api2/extjs/access/password',
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    allowBlank: false,
-	    name: 'password',
-	    listeners: {
-                change: function(field){
-		    field.next().validate();
-                },
-                blur: function(field){
-		    field.next().validate();
-                }
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'),
-	    name: 'verifypassword',
-	    allowBlank: false,
-	    vtype: 'password',
-	    initialPassField: 'password',
-	    submitValue: false
-	},
-	{
-	    xtype: 'hiddenfield',
-	    name: 'userid'
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	me.callParent();
-	me.down('[name=userid]').setValue(me.userid);
-    }
-});
-Ext.define('Proxmox.window.TaskProgress', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskProgress',
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: {
-		status: { defaultValue: 'unknown' },
-		exitstatus: { defaultValue: 'unknown' }
-	    }
-	});
-
-	me.on('destroy', statstore.stopUpdate);
-
-	var getObjectValue = function(key, defaultValue) {
-	    var rec = statstore.getById(key);
-	    if (rec) {
-		return rec.data.value;
-	    }
-	    return defaultValue;
-	};
-
-	var pbar = Ext.create('Ext.ProgressBar', { text: 'running...' });
-
-	me.mon(statstore, 'load', function() {
-	    var status = getObjectValue('status');
-	    if (status === 'stopped') {
-		var exitstatus = getObjectValue('exitstatus');
-		if (exitstatus == 'OK') {
-		    pbar.reset();
-		    pbar.updateText("Done!");
-		    Ext.Function.defer(me.close, 1000, me);
-		} else {
-		    me.close();
-		    Ext.Msg.alert('Task failed', exitstatus);
-		}
-		me.taskDone(exitstatus == 'OK');
-	    }
-	});
-
-	var descr = Proxmox.Utils.format_task_description(task.type, task.id);
-
-	Ext.apply(me, {
-	    title: gettext('Task') + ': ' + descr,
-	    width: 300,
-	    layout: 'auto',
-	    modal: true,
-	    bodyPadding: 5,
-	    items: pbar,
-	    buttons: [
-		{
-		    text: gettext('Details'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    taskDone: me.taskDone,
-			    upid: me.upid
-			});
-			win.show();
-			me.close();
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	statstore.startUpdate();
-
-	pbar.wait();
-    }
-});
-
-// fixme: how can we avoid those lint errors?
-/*jslint confusion: true */
-
-Ext.define('Proxmox.window.TaskViewer', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.proxmoxTaskViewer',
-
-    extraTitle: '', // string to prepend after the generic task title
-
-    taskDone: Ext.emptyFn,
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.upid) {
-	    throw "no task specified";
-	}
-
-	var task = Proxmox.Utils.parse_task_upid(me.upid);
-
-	var statgrid;
-
-	var rows = {
-	    status: {
-		header: gettext('Status'),
-		defaultValue: 'unknown',
-		renderer: function(value) {
-		    if (value != 'stopped') {
-			return value;
-		    }
-		    var es = statgrid.getObjectValue('exitstatus');
-		    if (es) {
-			return value + ': ' + es;
-		    }
-		}
-	    },
-	    exitstatus: {
-		visible: false
-	    },
-	    type: {
-		header: gettext('Task type'),
-		required: true
-	    },
-	    user: {
-		header: gettext('User name'),
-		required: true
-	    },
-	    node: {
-		header: gettext('Node'),
-		required: true
-	    },
-	    pid: {
-		header: gettext('Process ID'),
-		required: true
-	    },
-	    task_id: {
-		header: gettext('Task ID'),
-	    },
-	    starttime: {
-		header: gettext('Start Time'),
-		required: true,
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    upid: {
-		header: gettext('Unique task ID')
-	    }
-	};
-
-	var statstore = Ext.create('Proxmox.data.ObjectStore', {
-            url: "/api2/json/nodes/" + task.node + "/tasks/" + me.upid + "/status",
-	    interval: 1000,
-	    rows: rows
-	});
-
-	me.on('destroy', statstore.stopUpdate);
-
-	var stop_task = function() {
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + task.node + "/tasks/" + me.upid,
-		waitMsgTarget: me,
-		method: 'DELETE',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var stop_btn1 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	var stop_btn2 = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: stop_task
-	});
-
-	statgrid = Ext.create('Proxmox.grid.ObjectGrid', {
-	    title: gettext('Status'),
-	    layout: 'fit',
-	    tbar: [ stop_btn1 ],
-	    rstore: statstore,
-	    rows: rows,
-	    border: false
-	});
-
-	var logView = Ext.create('Proxmox.panel.LogView', {
-	    title: gettext('Output'),
-	    tbar: [ stop_btn2 ],
-	    border: false,
-	    url: "/api2/extjs/nodes/" + task.node + "/tasks/" + me.upid + "/log"
-	});
-
-	me.mon(statstore, 'load', function() {
-	    var status = statgrid.getObjectValue('status');
-
-	    if (status === 'stopped') {
-		logView.scrollToEnd = false;
-		logView.requestUpdate();
-		statstore.stopUpdate();
-		me.taskDone(statgrid.getObjectValue('exitstatus') == 'OK');
-	    }
-
-	    stop_btn1.setDisabled(status !== 'running');
-	    stop_btn2.setDisabled(status !== 'running');
-	});
-
-	statstore.startUpdate();
-
-	Ext.apply(me, {
-	    title: "Task viewer: " + task.desc + me.extraTitle,
-	    width: 800,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [{
-		xtype: 'tabpanel',
-		region: 'center',
-		items: [ logView, statgrid ]
-	    }]
-        });
-
-	me.callParent();
-
-	logView.fireEvent('show', logView);
-    }
-});
-
-Ext.define('apt-pkglist', {
-    extend: 'Ext.data.Model',
-    fields: [ 'Package', 'Title', 'Description', 'Section', 'Arch',
-	      'Priority', 'Version', 'OldVersion', 'ChangeLogUrl', 'Origin' ],
-    idProperty: 'Package'
-});
-
-Ext.define('Proxmox.node.APT', {
-    extend: 'Ext.grid.GridPanel',
-
-    xtype: 'proxmoxNodeAPT',
-
-    upgradeBtn: undefined,
-
-    columns: [
-	{
-	    header: gettext('Package'),
-	    width: 200,
-	    sortable: true,
-	    dataIndex: 'Package'
-	},
-	{
-	    text: gettext('Version'),
-	    columns: [
-		{
-		    header: gettext('current'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'OldVersion'
-		},
-		{
-		    header: gettext('new'),
-		    width: 100,
-		    sortable: false,
-		    dataIndex: 'Version'
-		}
-	    ]
-	},
-	{
-	    header: gettext('Description'),
-	    sortable: false,
-	    dataIndex: 'Title',
-	    flex: 1
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'apt-pkglist',
-	    groupField: 'Origin',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/apt/update"
-	    },
-	    sorters: [
-		{
-		    property : 'Package',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping', {
-            groupHeaderTpl: '{[ "Origin: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})',
-	    enableGroupingMenu: false
-	});
-
-	var rowBodyFeature = Ext.create('Ext.grid.feature.RowBody', {
-            getAdditionalData: function (data, rowIndex, record, orig) {
-		var headerCt = this.view.headerCt;
-		var colspan = headerCt.getColumnCount();
-		return {
-		    rowBody: '<div style="padding: 1em">' +
-			Ext.String.htmlEncode(data.Description) +
-			'</div>',
-		    rowBodyCls: me.full_description ? '' : Ext.baseCSSPrefix + 'grid-row-body-hidden',
-		    rowBodyColspan: colspan
-		};
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	var apt_command = function(cmd){
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/apt/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.mon(win, 'close', reload);
-		}
-	    });
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var update_btn = new Ext.Button({
-	    text: gettext('Refresh'),
-	    handler: function() {
-		Proxmox.Utils.checked_command(function() { apt_command('update'); });
-	    }
-	});
-
-	var show_changelog = function(rec) {
-	    if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		return;
-	    }
-
-	    var view = Ext.createWidget('component', {
-		autoScroll: true,
-		style: {
-		    'background-color': 'white',
-		    'white-space': 'pre',
-		    'font-family': 'monospace',
-		    padding: '5px'
-		}
-	    });
-
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Changelog') + ": " + rec.data.Package,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		modal: true,
-		items: [ view ]
-	    });
-
-	    Proxmox.Utils.API2Request({
-		waitMsgTarget: me,
-		url: "/nodes/" + me.nodename + "/apt/changelog",
-		params: {
-		    name: rec.data.Package,
-		    version: rec.data.Version
-		},
-		method: 'GET',
-		failure: function(response, opts) {
-		    win.close();
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    win.show();
-		    view.update(Ext.htmlEncode(response.result.data));
-		}
-	    });
-
-	};
-
-	var changelog_btn = new Proxmox.button.Button({
-	    text: gettext('Changelog'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec || !rec.data || !(rec.data.ChangeLogUrl && rec.data.Package)) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function(b, e, rec) {
-		show_changelog(rec);
-	    }
-	});
-
-	var verbose_desc_checkbox = new Ext.form.field.Checkbox({
-	    boxLabel: gettext('Show details'),
-	    value: false,
-	    listeners: {
-		change: (f, val) => {
-		    me.full_description = val;
-		    me.getView().refresh();
-		}
-	    }
-	});
-
-	if (me.upgradeBtn) {
-	    me.tbar =  [ update_btn, me.upgradeBtn, changelog_btn, '->', verbose_desc_checkbox ];
-	} else {
-	    me.tbar =  [ update_btn, changelog_btn, '->', verbose_desc_checkbox ];
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-update',
-	    selModel: sm,
-            viewConfig: {
-		stripeRows: false,
-		emptyText: '<div style="display:table; width:100%; height:100%;"><div style="display:table-cell; vertical-align: middle; text-align:center;"><b>' + gettext('No updates available.') + '</div></div>'
-	    },
-	    features: [ groupingFeature, rowBodyFeature ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: function(v, rec) {
-		    show_changelog(rec);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeNetworkEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.iftype) {
-	    throw "no network device type specified";
-	}
-
-	me.isCreate = !me.iface;
-
-	var iface_vtype;
-
-	if (me.iftype === 'bridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'bond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'eth' && !me.isCreate) {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'vlan') {
-	    iface_vtype = 'VlanName';
-	} else if (me.iftype === 'OVSBridge') {
-	    iface_vtype = 'BridgeName';
-	} else if (me.iftype === 'OVSBond') {
-	    iface_vtype = 'BondName';
-	} else if (me.iftype === 'OVSIntPort') {
-	    iface_vtype = 'InterfaceName';
-	} else if (me.iftype === 'OVSPort') {
-	    iface_vtype = 'InterfaceName';
-	} else {
-	    console.log(me.iftype);
-	    throw "unknown network device type specified";
-	}
-
-	me.subject = Proxmox.Utils.render_network_iface_type(me.iftype);
-
-	let column1 = [],
-	    column2 = [],
-	    columnB = [],
-	    advancedColumn1 = [],
-	    advancedColumn2 = [];
-
-	if (!(me.iftype === 'OVSIntPort' || me.iftype === 'OVSPort' || me.iftype === 'OVSBond')) {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Autostart'),
-		name: 'autostart',
-		uncheckedValue: 0,
-		checked: me.isCreate ? true : undefined
-	    });
-	}
-
-	if (me.iftype === 'bridge') {
-	    column2.push({
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('VLAN aware'),
-		name: 'bridge_vlan_aware',
-		deleteEmpty: !me.isCreate
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'bridge_ports'
-	    });
-	} else if (me.iftype === 'OVSBridge') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Bridge ports'),
-		name: 'ovs_ports'
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'OVSPort' || me.iftype === 'OVSIntPort') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	} else if (me.iftype === 'vlan') {
-
-	    if (!me.isCreate) {
-
-		me.disablevlanid = false;
-		me.disablevlanrawdevice = false;
-		me.vlanrawdevicevalue = '';
-		me.vlanidvalue = '';
-
-		if (Proxmox.Utils.VlanInterface_match.test(me.iface)) {
-		   me.disablevlanid = true;
-		   me.disablevlanrawdevice = true;
-		   var arr = Proxmox.Utils.VlanInterface_match.exec(me.iface);
-		   me.vlanrawdevicevalue = arr[1];
-		   me.vlanidvalue = arr[2];
-
-		} else if (Proxmox.Utils.Vlan_match.test(me.iface)) {
-		   me.disablevlanid = true;
-		   var arr = Proxmox.Utils.Vlan_match.exec(me.iface);
-		   me.vlanidvalue = arr[1];
-		}
-	    } else {
-
-		me.disablevlanid = true;
-		me.disablevlanrawdevice = true;
-           }
-
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Vlan raw device'),
-		name: 'vlan-raw-device',
-		value: me.vlanrawdevicevalue,
-		disabled: me.disablevlanrawdevice
-	    });
-
-	    column2.push({
-		xtype: 'pveVlanField',
-		name: 'vlan-id',
-		value: me.vlanidvalue,
-		disabled: me.disablevlanid
-	    });
-
-	    columnB.push({
-		xtype: 'label',
-		userCls: 'pmx-hint',
-		text: 'Either add the VLAN number to an existing interface name, or choose your own name and set the VLAN raw device (for the latter ifupdown1 supports vlanXY naming only)',
-	    });
-
-	} else if (me.iftype === 'bond') {
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('Slaves'),
-		name: 'slaves'
-	    });
-
-	    var policySelector = Ext.createWidget('bondPolicySelector', {
-		fieldLabel: gettext('Hash policy'),
-		name: 'bond_xmit_hash_policy',
-		deleteEmpty: !me.isCreate,
-		disabled: true
-	    });
-
-	    var primaryfield = Ext.createWidget('textfield', {
-		fieldLabel: gettext('bond-primary'),
-		name: 'bond-primary',
-		value: '',
-		disabled: true
-	    });
-
-	    column2.push({
-		xtype: 'bondModeSelector',
-		fieldLabel: gettext('Mode'),
-		name: 'bond_mode',
-		value: me.isCreate ? 'balance-rr' : undefined,
-		listeners: {
-		    change: function(f, value) {
-			if (value === 'balance-xor' ||
-			    value === '802.3ad') {
-			    policySelector.setDisabled(false);
-			    primaryfield.setDisabled(true);
-			    primaryfield.setValue('');
-			} else if (value === 'active-backup') {
-			    primaryfield.setDisabled(false);
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			} else {
-			    policySelector.setDisabled(true);
-			    policySelector.setValue('');
-			    primaryfield.setDisabled(true);
-			    primaryfield.setValue('');
-			}
-		    }
-		},
-		allowBlank: false
-	    });
-
-	    column2.push(policySelector);
-	    column2.push(primaryfield);
-
-	} else if (me.iftype === 'OVSBond') {
-	    column2.push({
-		xtype: me.isCreate ? 'PVE.form.BridgeSelector' : 'displayfield',
-		fieldLabel: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		allowBlank: false,
-		nodename: me.nodename,
-		bridgeType: 'OVSBridge',
-		name: 'ovs_bridge'
-	    });
-	    column2.push({
-		xtype: 'pveVlanField',
-		deleteEmpty: !me.isCreate,
-		name: 'ovs_tag',
-		value: ''
-	    });
-	    column2.push({
-		xtype: 'textfield',
-		fieldLabel: gettext('OVS options'),
-		name: 'ovs_options'
-	    });
-	}
-
-	column2.push({
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Comment'),
-	    allowBlank: true,
-	    nodename: me.nodename,
-	    name: 'comments'
-	});
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network";
-	    method = 'POST';
-	} else {
-	    url = "/api2/extjs/nodes/" + me.nodename + "/network/" + me.iface;
-	    method = 'PUT';
-	}
-
-	column1.push({
-	    xtype: 'hiddenfield',
-	    name: 'type',
-	    value: me.iftype
-	},
-	{
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'iface',
-	    value: me.iface,
-	    vtype: iface_vtype,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    if (me.isCreate && iface_vtype === 'VlanName') {
-			var vlanidField = me.down('field[name=vlan-id]');
-			var vlanrawdeviceField = me.down('field[name=vlan-raw-device]');
-			if (Proxmox.Utils.VlanInterface_match.test(value)) {
-			    vlanidField.setDisabled(true);
-			    vlanrawdeviceField.setDisabled(true);
-			} else if (Proxmox.Utils.Vlan_match.test(value)) {
-			    vlanidField.setDisabled(true);
-			    vlanrawdeviceField.setDisabled(false);
-			} else {
-			    vlanidField.setDisabled(false);
-			    vlanrawdeviceField.setDisabled(false);
-			}
-		    }
-		}
-	    }
-	});
-
-	if (me.iftype === 'OVSBond') {
-	    column1.push(
-		{
-		    xtype: 'bondModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    name: 'bond_mode',
-		    openvswitch: true,
-		    value: me.isCreate ? 'active-backup' : undefined,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Slaves'),
-		    name: 'ovs_bonds'
-		}
-	    );
-	} else {
-
-	    column1.push(
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv4/CIDR',
-		    vtype: 'IPCIDRAddress',
-		    name: 'cidr'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv4)',
-		    vtype: 'IPAddress',
-		    name: 'gateway'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: 'IPv6/CIDR',
-		    vtype: 'IP6CIDRAddress',
-		    name: 'cidr6'
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    deleteEmpty: !me.isCreate,
-		    fieldLabel: gettext('Gateway') + ' (IPv6)',
-		    vtype: 'IP6Address',
-		    name: 'gateway6'
-		},
-	    );
-	    advancedColumn1. push(
-		{
-		    xtype: 'proxmoxintegerfield',
-		    minValue: 1280,
-		    maxValue: 65520,
-		    deleteEmpty: !me.isCreate,
-		    emptyText: 1500,
-		    fieldLabel: 'MTU',
-		    name: 'mtu'
-		},
-	    );
-	}
-
-	Ext.applyIf(me, {
-	    url: url,
-	    method: method,
-	    items: {
-                xtype: 'inputpanel',
-		column1: column1,
-		column2: column2,
-		columnB: columnB,
-		advancedColumn1: advancedColumn1,
-		advancedColumn2: advancedColumn2,
-	    }
-	});
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.down('field[name=iface]').setValue(me.iface_default);
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.type !== me.iftype) {
-			var msg = "Got unexpected device type";
-			Ext.Msg.alert(gettext('Error'), msg, function() {
-			    me.close();
-			});
-			return;
-		    }
-		    me.setValues(data);
-		    me.isValid(); // trigger validation
-		}
-	    });
-	}
-    }
-});
-Ext.define('proxmox-networks', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'iface', 'type', 'active', 'autostart',
-	'bridge_ports', 'slaves',
-	'address', 'netmask', 'gateway',
-	'address6', 'netmask6', 'gateway6',
-	'cidr', 'cidr6',
-	'comments'
-    ],
-    idProperty: 'iface'
-});
-
-Ext.define('Proxmox.node.NetworkView', {
-    extend: 'Ext.panel.Panel',
-
-    alias: ['widget.proxmoxNodeNetworkView'],
-
-    // defines what types of network devices we want to create
-    // order is always the same
-    types: ['bridge', 'bond', 'vlan', 'ovs'],
-
-    showApplyBtn: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseUrl = '/nodes/' + me.nodename + '/network';
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'proxmox-networks',
-	    proxy: {
-                type: 'proxmox',
-                url: '/api2/json' + baseUrl
-	    },
-	    sorters: [
-		{
-		    property : 'iface',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reload = function() {
-	    var changeitem = me.down('#changes');
-	    var apply_btn = me.down('#apply');
-	    var revert_btn = me.down('#revert');
-	    Proxmox.Utils.API2Request({
-		url: baseUrl,
-		failure: function(response, opts) {
-		    store.loadData({});
-		    Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		    changeitem.update('');
-		    changeitem.setHidden(true);
-		},
-		success: function(response, opts) {
-		    var result = Ext.decode(response.responseText);
-		    store.loadData(result.data);
-		    var changes = result.changes;
-		    if (changes === undefined || changes === '') {
-			changes = gettext("No changes");
-			changeitem.setHidden(true);
-			apply_btn.setDisabled(true);
-			revert_btn.setDisabled(true);
-		    } else {
-			changeitem.update("<pre>" + Ext.htmlEncode(changes) + "</pre>");
-			changeitem.setHidden(false);
-			apply_btn.setDisabled(false);
-			revert_btn.setDisabled(false);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.node.NetworkEdit', {
-		nodename: me.nodename,
-		iface: rec.data.iface,
-		iftype: rec.data.type
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: run_editor
-	});
-
-	var del_btn = new Ext.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    handler: function(){
-		var grid = me.down('gridpanel');
-		var sm = grid.getSelectionModel();
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		var iface = rec.data.iface;
-
-		Proxmox.Utils.API2Request({
-		    url: baseUrl + '/' + iface,
-		    method: 'DELETE',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var apply_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Apply Configuration'),
-	    itemId: 'apply',
-	    disabled: true,
-	    confirmMsg: 'Do you want to apply pending network changes?',
-	    hidden: !me.showApplyBtn,
-	    handler: function() {
-		Proxmox.Utils.API2Request({
-		    url: baseUrl,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    taskDone: reload,
-			    upid: upid
-			});
-			win.show();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var set_button_status = function() {
-	    var grid = me.down('gridpanel');
-	    var sm = grid.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    edit_btn.setDisabled(!rec);
-	    del_btn.setDisabled(!rec);
-	};
-
-	var render_ports = function(value, metaData, record) {
-	    if (value === 'bridge') {
-		return record.data.bridge_ports;
-	    } else if (value === 'bond') {
-		return record.data.slaves;
-	    } else if (value === 'OVSBridge') {
-		return record.data.ovs_ports;
-	    } else if (value === 'OVSBond') {
-		return record.data.ovs_bonds;
-	    }
-	};
-
-	var find_next_iface_id = function(prefix) {
-	    var next;
-	    for (next = 0; next <= 9999; next++) {
-		if (!store.getById(prefix + next.toString())) {
-		    break;
-		}
-	    }
-	    return prefix + next.toString();
-	};
-
-	var menu_items = [];
-
-	if (me.types.indexOf('bridge') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bridge'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bridge',
-			iface_default: find_next_iface_id('vmbr'),
-			onlineHelp: 'sysadmin_network_configuration',
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('bond') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('bond'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'bond',
-			iface_default: find_next_iface_id('bond'),
-			onlineHelp: 'sysadmin_network_configuration',
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('vlan') !== -1) {
-	    menu_items.push({
-		text: Proxmox.Utils.render_network_iface_type('vlan'),
-		handler: function() {
-		    var win = Ext.create('Proxmox.node.NetworkEdit', {
-			nodename: me.nodename,
-			iftype: 'vlan',
-			iface_default: 'interfaceX.1',
-			onlineHelp: 'sysadmin_network_configuration',
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	if (me.types.indexOf('ovs') !== -1) {
-	    if (menu_items.length > 0) {
-		menu_items.push({ xtype: 'menuseparator' });
-	    }
-
-	    menu_items.push(
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBridge'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBridge',
-			    iface_default: find_next_iface_id('vmbr')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSBond'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSBond',
-			    iface_default: find_next_iface_id('bond')
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    text: Proxmox.Utils.render_network_iface_type('OVSIntPort'),
-		    handler: function() {
-			var win = Ext.create('Proxmox.node.NetworkEdit', {
-			    nodename: me.nodename,
-			    iftype: 'OVSIntPort'
-			});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		}
-	    );
-	}
-
-	var renderer_generator = function(fieldname) {
-	    return function(val, metaData, rec) {
-		var tmp = [];
-		if (rec.data[fieldname]) {
-		    tmp.push(rec.data[fieldname]);
-		}
-		if (rec.data[fieldname + '6']) {
-		    tmp.push(rec.data[fieldname + '6']);
-		}
-		return tmp.join('<br>') || '';
-	    };
-	};
-
-	Ext.apply(me, {
-	    layout: 'border',
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    menu: {
-			plain: true,
-			items: menu_items
-		    }
-		}, '-',
-		{
-		    text: gettext('Revert'),
-		    itemId: 'revert',
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: baseUrl,
-			    method: 'DELETE',
-			    waitMsgTarget: me,
-			    callback: function() {
-				reload();
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		edit_btn,
-		del_btn,
-		'-',
-		apply_btn
-	    ],
-	    items: [
-		{
-		    xtype: 'gridpanel',
-		    stateful: true,
-		    stateId: 'grid-node-network',
-		    store: store,
-		    region: 'center',
-		    border: false,
-		    columns: [
-			{
-			    header: gettext('Name'),
-			    sortable: true,
-			    dataIndex: 'iface'
-			},
-			{
-			    header: gettext('Type'),
-			    sortable: true,
-			    width: 120,
-			    renderer: Proxmox.Utils.render_network_iface_type,
-			    dataIndex: 'type'
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Active'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'active',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText,
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('Autostart'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'autostart',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    xtype: 'booleancolumn',
-			    header: gettext('VLAN aware'),
-			    width: 80,
-			    sortable: true,
-			    dataIndex: 'bridge_vlan_aware',
-			    trueText: Proxmox.Utils.yesText,
-			    falseText: Proxmox.Utils.noText,
-			    undefinedText: Proxmox.Utils.noText
-			},
-			{
-			    header: gettext('Ports/Slaves'),
-			    dataIndex: 'type',
-			    renderer: render_ports
-			},
-			{
-			    header: gettext('Bond Mode'),
-			    dataIndex: 'bond_mode',
-			    renderer: Proxmox.Utils.render_bond_mode,
-			},
-			{
-			    header: gettext('Hash Policy'),
-			    hidden: true,
-			    dataIndex: 'bond_xmit_hash_policy',
-			},
-			{
-			    header: gettext('IP address'),
-			    sortable: true,
-			    width: 120,
-			    hidden: true,
-			    dataIndex: 'address',
-			    renderer: renderer_generator('address'),
-			},
-			{
-			    header: gettext('Subnet mask'),
-			    width: 120,
-			    sortable: true,
-			    hidden: true,
-			    dataIndex: 'netmask',
-			    renderer: renderer_generator('netmask'),
-			},
-			{
-			    header: gettext('CIDR'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'cidr',
-			    renderer: renderer_generator('cidr'),
-			},
-			{
-			    header: gettext('Gateway'),
-			    width: 120,
-			    sortable: true,
-			    dataIndex: 'gateway',
-			    renderer: renderer_generator('gateway'),
-			},
-			{
-			    header: gettext('Comment'),
-			    dataIndex: 'comments',
-			    flex: 1,
-			    renderer: Ext.String.htmlEncode
-			}
-		    ],
-		    listeners: {
-			selectionchange: set_button_status,
-			itemdblclick: run_editor
-		    }
-		},
-		{
-		    border: false,
-		    region: 'south',
-		    autoScroll: true,
-		    hidden: true,
-		    itemId: 'changes',
-		    tbar: [
-			gettext('Pending changes') + ' (' +
-			    gettext("Either reboot or use 'Apply Configuration' (needs ifupdown2) to activate") + ')'
-		    ],
-		    split: true,
-		    bodyPadding: 5,
-		    flex: 0.6,
-		    html: gettext("No changes")
-		}
-	    ],
-	});
-
-	me.callParent();
-	reload();
-    }
-});
-Ext.define('Proxmox.node.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeDNSEdit'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-                fieldLabel: gettext('Search domain'),
-                name: 'search',
-                allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 1",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns1'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS server') + " 2",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns2'
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-                fieldLabel: gettext('DNS server') + " 3",
-		vtype: 'IP64Address',
-		skipEmptyText: true,
-                name: 'dns3'
-	    }
-	];
-
-	Ext.applyIf(me, {
-	    subject: gettext('DNS'),
-	    url: "/api2/extjs/nodes/" + me.nodename + "/dns",
-	    fieldDefaults: {
-		labelWidth: 120
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('Proxmox.node.HostsView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'proxmoxNodeHostsView',
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-    },
-
-    tbar: [
-	{
-	    text: gettext('Save'),
-	    disabled: true,
-	    itemId: 'savebtn',
-	    handler: function() {
-		var me = this.up('panel');
-		Proxmox.Utils.API2Request({
-		    params: {
-			digest: me.digest,
-			data: me.down('#hostsfield').getValue()
-		    },
-		    method: 'POST',
-		    url: '/nodes/' + me.nodename + '/hosts',
-		    waitMsgTarget: me,
-		    success: function(response, opts) {
-			me.reload();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	{
-	    text: gettext('Revert'),
-	    disabled: true,
-	    itemId: 'resetbtn',
-	    handler: function() {
-		var me = this.up('panel');
-		me.down('#hostsfield').reset();
-	    }
-	}
-    ],
-
-	    layout: 'fit',
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'hostsfield',
-	    fieldStyle: {
-		'font-family': 'monospace',
-		'white-space': 'pre'
-	    },
-	    listeners: {
-		dirtychange: function(ta, dirty) {
-		    var me = this.up('panel');
-		    me.down('#savebtn').setDisabled(!dirty);
-		    me.down('#resetbtn').setDisabled(!dirty);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/nodes/" + me.nodename + "/hosts",
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.store);
-
-	me.mon(me.store, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    me.digest = records[0].data.digest;
-	    var data = records[0].data.data;
-	    me.down('#hostsfield').setValue(data);
-	    me.down('#hostsfield').resetOriginalValue();
-	});
-
-	me.reload();
-    }
-});
-Ext.define('Proxmox.node.DNSView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeDNSView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.DNSEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/dns",
-	    cwidth1: 130,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		search: {
-		    header: 'Search domain',
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns1: {
-		    header: gettext('DNS server') + " 1",
-		    required: true,
-		    renderer: Ext.htmlEncode
-		},
-		dns2: {
-		    header: gettext('DNS server') + " 2",
-		    renderer: Ext.htmlEncode
-		},
-		dns3: {
-		    header: gettext('DNS server') + " 3",
-		    renderer: Ext.htmlEncode
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
-Ext.define('Proxmox.node.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeTasks'],
-    stateful: true,
-    stateId: 'grid-node-tasks',
-    loadMask: true,
-    sortableColumns: false,
-    vmidFilter: 0,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.BufferedStore', {
-	    pageSize: 500,
-	    autoLoad: true,
-	    remoteFilter: true,
-	    model: 'proxmox-tasks',
-	    proxy: {
-                type: 'proxmox',
-		startParam: 'start',
-		limitParam: 'limit',
-                url: "/api2/json/nodes/" + me.nodename + "/tasks"
-	    }
-	});
-
-	var userfilter = '';
-	var filter_errors = 0;
-
-	var updateProxyParams = function() {
-	    var params = {
-		errors: filter_errors
-	    };
-	    if (userfilter) {
-		params.userfilter = userfilter;
-	    }
-	    if (me.vmidFilter) {
-		params.vmid = me.vmidFilter;
-	    }
-	    store.proxy.extraParams = params;
-	};
-
-	updateProxyParams();
-
-	var reload_task = Ext.create('Ext.util.DelayedTask',function() {
-	    updateProxyParams();
-	    store.reload();
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	var view_btn = new Ext.Button({
-	    text: gettext('View'),
-	    disabled: true,
-	    handler: run_task_viewer
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store, true);
-
-	Ext.apply(me, {
-	    store: store,
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: false, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    tbar: [
-		view_btn, '->', gettext('User name') +':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: userfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    userfilter = field.getValue();
-			    reload_task.delay(500);
-			}
-		    }
-		}, ' ', gettext('Only Errors') + ':', ' ',
-		{
-		    xtype: 'checkbox',
-		    hideLabel: true,
-		    checked: filter_errors,
-		    listeners: {
-			change: function(field, checked) {
-			    filter_errors = checked ? 1 : 0;
-			    reload_task.delay(10);
-			}
-		    }
-		}, ' '
-	    ],
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 100,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 100,
-		    renderer: function(value, metaData, record) {
-			return Ext.Date.format(value,"M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return "ERROR: " + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		selectionchange: function(v, selections) {
-		    view_btn.setDisabled(!(selections && selections[0]));
-		},
-		show: function() { reload_task.delay(10); },
-		destroy: function() { reload_task.cancel(); }
-	    }
-	});
-
-	me.callParent();
-
-    }
-});
-Ext.define('proxmox-services', {
-    extend: 'Ext.data.Model',
-    fields: [ 'service', 'name', 'desc', 'state' ],
-    idProperty: 'service'
-});
-
-Ext.define('Proxmox.node.ServiceView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.proxmoxNodeServiceView'],
-
-    startOnlyServices: {},
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 1000,
-	    storeid: 'proxmox-services' + me.nodename,
-	    model: 'proxmox-services',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + me.nodename + "/services"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    sortAfterUpdate: true,
-	    sorters: [
-		{
-		    property : 'name',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var view_service_log = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + rec.data.service,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: {
-		    xtype: 'proxmoxLogView',
-		    url: "/api2/extjs/nodes/" + me.nodename + "/syslog?service=" +
-			rec.data.service,
-		    log_select_timespan: 1
-		}
-	    });
-	    win.show();
-	};
-
-	var service_cmd = function(cmd) {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + me.nodename + "/services/" + rec.data.service + "/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.loading = true;
-		},
-		success: function(response, opts) {
-		    rstore.startUpdate();
-		    var upid = response.result.data;
-
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid
-		    });
-		    win.show();
-		}
-	    });
-	};
-
-	var start_btn = new Ext.Button({
-	    text: gettext('Start'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("start");
-	    }
-	});
-
-	var stop_btn = new Ext.Button({
-	    text: gettext('Stop'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("stop");
-	    }
-	});
-
-	var restart_btn = new Ext.Button({
-	    text: gettext('Restart'),
-	    disabled: true,
-	    handler: function(){
-		service_cmd("restart");
-	    }
-	});
-
-	var syslog_btn = new Ext.Button({
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: view_service_log
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		start_btn.disable();
-		stop_btn.disable();
-		restart_btn.disable();
-		syslog_btn.disable();
-		return;
-	    }
-	    var service = rec.data.service;
-	    var state = rec.data.state;
-
-	    syslog_btn.enable();
-
-	    if (me.startOnlyServices[service]) {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		}
-		stop_btn.disable();
-	    } else {
-		if (state == 'running') {
-		    start_btn.disable();
-		    restart_btn.enable();
-		    stop_btn.enable();
-		} else {
-		    start_btn.enable();
-		    restart_btn.disable();
-		    stop_btn.disable();
-		}
-	    }
-	};
-
-	me.mon(store, 'refresh', set_button_status);
-
-	Proxmox.Utils.monStoreErrors(me, rstore);
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    tbar: [ start_btn, stop_btn, restart_btn, syslog_btn ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Description'),
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'desc',
-		    flex: 2
-		}
-	    ],
-	    listeners: {
-		selectionchange: set_button_status,
-		itemdblclick: view_service_log,
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.proxmoxNodeTimeEdit'],
-
-    subject: gettext('Time zone'),
-
-    width: 400,
-
-    autoLoad: true,
-
-    fieldDefaults: {
-	labelWidth: 70
-    },
-
-    items: {
-	xtype: 'combo',
-	fieldLabel: gettext('Time zone'),
-	name: 'timezone',
-	queryMode: 'local',
-	store: Ext.create('Proxmox.data.TimezoneStore'),
-	displayField: 'zone',
-	editable: true,
-	anyMatch: true,
-	forceSelection: true,
-	allowBlank: false
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/time";
-
-	me.callParent();
-    }
-});
-Ext.define('Proxmox.node.TimeView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.proxmoxNodeTimeView'],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var tzoffset = (new Date()).getTimezoneOffset()*60000;
-	var renderlocaltime = function(value) {
-	    var servertime = new Date((value * 1000) + tzoffset);
-	    return Ext.Date.format(servertime, 'Y-m-d H:i:s');
-	};
-
-	var run_editor = function() {
-	    var win = Ext.create('Proxmox.node.TimeEdit', {
-		nodename: me.nodename
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + me.nodename + "/time",
-	    cwidth1: 150,
-	    interval: 1000,
-	    run_editor: run_editor,
-	    rows: {
-		timezone: {
-		    header: gettext('Time zone'),
-		    required: true
-		},
-		localtime: {
-		    header: gettext('Server time'),
-		    required: true,
-		    renderer: renderlocaltime
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext("Edit"),
-		    handler: run_editor
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-    }
-});
diff --git a/serverside/jsmod/6.1-3/pvemanagerlib.js.original b/serverside/jsmod/6.1-3/pvemanagerlib.js.original
deleted file mode 100644
index df8b7ac0195e13c405c14b69414884b0f7e59d29..0000000000000000000000000000000000000000
--- a/serverside/jsmod/6.1-3/pvemanagerlib.js.original
+++ /dev/null
@@ -1,40953 +0,0 @@
-var pveOnlineHelpInfo = {
-   "ceph_rados_block_devices" : {
-      "link" : "/pve-docs/chapter-pvesm.html#ceph_rados_block_devices",
-      "title" : "Ceph RADOS Block Devices (RBD)"
-   },
-   "chapter_ha_manager" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#chapter_ha_manager",
-      "title" : "High Availability"
-   },
-   "chapter_lvm" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_lvm",
-      "title" : "Logical Volume Manager (LVM)"
-   },
-   "chapter_pct" : {
-      "link" : "/pve-docs/chapter-pct.html#chapter_pct",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "chapter_pve_firewall" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#chapter_pve_firewall",
-      "title" : "Proxmox VE Firewall"
-   },
-   "chapter_pveceph" : {
-      "link" : "/pve-docs/chapter-pveceph.html#chapter_pveceph",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "chapter_pvecm" : {
-      "link" : "/pve-docs/chapter-pvecm.html#chapter_pvecm",
-      "title" : "Cluster Manager"
-   },
-   "chapter_pvesr" : {
-      "link" : "/pve-docs/chapter-pvesr.html#chapter_pvesr",
-      "title" : "Storage Replication"
-   },
-   "chapter_storage" : {
-      "link" : "/pve-docs/chapter-pvesm.html#chapter_storage",
-      "title" : "Proxmox VE Storage"
-   },
-   "chapter_system_administration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_system_administration",
-      "title" : "Host System Administration"
-   },
-   "chapter_user_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#chapter_user_management",
-      "title" : "User Management"
-   },
-   "chapter_virtual_machines" : {
-      "link" : "/pve-docs/chapter-qm.html#chapter_virtual_machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "chapter_vzdump" : {
-      "link" : "/pve-docs/chapter-vzdump.html#chapter_vzdump",
-      "title" : "Backup and Restore"
-   },
-   "chapter_zfs" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#chapter_zfs",
-      "title" : "ZFS on Linux"
-   },
-   "datacenter_configuration_file" : {
-      "link" : "/pve-docs/pve-admin-guide.html#datacenter_configuration_file",
-      "title" : "Datacenter Configuration"
-   },
-   "getting_help" : {
-      "link" : "/pve-docs/pve-admin-guide.html#getting_help",
-      "title" : "Getting Help"
-   },
-   "gui_my_settings" : {
-      "link" : "/pve-docs/chapter-pve-gui.html#gui_my_settings",
-      "subtitle" : "My Settings",
-      "title" : "Graphical User Interface"
-   },
-   "ha_manager_fencing" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_fencing",
-      "subtitle" : "Fencing",
-      "title" : "High Availability"
-   },
-   "ha_manager_groups" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_groups",
-      "subtitle" : "Groups",
-      "title" : "High Availability"
-   },
-   "ha_manager_resource_config" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resource_config",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_resources" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_resources",
-      "subtitle" : "Resources",
-      "title" : "High Availability"
-   },
-   "ha_manager_shutdown_policy" : {
-      "link" : "/pve-docs/chapter-ha-manager.html#ha_manager_shutdown_policy",
-      "subtitle" : "Shutdown Policy",
-      "title" : "High Availability"
-   },
-   "pct_configuration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_configuration",
-      "subtitle" : "Configuration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_images" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_images",
-      "subtitle" : "Container Images",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_network" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_network",
-      "subtitle" : "Network",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_container_storage" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_container_storage",
-      "subtitle" : "Container Storage",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_cpu" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_cpu",
-      "subtitle" : "CPU",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_general" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_general",
-      "subtitle" : "General Settings",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_memory" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_memory",
-      "subtitle" : "Memory",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_migration" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_migration",
-      "subtitle" : "Migration",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_options" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_options",
-      "subtitle" : "Options",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pct_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-pct.html#pct_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Containers",
-      "title" : "Proxmox Container Toolkit"
-   },
-   "pve_admin_guide" : {
-      "link" : "/pve-docs/pve-admin-guide.html",
-      "title" : "Proxmox VE Administration Guide"
-   },
-   "pve_ceph_install" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_install",
-      "subtitle" : "Installation of Ceph Packages",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "pve_ceph_osds" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_osds",
-      "subtitle" : "Ceph OSDs",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "pve_ceph_pools" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pve_ceph_pools",
-      "subtitle" : "Ceph Pools",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "pve_documentation_index" : {
-      "link" : "/pve-docs/index.html",
-      "title" : "Proxmox VE Documentation Index"
-   },
-   "pve_firewall_cluster_wide_setup" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_cluster_wide_setup",
-      "subtitle" : "Cluster Wide Setup",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_host_specific_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_host_specific_configuration",
-      "subtitle" : "Host Specific Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_aliases" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_aliases",
-      "subtitle" : "IP Aliases",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_ip_sets" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_ip_sets",
-      "subtitle" : "IP Sets",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_firewall_vm_container_configuration" : {
-      "link" : "/pve-docs/chapter-pve-firewall.html#pve_firewall_vm_container_configuration",
-      "subtitle" : "VM/Container Configuration",
-      "title" : "Proxmox VE Firewall"
-   },
-   "pve_service_daemons" : {
-      "link" : "/pve-docs/index.html#_service_daemons",
-      "title" : "Service Daemons"
-   },
-   "pveceph_fs" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs",
-      "subtitle" : "CephFS",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "pveceph_fs_create" : {
-      "link" : "/pve-docs/chapter-pveceph.html#pveceph_fs_create",
-      "subtitle" : "Create CephFS",
-      "title" : "Deploy Hyper-Converged Ceph Cluster"
-   },
-   "pvecm_create_cluster" : {
-      "link" : "/pve-docs/chapter-pvecm.html#pvecm_create_cluster",
-      "subtitle" : "Create a Cluster",
-      "title" : "Cluster Manager"
-   },
-   "pvecm_join_node_to_cluster" : {
-      "link" : "/pve-docs/chapter-pvecm.html#pvecm_join_node_to_cluster",
-      "subtitle" : "Adding Nodes to the Cluster",
-      "title" : "Cluster Manager"
-   },
-   "pvesr_schedule_time_format" : {
-      "link" : "/pve-docs/chapter-pvesr.html#pvesr_schedule_time_format",
-      "subtitle" : "Schedule Format",
-      "title" : "Storage Replication"
-   },
-   "pveum_authentication_realms" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_authentication_realms",
-      "subtitle" : "Authentication Realms",
-      "title" : "User Management"
-   },
-   "pveum_configure_u2f" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_configure_u2f",
-      "subtitle" : "Server side U2F configuration",
-      "title" : "User Management"
-   },
-   "pveum_groups" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_groups",
-      "subtitle" : "Groups",
-      "title" : "User Management"
-   },
-   "pveum_permission_management" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_permission_management",
-      "subtitle" : "Permission Management",
-      "title" : "User Management"
-   },
-   "pveum_pools" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_pools",
-      "subtitle" : "Pools",
-      "title" : "User Management"
-   },
-   "pveum_roles" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_roles",
-      "subtitle" : "Roles",
-      "title" : "User Management"
-   },
-   "pveum_tfa_auth" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_tfa_auth",
-      "subtitle" : "Two-factor authentication",
-      "title" : "User Management"
-   },
-   "pveum_users" : {
-      "link" : "/pve-docs/chapter-pveum.html#pveum_users",
-      "subtitle" : "Users",
-      "title" : "User Management"
-   },
-   "qm_bios_and_uefi" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_bios_and_uefi",
-      "subtitle" : "BIOS and UEFI",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cloud_init" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cloud_init",
-      "title" : "Cloud-Init Support"
-   },
-   "qm_copy_and_clone" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_copy_and_clone",
-      "subtitle" : "Copies and Clones",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_cpu" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_cpu",
-      "subtitle" : "CPU",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_display" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_display",
-      "subtitle" : "Display",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_general_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_general_settings",
-      "subtitle" : "General Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_hard_disk" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_hard_disk",
-      "subtitle" : "Hard Disk",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_memory" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_memory",
-      "subtitle" : "Memory",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_migration" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_migration",
-      "subtitle" : "Migration",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_network_device" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_network_device",
-      "subtitle" : "Network Device",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_options" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_options",
-      "subtitle" : "Options",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_os_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_os_settings",
-      "subtitle" : "OS Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_pci_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_pci_passthrough",
-      "title" : "PCI(e) Passthrough"
-   },
-   "qm_spice_enhancements" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_spice_enhancements",
-      "subtitle" : "SPICE Enhancements",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_startup_and_shutdown" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_startup_and_shutdown",
-      "subtitle" : "Automatic Start and Shutdown of Virtual Machines",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_system_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_system_settings",
-      "subtitle" : "System Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_usb_passthrough" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_usb_passthrough",
-      "subtitle" : "USB Passthrough",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "qm_virtual_machines_settings" : {
-      "link" : "/pve-docs/chapter-qm.html#qm_virtual_machines_settings",
-      "subtitle" : "Virtual Machines Settings",
-      "title" : "Qemu/KVM Virtual Machines"
-   },
-   "storage_cephfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cephfs",
-      "title" : "Ceph Filesystem (CephFS)"
-   },
-   "storage_cifs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_cifs",
-      "title" : "CIFS Backend"
-   },
-   "storage_directory" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_directory",
-      "title" : "Directory Backend"
-   },
-   "storage_glusterfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_glusterfs",
-      "title" : "GlusterFS Backend"
-   },
-   "storage_lvm" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvm",
-      "title" : "LVM Backend"
-   },
-   "storage_lvmthin" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_lvmthin",
-      "title" : "LVM thin Backend"
-   },
-   "storage_nfs" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_nfs",
-      "title" : "NFS Backend"
-   },
-   "storage_open_iscsi" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_open_iscsi",
-      "title" : "Open-iSCSI initiator"
-   },
-   "storage_zfspool" : {
-      "link" : "/pve-docs/chapter-pvesm.html#storage_zfspool",
-      "title" : "Local ZFS Pool Backend"
-   },
-   "sysadmin_certificate_management" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_certificate_management",
-      "title" : "Certificate Management"
-   },
-   "sysadmin_network_configuration" : {
-      "link" : "/pve-docs/chapter-sysadmin.html#sysadmin_network_configuration",
-      "title" : "Network Configuration"
-   }
-};
-Ext.ns('PVE');
-
-// avoid errors related to Accessible Rich Internet Applications
-// (access for people with disabilities)
-// TODO reenable after all components are upgraded
-Ext.enableAria = false;
-Ext.enableAriaButtons = false;
-Ext.enableAriaPanels = false;
-
-// avoid errors when running without development tools
-if (!Ext.isDefined(Ext.global.console)) {
-    var console = {
-	log: function() {}
-    };
-}
-console.log("Starting PVE Manager");
-
-Ext.Ajax.defaultHeaders = {
-    'Accept': 'application/json'
-};
-
-/*jslint confusion: true */
-Ext.define('PVE.Utils', { utilities: {
-
-    // this singleton contains miscellaneous utilities
-
-    toolkit: undefined, // (extjs|touch), set inside Toolkit.js
-
-    bus_match: /^(ide|sata|virtio|scsi)\d+$/,
-
-    log_severity_hash: {
-	0: "panic",
-	1: "alert",
-	2: "critical",
-	3: "error",
-	4: "warning",
-	5: "notice",
-	6: "info",
-	7: "debug"
-    },
-
-    support_level_hash: {
-	'c': gettext('Community'),
-	'b': gettext('Basic'),
-	's': gettext('Standard'),
-	'p': gettext('Premium')
-    },
-
-    noSubKeyHtml: 'You do not have a valid subscription for this server. Please visit <a target="_blank" href="https://www.proxmox.com/products/proxmox-ve/subscription-service-plans">www.proxmox.com</a> to get a list of available options.',
-
-    kvm_ostypes: {
-	'Linux': [
-	    { desc: '5.x - 2.6 Kernel', val: 'l26' },
-	    { desc: '2.4 Kernel', val: 'l24' }
-	],
-	'Microsoft Windows': [
-	    { desc: '10/2016/2019', val: 'win10' },
-	    { desc: '8.x/2012/2012r2', val: 'win8' },
-	    { desc: '7/2008r2', val: 'win7' },
-	    { desc: 'Vista/2008', val: 'w2k8' },
-	    { desc: 'XP/2003', val: 'wxp' },
-	    { desc: '2000', val: 'w2k' }
-	],
-	'Solaris Kernel': [
-	    { desc: '-', val: 'solaris'}
-	],
-	'Other': [
-	    { desc: '-', val: 'other'}
-	]
-    },
-
-    get_health_icon: function(state, circle) {
-	if (circle === undefined) {
-	    circle = false;
-	}
-
-	if (state === undefined) {
-	    state = 'uknown';
-	}
-
-	var icon = 'faded fa-question';
-	switch(state) {
-	    case 'good':
-		icon = 'good fa-check';
-		break;
-	    case 'upgrade':
-		icon = 'warning fa-upload';
-		break;
-	    case 'old':
-		icon = 'warning fa-refresh';
-		break;
-	    case 'warning':
-		icon = 'warning fa-exclamation';
-		break;
-	    case 'critical':
-		icon = 'critical fa-times';
-		break;
-	    default: break;
-	}
-
-	if (circle) {
-	    icon += '-circle';
-	}
-
-	return icon;
-    },
-
-    parse_ceph_version: function(service) {
-	if (service.ceph_version_short) {
-	    return service.ceph_version_short;
-	}
-
-	if (service.ceph_version) {
-	    var match = service.ceph_version.match(/version (\d+(\.\d+)*)/);
-	    if (match) {
-		return match[1];
-	    }
-	}
-
-	return undefined;
-    },
-
-    compare_ceph_versions: function(a, b) {
-	if (a === b) {
-	    return 0;
-	}
-	let avers = a.toString().split('.');
-	let bvers = b.toString().split('.');
-
-	while (true) {
-	    let av = avers.shift();
-	    let bv = bvers.shift();
-
-	    if (av === undefined && bv === undefined) {
-		return 0;
-	    } else if (av === undefined)  {
-		return -1;
-	    } else if (bv === undefined) {
-		return 1;
-	    } else {
-		let diff = parseInt(av, 10) - parseInt(bv, 10);
-		if (diff != 0) return diff;
-		// else we need to look at the next parts
-	    }
-	}
-
-    },
-
-    get_ceph_icon_html: function(health, fw) {
-	var state = PVE.Utils.map_ceph_health[health];
-	var cls = PVE.Utils.get_health_icon(state);
-	if (fw) {
-	    cls += ' fa-fw';
-	}
-	return "<i class='fa " + cls + "'></i> ";
-    },
-
-    map_ceph_health: {
-	'HEALTH_OK':'good',
-	'HEALTH_UPGRADE':'upgrade',
-	'HEALTH_OLD':'old',
-	'HEALTH_WARN':'warning',
-	'HEALTH_ERR':'critical'
-    },
-
-    render_ceph_health: function(healthObj) {
-	var state = {
-	    iconCls: PVE.Utils.get_health_icon(),
-	    text: ''
-	};
-
-	if (!healthObj || !healthObj.status) {
-	    return state;
-	}
-
-	var health = PVE.Utils.map_ceph_health[healthObj.status];
-
-	state.iconCls = PVE.Utils.get_health_icon(health, true);
-	state.text = healthObj.status;
-
-	return state;
-    },
-
-    render_zfs_health: function(value) {
-	if (typeof value == 'undefined'){
-	    return "";
-	}
-	var iconCls = 'question-circle';
-	switch (value) {
-	    case 'AVAIL':
-	    case 'ONLINE':
-		iconCls = 'check-circle good';
-		break;
-	    case 'REMOVED':
-	    case 'DEGRADED':
-		iconCls = 'exclamation-circle warning';
-		break;
-	    case 'UNAVAIL':
-	    case 'FAULTED':
-	    case 'OFFLINE':
-		iconCls = 'times-circle critical';
-		break;
-	    default: //unknown
-	}
-
-	return '<i class="fa fa-' + iconCls + '"></i> ' + value;
-
-    },
-
-    get_kvm_osinfo: function(value) {
-	var info = { base: 'Other' }; // default
-	if (value) {
-	    Ext.each(Object.keys(PVE.Utils.kvm_ostypes), function(k) {
-		Ext.each(PVE.Utils.kvm_ostypes[k], function(e) {
-		    if (e.val === value) {
-			info = { desc: e.desc, base: k };
-		    }
-		});
-	    });
-	}
-	return info;
-    },
-
-    render_kvm_ostype: function (value) {
-	var osinfo = PVE.Utils.get_kvm_osinfo(value);
-	if (osinfo.desc && osinfo.desc !== '-') {
-	    return osinfo.base + ' ' + osinfo.desc;
-	} else {
-	    return osinfo.base;
-	}
-    },
-
-    render_hotplug_features: function (value) {
-	var fa = [];
-
-	if (!value || (value === '0')) {
-	    return gettext('Disabled');
-	}
-
-	if (value === '1') {
-	    value = 'disk,network,usb';
-	}
-
-	Ext.each(value.split(','), function(el) {
-	    if (el === 'disk') {
-		fa.push(gettext('Disk'));
-	    } else if (el === 'network') {
-		fa.push(gettext('Network'));
-	    } else if (el === 'usb') {
-		fa.push('USB');
-	    } else if (el === 'memory') {
-		fa.push(gettext('Memory'));
-	    } else if (el === 'cpu') {
-		fa.push(gettext('CPU'));
-	    } else {
-		fa.push(el);
-	    }
-	});
-
-	return fa.join(', ');
-    },
-
-    render_qga_features: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (' + Proxmox.Utils.disabledText  + ')';
-	}
-	var props = PVE.Parser.parsePropertyString(value, 'enabled');
-	if (!PVE.Parser.parseBoolean(props.enabled)) {
-	    return Proxmox.Utils.disabledText;
-	}
-
-	delete props.enabled;
-	var agentstring = Proxmox.Utils.enabledText;
-
-	Ext.Object.each(props, function(key, value) {
-	    var keystring = '' ;
-	    agentstring += ', ' + key + ': ';
-
-	    if (key === 'type') {
-		let map = {
-		    isa: "ISA",
-		    virtio: "VirtIO",
-		};
-	        agentstring += map[value] || Proxmox.Utils.unknownText;
-	    } else {
-		if (PVE.Parser.parseBoolean(value)) {
-		    agentstring += Proxmox.Utils.enabledText;
-		} else {
-		    agentstring += Proxmox.Utils.disabledText;
-		}
-	    }
-	});
-
-	return agentstring;
-    },
-
-    render_qemu_machine: function(value) {
-	return value || (Proxmox.Utils.defaultText + ' (i440fx)');
-    },
-
-    render_qemu_bios: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (SeaBIOS)';
-	} else if (value === 'seabios') {
-	    return "SeaBIOS";
-	} else if (value === 'ovmf') {
-	    return "OVMF (UEFI)";
-	} else {
-	    return value;
-	}
-    },
-
-    render_dc_ha_opts: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	} else {
-	    return PVE.Parser.printPropertyString(value);
-	}
-    },
-    render_as_property_string: function(value) {
-	return (!value) ? Proxmox.Utils.defaultText
-	    : PVE.Parser.printPropertyString(value);
-    },
-
-    render_scsihw: function(value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText + ' (LSI 53C895A)';
-	} else if (value === 'lsi') {
-	    return 'LSI 53C895A';
-	} else if (value === 'lsi53c810') {
-	    return 'LSI 53C810';
-	} else if (value === 'megasas') {
-	    return 'MegaRAID SAS 8708EM2';
-	} else if (value === 'virtio-scsi-pci') {
-	    return 'VirtIO SCSI';
-	} else if (value === 'virtio-scsi-single') {
-	    return 'VirtIO SCSI single';
-	} else if (value === 'pvscsi') {
-	    return 'VMware PVSCSI';
-	} else {
-	    return value;
-	}
-    },
-
-    render_spice_enhancements: function(values) {
-	let props = PVE.Parser.parsePropertyString(values);
-	if (Ext.Object.isEmpty(props)) {
-	    return Proxmox.Utils.noneText;
-	}
-
-	let output = [];
-	if (PVE.Parser.parseBoolean(props.foldersharing)) {
-	    output.push('Folder Sharing: ' + gettext('Enabled'));
-	}
-	if (props.videostreaming === 'all' || props.videostreaming === 'filter') {
-	    output.push('Video Streaming: ' + props.videostreaming);
-	}
-	return output.join(', ');
-    },
-
-    // fixme: auto-generate this
-    // for now, please keep in sync with PVE::Tools::kvmkeymaps
-    kvm_keymaps: {
-	//ar: 'Arabic',
-	da: 'Danish',
-	de: 'German',
-	'de-ch': 'German (Swiss)',
-	'en-gb': 'English (UK)',
-	'en-us': 'English (USA)',
-	es: 'Spanish',
-	//et: 'Estonia',
-	fi: 'Finnish',
-	//fo: 'Faroe Islands',
-	fr: 'French',
-	'fr-be': 'French (Belgium)',
-	'fr-ca': 'French (Canada)',
-	'fr-ch': 'French (Swiss)',
-	//hr: 'Croatia',
-	hu: 'Hungarian',
-	is: 'Icelandic',
-	it: 'Italian',
-	ja: 'Japanese',
-	lt: 'Lithuanian',
-	//lv: 'Latvian',
-	mk: 'Macedonian',
-	nl: 'Dutch',
-	//'nl-be': 'Dutch (Belgium)',
-	no: 'Norwegian',
-	pl: 'Polish',
-	pt: 'Portuguese',
-	'pt-br': 'Portuguese (Brazil)',
-	//ru: 'Russian',
-	sl: 'Slovenian',
-	sv: 'Swedish',
-	//th: 'Thai',
-	tr: 'Turkish'
-    },
-
-    kvm_vga_drivers: {
-	std: gettext('Standard VGA'),
-	vmware: gettext('VMware compatible'),
-	qxl: 'SPICE',
-	qxl2: 'SPICE dual monitor',
-	qxl3: 'SPICE three monitors',
-	qxl4: 'SPICE four monitors',
-	serial0: gettext('Serial terminal') + ' 0',
-	serial1: gettext('Serial terminal') + ' 1',
-	serial2: gettext('Serial terminal') + ' 2',
-	serial3: gettext('Serial terminal') + ' 3',
-	virtio: 'VirtIO-GPU',
-	none: Proxmox.Utils.noneText
-    },
-
-    render_kvm_language: function (value) {
-	if (!value || value === '__default__') {
-	    return Proxmox.Utils.defaultText;
-	}
-	var text = PVE.Utils.kvm_keymaps[value];
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_keymap_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_language('')]];
-	Ext.Object.each(PVE.Utils.kvm_keymaps, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_language(value)]);
-	});
-
-	return data;
-    },
-
-    console_map: {
-	'__default__': Proxmox.Utils.defaultText + ' (xterm.js)',
-	'vv': 'SPICE (remote-viewer)',
-	'html5': 'HTML5 (noVNC)',
-	'xtermjs': 'xterm.js'
-    },
-
-    render_console_viewer: function(value) {
-	value = value || '__default__';
-	if (PVE.Utils.console_map[value]) {
-	    return PVE.Utils.console_map[value];
-	}
-	return value;
-    },
-
-    console_viewer_array: function() {
-	return Ext.Array.map(Object.keys(PVE.Utils.console_map), function(v) {
-	    return [v, PVE.Utils.render_console_viewer(v)];
-	});
-    },
-
-    render_kvm_vga_driver: function (value) {
-	if (!value) {
-	    return Proxmox.Utils.defaultText;
-	}
-	var vga = PVE.Parser.parsePropertyString(value, 'type');
-	var text = PVE.Utils.kvm_vga_drivers[vga.type];
-	if (!vga.type) {
-	    text = Proxmox.Utils.defaultText;
-	}
-	if (text) {
-	    return text + ' (' + value + ')';
-	}
-	return value;
-    },
-
-    kvm_vga_driver_array: function() {
-	var data = [['__default__', PVE.Utils.render_kvm_vga_driver('')]];
-	Ext.Object.each(PVE.Utils.kvm_vga_drivers, function(key, value) {
-	    data.push([key, PVE.Utils.render_kvm_vga_driver(value)]);
-	});
-
-	return data;
-    },
-
-    render_kvm_startup: function(value) {
-	var startup = PVE.Parser.parseStartup(value);
-
-	var res = 'order=';
-	if (startup.order === undefined) {
-	    res += 'any';
-	} else {
-	    res += startup.order;
-	}
-	if (startup.up !== undefined) {
-	    res += ',up=' + startup.up;
-	}
-	if (startup.down !== undefined) {
-	    res += ',down=' + startup.down;
-	}
-
-	return res;
-    },
-
-    extractFormActionError: function(action) {
-	var msg;
-	switch (action.failureType) {
-	case Ext.form.action.Action.CLIENT_INVALID:
-	    msg = gettext('Form fields may not be submitted with invalid values');
-	    break;
-	case Ext.form.action.Action.CONNECT_FAILURE:
-	    msg = gettext('Connection error');
-	    var resp = action.response;
-	    if (resp.status && resp.statusText) {
-		msg += " " + resp.status + ": " + resp.statusText;
-	    }
-	    break;
-	case Ext.form.action.Action.LOAD_FAILURE:
-	case Ext.form.action.Action.SERVER_INVALID:
-	    msg = Proxmox.Utils.extractRequestError(action.result, true);
-	    break;
-	}
-	return msg;
-    },
-
-    format_duration_short: function(ut) {
-
-	if (ut < 60) {
-	    return ut.toFixed(1) + 's';
-	}
-
-	if (ut < 3600) {
-	    var mins = ut / 60;
-	    return mins.toFixed(1) + 'm';
-	}
-
-	if (ut < 86400) {
-	    var hours = ut / 3600;
-	    return hours.toFixed(1) + 'h';
-	}
-
-	var days = ut / 86400;
-	return days.toFixed(1) + 'd';
-    },
-
-    contentTypes: {
-	'images': gettext('Disk image'),
-	'backup': gettext('VZDump backup file'),
-	'vztmpl': gettext('Container template'),
-	'iso': gettext('ISO image'),
-	'rootdir': gettext('Container'),
-	'snippets': gettext('Snippets')
-    },
-
-    volume_is_qemu_backup: function(volid, format) {
-	return format === 'pbs-vm' || volid.match(':backup/vzdump-qemu-');
-    },
-
-    volume_is_lxc_backup: function(volid, format) {
-	return format === 'pbs-ct' || volid.match(':backup/vzdump-(lxc|openvz)-');
-    },
-
-    storageSchema: {
-	dir: {
-	    name: Proxmox.Utils.directoryText,
-	    ipanel: 'DirInputPanel',
-	    faIcon: 'folder'
-	},
-	lvm: {
-	    name: 'LVM',
-	    ipanel: 'LVMInputPanel',
-	    faIcon: 'folder'
-	},
-	lvmthin: {
-	    name: 'LVM-Thin',
-	    ipanel: 'LvmThinInputPanel',
-	    faIcon: 'folder'
-	},
-	nfs: {
-	    name: 'NFS',
-	    ipanel: 'NFSInputPanel',
-	    faIcon: 'building'
-	},
-	cifs: {
-	    name: 'CIFS',
-	    ipanel: 'CIFSInputPanel',
-	    faIcon: 'building'
-	},
-	glusterfs: {
-	    name: 'GlusterFS',
-	    ipanel: 'GlusterFsInputPanel',
-	    faIcon: 'building'
-	},
-	iscsi: {
-	    name: 'iSCSI',
-	    ipanel: 'IScsiInputPanel',
-	    faIcon: 'building'
-	},
-	cephfs: {
-	    name: 'CephFS',
-	    ipanel: 'CephFSInputPanel',
-	    faIcon: 'building'
-	},
-	pvecephfs: {
-	    name: 'CephFS (PVE)',
-	    ipanel: 'CephFSInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	rbd: {
-	    name: 'RBD',
-	    ipanel: 'RBDInputPanel',
-	    faIcon: 'building'
-	},
-	pveceph: {
-	    name: 'RBD (PVE)',
-	    ipanel: 'RBDInputPanel',
-	    hideAdd: true,
-	    faIcon: 'building'
-	},
-	zfs: {
-	    name: 'ZFS over iSCSI',
-	    ipanel: 'ZFSInputPanel',
-	    faIcon: 'building'
-	},
-	zfspool: {
-	    name: 'ZFS',
-	    ipanel: 'ZFSPoolInputPanel',
-	    faIcon: 'folder'
-	},
-	drbd: {
-	    name: 'DRBD',
-	    hideAdd: true
-	}
-    },
-
-    format_storage_type: function(value, md, record) {
-	if (value === 'rbd') {
-	    value = (!record || record.get('monhost') ? 'rbd' : 'pveceph');
-	} else if (value === 'cephfs') {
-	    value = (!record || record.get('monhost') ? 'cephfs' : 'pvecephfs');
-	}
-
-	var schema = PVE.Utils.storageSchema[value];
-	if (schema) {
-	    return schema.name;
-	}
-	return Proxmox.Utils.unknownText;
-    },
-
-    format_ha: function(value) {
-	var text = Proxmox.Utils.noneText;
-
-	if (value.managed) {
-	    text = value.state || Proxmox.Utils.noneText;
-
-	    text += ', ' +  Proxmox.Utils.groupText + ': ';
-	    text += value.group || Proxmox.Utils.noneText;
-	}
-
-	return text;
-    },
-
-    format_content_types: function(value) {
-	return value.split(',').sort().map(function(ct) {
-	    return PVE.Utils.contentTypes[ct] || ct;
-	}).join(', ');
-    },
-
-    render_storage_content: function(value, metaData, record) {
-	var data = record.data;
-	if (Ext.isNumber(data.channel) &&
-	    Ext.isNumber(data.id) &&
-	    Ext.isNumber(data.lun)) {
-	    return "CH " +
-		Ext.String.leftPad(data.channel,2, '0') +
-		" ID " + data.id + " LUN " + data.lun;
-	}
-	return data.volid.replace(/^.*?:(.*?\/)?/,'');
-    },
-
-    render_serverity: function (value) {
-	return PVE.Utils.log_severity_hash[value] || value;
-    },
-
-    render_cpu: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	if (!(record.data.uptime && Ext.isNumeric(value))) {
-	    return '';
-	}
-
-	var maxcpu = record.data.maxcpu || 1;
-
-	if (!Ext.isNumeric(maxcpu) && (maxcpu >= 1)) {
-	    return '';
-	}
-
-	var per = value * 100;
-
-	return per.toFixed(1) + '% of ' + maxcpu.toString() + (maxcpu > 1 ? 'CPUs' : 'CPU');
-    },
-
-    render_size: function(value, metaData, record, rowIndex, colIndex, store) {
-	/*jslint confusion: true */
-
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value);
-    },
-
-    render_bandwidth: function(value) {
-	if (!Ext.isNumeric(value)) {
-	    return '';
-	}
-
-	return Proxmox.Utils.format_size(value) + '/s';
-    },
-
-    render_timestamp_human_readable: function(value) {
-	return Ext.Date.format(new Date(value * 1000), 'l d F Y H:i:s');
-    },
-
-    render_duration: function(value) {
-	if (value === undefined) {
-	    return '-';
-	}
-	return PVE.Utils.format_duration_short(value);
-    },
-
-    calculate_mem_usage: function(data) {
-	if (!Ext.isNumeric(data.mem) ||
-	    data.maxmem === 0 ||
-	    data.uptime < 1) {
-	    return -1;
-	}
-
-	return (data.mem / data.maxmem);
-    },
-
-    render_mem_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-	if (value > 1 ) {
-	    // we got no percentage but bytes
-	    var mem = value;
-	    var maxmem = record.data.maxmem;
-	    if (!record.data.uptime ||
-		maxmem === 0 ||
-		!Ext.isNumeric(mem)) {
-		return '';
-	    }
-
-	    return ((mem*100)/maxmem).toFixed(1) + " %";
-	}
-	return (value*100).toFixed(1) + " %";
-    },
-
-    render_mem_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var mem = value;
-	var maxmem = record.data.maxmem;
-
-	if (!record.data.uptime) {
-	    return '';
-	}
-
-	if (!(Ext.isNumeric(mem) && maxmem)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    calculate_disk_usage: function(data) {
-
-	if (!Ext.isNumeric(data.disk) ||
-	    data.type === 'qemu' ||
-	    (data.type === 'lxc' && data.uptime === 0) ||
-	    data.maxdisk === 0) {
-	    return -1;
-	}
-
-	return (data.disk / data.maxdisk);
-    },
-
-    render_disk_usage_percent: function(value, metaData, record, rowIndex, colIndex, store) {
-	if (!Ext.isNumeric(value) || value === -1) {
-	    return '';
-	}
-
-	return (value * 100).toFixed(1) + " %";
-    },
-
-    render_disk_usage: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var disk = value;
-	var maxdisk = record.data.maxdisk;
-	var type = record.data.type;
-
-	if (!Ext.isNumeric(disk) ||
-	    type === 'qemu' ||
-	    maxdisk === 0 ||
-	    (type === 'lxc' && record.data.uptime === 0)) {
-	    return '';
-	}
-
-	return PVE.Utils.render_size(value);
-    },
-
-    get_object_icon_class: function(type, record) {
-	var status = '';
-	var objType = type;
-
-	if (type === 'type') {
-	    // for folder view
-	    objType = record.groupbyid;
-	} else if (record.template) {
-	    // templates
-	    objType = 'template';
-	    status = type;
-	} else {
-	    // everything else
-	    status = record.status + ' ha-' + record.hastate;
-	}
-
-	if (record.lock) {
-	    status += ' locked lock-' + record.lock;
-	}
-
-	var defaults = PVE.tree.ResourceTree.typeDefaults[objType];
-	if (defaults && defaults.iconCls) {
-	    var retVal = defaults.iconCls + ' ' + status;
-	    return retVal;
-	}
-
-	return '';
-    },
-
-    render_resource_type: function(value, metaData, record, rowIndex, colIndex, store) {
-
-	var cls = PVE.Utils.get_object_icon_class(value,record.data);
-
-	var fa = '<i class="fa-fw x-grid-icon-custom ' + cls  + '"></i> ';
-	return fa + value;
-    },
-
-    render_support_level: function(value, metaData, record) {
-	return PVE.Utils.support_level_hash[value] || '-';
-    },
-
-    render_upid: function(value, metaData, record) {
-	var type = record.data.type;
-	var id = record.data.id;
-
-	return Proxmox.Utils.format_task_description(type, id);
-    },
-
-    /* render functions for new status panel */
-
-    render_usage: function(val) {
-	return (val*100).toFixed(2) + '%';
-    },
-
-    render_cpu_usage: function(val, max) {
-	return Ext.String.format(gettext('{0}% of {1}') +
-	    ' ' + gettext('CPU(s)'), (val*100).toFixed(2), max);
-    },
-
-    render_size_usage: function(val, max) {
-	if (max === 0) {
-	    return gettext('N/A');
-	}
-	return (val*100/max).toFixed(2) + '% '+ '(' +
-	    Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(val), PVE.Utils.render_size(max)) + ')';
-    },
-
-    /* this is different for nodes */
-    render_node_cpu_usage: function(value, record) {
-	return PVE.Utils.render_cpu_usage(value, record.cpus);
-    },
-
-    /* this is different for nodes */
-    render_node_size_usage: function(record) {
-	return PVE.Utils.render_size_usage(record.used, record.total);
-    },
-
-    render_optional_url: function(value) {
-	var match;
-	if (value && (match = value.match(/^https?:\/\//)) !== null) {
-	    return '<a target="_blank" href="' + value + '">' + value + '</a>';
-	}
-	return value;
-    },
-
-    render_san: function(value) {
-	var names = [];
-	if (Ext.isArray(value)) {
-	    value.forEach(function(val) {
-		if (!Ext.isNumber(val)) {
-		    names.push(val);
-		}
-	    });
-	    return names.join('<br>');
-	}
-	return value;
-    },
-
-    render_full_name: function(firstname, metaData, record) {
-	var first = firstname || '';
-	var last = record.data.lastname || '';
-	return Ext.htmlEncode(first + " " + last);
-    },
-
-    render_u2f_error: function(error) {
-	var ErrorNames = {
-	    '1': gettext('Other Error'),
-	    '2': gettext('Bad Request'),
-	    '3': gettext('Configuration Unsupported'),
-	    '4': gettext('Device Ineligible'),
-	    '5': gettext('Timeout')
-	};
-	return "U2F Error: "  + ErrorNames[error] || Proxmox.Utils.unknownText;
-    },
-
-    windowHostname: function() {
-	return window.location.hostname.replace(Proxmox.Utils.IP6_bracket_match,
-            function(m, addr, offset, original) { return addr; });
-    },
-
-    openDefaultConsoleWindow: function(consoles, vmtype, vmid, nodename, vmname, cmd) {
-	var dv = PVE.Utils.defaultViewer(consoles);
-	PVE.Utils.openConsoleWindow(dv, vmtype, vmid, nodename, vmname, cmd);
-    },
-
-    openConsoleWindow: function(viewer, vmtype, vmid, nodename, vmname, cmd) {
-	// kvm, lxc, shell, upgrade
-
-	if (vmid == undefined && (vmtype === 'kvm' || vmtype === 'lxc')) {
-	    throw "missing vmid";
-	}
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (viewer === 'html5') {
-	    PVE.Utils.openVNCViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'xtermjs') {
-	    Proxmox.Utils.openXtermJsViewer(vmtype, vmid, nodename, vmname, cmd);
-	} else if (viewer === 'vv') {
-	    var url;
-	    var params = { proxy: PVE.Utils.windowHostname() };
-	    if (vmtype === 'kvm') {
-		url = '/nodes/' + nodename + '/qemu/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'lxc') {
-		url = '/nodes/' + nodename + '/lxc/' + vmid.toString() + '/spiceproxy';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'shell') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'upgrade') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.upgrade = 1;
-		PVE.Utils.openSpiceViewer(url, params);
-	    } else if (vmtype === 'cmd') {
-		url = '/nodes/' + nodename + '/spiceshell';
-		params.cmd = cmd;
-		PVE.Utils.openSpiceViewer(url, params);
-	    }
-	} else {
-	    throw "unknown viewer type";
-	}
-    },
-
-    defaultViewer: function(consoles) {
-
-	var allowSpice, allowXtermjs;
-
-	if (consoles === true) {
-	    allowSpice = true;
-	    allowXtermjs = true;
-	} else if (typeof consoles === 'object') {
-	    allowSpice = consoles.spice;
-	    allowXtermjs = !!consoles.xtermjs;
-	}
-	var dv = PVE.VersionInfo.console || 'xtermjs';
-	if (dv === 'vv' && !allowSpice) {
-	    dv = (allowXtermjs) ? 'xtermjs' : 'html5';
-	} else if (dv === 'xtermjs' && !allowXtermjs) {
-	    dv = (allowSpice) ? 'vv' : 'html5';
-	}
-
-	return dv;
-    },
-
-    openVNCViewer: function(vmtype, vmid, nodename, vmname, cmd) {
-	let scaling = 'off';
-	if (Proxmox.Utils.toolkit !== 'touch') {
-	    var sp = Ext.state.Manager.getProvider();
-	    scaling = sp.get('novnc-scaling', 'off');
-	}
-	var url = Ext.Object.toQueryString({
-	    console: vmtype, // kvm, lxc, upgrade or shell
-	    novnc: 1,
-	    vmid: vmid,
-	    vmname: vmname,
-	    node: nodename,
-	    resize: scaling,
-	    cmd: cmd
-	});
-	var nw = window.open("?" + url, '_blank', "innerWidth=745,innerheight=427");
-	if (nw) {
-	    nw.focus();
-	}
-    },
-
-    openSpiceViewer: function(url, params){
-
-	var downloadWithName = function(uri, name) {
-	    var link = Ext.DomHelper.append(document.body, {
-		tag: 'a',
-		href: uri,
-		css : 'display:none;visibility:hidden;height:0px;'
-	    });
-
-	    // Note: we need to tell android the correct file name extension
-	    // but we do not set 'download' tag for other environments, because
-	    // It can have strange side effects (additional user prompt on firefox)
-	    var andriod = navigator.userAgent.match(/Android/i) ? true : false;
-	    if (andriod) {
-		link.download = name;
-	    }
-
-	    if (link.fireEvent) {
-		link.fireEvent('onclick');
-	    } else {
-                var evt = document.createEvent("MouseEvents");
-                evt.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
-		link.dispatchEvent(evt);
-	    }
-	};
-
-	Proxmox.Utils.API2Request({
-	    url: url,
-	    params: params,
-	    method: 'POST',
-	    failure: function(response, opts){
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, opts){
-		var raw = "[virt-viewer]\n";
-		Ext.Object.each(response.result.data, function(k, v) {
-		    raw += k + "=" + v + "\n";
-		});
-		var url = 'data:application/x-virt-viewer;charset=UTF-8,' +
-		    encodeURIComponent(raw);
-
-		downloadWithName(url, "pve-spice.vv");
-	    }
-	});
-    },
-
-    openTreeConsole: function(tree, record, item, index, e) {
-	e.stopEvent();
-	var nodename = record.data.node;
-	var vmid = record.data.vmid;
-	var vmname = record.data.name;
-	if (record.data.type === 'qemu' && !record.data.template) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    let conf = response.result.data;
-		    var consoles = {
-			spice: !!conf.spice,
-			xtermjs: !!conf.serial,
-		    };
-		    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-		}
-	    });
-	} else if (record.data.type === 'lxc' && !record.data.template) {
-	    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-	}
-    },
-
-    // test automation helper
-    call_menu_handler: function(menu, text) {
-
-	var list = menu.query('menuitem');
-
-	Ext.Array.each(list, function(item) {
-	    if (item.text === text) {
-		if (item.handler) {
-		    item.handler();
-		    return 1;
-		} else {
-		    return undefined;
-		}
-	    }
-	});
-    },
-
-    createCmdMenu: function(v, record, item, index, event) {
-	event.stopEvent();
-	if (!(v instanceof Ext.tree.View)) {
-	    v.select(record);
-	}
-	var menu;
-	var template = !!record.data.template;
-	var type = record.data.type;
-
-	if (template) {
-	    if (type === 'qemu' || type == 'lxc') {
-		menu = Ext.create('PVE.menu.TemplateMenu', {
-		    pveSelNode: record
-		});
-	    }
-	} else if (type === 'qemu' ||
-		   type === 'lxc' ||
-		   type === 'node') {
-	    menu = Ext.create('PVE.' + type + '.CmdMenu', {
-		pveSelNode: record,
-		nodename: record.data.node
-	    });
-	} else {
-	    return;
-	}
-
-	menu.showAt(event.getXY());
-	return menu;
-    },
-
-    // helper for deleting field which are set to there default values
-    delete_if_default: function(values, fieldname, default_val, create) {
-	if (values[fieldname] === '' || values[fieldname] === default_val) {
-	    if (!create) {
-		if (values['delete']) {
-		    values['delete'] += ',' + fieldname;
-		} else {
-		    values['delete'] = fieldname;
-		}
-	    }
-
-	    delete values[fieldname];
-	}
-    },
-
-    loadSSHKeyFromFile: function(file, callback) {
-	// ssh-keygen produces 740 bytes for an average 4096 bit rsa key, with
-	// a user@host comment, 1420 for 8192 bits; current max is 16kbit
-	// assume: 740*8 for max. 32kbit (5920 byte file)
-	// round upwards to nearest nice number => 8192 bytes, leaves lots of comment space
-	if (file.size > 8192) {
-	    Ext.Msg.alert(gettext('Error'), gettext("Invalid file size: ") + file.size);
-	    return;
-	}
-	/*global
-	  FileReader
-	*/
-	var reader = new FileReader();
-	reader.onload = function(evt) {
-	    callback(evt.target.result);
-	};
-	reader.readAsText(file);
-    },
-
-    diskControllerMaxIDs: {
-	ide: 4,
-	sata: 6,
-	scsi: 31,
-	virtio: 16,
-    },
-
-    // types is either undefined (all busses), an array of busses, or a single bus
-    forEachBus: function(types, func) {
-	var busses = Object.keys(PVE.Utils.diskControllerMaxIDs);
-	var i, j, count, cont;
-
-	if (Ext.isArray(types)) {
-	    busses = types;
-	} else if (Ext.isDefined(types)) {
-	    busses = [ types ];
-	}
-
-	// check if we only have valid busses
-	for (i = 0; i < busses.length; i++) {
-	    if (!PVE.Utils.diskControllerMaxIDs[busses[i]]) {
-		throw "invalid bus: '" + busses[i] + "'";
-	    }
-	}
-
-	for (i = 0; i < busses.length; i++) {
-	    count = PVE.Utils.diskControllerMaxIDs[busses[i]];
-	    for (j = 0; j < count; j++) {
-		cont = func(busses[i], j);
-		if (!cont && cont !== undefined) {
-		    return;
-		}
-	    }
-	}
-    },
-
-    mp_counts: { mps: 256, unused: 256 },
-
-    forEachMP: function(func, includeUnused) {
-	var i, cont;
-	for (i = 0; i < PVE.Utils.mp_counts.mps; i++) {
-	    cont = func('mp', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-
-	if (!includeUnused) {
-	    return;
-	}
-
-	for (i = 0; i < PVE.Utils.mp_counts.unused; i++) {
-	    cont = func('unused', i);
-	    if (!cont && cont !== undefined) {
-		return;
-	    }
-	}
-    },
-
-    hardware_counts: { net: 32, usb: 5, hostpci: 16, audio: 1, efidisk: 1, serial: 4, rng: 1 },
-
-    cleanEmptyObjectKeys: function (obj) {
-	var propName;
-	for (propName in obj) {
-	    if (obj.hasOwnProperty(propName)) {
-		if (obj[propName] === null || obj[propName] === undefined) {
-		    delete obj[propName];
-		}
-	    }
-	}
-    },
-
-    handleStoreErrorOrMask: function(me, store, regex, callback) {
-
-	me.mon(store, 'load', function (proxy, response, success, operation) {
-
-	    if (success) {
-		Proxmox.Utils.setErrorMask(me, false);
-		return;
-	    }
-	    var msg;
-
-	    if (operation.error.statusText) {
-		if (operation.error.statusText.match(regex)) {
-		    callback(me, operation.error);
-		    return;
-		} else {
-		    msg = operation.error.statusText + ' (' + operation.error.status + ')';
-		}
-	    } else {
-		msg = gettext('Connection error');
-	    }
-	    Proxmox.Utils.setErrorMask(me, msg);
-	});
-    },
-
-    showCephInstallOrMask: function(container, msg, nodename, callback){
-	var regex = new RegExp("not (installed|initialized)", "i");
-	if (msg.match(regex)) {
-	    if (Proxmox.UserName === 'root@pam') {
-		container.el.mask();
-		if (!container.down('pveCephInstallWindow')){
-		    var isInstalled = msg.match(/not initialized/i) ? true : false;
-		    var win = Ext.create('PVE.ceph.Install', {
-			nodename: nodename
-		    });
-		    win.getViewModel().set('isInstalled', isInstalled);
-		    container.add(win);
-		    win.show();
-		    callback(win);
-		}
-	    } else {
-		container.mask(Ext.String.format(gettext('{0} not installed.') +
-		    ' ' + gettext('Log in as root to install.'), 'Ceph'), ['pve-static-mask']);
-	    }
-	    return true;
-	} else {
-	    return false;
-	}
-    },
-
-    propertyStringSet: function(target, source, name, value) {
-	if (source) {
-	    if (value === undefined) {
-		target[name] = source;
-	    } else {
-		target[name] = value;
-	    }
-	} else {
-	    delete target[name];
-	}
-    },
-
-    updateColumns: function(container) {
-	let mode = Ext.state.Manager.get('summarycolumns') || 'auto';
-	let factor;
-	if (mode !== 'auto') {
-	    factor = parseInt(mode, 10);
-	    if (Number.isNaN(factor)) {
-		factor = 1;
-	    }
-	} else {
-	    factor = container.getSize().width < 1400 ? 1 : 2;
-	}
-
-	if (container.oldFactor === factor) {
-	    return;
-	}
-
-	let items = container.query('>'); // direct childs
-	factor = Math.min(factor, items.length);
-	container.oldFactor = factor;
-
-	items.forEach((item) => {
-	    item.columnWidth = 1 / factor;
-	});
-
-	// we have to update the layout twice, since the first layout change
-	// can trigger the scrollbar which reduces the amount of space left
-	container.updateLayout();
-	container.updateLayout();
-    },
-
-    forEachCorosyncLink: function(nodeinfo, cb) {
-	let re = /(?:ring|link)(\d+)_addr/;
-	Ext.iterate(nodeinfo, (prop, val) => {
-	    let match = re.exec(prop);
-	    if (match) {
-		cb(Number(match[1]), val);
-	    }
-	});
-    },
-},
-
-    singleton: true,
-    constructor: function() {
-	var me = this;
-	Ext.apply(me, me.utilities);
-    }
-
-});
-// ExtJS related things
-
-Proxmox.Utils.toolkit = 'extjs';
-
-// custom PVE specific VTypes
-Ext.apply(Ext.form.field.VTypes, {
-
-    QemuStartDate: function(v) {
-	return (/^(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)$/).test(v);
-    },
-    QemuStartDateText: gettext('Format') + ': "now" or "2006-06-17T16:01:21" or "2006-06-17"',
-    IP64AddressList: function(v) {
-	var list = v.split(/[\ \,\;]+/);
-	var i;
-	for (i = 0; i < list.length; i++) {
-	    if (list[i] == '') {
-		continue;
-	    }
-
-	    if (!Proxmox.Utils.IP64_match.test(list[i])) {
-		return false;
-	    }
-	}
-
-	return true;
-    },
-    IP64AddressListText: gettext('Example') + ': 192.168.1.1,192.168.1.2',
-    IP64AddressListMask: /[A-Fa-f0-9\,\:\.\;\ ]/
-});
-
-Ext.define('PVE.form.field.Display', {
-    override: 'Ext.form.field.Display',
-
-    setSubmitValue: function(value) {
-	// do nothing, this is only to allow generalized  bindings for the:
-	// `me.isCreate ? 'textfield' : 'displayfield'` cases we have.
-    }
-});
-// Some configuration values are complex strings -
-// so we need parsers/generators for them.
-
-Ext.define('PVE.Parser', { statics: {
-
-    // this class only contains static functions
-
-    parseACME: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-	var errors = false;
-
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; //continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^(?:domains=)?((?:[a-zA-Z0-9\-\.]+[;, ]?)+)$/)) !== null) {
-		res.domains = match_res[1].split(/[;, ]/);
-	    } else {
-		errors = true;
-		return false;
-	    }
-	});
-
-	if (errors || !res) {
-	    return;
-	}
-
-	return res;
-    },
-
-    parseBoolean: function(value, default_value) {
-	if (!Ext.isDefined(value)) {
-	    return default_value;
-	}
-	value = value.toLowerCase();
-	return value === '1' ||
-	       value === 'on' ||
-	       value === 'yes' ||
-	       value === 'true';
-    },
-
-    parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
-
-	if (typeof value !== 'string' || value === '') {
-	    return res;
-	}
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
-		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	});
-
-	if (error !== undefined) {
-	    console.error(error);
-	    return;
-	}
-
-	return res;
-    },
-
-    printPropertyString: function(data, defaultKey) {
-	var stringparts = [],
-	    gotDefaultKeyVal = false,
-	    defaultKeyVal;
-
-	Ext.Object.each(data, function(key, value) {
-	    if (defaultKey !== undefined && key === defaultKey) {
-		gotDefaultKeyVal = true;
-		defaultKeyVal = value;
-	    } else if (value !== '') {
-		stringparts.push(key + '=' + value);
-	    }
-	});
-
-	stringparts = stringparts.sort();
-	if (gotDefaultKeyVal) {
-	    stringparts.unshift(defaultKeyVal);
-	}
-
-	return stringparts.join(',');
-    },
-
-    parseQemuNetwork: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|vmxnet3|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i)) !== null) {
-		res.model = match_res[1].toLowerCase();
-		if (match_res[3]) {
-		    res.macaddr = match_res[3];
-		}
-	    } else if ((match_res = p.match(/^bridge=(\S+)$/)) !== null) {
-		res.bridge = match_res[1];
-	    } else if ((match_res = p.match(/^rate=(\d+(\.\d+)?)$/)) !== null) {
-		res.rate = match_res[1];
-	    } else if ((match_res = p.match(/^tag=(\d+(\.\d+)?)$/)) !== null) {
-		res.tag = match_res[1];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		res.firewall = match_res[1];
-	    } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) {
-		res.disconnect = match_res[1];
-	    } else if ((match_res = p.match(/^queues=(\d+)$/)) !== null) {
-		res.queues = match_res[1];
-	    } else if ((match_res = p.match(/^trunks=(\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*)$/)) !== null) {
-		res.trunks = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors || !res.model) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuNetwork: function(net) {
-
-	var netstr = net.model;
-	if (net.macaddr) {
-	    netstr += "=" + net.macaddr;
-	}
-	if (net.bridge) {
-	    netstr += ",bridge=" + net.bridge;
-	    if (net.tag) {
-		netstr += ",tag=" + net.tag;
-	    }
-	    if (net.firewall) {
-		netstr += ",firewall=" + net.firewall;
-	    }
-	}
-	if (net.rate) {
-	    netstr += ",rate=" + net.rate;
-	}
-	if (net.queues) {
-	    netstr += ",queues=" + net.queues;
-	}
-	if (net.disconnect) {
-	    netstr += ",link_down=" + net.disconnect;
-	}
-	if (net.trunks) {
-	    netstr += ",trunks=" + net.trunks;
-	}
-	return netstr;
-    },
-
-    parseQemuDrive: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var match_res = key.match(/^([a-z]+)(\d+)$/);
-	if (!match_res) {
-	    return;
-	}
-	res['interface'] = match_res[1];
-	res.index = match_res[2];
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    if (k === 'cache' && v === 'off') {
-		v = 'none';
-	    }
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuDrive: function(drive) {
-
-	var drivestr = drive.file;
-
-	Ext.Object.each(drive, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'index' || key === 'interface') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseIPConfig: function(key, value) {
-	if (!(key && value)) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-	    if ((match_res = p.match(/^ip=(\S+)$/)) !== null) {
-		res.ip = match_res[1];
-	    } else if ((match_res = p.match(/^gw=(\S+)$/)) !== null) {
-		res.gw = match_res[1];
-	    } else if ((match_res = p.match(/^ip6=(\S+)$/)) !== null) {
-		res.ip6 = match_res[1];
-	    } else if ((match_res = p.match(/^gw6=(\S+)$/)) !== null) {
-		res.gw6 = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printIPConfig: function(cfg) {
-	var c = "";
-	var str = "";
-	if (cfg.ip) {
-	    str += "ip=" + cfg.ip;
-	    c = ",";
-	}
-	if (cfg.gw) {
-	    str += c + "gw=" + cfg.gw;
-	    c = ",";
-	}
-	if (cfg.ip6) {
-	    str += c + "ip6=" + cfg.ip6;
-	    c = ",";
-	}
-	if (cfg.gw6) {
-	    str += c + "gw6=" + cfg.gw6;
-	    c = ",";
-	}
-	return str;
-    },
-
-    parseOpenVZNetIf: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(';'), function(item) {
-	    if (!item || item.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var data = {};
-	    Ext.Array.each(item.split(','), function(p) {
-		if (!p || p.match(/^\s*$/)) {
-		    return; // continue
-		}
-		var match_res = p.match(/^(ifname|mac|bridge|host_ifname|host_mac|mac_filter)=(\S+)$/);
-		if (!match_res) {
-		    errors = true;
-		    return false; // break
-		}
-		if (match_res[1] === 'bridge'){
-		    var bridgevlanf = match_res[2];
-		    var bridge_res = bridgevlanf.match(/^(vmbr(\d+))(v(\d+))?(f)?$/);
-		    if (!bridge_res) {
-			errors = true;
-			return false; // break
-		    }
-		    data.bridge = bridge_res[1];
-		    data.tag = bridge_res[4];
-		    /*jslint confusion: true*/
-		    data.firewall = bridge_res[5] ? 1 : 0;
-		    /*jslint confusion: false*/
-		} else {
-		    data[match_res[1]] = match_res[2];
-		}
-	    });
-
-	    if (errors || !data.ifname) {
-		errors = true;
-		return false; // break
-	    }
-
-	    data.raw = item;
-
-	    res[data.ifname] = data;
-	});
-
-	return errors ? undefined: res;
-    },
-
-    printOpenVZNetIf: function(netif) {
-	var netarray = [];
-
-	Ext.Object.each(netif, function(iface, data) {
-	    var tmparray = [];
-	    Ext.Array.each(['ifname', 'mac', 'bridge', 'host_ifname' , 'host_mac', 'mac_filter', 'tag', 'firewall'], function(key) {
-		var value = data[key];
-		if (key === 'bridge'){
-		    if(data.tag){
-			value = value + 'v' + data.tag;
-		    }
-		    if (data.firewall){
-			value = value + 'f';
-		    }
-		}
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-
-	    });
-	    netarray.push(tmparray.join(','));
-	});
-
-	return netarray.join(';');
-    },
-
-    parseLxcNetwork: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var data = {};
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|tag|rate)=(\S+)$/);
-	    if (match_res) {
-		data[match_res[1]] = match_res[2];
-	    } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) {
-		data.firewall = PVE.Parser.parseBoolean(match_res[1]);
-	    } else {
-		// todo: simply ignore errors ?
-		return; // continue
-	    }
-	});
-
-	return data;
-    },
-
-    printLxcNetwork: function(data) {
-	var tmparray = [];
-	Ext.Array.each(['bridge', 'hwaddr', 'mtu', 'name', 'ip',
-			'gw', 'ip6', 'gw6', 'firewall', 'tag'], function(key) {
-		var value = data[key];
-		if (value) {
-		    tmparray.push(key + '=' + value);
-		}
-	});
-
-	/*jslint confusion: true*/
-	if (data.rate > 0) {
-	    tmparray.push('rate=' + data.rate);
-	}
-	/*jslint confusion: false*/
-	return tmparray.join(',');
-    },
-
-    parseLxcMountPoint: function(value) {
-	if (!value) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-	    var match_res = p.match(/^([a-z_]+)=(.+)$/);
-	    if (!match_res) {
-		if (!p.match(/\=/)) {
-		    res.file = p;
-		    return; // continue
-		}
-		errors = true;
-		return false; // break
-	    }
-	    var k = match_res[1];
-	    if (k === 'volume') {
-		k = 'file';
-	    }
-
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var v = match_res[2];
-
-	    res[k] = v;
-	});
-
-	if (errors || !res.file) {
-	    return;
-	}
-
-	var m = res.file.match(/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):/i);
-	if (m) {
-	    res.storage = m[1];
-	    res.type = 'volume';
-	} else if (res.file.match(/^\/dev\//)) {
-	    res.type = 'device';
-	} else {
-	    res.type = 'bind';
-	}
-
-	return res;
-    },
-
-    printLxcMountPoint: function(mp) {
-	var drivestr = mp.file;
-
-	Ext.Object.each(mp, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'file' ||
-		key === 'type' || key === 'storage') {
-		return; // continue
-	    }
-	    drivestr += ',' + key + '=' + value;
-	});
-
-	return drivestr;
-    },
-
-    parseStartup: function(value) {
-	if (value === undefined) {
-	    return;
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    var match_res;
-
-	    if ((match_res = p.match(/^(order)?=(\d+)$/)) !== null) {
-		res.order = match_res[2];
-	    } else if ((match_res = p.match(/^up=(\d+)$/)) !== null) {
-		res.up = match_res[1];
-	    } else if ((match_res = p.match(/^down=(\d+)$/)) !== null) {
-                res.down = match_res[1];
-	    } else {
-		errors = true;
-		return false; // break
-	    }
-	});
-
-	if (errors) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printStartup: function(startup) {
-	var arr = [];
-	if (startup.order !== undefined && startup.order !== '') {
-	    arr.push('order=' + startup.order);
-	}
-	if (startup.up !== undefined && startup.up !== '') {
-	    arr.push('up=' + startup.up);
-	}
-	if (startup.down !== undefined && startup.down !== '') {
-	    arr.push('down=' + startup.down);
-	}
-
-	return arr.join(',');
-    },
-
-    parseQemuSmbios1: function(value) {
-	var res = value.split(',').reduce(function (accumulator, currentValue) {
-	    var splitted = currentValue.split(new RegExp("=(.+)"));
-	    accumulator[splitted[0]] = splitted[1];
-	    return accumulator;
-	}, {});
-
-	if (PVE.Parser.parseBoolean(res.base64, false)) {
-	    Ext.Object.each(res, function(key, value) {
-		if (key === 'uuid') { return; }
-		res[key] = Ext.util.Base64.decode(value);
-	    });
-	}
-
-	return res;
-    },
-
-    printQemuSmbios1: function(data) {
-
-	var datastr = '';
-	var base64 = false;
-	Ext.Object.each(data, function(key, value) {
-	    if (value === '') { return; }
-	    if (key === 'uuid') {
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + value;
-	    } else {
-		// values should be base64 encoded from now on, mark config strings correspondingly
-		if (!base64) {
-		    base64 = true;
-		    datastr += (datastr !== '' ? ',' : '') + 'base64=1';
-		}
-		datastr += (datastr !== '' ? ',' : '') + key + '=' + Ext.util.Base64.encode(value);
-	    }
-	});
-
-	return datastr;
-    },
-
-    parseTfaConfig: function(value) {
-	var res = {};
-
-	Ext.Array.each(value.split(','), function(p) {
-	    var kva = p.split('=', 2);
-	    res[kva[0]] = kva[1];
-	});
-
-	return res;
-    },
-
-    parseTfaType: function(value) {
-	/*jslint confusion: true*/
-	var match;
-	if (!value || !value.length) {
-	    return undefined;
-	} else if (value === 'x!oath') {
-	    return 'totp';
-	} else if (!!(match = value.match(/^x!(.+)$/))) {
-	    return match[1];
-	} else {
-	    return 1;
-	}
-    },
-
-    parseQemuCpu: function(value) {
-	if (!value) {
-	    return {};
-	}
-
-	var res = {};
-
-	var errors = false;
-	Ext.Array.each(value.split(','), function(p) {
-	    if (!p || p.match(/^\s*$/)) {
-		return; // continue
-	    }
-
-	    if (!p.match(/\=/)) {
-		if (Ext.isDefined(res.cpu)) {
-		    errors = true;
-		    return false; // break
-		}
-		res.cputype = p;
-		return; // continue
-	    }
-
-	    var match_res = p.match(/^([a-z_]+)=(\S+)$/);
-	    if (!match_res) {
-		errors = true;
-		return false; // break
-	    }
-
-	    var k = match_res[1];
-	    if (Ext.isDefined(res[k])) {
-		errors = true;
-		return false; // break
-	    }
-
-	    res[k] = match_res[2];
-	});
-
-	if (errors || !res.cputype) {
-	    return;
-	}
-
-	return res;
-    },
-
-    printQemuCpu: function(cpu) {
-	var cpustr = cpu.cputype;
-	var optstr = '';
-
-	Ext.Object.each(cpu, function(key, value) {
-	    if (!Ext.isDefined(value) || key === 'cputype') {
-		return; // continue
-	    }
-	    optstr += ',' + key + '=' + value;
-	});
-
-	if (!cpustr) {
-	    if (optstr) {
-		return 'kvm64' + optstr;
-	    }
-	    return;
-	}
-
-	return cpustr + optstr;
-    },
-
-    parseSSHKey: function(key) {
-	//                |--- options can have quotes--|     type    key        comment
-	var keyre = /^(?:((?:[^\s"]|\"(?:\\.|[^"\\])*")+)\s+)?(\S+)\s+(\S+)(?:\s+(.*))?$/;
-	var typere = /^(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)$/;
-
-	var m = key.match(keyre);
-	if (!m) {
-	    return null;
-	}
-	if (m.length < 3 || !m[2]) { // [2] is always either type or key
-	    return null;
-	}
-	if (m[1] && m[1].match(typere)) {
-	    return {
-		type: m[1],
-		key: m[2],
-		comment: m[3]
-	    };
-	}
-	if (m[2].match(typere)) {
-	    return {
-		options: m[1],
-		type: m[2],
-		key: m[3],
-		comment: m[4]
-	    };
-	}
-	return null;
-    }
-}});
-/* This state provider keeps part of the state inside
- * the browser history.
- *
- * We compress (shorten) url using dictionary based compression
- * i.e. use column separated list instead of url encoded hash:
- * #v\d*       version/format
- * :=          indicates string values
- * :\d+        lookup value in dictionary hash
- * #v1:=value1:5:=value2:=value3:...
-*/
-
-Ext.define('PVE.StateProvider', {
-    extend: 'Ext.state.LocalStorageProvider',
-
-    // private
-    setHV: function(name, newvalue, fireEvents) {
-	var me = this;
-
-	var changes = false;
-	var oldtext = Ext.encode(me.UIState[name]);
-	var newtext = Ext.encode(newvalue);
-	if (newtext != oldtext) {
-	    changes = true;
-	    me.UIState[name] = newvalue;
-	    //console.log("changed old " + name + " " + oldtext);
-	    //console.log("changed new " + name + " " + newtext);
-	    if (fireEvents) {
-		me.fireEvent("statechange", me, name, { value: newvalue });
-	    }
-	}
-	return changes;
-    },
-
-    // private
-    hslist: [
-	// order is important for notifications
-	// [ name, default ]
-	['view', 'server'],
-	['rid', 'root'],
-	['ltab', 'tasks'],
-	['nodetab', ''],
-	['storagetab', ''],
-	['pooltab', ''],
-	['kvmtab', ''],
-	['lxctab', ''],
-	['dctab', '']
-    ],
-
-    hprefix: 'v1',
-
-    compDict: {
-	cloudinit: 52,
-	replication: 51,
-	system: 50,
-	monitor: 49,
-	'ha-fencing': 48,
-	'ha-groups': 47,
-	'ha-resources': 46,
-	'ceph-log': 45,
-	'ceph-crushmap':44,
-	'ceph-pools': 43,
-	'ceph-osdtree': 42,
-	'ceph-disklist': 41,
-	'ceph-monlist': 40,
-	'ceph-config': 39,
-	ceph: 38,
-	'firewall-fwlog': 37,
-	'firewall-options': 36,
-	'firewall-ipset': 35,
-	'firewall-aliases': 34,
-	'firewall-sg': 33,
-	firewall: 32,
-	apt: 31,
-	members: 30,
-	snapshot: 29,
-	ha: 28,
-	support: 27,
-	pools: 26,
-	syslog: 25,
-	ubc: 24,
-	initlog: 23,
-	openvz: 22,
-	backup: 21,
-	resources: 20,
-	content: 19,
-	root: 18,
-	domains: 17,
-	roles: 16,
-	groups: 15,
-	users: 14,
-	time: 13,
-	dns: 12,
-	network: 11,
-	services: 10,
-	options: 9,
-	console: 8,
-	hardware: 7,
-	permissions: 6,
-	summary: 5,
-	tasks: 4,
-	clog: 3,
-	storage: 2,
-	folder: 1,
-	server: 0
-    },
-
-    decodeHToken: function(token) {
-	var me = this;
-
-	var state = {};
-	if (!token) {
-	    Ext.Array.each(me.hslist, function(rec) {
-		state[rec[0]] = rec[1];
-	    });
-	    return state;
-	}
-
-	// return Ext.urlDecode(token);
-
-	var items = token.split(':');
-	var prefix = items.shift();
-
-	if (prefix != me.hprefix) {
-	    return me.decodeHToken();
-	}
-
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = items.shift();
-	    if (value) {
-		if (value[0] === '=') {
-		    value = decodeURIComponent(value.slice(1));
-		} else {
-		    Ext.Object.each(me.compDict, function(key, cv) {
-			if (value == cv) {
-			    value = key;
-			    return false;
-			}
-		    });
-		}
-	    }
-	    state[rec[0]] = value;
-	});
-
-	return state;
-    },
-
-    encodeHToken: function(state) {
-	var me = this;
-
-	// return Ext.urlEncode(state);
-
-	var ctoken = me.hprefix;
-	Ext.Array.each(me.hslist, function(rec) {
-	    var value = state[rec[0]];
-	    if (!Ext.isDefined(value)) {
-		value = rec[1];
-	    }
-	    value = encodeURIComponent(value);
-	    if (!value) {
-		ctoken += ':';
-	    } else {
-		var comp = me.compDict[value];
-		if (Ext.isDefined(comp)) {
-		    ctoken += ":" + comp;
-		} else {
-		    ctoken += ":=" + value;
-		}
-	    }
-	});
-
-	return ctoken;
-    },
-
-    constructor: function(config){
-	var me = this;
-
-	me.callParent([config]);
-
-	me.UIState = me.decodeHToken(); // set default
-
-	var history_change_cb = function(token) {
-	    //console.log("HC " + token);
-	    if (!token) {
-		var res = window.confirm(gettext('Are you sure you want to navigate away from this page?'));
-		if (res){
-		    // process text value and close...
-		    Ext.History.back();
-		} else {
-		    Ext.History.forward();
-		}
-		return;
-	    }
-
-	    var newstate = me.decodeHToken(token);
-	    Ext.Array.each(me.hslist, function(rec) {
-		if (typeof newstate[rec[0]] == "undefined") {
-		    return;
-		}
-		me.setHV(rec[0], newstate[rec[0]], true);
-	    });
-	};
-
-	var start_token = Ext.History.getToken();
-	if (start_token) {
-	    history_change_cb(start_token);
-	} else {
-	    var htext = me.encodeHToken(me.UIState);
-	    Ext.History.add(htext);
-	}
-
-	Ext.History.on('change', history_change_cb);
-    },
-
-    get: function(name, defaultValue){
-	/*jslint confusion: true */
-	var me = this;
-	var data;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    data = { value: me.UIState[name] };
-	} else {
-	    data = me.callParent(arguments);
-	    if (!data && name === 'GuiCap') {
-		data = { vms: {}, storage: {}, access: {}, nodes: {}, dc: {} };
-	    }
-	}
-
-	//console.log("GET " + name + " " + Ext.encode(data));
-	return data;
-    },
-
-    clear: function(name){
-	var me = this;
-
-	if (typeof me.UIState[name] != "undefined") {
-	    me.UIState[name] = null;
-	}
-
-	me.callParent(arguments);
-    },
-
-    set: function(name, value, fireevent){
-        var me = this;
-
-	//console.log("SET " + name + " " + Ext.encode(value));
-	if (typeof me.UIState[name] != "undefined") {
-	    var newvalue = value ? value.value : null;
-	    if (me.setHV(name, newvalue, fireevent)) {
-		var htext = me.encodeHToken(me.UIState);
-		Ext.History.add(htext);
-	    }
-	} else {
-	    me.callParent(arguments);
-	}
-    }
-});
-Ext.define('PVE.menu.Item', {
-    extend: 'Ext.menu.Item',
-    alias: 'widget.pveMenuItem',
-
-    // set to wrap the handler callback in a confirm dialog  showing this text
-    confirmMsg: false,
-
-    // set to focus 'No' instead of 'Yes' button and show a warning symbol
-    dangerous: false,
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.handler) {
-	    me.setHandler(me.handler, me.scope);
-	}
-
-	me.callParent();
-    },
-
-    setHandler: function(fn, scope) {
-	var me = this;
-	me.scope = scope;
-	me.handler = function(button, e) {
-	    var rec, msg;
-	    if (me.confirmMsg) {
-		msg = me.confirmMsg;
-		Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: msg,
-		    buttons: Ext.Msg.YESNO,
-		    defaultFocus: me.dangerous ? 'no' : 'yes',
-		    callback: function(btn) {
-			if (btn === 'yes') {
-			    Ext.callback(fn, me.scope, [me, e], 0, me);
-			}
-		    }
-		});
-	    } else {
-		Ext.callback(fn, me.scope, [me, e], 0, me);
-	    }
-	};
-    }
-});
-Ext.define('PVE.menu.TemplateMenu', {
-    extend: 'Ext.menu.Menu',
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var guestType = me.pveSelNode.data.type;
-	if (guestType !== 'qemu' && guestType != 'lxc') {
-	    throw "invalid guest type";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var template = me.pveSelNode.data.template;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	me.title = (guestType === 'qemu' ? 'VM ' : 'CT ') + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: guestType,
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		handler: function() {
-		    var win = Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: template
-		    });
-		    win.show();
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.ConsoleButton', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveConsoleButton',
-
-    consoleType: 'shell', // one of 'shell', 'kvm', 'lxc', 'upgrade', 'cmd'
-
-    cmd: undefined,
-
-    consoleName: undefined,
-
-    iconCls: 'fa fa-terminal',
-
-    enableSpice: true,
-    enableXtermjs: true,
-
-    nodename: undefined,
-
-    vmid: 0,
-
-    text: gettext('Console'),
-
-    setEnableSpice: function(enable){
-	var me = this;
-
-	me.enableSpice = enable;
-	me.down('#spicemenu').setDisabled(!enable);
-    },
-
-    setEnableXtermJS: function(enable){
-	var me = this;
-
-	me.enableXtermjs = enable;
-	me.down('#xtermjs').setDisabled(!enable);
-    },
-
-    handler: function() {
-	var me = this;
-	var consoles = {
-	    spice: me.enableSpice,
-	    xtermjs: me.enableXtermjs
-	};
-	PVE.Utils.openDefaultConsoleWindow(consoles, me.consoleType, me.vmid,
-					   me.nodename, me.consoleName, me.cmd);
-    },
-
-    menu: [
-	{
-	    xtype:'menuitem',
-	    text: 'noVNC',
-	    iconCls: 'pve-itype-icon-novnc',
-	    type: 'html5',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    xterm: 'menuitem',
-	    itemId: 'spicemenu',
-	    text: 'SPICE',
-	    type: 'vv',
-	    iconCls: 'pve-itype-icon-virt-viewer',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	},
-	{
-	    text: 'xterm.js',
-	    itemId: 'xtermjs',
-	    iconCls: 'pve-itype-icon-xtermjs',
-	    type: 'xtermjs',
-	    handler: function(button) {
-		var me = this.up('button');
-		PVE.Utils.openConsoleWindow(button.type, me.consoleType, me.vmid, me.nodename, me.consoleName, me.cmd);
-	    }
-	}
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.button.PendingRevert', {
-    extend: 'Proxmox.button.Button',
-    alias: 'widget.pvePendingRevertButton',
-
-    text: gettext('Revert'),
-    disabled: true,
-    config: {
-	pendingGrid: null,
-	apiurl: undefined,
-    },
-
-    handler: function() {
-	if (!this.pendingGrid) {
-	    this.pendingGrid = this.up('proxmoxPendingObjectGrid');
-	    if (!this.pendingGrid) throw "revert button requires a pendingGrid";
-	}
-	let view = this.pendingGrid;
-
-	let rec = view.getSelectionModel().getSelection()[0];
-	if (!rec) return;
-
-	let rowdef = view.rows[rec.data.key] || {};
-	let keys = rowdef.multiKey ||  [ rec.data.key ];
-
-	Proxmox.Utils.API2Request({
-	    url: this.apiurl || view.editorConfig.url,
-	    waitMsgTarget: view,
-	    selModel: view.getSelectionModel(),
-	    method: 'PUT',
-	    params: {
-		'revert': keys.join(',')
-	    },
-	    callback: () => view.reload(),
-	    failure: (response) => Ext.Msg.alert('Error', response.htmlStatus),
-	});
-    },
-});
-/* Button features:
- * - observe selection changes to enable/disable the button using enableFn()
- * - pop up confirmation dialog using confirmMsg()
- *
- *   does this for the button and every menu item
- */
-Ext.define('PVE.button.Split', {
-    extend: 'Ext.button.Split',
-    alias: 'widget.pveSplitButton',
-
-    // the selection model to observe
-    selModel: undefined,
-
-    // if 'false' handler will not be called (button disabled)
-    enableFn: function(record) { },
-
-    // function(record) or text
-    confirmMsg: false,
-
-    // take special care in confirm box (select no as default).
-    dangerous: false,
-
-    handlerWrapper: function(button, event) {
-	var me = this;
-	var rec, msg;
-	if (me.selModel) {
-	    rec = me.selModel.getSelection()[0];
-	    if (!rec || (me.enableFn(rec) === false)) {
-		return;
-	    }
-	}
-
-	if (me.confirmMsg) {
-	    msg = me.confirmMsg;
-	    // confirMsg can be boolean or function
-	    /*jslint confusion: true*/
-	    if (Ext.isFunction(me.confirmMsg)) {
-		msg = me.confirmMsg(rec);
-	    }
-	    /*jslint confusion: false*/
-	    Ext.MessageBox.defaultButton = me.dangerous ? 2 : 1;
-	    Ext.Msg.show({
-		title: gettext('Confirm'),
-		icon: me.dangerous ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		msg: msg,
-		buttons: Ext.Msg.YESNO,
-		callback: function(btn) {
-		    if (btn !== 'yes') {
-			return;
-		    }
-		    me.realHandler(button, event, rec);
-		}
-	    });
-	} else {
-	    me.realHandler(button, event, rec);
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-
-        var me = this;
-
-	if (me.handler) {
-	    me.realHandler = me.handler;
-	    me.handler = me.handlerWrapper;
-	}
-
-	if (me.menu && me.menu.items) {
-	    me.menu.items.forEach(function(item) {
-		if (item.handler) {
-		    item.realHandler = item.handler;
-		    item.handler = me.handlerWrapper;
-		}
-
-		if (item.selModel) {
-		    me.mon(item.selModel, "selectionchange", function() {
-			var rec = item.selModel.getSelection()[0];
-			if (!rec || (item.enableFn(rec) === false )) {
-			    item.setDisabled(true);
-			} else {
-			    item.setDisabled(false);
-			}
-		    });
-		}
-	    });
-	}
-
-	me.callParent();
-
-	if (me.selModel) {
-
-	    me.mon(me.selModel, "selectionchange", function() {
-		var rec = me.selModel.getSelection()[0];
-		if (!rec || (me.enableFn(rec) === false)) {
-		    me.setDisabled(true);
-		} else {
-		    me.setDisabled(false);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.controller.StorageEdit', {
-    extend: 'Ext.app.ViewController',
-    alias: 'controller.storageEdit',
-    control: {
-	'field[name=content]': {
-	    change: function(field, value) {
-		var hasBackups = Ext.Array.contains(value, 'backup');
-		var maxfiles = this.lookupReference('maxfiles');
-		if (!maxfiles) {
-		    return;
-		}
-
-		if (!hasBackups) {
-		// clear values which will never be submitted
-		    maxfiles.reset();
-		}
-		maxfiles.setDisabled(!hasBackups);
-	    }
-	}
-    }
-});
-Ext.define('PVE.qemu.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'suspended':
-		stopped = false;
-		suspended = true;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = "VM " + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: running || suspended,
-		disabled: running || suspended,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-	    {
-		text: gettext('Pause'),
-		iconCls: 'fa fa-fw fa-pause',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmpause', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Hibernate'),
-		iconCls: 'fa fa-fw fa-download',
-		hidden: stopped || suspended,
-		disabled: stopped || suspended,
-		tooltip: gettext('Suspend to disk'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmsuspend', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			vm_command('suspend', { todisk: 1 });
-		    });
-		}
-	    },
-	    {
-		text: gettext('Resume'),
-		iconCls: 'fa fa-fw fa-play',
-		hidden: !suspended,
-		handler: function() {
-		    vm_command('resume');
-		}
-	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		text: gettext('Reboot'),
-		iconCls: 'fa fa-fw fa-refresh',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Reboot {0}'), 'VM'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmreboot', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("reboot");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'qemu',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'qemu');
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		hidden: !caps.vms['VM.Allocate'],
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('qmtemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			     url: '/nodes/' + nodename + '/qemu/' + vmid + '/template',
-			     method: 'POST',
-			     failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			     }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    Proxmox.Utils.API2Request({
-			url: '/nodes/' + nodename + '/qemu/' + vmid + '/status/current',
-			failure: function(response, opts) {
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, opts) {
-			    var allowSpice = response.result.data.spice;
-			    var allowXtermjs = response.result.data.serial;
-			    var consoles = {
-				spice: allowSpice,
-				xtermjs: allowXtermjs
-			    };
-			    PVE.Utils.openDefaultConsoleWindow(consoles, 'kvm', vmid, nodename, vmname);
-			}
-		    });
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.lxc.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-
-    showSeparator: false,
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no CT ID specified";
-	}
-	var vmname = me.pveSelNode.data.name;
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + nodename + '/lxc/' + vmid + "/status/" + cmd,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var running = false;
-	var stopped = true;
-	var suspended = false;
-	var standalone = PVE.data.ResourceStore.getNodes().length < 2;
-
-	switch (me.pveSelNode.data.status) {
-	    case 'running':
-		running = true;
-		stopped = false;
-		break;
-	    case 'paused':
-		stopped = false;
-		suspended = true;
-		break;
-	    default: break;
-	}
-
-	me.title = 'CT ' + vmid;
-
-	me.items = [
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-fw fa-play',
-		disabled: running,
-		handler: function() {
-		    vm_command('start');
-		}
-	    },
-//	    {
-//		text: gettext('Suspend'),
-//		iconCls: 'fa fa-fw fa-pause',
-//		hidde: suspended,
-//		disabled: stopped || suspended,
-//		handler: function() {
-//		    var msg = Proxmox.Utils.format_task_description('vzsuspend', vmid);
-//		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-//			if (btn !== 'yes') {
-//			    return;
-//			}
-//
-//			vm_command('suspend');
-//		    });
-//		}
-//	    },
-//	    {
-//		text: gettext('Resume'),
-//		iconCls: 'fa fa-fw fa-play',
-//		hidden: !suspended,
-//		handler: function() {
-//		    vm_command('resume');
-//		}
-//	    },
-	    {
-		text: gettext('Shutdown'),
-		iconCls: 'fa fa-fw fa-power-off',
-		disabled: stopped || suspended,
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzshutdown', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command('shutdown');
-		    });
-		}
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-fw fa-stop',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzstop', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("stop");
-		    });
-		}
-	    },
-	    {
-		text: gettext('Reboot'),
-		iconCls: 'fa fa-fw fa-refresh',
-		disabled: stopped,
-		tooltip: Ext.String.format(gettext('Reboot {0}'), 'CT'),
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vzreboot', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			vm_command("reboot");
-		    });
-		}
-	    },
-	    {
-		xtype: 'menuseparator',
-		hidden: (standalone || !caps.vms['VM.Migrate']) && !caps.vms['VM.Allocate'] && !caps.vms['VM.Clone']
-	    },
-	    {
-		text: gettext('Clone'),
-		iconCls: 'fa fa-fw fa-clone',
-		hidden: !caps.vms['VM.Clone'],
-		handler: function() {
-		    PVE.window.Clone.wrap(nodename, vmid, me.isTemplate, 'lxc');
-		}
-	    },
-	    {
-		text: gettext('Migrate'),
-		iconCls: 'fa fa-fw fa-send-o',
-		hidden: standalone || !caps.vms['VM.Migrate'],
-		handler: function() {
-		    var win = Ext.create('PVE.window.Migrate', {
-			vmtype: 'lxc',
-			nodename: nodename,
-			vmid: vmid
-		    });
-		    win.show();
-		}
-	    },
-	    {
-		text: gettext('Convert to template'),
-		iconCls: 'fa fa-fw fa-file-o',
-		handler: function() {
-		    var msg = Proxmox.Utils.format_task_description('vztemplate', vmid);
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/lxc/' + vmid + '/template',
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    });
-		}
-	    },
-	    { xtype: 'menuseparator' },
-	    {
-		text: gettext('Console'),
-		iconCls: 'fa fa-fw fa-terminal',
-		handler: function() {
-		    PVE.Utils.openDefaultConsoleWindow(true, 'lxc', vmid, nodename, vmname);
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CmdMenu', {
-    extend: 'Ext.menu.Menu',
-    xtype: 'nodeCmdMenu',
-
-    showSeparator: false,
-
-    items: [
-	{
-	    text: gettext('Create VM'),
-	    itemId: 'createvm',
-	    iconCls: 'fa fa-desktop',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{
-	    text: gettext('Create CT'),
-	    itemId: 'createct',
-	    iconCls: 'fa fa-cube',
-	    handler: function() {
-		var me = this.up('menu');
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {
-		    nodename: me.nodename
-		});
-		wiz.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Bulk Start'),
-	    itemId: 'bulkstart',
-	    iconCls: 'fa fa-fw fa-play',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Start'),
-		    btnText: gettext('Start'),
-		    action: 'startall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Stop'),
-	    itemId: 'bulkstop',
-	    iconCls: 'fa fa-fw fa-stop',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Stop'),
-		    btnText: gettext('Stop'),
-		    action: 'stopall'
-		});
-		win.show();
-	    }
-	},
-	{
-	    text: gettext('Bulk Migrate'),
-	    itemId: 'bulkmigrate',
-	    iconCls: 'fa fa-fw fa-send-o',
-	    handler: function() {
-		var me = this.up('menu');
-		var win = Ext.create('PVE.window.BulkAction', {
-		    nodename: me.nodename,
-		    title: gettext('Bulk Migrate'),
-		    btnText: gettext('Migrate'),
-		    action: 'migrateall'
-		});
-		win.show();
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Shell'),
-	    itemId: 'shell',
-	    iconCls: 'fa fa-fw fa-terminal',
-	    handler: function() {
-		var me = this.up('menu');
-		PVE.Utils.openDefaultConsoleWindow(true, 'shell', undefined, me.nodename, undefined);
-	    }
-	},
-	{ xtype: 'menuseparator' },
-	{
-	    text: gettext('Wake-on-LAN'),
-	    itemId: 'wakeonlan',
-	    iconCls: 'fa fa-fw fa-power-off',
-	    handler: function() {
-		var me = this.up('menu');
-		Proxmox.Utils.API2Request({
-		    param: {},
-		    url: '/nodes/' + me.nodename + '/wakeonlan',
-		    method: 'POST',
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, opts) {
-			Ext.Msg.show({
-			    title: 'Success',
-			    icon: Ext.Msg.INFO,
-			    msg: Ext.String.format(gettext("Wake on LAN packet send for '{0}': '{1}'"), me.nodename, response.result.data)
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no nodename specified';
-	}
-
-	me.title = gettext('Node') + " '" + me.nodename + "'";
-	me.callParent();
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	// disable not allowed options
-	if (!caps.vms['VM.Allocate']) {
-	    me.getComponent('createct').setDisabled(true);
-	    me.getComponent('createvm').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.PowerMgmt']) {
-	    me.getComponent('bulkstart').setDisabled(true);
-	    me.getComponent('bulkstop').setDisabled(true);
-	    me.getComponent('bulkmigrate').setDisabled(true);
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-
-	if (!caps.nodes['Sys.Console']) {
-	    me.getComponent('shell').setDisabled(true);
-	}
-
-	if (me.pveSelNode.data.running) {
-	    me.getComponent('wakeonlan').setDisabled(true);
-	}
-    }
-});
-Ext.define('PVE.noVncConsole', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNoVncConsole',
-
-    nodename: undefined,
-    vmid: undefined,
-    cmd: undefined,
-
-    consoleType: undefined, // lxc, kvm, shell, cmd
-    xtermjs: false,
-
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.consoleType) {
-	    throw "no console type specified";
-	}
-
-	if (!me.vmid && me.consoleType !== 'shell' && me.consoleType !== 'cmd') {
-	    throw "no VM ID specified";
-	}
-
-	// always use same iframe, to avoid running several noVnc clients
-	// at same time (to avoid performance problems)
-	var box = Ext.create('Ext.ux.IFrame', { itemid : "vncconsole" });
-
-	var type = me.xtermjs ? 'xtermjs' : 'novnc';
-	Ext.apply(me, {
-	    items: box,
-	    listeners: {
-		activate: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var queryDict = {
-			console: me.consoleType, // kvm, lxc, upgrade or shell
-			vmid: me.vmid,
-			node: me.nodename,
-			cmd: me.cmd,
-			resize: sp.get('novnc-scaling', 'scale'),
-		    };
-		    queryDict[type] = 1;
-		    PVE.Utils.cleanEmptyObjectKeys(queryDict);
-		    var url = '/?' + Ext.Object.toQueryString(queryDict);
-		    box.load(url);
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.on('afterrender', function() {
-	    me.focus();
-	});
-    },
-
-    reload: function() {
-	// reload IFrame content to forcibly reconnect VNC/xterm.js to VM
-	var box = this.down('[itemid=vncconsole]');
-	box.getWin().location.reload();
-    }
-});
-
-Ext.define('PVE.data.PermPathStore', {
-    extend: 'Ext.data.Store',
-    alias: 'store.pvePermPath',
-    fields: [ 'value' ],
-    autoLoad: false,
-    data: [
-	{'value':  '/'},
-	{'value':  '/access'},
-	{'value': '/nodes'},
-	{'value': '/pool'},
-	{'value': '/storage'},
-	{'value': '/vms'}
-    ],
-
-    constructor: function(config) {
-	var me = this;
-
-	config = config || {};
-
-	me.callParent([config]);
-
-	me.suspendEvents();
-	PVE.data.ResourceStore.each(function(record) {
-	    switch (record.get('type')) {
-		case 'node':
-		    me.add({value: '/nodes/' + record.get('text')});
-		    break;
-
-		case 'qemu':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'lxc':
-		    me.add({value: '/vms/' + record.get('vmid')});
-		    break;
-
-		case 'storage':
-		    me.add({value: '/storage/' + record.get('storage')});
-		    break;
-		case 'pool':
-		    me.add({value: '/pool/' + record.get('pool')});
-		    break;
-	    }
-	});
-	me.resumeEvents();
-
-	me.fireEvent('refresh', me);
-	me.fireEvent('datachanged', me);
-
-	me.sort({
-	    property: 'value',
-	    direction: 'ASC'
-	});
-    }
-});
-Ext.define('PVE.data.ResourceStore', {
-    extend: 'Proxmox.data.UpdateStore',
-    singleton: true,
-
-    findVMID: function(vmid) {
-	var me = this, i;
-
-	return (me.findExact('vmid', parseInt(vmid, 10)) >= 0);
-    },
-
-    // returns the cached data from all nodes
-    getNodes: function() {
-	var me = this;
-
-	var nodes = [];
-	me.each(function(record) {
-	    if (record.get('type') == "node") {
-		nodes.push( record.getData() );
-	    }
-	});
-
-	return nodes;
-    },
-
-    storageIsShared: function(storage_path) {
-	var me = this;
-
-	var index = me.findExact('id', storage_path);
-
-	return me.getAt(index).data.shared;
-    },
-
-    guestNode: function(vmid) {
-	var me = this;
-
-	var index = me.findExact('vmid', parseInt(vmid, 10));
-
-	return me.getAt(index).data.node;
-    },
-
-    guestName: function(vmid) {
-	let me = this;
-	let index = me.findExact('vmid', parseInt(vmid, 10));
-	if (index < 0) {
-	    return '-';
-	}
-	let rec = me.getAt(index).data;
-	if ('name' in rec) {
-	    return rec.name;
-	}
-	return '';
-    },
-
-    constructor: function(config) {
-	// fixme: how to avoid those warnings
-	/*jslint confusion: true */
-
-	var me = this;
-
-	config = config || {};
-
-	var field_defaults = {
-	    type: {
-		header: gettext('Type'),
-		type: 'string',
-		renderer: PVE.Utils.render_resource_type,
-		sortable: true,
-		hideable: false,
-		width: 100
-	    },
-	    id: {
-		header: 'ID',
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    running: {
-		header: gettext('Online'),
-		type: 'boolean',
-		renderer: Proxmox.Utils.format_boolean,
-		hidden: true,
-		convert: function(value, record) {
-		    var info = record.data;
-		    return (Ext.isNumeric(info.uptime) && (info.uptime > 0));
-		}
-	    },
-	    text: {
-		header: gettext('Description'),
-		type: 'string',
-		sortable: true,
-		width: 200,
-		convert: function(value, record) {
-		    var info = record.data;
-		    var text;
-
-		    if (value) {
-			return value;
-		    }
-
-		    if (Ext.isNumeric(info.vmid) && info.vmid > 0) {
-			text = String(info.vmid);
-			if (info.name) {
-			    text += " (" + info.name + ')';
-			}
-		    } else { // node, pool, storage
-			text = info[info.type] || info.id;
-			if (info.node && info.type !== 'node') {
-			    text += " (" + info.node + ")";
-			}
-		    }
-
-		    return text;
-		}
-	    },
-	    vmid: {
-		header: 'VMID',
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 80
-	    },
-	    name: {
-		header: gettext('Name'),
-		hidden: true,
-		sortable: true,
-		type: 'string'
-	    },
-	    disk: {
-		header: gettext('Disk usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_disk_usage,
-		sortable: true,
-		width: 100,
-		hidden: true
-	    },
-	    diskuse: {
-		header: gettext('Disk usage') + " %",
-		type: 'number',
-		sortable: true,
-		renderer: PVE.Utils.render_disk_usage_percent,
-		width: 100,
-		calculate: PVE.Utils.calculate_disk_usage,
-		sortType: 'asFloat'
-	    },
-	    maxdisk: {
-		header: gettext('Disk size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    mem: {
-		header: gettext('Memory usage'),
-		type: 'integer',
-		renderer: PVE.Utils.render_mem_usage,
-		sortable: true,
-		hidden: true,
-		width: 100
-	    },
-	    memuse: {
-		header: gettext('Memory usage') + " %",
-		type: 'number',
-		renderer: PVE.Utils.render_mem_usage_percent,
-		calculate: PVE.Utils.calculate_mem_usage,
-		sortType: 'asFloat',
-		sortable: true,
-		width: 100
-	    },
-	    maxmem: {
-		header: gettext('Memory size'),
-		type: 'integer',
-		renderer: PVE.Utils.render_size,
-		hidden: true,
-		sortable: true,
-		width: 100
-	    },
-	    cpu: {
-		header: gettext('CPU usage'),
-		type: 'float',
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100
-	    },
-	    maxcpu: {
-		header: gettext('maxcpu'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    diskread: {
-		header: gettext('Total Disk Read'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    diskwrite: {
-		header: gettext('Total Disk Write'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netin: {
-		header: gettext('Total NetIn'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    netout: {
-		header: gettext('Total NetOut'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		renderer: Proxmox.Utils.format_size,
-		width: 100
-	    },
-	    template: {
-		header: gettext('Template'),
-		type: 'integer',
-		hidden: true,
-		sortable: true,
-		width: 60
-	    },
-	    uptime: {
-		header: gettext('Uptime'),
-		type: 'integer',
-		renderer: Proxmox.Utils.render_uptime,
-		sortable: true,
-		width: 110
-	    },
-	    node: {
-		header: gettext('Node'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    storage: {
-		header: gettext('Storage'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    pool: {
-		header: gettext('Pool'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    hastate: {
-		header: gettext('HA State'),
-		type: 'string',
-		defaultValue: 'unmanaged',
-		hidden: true,
-		sortable: true
-	    },
-	    status: {
-		header: gettext('Status'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    },
-	    lock: {
-		header: gettext('Lock'),
-		type: 'string',
-		hidden: true,
-		sortable: true,
-		width: 110
-	    }
-	};
-
-	var fields = [];
-	var fieldNames = [];
-	Ext.Object.each(field_defaults, function(key, value) {
-	    var field = {name: key, type: value.type};
-	    if (Ext.isDefined(value.convert)) {
-		field.convert = value.convert;
-	    }
-
-	    if (Ext.isDefined(value.calculate)) {
-		field.calculate = value.calculate;
-	    }
-
-	    if (Ext.isDefined(value.defaultValue)) {
-		field.defaultValue = value.defaultValue;
-	    }
-
-	    fields.push(field);
-	    fieldNames.push(key);
-	});
-
-	Ext.define('PVEResources', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/resources'
-	    }
-	});
-
-	Ext.define('PVETree', {
-	    extend: "Ext.data.Model",
-	    fields: fields,
-	    proxy: { type: 'memory' }
-	});
-
-	Ext.apply(config, {
-	    storeid: 'PVEResources',
-	    model: 'PVEResources',
-	    defaultColumns: function() {
-		var res = [];
-		Ext.Object.each(field_defaults, function(field, info) {
-		    var fi = Ext.apply({ dataIndex: field }, info);
-		    res.push(fi);
-		});
-		return res;
-	    },
-	    fieldNames: fieldNames
-	});
-
-	me.callParent([config]);
-    }
-});
-Ext.define('pve-domains', {
-    extend: "Ext.data.Model",
-    fields: [
-	'realm', 'type', 'comment', 'default', 'tfa',
-	{
-	    name: 'descr',
-	    // Note: We use this in the RealmComboBox.js (see Bug #125)
-	    convert: function(value, record) {
-		if (value) {
-		    return value;
-		}
-
-		var info = record.data;
-		// return realm if there is no comment
-		var text = info.comment || info.realm;
-
-		if (info.tfa) {
-		    text += " (+ " + info.tfa + ")";
-		}
-
-		return Ext.String.htmlEncode(text);
-	    }
-	}
-    ],
-    idProperty: 'realm',
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/domains"
-    }
-});
-Ext.define('pve-rrd-node', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	{
-	    name:'iowait',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'loadavg',
-	'maxcpu',
-	'memtotal',
-	'memused',
-	'netin',
-	'netout',
-	'roottotal',
-	'rootused',
-	'swaptotal',
-	'swapused',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-guest', {
-    extend: 'Ext.data.Model',
-    fields: [
-	{
-	    name:'cpu',
-	    // percentage
-	    convert: function(value) {
-		return value*100;
-	    }
-	},
-	'maxcpu',
-	'netin',
-	'netout',
-	'mem',
-	'maxmem',
-	'disk',
-	'maxdisk',
-	'diskread',
-	'diskwrite',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-
-Ext.define('pve-rrd-storage', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'used',
-	'total',
-	{ type: 'date', dateFormat: 'timestamp', name: 'time' }
-    ]
-});
-Ext.define('PVE.form.VlanField', {
-    extend: 'Ext.form.field.Number',
-    alias: ['widget.pveVlanField'],
-
-    deleteEmpty: false,
-
-    emptyText: 'no VLAN',
-    
-    fieldLabel: gettext('VLAN Tag'),
-
-    allowBlank: true,
-    
-    getSubmitData: function() {
-        var me = this,
-            data = null,
-            val;
-        if (!me.disabled && me.submitValue) {
-            val = me.getSubmitValue();
-            if (val) {
-                data = {};
-                data[me.getName()] = val;
-            } else if (me.deleteEmpty) {
-		data = {};
-                data['delete'] = me.getName();
-	    }
-        }
-        return data;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    minValue: 1,
-	    maxValue: 4094
-	});
-
-	me.callParent();
-    }
-});
-// boolean type including 'Default' (delete property from file)
-Ext.define('PVE.form.Boolean', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.booleanfield'],
-    comboItems: [
-	['__default__', gettext('Default')],
-	[1, gettext('Yes')],
-	[0, gettext('No')]
-    ]
-});
-Ext.define('PVE.form.BandwidthField', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveBandwidthField',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    viewModel: {
-	data: {
-	    unit: 'MiB',
-	},
-	formulas: {
-	    unitlabel: (get) => get('unit') + '/s',
-	}
-    },
-
-    emptyText: '',
-
-    layout: 'hbox',
-    defaults: {
-	hideLabel: true
-    },
-
-    units: {
-	'KiB': 1024,
-	'MiB': 1024*1024,
-	'GiB': 1024*1024*1024,
-	'KB': 1000,
-	'MB': 1000*1000,
-	'GB': 1000*1000*1000,
-    },
-
-    // display unit (TODO: make (optionally) selectable)
-    unit: 'MiB',
-
-    // use this if the backend saves values in another unit tha bytes, e.g.,
-    // for KiB set it to 'KiB'
-    backendUnit: undefined,
-
-    items: [
-	{
-	    xtype: 'numberfield',
-	    cbind: {
-		name: '{name}',
-		emptyText: '{emptyText}',
-	    },
-	    minValue: 0,
-	    step: 1,
-	    submitLocaleSeparator: false,
-	    fieldStyle: 'text-align: right',
-	    flex: 1,
-	    enableKeyEvents: true,
-	    setValue: function(v) {
-		if (!this._transformed) {
-		    let fieldct = this.up('pveBandwidthField');
-		    let vm = fieldct.getViewModel();
-		    let unit = vm.get('unit');
-
-		    v /= fieldct.units[unit];
-		    v *= fieldct.backendFactor;
-
-		    this._transformed = true;
-		}
-
-		if (v == 0) v = undefined;
-
-		return Ext.form.field.Text.prototype.setValue.call(this, v);
-	    },
-	    getSubmitValue: function() {
-		let v = this.processRawValue(this.getRawValue());
-		v = v.replace(this.decimalSeparator, '.')
-
-		if (v === undefined) return null;
-		// FIXME: make it configurable, as this only works if 0 === default
-		if (v == 0 || v == 0.0) return null;
-
-		let fieldct = this.up('pveBandwidthField');
-		let vm = fieldct.getViewModel();
-		let unit = vm.get('unit');
-
-		v = parseFloat(v) * fieldct.units[unit];
-		v /= fieldct.backendFactor;
-
-		return ''+ Math.floor(v);
-	    },
-	    listeners: {
-		// our setValue gets only called if we have a value, avoid
-		// transformation of the first user-entered value
-		keydown: function () { this._transformed = true; },
-	    },
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'unit',
-	    submitValue: false,
-	    padding: '0 0 0 10',
-	    bind: {
-		value: '{unitlabel}',
-	    },
-	    listeners: {
-		change: (f, v) => f.originalValue = v,
-	    },
-	    width: 40,
-	},
-    ],
-
-    initComponent: function() {
-	let me = this;
-
-	me.unit = me.unit || 'MiB';
-	if (!(me.unit in me.units)) {
-	    throw "unknown unit: " + me.unit;
-	}
-
-	me.backendFactor = 1;
-	if (me.backendUnit !== undefined) {
-	    if (!(me.unit in me.units)) {
-		throw "unknown backend unit: " + me.backendUnit;
-	    }
-	    me.backendFactor = me.units[me.backendUnit];
-	}
-
-
-	me.callParent(arguments);
-
-	me.getViewModel().set('unit', me.unit);
-    },
-});
-
-Ext.define('PVE.form.CompressionSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveCompressionSelector'],
-    comboItems: [
-                ['0', Proxmox.Utils.noneText],
-                ['lzo', 'LZO (' + gettext('fast') + ')'],
-                ['gzip', 'GZIP (' + gettext('good') + ')']
-    ]
-});
-Ext.define('PVE.form.PoolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pvePoolSelector'],
-
-    allowBlank: false,
-    valueField: 'poolid',
-    displayField: 'poolid',
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: 'poolid'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    autoSelect: false,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Pool'),
-			sortable: true,
-			dataIndex: 'poolid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-pools', {
-	extend: 'Ext.data.Model',
-	fields: [ 'poolid', 'comment' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/pools"
-	},
-	idProperty: 'poolid'
-    });
-
-});
-Ext.define('PVE.form.PrivilegesSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    xtype: 'pvePrivilegesSelector',
-
-    multiSelect: true,
-
-    initComponent: function() {
-	var me = this;
-
-	// So me.store is available.
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/roles/Administrator',
-	    method: 'GET',
-	    success: function(response, options) {
-		var data = [], key;
-		/*jslint forin: true */
-		for (key in response.result.data) {
-		    data.push([key, key]);
-		}
-		/*jslint forin: false */
-
-		me.store.setData(data);
-
-		me.store.sort({
-		    property: 'key',
-		    direction: 'ASC'
-		});
-	    },
-
-	    failure: function (response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    }
-});
-Ext.define('pve-groups', {
-    extend: 'Ext.data.Model',
-    fields: [ 'groupid', 'comment', 'users' ],
-    proxy: {
-	type: 'proxmox',
-	url: "/api2/json/access/groups"
-    },
-    idProperty: 'groupid'
-});
-
-Ext.define('PVE.form.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveGroupSelector',
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'groupid',
-    displayField: 'groupid',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		sortable: true,
-		dataIndex: 'groupid',
-		flex: 1
-	    },
-	    {
-		header: gettext('Comment'),
-		sortable: false,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    },
-	    {
-		header: gettext('Users'),
-		sortable: false,
-		dataIndex: 'users',
-		flex: 1
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: [{
-		property: 'groupid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-Ext.define('PVE.form.UserSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUserSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'userid',
-    displayField: 'userid',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-users',
-	    sorters: [{
-		property: 'userid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('User'),
-			sortable: true,
-			dataIndex: 'userid',
-			flex: 1
-		    },
-		    {
-			header: gettext('Name'),
-			sortable: true,
-			renderer: PVE.Utils.render_full_name,
-			dataIndex: 'firstname',
-			flex: 1
-		    },
-		    {
-			header: gettext('Comment'),
-			sortable: false,
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load({ params: { enabled: 1 }});
-    }
-
-}, function() {
-
-    Ext.define('pve-users', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'userid', 'firstname', 'lastname' , 'email', 'comment',
-	    { type: 'boolean', name: 'enable' },
-	    { type: 'date', dateFormat: 'timestamp', name: 'expire' }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/users"
-	},
-	idProperty: 'userid'
-    });
-
-});
-
-
-Ext.define('PVE.form.RoleSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveRoleSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'roleid',
-    displayField: 'roleid',
-    initComponent: function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: [{
-		property: 'roleid'
-	    }]
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Role'),
-			sortable: true,
-			dataIndex: 'roleid',
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-roles', {
-	extend: 'Ext.data.Model',
-	fields: [ 'roleid', 'privs' ],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/access/roles"
-	},
-	idProperty: 'roleid'
-    });
-
-});
-Ext.define('PVE.form.GuestIDSelector', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveGuestIDSelector',
-
-    allowBlank: false,
-
-    minValue: 100,
-
-    maxValue: 999999999,
-
-    validateExists: undefined,
-
-    loadNextFreeID: false,
-
-    guestType: undefined,
-
-    validator: function(value) {
-	var me = this;
-
-	if (!Ext.isNumeric(value) ||
-	    value < me.minValue ||
-	    value > me.maxValue) {
-	    // check is done by ExtJS
-	    return true;
-	}
-
-	if (me.validateExists === true && !me.exists) {
-	    return me.unknownID;
-	}
-
-	if (me.validateExists === false && me.exists) {
-	    return me.inUseID;
-	}
-
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var label = '{0} ID';
-	var unknownID = gettext('This {0} ID does not exist');
-	var inUseID = gettext('This {0} ID is already in use');
-	var type = 'CT/VM';
-
-	if (me.guestType === 'lxc') {
-	    type = 'CT';
-	} else if (me.guestType === 'qemu') {
-	    type = 'VM';
-	}
-
-	me.label = Ext.String.format(label, type);
-	me.unknownID = Ext.String.format(unknownID, type);
-	me.inUseID = Ext.String.format(inUseID, type);
-
-	Ext.apply(me, {
-	    fieldLabel: me.label,
-	    listeners: {
-		'change': function(field, newValue, oldValue) {
-		    if (!Ext.isDefined(me.validateExists)) {
-			return;
-		    }
-		    Proxmox.Utils.API2Request({
-			params: { vmid: newValue },
-			url: '/cluster/nextid',
-			method: 'GET',
-			success: function(response, opts) {
-			    me.exists = false;
-			    me.validate();
-			},
-			failure: function(response, opts) {
-			    me.exists = true;
-			    me.validate();
-			}
-		    });
-		}
-	    }
-	});
-
-        me.callParent();
-
-	if (me.loadNextFreeID) {
-	    Proxmox.Utils.API2Request({
-		url: '/cluster/nextid',
-		method: 'GET',
-		success: function(response, opts) {
-		    me.setRawValue(response.result.data);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.form.MemoryField', {
-    extend: 'Ext.form.field.Number',
-    alias: 'widget.pveMemoryField',
-
-    allowBlank: false,
-
-    hotplug: false,
-
-    minValue: 32,
-
-    maxValue: 4178944,
-
-    step: 32,
-
-    value: '512', // qm default
-
-    allowDecimals: false,
-
-    allowExponential: false,
-
-    computeUpDown: function(value) {
-	var me = this;
-
-	if (!me.hotplug) {
-	    return { up: value + me.step, down: value - me.step };
-	}
-	
-	var dimm_size = 512;
-	var prev_dimm_size = 0;
-	var min_size = 1024;
-	var current_size = min_size;
-	var value_up = min_size;
-	var value_down = min_size;
-	var value_start = min_size;
-
-	var i, j;
-	for (j = 0; j < 9; j++) {
-	    for (i = 0; i < 32; i++) {
-		if ((value >= current_size) && (value < (current_size + dimm_size))) {
-		    value_start = current_size;
-		    value_up = current_size + dimm_size;
-		    value_down = current_size - ((i === 0) ? prev_dimm_size : dimm_size);
-		}
-		current_size += dimm_size;				
-	    }
-	    prev_dimm_size = dimm_size;
-	    dimm_size = dimm_size*2;
-	}
-
-	return { up: value_up, down: value_down, start: value_start };
-    },
-
-    onSpinUp: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.up, me.minValue, me.maxValue));
-	}
-    },
-
-    onSpinDown: function() {
-	var me = this;
-	if (!me.readOnly) {
-	    var res = me.computeUpDown(me.getValue());
-	    me.setValue(Ext.Number.constrain(res.down, me.minValue, me.maxValue));
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	if (me.hotplug) {
-	    me.minValue = 1024;
-
-	    me.on('blur', function(field) {
-		var value = me.getValue();
-		var res = me.computeUpDown(value);
-		if (value === res.start || value === res.up || value === res.down) {
-		    return;
-		}
-		field.setValue(res.up);
-	    });
-	}
-
-        me.callParent();
-    }
-});
-Ext.define('PVE.form.NetworkCardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveNetworkCardSelector',
-    comboItems: [
-	['e1000', 'Intel E1000'],
-	['virtio', 'VirtIO (' + gettext('paravirtualized') + ')'],
-	['rtl8139', 'Realtek RTL8139'],
-	['vmxnet3', 'VMware vmxnet3']
-    ]
-});
-Ext.define('PVE.form.DiskFormatSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveDiskFormatSelector',
-    comboItems:  [
-	['raw', gettext('Raw disk image') + ' (raw)'],
-	['qcow2', gettext('QEMU image format') + ' (qcow2)'],
-	['vmdk', gettext('VMware image format') + ' (vmdk)']
-    ]
-});
-Ext.define('PVE.form.DiskSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveDiskSelector',
-
-    // can be
-    // undefined: all
-    // unused: only unused
-    // journal_disk: all disks with gpt
-    diskType: undefined,
-
-    valueField: 'devpath',
-    displayField: 'devpath',
-    emptyText: gettext('No Disks unused'),
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Device'),
-		flex: 3,
-		sortable: true,
-		dataIndex: 'devpath'
-	    },
-	    {
-		header: gettext('Size'),
-		flex: 2,
-		sortable: false,
-		renderer: Proxmox.Utils.format_size,
-		dataIndex: 'size'
-	    },
-	    {
-		header: gettext('Serial'),
-		flex: 5,
-		sortable: true,
-		dataIndex: 'serial'
-	    }
-	]
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    filterOnLoad: true,
-	    model: 'pve-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list",
-		extraParams: { type: me.diskType }
-	    },
-	    sorters: [
-		{
-		    property : 'devpath',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-}, function() {
-
-    Ext.define('pve-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial'],
-	idProperty: 'devpath'
-    });
-});
-Ext.define('PVE.form.BusTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: 'widget.pveBusSelector',
-  
-    noVirtIO: false,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [['ide', 'IDE'], ['sata', 'SATA']];
-
-	if (!me.noVirtIO) {
-	    me.comboItems.push(['virtio', 'VirtIO Block']);
-	}
-
-	me.comboItems.push(['scsi', 'SCSI']);
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.ControllerSelector', {
-    extend: 'Ext.form.FieldContainer',
-    alias: 'widget.pveControllerSelector',
-
-    noVirtIO: false,
-
-    vmconfig: {}, // used to check for existing devices
-
-    sortByPreviousUsage: function(vmconfig, controllerList) {
-	let usedControllers = {};
-	for (const type of Object.keys(PVE.Utils.diskControllerMaxIDs)) {
-	    usedControllers[type] = 0;
-	}
-
-	for (const property of Object.keys(vmconfig)) {
-	    if (property.match(PVE.Utils.bus_match) && !vmconfig[property].match(/media=cdrom/)) {
-		const foundController = property.match(PVE.Utils.bus_match)[1];
-		usedControllers[foundController]++;
-	    }
-	}
-
-	var sortPriority = PVE.qemu.OSDefaults.getDefaults(vmconfig.ostype).busPriority;
-
-	var sortedList = Ext.clone(controllerList);
-	sortedList.sort(function(a, b) {
-	    if (usedControllers[b] == usedControllers[a]) {
-		return sortPriority[b] - sortPriority[a];
-	    }
-	    return usedControllers[b] - usedControllers[a];
-	});
-
-	return sortedList;
-    },
-
-    setVMConfig: function(vmconfig, autoSelect) {
-	var me = this;
-
-	me.vmconfig = Ext.apply({}, vmconfig);
-
-	var clist = ['ide', 'virtio', 'scsi', 'sata'];
-	var bussel = me.down('field[name=controller]');
-	var deviceid = me.down('field[name=deviceid]');
-
-	if (autoSelect === 'cdrom') {
-	    if (!Ext.isDefined(me.vmconfig.ide2)) {
-		bussel.setValue('ide');
-		deviceid.setValue(2);
-		return;
-	    }
-	    clist = ['ide', 'scsi', 'sata'];
-	} else  {
-	    // in most cases we want to add a disk to the same controller
-	    // we previously used
-	    clist = me.sortByPreviousUsage(me.vmconfig, clist);
-	}
-
-clist_loop:
-	for (const controller of clist) {
-	    bussel.setValue(controller);
-	    for (let i = 0; i < PVE.Utils.diskControllerMaxIDs[controller]; i++) {
-		let confid = controller + i.toString();
-		if (!Ext.isDefined(me.vmconfig[confid])) {
-		    deviceid.setValue(i);
-		    break clist_loop; // we found the desired controller/id combo
-		}
-	    }
-	}
-	deviceid.validate();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    fieldLabel: gettext('Bus/Device'),
-	    layout: 'hbox',
-	    defaults: {
-                hideLabel: true
-	    },
-	    items: [
-		{
-		    xtype: 'pveBusSelector',
-		    name: 'controller',
-		    value: PVE.qemu.OSDefaults.generic.busType,
-		    noVirtIO: me.noVirtIO,
-		    allowBlank: false,
-		    flex: 2,
-		    listeners: {
-			change: function(t, value) {
-			    if (!value) {
-				return;
-			    }
-			    var field = me.down('field[name=deviceid]');
-			    field.setMaxValue(PVE.Utils.diskControllerMaxIDs[value]);
-			    field.validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'deviceid',
-		    minValue: 0,
-		    maxValue: PVE.Utils.diskControllerMaxIDs.ide,
-		    value: '0',
-		    flex: 1,
-		    allowBlank: false,
-		    validator: function(value) {
-			/*jslint confusion: true */
-			if (!me.rendered) {
-			    return;
-			}
-			var field = me.down('field[name=controller]');
-			var controller = field.getValue();
-			var confid = controller + value;
-			if (Ext.isDefined(me.vmconfig[confid])) {
-			    return "This device is already in use.";
-			}
-			return true;
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.EmailNotificationSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveEmailNotificationSelector'],
-    comboItems: [
-                ['always', gettext('Always')],
-                ['failure', gettext('On failure only')]
-    ]
-});
-/*global Proxmox*/
-Ext.define('PVE.form.RealmComboBox', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveRealmComboBox'],
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    view.store.on('load', this.onLoad, view);
-	},
-
-	onLoad: function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-	    var me = this;
-	    var val = me.getValue();
-	    if (!val || !me.store.findRecord('realm', val)) {
-		var def = 'pam';
-		Ext.each(records, function(rec) {
-		    if (rec.data && rec.data['default']) {
-			def = rec.data.realm;
-		    }
-		});
-		me.setValue(def);
-	    }
-	}
-    },
-
-    fieldLabel: gettext('Realm'),
-    name: 'realm',
-    queryMode: 'local',
-    allowBlank: false,
-    editable: false,
-    forceSelection: true,
-    autoSelect: false,
-    triggerAction: 'all',
-    valueField: 'realm',
-    displayField: 'descr',
-    getState: function() {
-	return { value: this.getValue() };
-    },
-    applyState : function(state) {
-	if (state && state.value) {
-	    this.setValue(state.value);
-	}
-    },
-    stateEvents: [ 'select' ],
-    stateful: true, // last chosen auth realm is saved between page reloads
-    id: 'pveloginrealm', // We need stable ids when using stateful, not autogenerated
-    stateID: 'pveloginrealm',
-
-    needOTP: function(realm) {
-	var me = this;
-	// use exact match
-	var rec = me.store.findRecord('realm', realm, 0, false, false, true);
-	return rec && rec.data && rec.data.tfa ? rec.data.tfa : undefined;
-    },
-
-    store: {
-	model: 'pve-domains',
-	autoLoad: true
-    }
-});
-/*
- * Top left combobox, used to select a view of the underneath RessourceTree
- */
-Ext.define('PVE.form.ViewSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: ['widget.pveViewSelector'],
-
-    editable: false,
-    allowBlank: false,
-    forceSelection: true,
-    autoSelect: false,
-    valueField: 'key',
-    displayField: 'value',
-    hideLabel: true,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	var default_views = {
-	    server: {
-		text: gettext('Server View'),
-		groups: ['node']
-	    },
-	    folder: {
-		text: gettext('Folder View'),
-		groups: ['type']
-	    },
-	    storage: {
-		text: gettext('Storage View'),
-		groups: ['node'],
-		filterfn: function(node) {
-		    return node.data.type === 'storage' || node.data.type === 'node';
-		}
-	    },
-	    pool: { 
-		text: gettext('Pool View'), 
-		groups: ['pool'],
-                // Pool View only lists VMs and Containers
-                filterfn: function(node) {
-                    return node.data.type === 'qemu' || node.data.type === 'lxc' || node.data.type === 'openvz' || 
-			node.data.type === 'pool';
-                }
-	    }
-	};
-
-	var groupdef = [];
-	Ext.Object.each(default_views, function(viewname, value) {
-	    groupdef.push([viewname, value.text]);
-	});
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'KeyValue',
-            proxy: {
-		type: 'memory',
-		reader: 'array'
-            },
-	    data: groupdef,
-	    autoload: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    value: groupdef[0][0],
-	    getViewFilter: function() {
-		var view = me.getValue();
-		return Ext.apply({ id: view }, default_views[view] || default_views.server);
-	    },
-
-	    getState: function() {
-		return { value: me.getValue() };
-	    },
-
-	    applyState : function(state, doSelect) {
-		var view = me.getValue();
-		if (state && state.value && (view != state.value)) {
-		    var record = store.findRecord('key', state.value);
-		    if (record) {
-			me.setValue(state.value, true);
-			if (doSelect) {
-			    me.fireEvent('select', me, [record]);
-			}
-		    }
-		}
-	    },
-	    stateEvents: [ 'select' ],
-	    stateful: true,
-	    stateId: 'pveview',
-	    id: 'view'
-	});
-
-	me.callParent();
-
-	var statechange = function(sp, key, value) {
-	    if (key === me.id) {
-		me.applyState(value, true);
-	    }
-	};
-
-	var sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', statechange, me);
-    }
-});
-Ext.define('PVE.form.NodeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveNodeSelector'],
-
-    // invalidate nodes which are offline
-    onlineValidator: false,
-
-    selectCurNode: false,
-
-    // do not allow those nodes (array)
-    disallowedNodes: undefined,
-
-    // only allow those nodes (array)
-    allowedNodes: undefined,
-    // set default value to empty array, else it inits it with
-    // null and after the store load it is an empty array,
-    // triggering dirtychange
-    value: [],
-    valueField: 'node',
-    displayField: 'node',
-    store: {
-	    fields: [ 'node', 'cpu', 'maxcpu', 'mem', 'maxmem', 'uptime' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes'
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		},
-		{
-		    property : 'mem',
-		    direction: 'DESC'
-		}
-	    ]
-	},
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node',
-		sortable: true,
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Memory usage') + " %",
-		renderer: PVE.Utils.render_mem_usage_percent,
-		sortable: true,
-		width: 100,
-		dataIndex: 'mem'
-	    },
-	    {
-		header: gettext('CPU usage'),
-		renderer: PVE.Utils.render_cpu,
-		sortable: true,
-		width: 100,
-		dataIndex: 'cpu'
-	    }
-	]
-    },
-
-    validator: function(value) {
-	/*jslint confusion: true */
-	var me = this;
-	if (!me.onlineValidator || (me.allowBlank && !value)) {
-	    return true;
-	}
-
-	var offline = [];
-	var notAllowed = [];
-
-	Ext.Array.each(value.split(/\s*,\s*/), function(node) {
-	    var rec = me.store.findRecord(me.valueField, node);
-	    if (!(rec && rec.data) || rec.data.status !== 'online') {
-		offline.push(node);
-	    } else if (me.allowedNodes && !Ext.Array.contains(me.allowedNodes, node)) {
-		notAllowed.push(node);
-	    }
-	});
-
-	if (value && notAllowed.length !== 0) {
-	    return "Node " + notAllowed.join(', ') + " is not allowed for this action!";
-	}
-
-	if (value && offline.length !== 0) {
-	    return "Node " + offline.join(', ') + " seems to be offline!";
-	}
-	return true;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (me.selectCurNode && PVE.curSelectedNode && PVE.curSelectedNode.data.node) {
-            me.preferredValue = PVE.curSelectedNode.data.node;
-        }
-
-        me.callParent();
-        me.getStore().load();
-
-	// filter out disallowed nodes
-	me.getStore().addFilter(new Ext.util.Filter({
-	    filterFn: function(item) {
-		if (Ext.isArray(me.disallowedNodes)) {
-		    return !Ext.Array.contains(me.disallowedNodes, item.data.node);
-		} else {
-		    return true;
-		}
-	    }
-	}));
-
-	me.mon(me.getStore(), 'load', function(){
-	    me.isValid();
-	});
-    }
-});
-Ext.define('PVE.form.FileSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFileSelector',
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    listeners: {
-	afterrender: function() {
-	    var me = this;
-	    if (!me.disabled) {
-		me.setStorage(me.storage, me.nodename);
-	    }
-	}
-    },
-
-    setStorage: function(storage, nodename) {
-	var me = this;
-
-	var change = false;
-	if (storage && (me.storage !== storage)) {
-	    me.storage = storage;
-	    change = true;
-	}
-
-	if (nodename && (me.nodename !== nodename)) {
-	    me.nodename = nodename;
-	    change = true;
-	}
-
-	if (!(me.storage && me.nodename && change)) {
-	    return;
-	}
-
-	var url = '/api2/json/nodes/' + me.nodename + '/storage/' + me.storage + '/content';
-	if (me.storageContent) {
-	    url += '?content=' + me.storageContent;
-	}
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url
-	});
-
-	me.store.removeAll();
-	me.store.load();
-    },
-
-    setNodename: function(nodename) {
-	this.setStorage(undefined, nodename);
-    },
-
-    store: {
-	model: 'pve-storage-content'
-    },
-
-    allowBlank: false,
-    autoSelect: false,
-    valueField: 'volid',
-    displayField: 'text',
-
-    listConfig: {
-	width: 600,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'text',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Format'),
-		width: 60,
-		dataIndex: 'format'
-	    },
-	    {
-		header: gettext('Size'),
-		width: 100,
-		dataIndex: 'size',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.StorageSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveStorageSelector',
-
-    allowBlank: false,
-    valueField: 'storage',
-    displayField: 'storage',
-    listConfig: {
-	width: 450,
-	columns: [
-	    {
-		header: gettext('Name'),
-		dataIndex: 'storage',
-		hideable: false,
-		flex: 1
-	    },
-	    {
-		header: gettext('Type'),
-		width: 75,
-		dataIndex: 'type'
-	    },
-	    {
-		header: gettext('Avail'),
-		width: 90,
-		dataIndex: 'avail',
-		renderer: Proxmox.Utils.format_size
-	    },
-	    {
-		header: gettext('Capacity'),
-		width: 90,
-		dataIndex: 'total',
-		renderer: Proxmox.Utils.format_size
-	    }
-	]
-    },
-
-    reloadStorageList: function() {
-	var me = this;
-	if (!me.nodename) {
-	    return;
-	}
-
-	var params = {
-	    format: 1
-	};
-	var url = '/api2/json/nodes/' + me.nodename + '/storage';
-	if (me.storageContent) {
-	    params.content = me.storageContent;
-	}
-	if (me.targetNode) {
-	    params.target = me.targetNode;
-	    params.enabled = 1; // skip disabled storages
-	}
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: url,
-	    extraParams: params
-	});
-
-	me.store.load();
- 
-    },
-
-    setTargetNode: function(targetNode) {
-	var me = this;
-
-	if (!targetNode || (me.targetNode === targetNode)) {
-	    return;
-	}
-
-	me.targetNode = targetNode;
-
-	me.reloadStorageList();
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.reloadStorageList();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-status',
-	    sorters: {
-		property: 'storage', 
-		order: 'DESC' 
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	if (nodename) {
-	    me.setNodename(nodename);
-	}
-    }
-}, function() {
-
-    Ext.define('pve-storage-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 'storage', 'active', 'type', 'avail', 'total' ],
-	idProperty: 'storage'
-    });
-
-});
-Ext.define('PVE.form.DiskStorageSelector', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveDiskStorageSelector',
-
-    layout: 'fit',
-    defaults: {
-	margin: '0 0 5 0'
-    },
-
-    // the fieldLabel for the storageselector
-    storageLabel: gettext('Storage'),
-
-    // the content to show (e.g., images or rootdir)
-    storageContent: undefined,
-
-    // if true, selects the first available storage
-    autoSelect: false,
-
-    allowBlank: false,
-    emptyText: '',
-
-    // hides the selection field
-    // this is always hidden on creation,
-    // and only shown when the storage needs a selection and
-    // hideSelection is not true
-    hideSelection: undefined,
-
-    // hides the size field (e.g, for the efi disk dialog)
-    hideSize: false,
-
-    // sets the initial size value
-    // string because else we get a type confusion
-    defaultSize: '32',
-
-    changeStorage: function(f, value) {
-	var me = this;
-	var formatsel = me.getComponent('diskformat');
-	var hdfilesel = me.getComponent('hdimage');
-	var hdsizesel = me.getComponent('disksize');
-
-	// initial store load, and reset/deletion of the storage
-	if (!value) {
-	    hdfilesel.setDisabled(true);
-	    hdfilesel.setVisible(false);
-
-	    formatsel.setDisabled(true);
-	    return;
-	}
-
-	var rec = f.store.getById(value);
-	// if the storage is not defined, or valid,
-	// we cannot know what to enable/disable
-	if (!rec) {
-	    return;
-	}
-
-	var selectformat = false;
-	if (rec.data.format) {
-	    var format = rec.data.format[0]; // 0 is the formats, 1 the default in the backend
-	    delete format.subvol; // we never need subvol in the gui
-	    selectformat = (Ext.Object.getSize(format) > 1);
-	}
-
-	var select = !!rec.data.select_existing && !me.hideSelection;
-
-	formatsel.setDisabled(!selectformat);
-	formatsel.setValue(selectformat ? 'qcow2' : 'raw');
-
-	hdfilesel.setDisabled(!select);
-	hdfilesel.setVisible(select);
-	if (select) {
-	    hdfilesel.setStorage(value);
-	}
-
-	hdsizesel.setDisabled(select || me.hideSize);
-	hdsizesel.setVisible(!select && !me.hideSize);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-	var hdfilesel = me.getComponent('hdimage');
-
-	hdstorage.setNodename(nodename);
-	hdfilesel.setNodename(nodename);
-    },
-
-    setDisabled: function(value) {
-	var me = this;
-	var hdstorage = me.getComponent('hdstorage');
-
-	// reset on disable
-	if (value) {
-	    hdstorage.setValue();
-	}
-	hdstorage.setDisabled(value);
-
-	// disabling does not always fire this event and we do not need
-	// the value of the validity
-	hdstorage.fireEvent('validitychange');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'pveStorageSelector',
-		itemId: 'hdstorage',
-		name: 'hdstorage',
-		reference: 'hdstorage',
-		fieldLabel: me.storageLabel,
-		nodename: me.nodename,
-		storageContent: me.storageContent,
-		disabled: me.disabled,
-		autoSelect: me.autoSelect,
-		allowBlank: me.allowBlank,
-		emptyText: me.emptyText,
-		listeners: {
-		    change: {
-			fn: me.changeStorage,
-			scope: me
-		    }
-		}
-	    },
-	    {
-		xtype: 'pveFileSelector',
-		name: 'hdimage',
-		reference: 'hdimage',
-		itemId: 'hdimage',
-		fieldLabel: gettext('Disk image'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: true
-	    },
-	    {
-		xtype: 'numberfield',
-		itemId: 'disksize',
-		reference: 'disksize',
-		name: 'disksize',
-		fieldLabel: gettext('Disk size') + ' (GiB)',
-		hidden: me.hideSize,
-		disabled: me.hideSize,
-		minValue: 0.001,
-		maxValue: 128*1024,
-		decimalPrecision: 3,
-		value: me.defaultSize,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveDiskFormatSelector',
-		itemId: 'diskformat',
-		reference: 'diskformat',
-		name: 'diskformat',
-		fieldLabel: gettext('Format'),
-		nodename: me.nodename,
-		disabled: true,
-		hidden: me.storageContent === 'rootdir',
-		value: 'qcow2',
-		allowBlank: false
-	    }
-	];
-
-	// use it to disable the children but not ourself
-	me.disabled = false;
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.BridgeSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.BridgeSelector'],
-
-    bridgeType: 'any_bridge', // bridge, OVSBridge or any_bridge
-
-    store: {
-	fields: [ 'iface', 'active', 'type' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'iface',
-		direction: 'ASC'
-	    }
-	]
-    },
-    valueField: 'iface',
-    displayField: 'iface',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Bridge'),
-		dataIndex: 'iface',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Active'),
-		width: 60,
-		dataIndex: 'active',
-		renderer: Proxmox.Utils.format_boolean
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comments',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/network?type=' +
-		me.bridgeType
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined; 
-
-        me.callParent();
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.PCISelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pvePCISelector',
-
-    store: {
-	fields: [ 'id','vendor_name', 'device_name', 'vendor', 'device', 'iommugroup', 'mdev' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'id',
-		direction: 'ASC'
-	    }
-	]
-    },
-
-    autoSelect: false,
-    valueField: 'id',
-    displayField: 'id',
-
-    // can contain a load callback for the store
-    // useful to determine the state of the IOMMU
-    onLoadCallBack: undefined,
-
-    listConfig: {
-	width: 800,
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'id',
-		width: 100
-	    },
-	    {
-		header: gettext('IOMMU Group'),
-		dataIndex: 'iommugroup',
-		width: 50
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor_name',
-		flex: 2
-	    },
-	    {
-		header: gettext('Device'),
-		dataIndex: 'device_name',
-		flex: 6
-	    },
-	    {
-		header: gettext('Mediated Devices'),
-		dataIndex: 'mdev',
-		flex: 1,
-		renderer: function(val) {
-		    return Proxmox.Utils.format_boolean(!!val);
-		}
-	    }
-	]
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	me.nodename = undefined;
-
-        me.callParent();
-
-	if (me.onLoadCallBack !== undefined) {
-	    me.mon(me.getStore(), 'load', me.onLoadCallBack);
-	}
-
-	me.setNodename(nodename);
-    }
-});
-
-Ext.define('PVE.form.MDevSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    xtype: 'pveMDevSelector',
-
-    store: {
-	fields: [ 'type','available', 'description' ],
-	filterOnLoad: true,
-	sorters: [
-	    {
-		property : 'type',
-		direction: 'ASC'
-	    }
-	]
-    },
-    autoSelect: false,
-    valueField: 'type',
-    displayField: 'type',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		flex: 1
-	    },
-	    {
-		header: gettext('Available'),
-		dataIndex: 'available',
-		width: 80
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'description',
-		flex: 1,
-		renderer: function(value) {
-		    if (!value) {
-			return '';
-		    }
-
-		    return value.split('\n').join('<br>');
-		}
-	    }
-	]
-    },
-
-    setPciID: function(pciid, force) {
-	var me = this;
-
-	if (!force && (!pciid || (me.pciid === pciid))) {
-	    return;
-	}
-
-	me.pciid = pciid;
-	me.updateProxy();
-    },
-
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-	me.updateProxy();
-    },
-
-    updateProxy: function() {
-	var me = this;
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/hardware/pci/' + me.pciid + '/mdev'
-	});
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw 'no node name specified';
-	}
-
-        me.callParent();
-
-	if (me.pciid) {
-	    me.setPciID(me.pciid, true);
-	}
-    }
-});
-
-Ext.define('PVE.form.SecurityGroupsSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveSecurityGroupsSelector'],
-
-    valueField: 'group',
-    displayField: 'group',
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'group', 'comment' ],
-	    idProperty: 'group',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/groups"
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Security Group'),
-			dataIndex: 'group',
-			hideable: false,
-			width: 100
-		    },
-		    {
-			header: gettext('Comment'),  
-			dataIndex: 'comment',
-			renderer: Ext.String.htmlEncode,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPRefSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPRefSelector'],
-
-    base_url: undefined,
-
-    preferredValue: '', // hack: else Form sets dirty flag?
-
-    ref_type: undefined, // undefined = any [undefined, 'ipset' or 'alias']
-
-    valueField: 'ref',
-    displayField: 'ref',
-    notFoundIsValid: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-
-	var url = "/api2/json" + me.base_url;
-	if (me.ref_type) {
-	    url += "?type=" + me.ref_type;
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'type', 'name', 'ref', 'comment' ],
-	    idProperty: 'ref',
-	    proxy: {
-		type: 'proxmox',
-		url: url
-	    },
-	    sorters: {
-		property: 'ref',
-		order: 'DESC'
-	    }
-	});
-
-	var disable_query_for_ips = function(f, value) {
-	    if (value === null || 
-		value.match(/^\d/)) { // IP address starts with \d
-		f.queryDelay = 9999999999; // hack: disable with long delay
-	    } else {
-		f.queryDelay = 10;
-	    }
-	};
-
-	var columns = [];
-
-	if (!me.ref_type) {
-	    columns.push({
-		header: gettext('Type'),
-		dataIndex: 'type',
-		hideable: false,
-		width: 60
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Name'),
-		dataIndex: 'ref',
-		hideable: false,
-		width: 140
-	    },
-	    {
-		header: gettext('Comment'),  
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode,
-		flex: 1
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: { columns: columns }
-	});
-
-	me.on('change', disable_query_for_ips);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.form.IPProtocolSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveIPProtocolSelector'],
-    valueField: 'p',
-    displayField: 'p',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'p',
-		hideable: false,
-		sortable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Number'),
-		dataIndex: 'n',
-		hideable: false,
-		sortable: false,
-		width: 50
-	    },
-	    {
-		header: gettext('Description'),
-		dataIndex: 'd',
-		hideable: false,
-		sortable: false,
-		flex: 1
-	    }
-	]
-    },
-    store: {
-	    fields: [ 'p', 'd', 'n'],
-	    data: [
-		{ p: 'tcp', n: 6, d: 'Transmission Control Protocol' },
-		{ p: 'udp', n: 17, d: 'User Datagram Protocol' },
-		{ p: 'icmp', n: 1, d: 'Internet Control Message Protocol' },
-		{ p: 'igmp', n: 2,  d: 'Internet Group Management' },
-		{ p: 'ggp', n: 3, d: 'gateway-gateway protocol' },
-		{ p: 'ipencap', n: 4, d: 'IP encapsulated in IP' },
-		{ p: 'st', n: 5, d: 'ST datagram mode' },
-		{ p: 'egp', n: 8, d: 'exterior gateway protocol' },
-		{ p: 'igp', n: 9, d: 'any private interior gateway (Cisco)' },
-		{ p: 'pup', n: 12, d: 'PARC universal packet protocol' },
-		{ p: 'hmp', n: 20, d: 'host monitoring protocol' },
-		{ p: 'xns-idp', n: 22, d: 'Xerox NS IDP' },
-		{ p: 'rdp', n: 27, d: '"reliable datagram" protocol' },
-		{ p: 'iso-tp4', n: 29, d: 'ISO Transport Protocol class 4 [RFC905]' },
-		{ p: 'dccp', n: 33, d: 'Datagram Congestion Control Prot. [RFC4340]' },
-		{ p: 'xtp', n: 36, d: 'Xpress Transfer Protocol' },
-		{ p: 'ddp', n: 37, d: 'Datagram Delivery Protocol' },
-		{ p: 'idpr-cmtp', n: 38, d: 'IDPR Control Message Transport' },
-		{ p: 'ipv6', n: 41, d: 'Internet Protocol, version 6' },
-		{ p: 'ipv6-route', n: 43, d: 'Routing Header for IPv6' },
-		{ p: 'ipv6-frag', n: 44, d: 'Fragment Header for IPv6' },
-		{ p: 'idrp', n: 45, d: 'Inter-Domain Routing Protocol' },
-		{ p: 'rsvp', n: 46, d: 'Reservation Protocol' },
-		{ p: 'gre', n: 47, d: 'General Routing Encapsulation' },
-		{ p: 'esp', n: 50, d: 'Encap Security Payload [RFC2406]' },
-		{ p: 'ah', n: 51, d: 'Authentication Header [RFC2402]' },
-		{ p: 'skip', n: 57, d: 'SKIP' },
-		{ p: 'ipv6-icmp', n: 58, d: 'ICMP for IPv6' },
-		{ p: 'ipv6-nonxt', n: 59, d: 'No Next Header for IPv6' },
-		{ p: 'ipv6-opts', n: 60, d: 'Destination Options for IPv6' },
-		{ p: 'vmtp', n: 81, d: 'Versatile Message Transport' },
-		{ p: 'eigrp', n: 88, d: 'Enhanced Interior Routing Protocol (Cisco)' },
-		{ p: 'ospf', n: 89, d: 'Open Shortest Path First IGP' },
-		{ p: 'ax.25', n: 93, d: 'AX.25 frames' },
-		{ p: 'ipip', n: 94, d: 'IP-within-IP Encapsulation Protocol' },
-		{ p: 'etherip', n: 97, d: 'Ethernet-within-IP Encapsulation [RFC3378]' },
-		{ p: 'encap', n: 98, d: 'Yet Another IP encapsulation [RFC1241]' },
-		{ p: 'pim', n: 103, d: 'Protocol Independent Multicast' },
-		{ p: 'ipcomp', n: 108, d: 'IP Payload Compression Protocol' },
-		{ p: 'vrrp', n: 112, d: 'Virtual Router Redundancy Protocol [RFC5798]' },
-		{ p: 'l2tp', n: 115, d: 'Layer Two Tunneling Protocol [RFC2661]' },
-		{ p: 'isis', n: 124, d: 'IS-IS over IPv4' },
-		{ p: 'sctp', n: 132, d: 'Stream Control Transmission Protocol' },
-		{ p: 'fc', n: 133, d: 'Fibre Channel' },
-		{ p: 'mobility-header', n: 135, d: 'Mobility Support for IPv6 [RFC3775]' },
-		{ p: 'udplite', n: 136, d: 'UDP-Lite [RFC3828]' },
-		{ p: 'mpls-in-ip', n: 137, d: 'MPLS-in-IP [RFC4023]' },
-		{ p: 'hip', n: 139, d: 'Host Identity Protocol' },
-		{ p: 'shim6', n: 140, d: 'Shim6 Protocol [RFC5533]' },
-		{ p: 'wesp', n: 141, d: 'Wrapped Encapsulating Security Payload' },
-		{ p: 'rohc', n: 142, d: 'Robust Header Compression' }
-	    ]
-	}
-});
-Ext.define('PVE.form.CPUModelSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.CPUModelSelector'],
-
-    valueField: 'value',
-    displayField: 'value',
-
-    emptyText: Proxmox.Utils.defaultText + ' (kvm64)',
-    allowBlank: true,
-
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-    autoSelect: false,
-
-    deleteEmpty: true,
-
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Model'),
-		dataIndex: 'value',
-		hideable: false,
-		sortable: true,
-		flex: 2
-	    },
-	    {
-		header: gettext('Vendor'),
-		dataIndex: 'vendor',
-		hideable: false,
-		sortable: true,
-		flex: 1
-	    }
-	],
-	width: 320
-    },
-
-    store: {
-	fields: [ 'value', 'vendor' ],
-	data: [
-	    {
-		value: 'athlon',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'phenom',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'Opteron_G1',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'Opteron_G2',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'Opteron_G3',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'Opteron_G4',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'Opteron_G5',
-		vendor: 'AMD'
-	    },
-	    {
-		value: 'EPYC',
-		vendor: 'AMD'
-	    },
-	    {
-		value: '486',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'core2duo',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'coreduo',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'pentium',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'pentium2',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'pentium3',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Conroe',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Penryn',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Nehalem',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Westmere',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'SandyBridge',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'IvyBridge',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Haswell',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Haswell-noTSX',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Broadwell',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Broadwell-noTSX',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Skylake-Client',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Skylake-Server',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'Cascadelake-Server',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'KnightsMill',
-		vendor: 'Intel'
-	    },
-	    {
-		value: 'kvm32',
-		vendor: 'QEMU'
-	    },
-	    {
-		value: 'kvm64',
-		vendor: 'QEMU'
-	    },
-	    {
-		value: 'qemu32',
-		vendor: 'QEMU'
-	    },
-	    {
-		value: 'qemu64',
-		vendor: 'QEMU'
-	    },
-	    {
-		value: 'host',
-		vendor: 'Host'
-	    }
-	]
-    }
-});
-Ext.define('PVE.form.VNCKeyboardSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.VNCKeyboardSelector'],
-    comboItems: PVE.Utils.kvm_keymap_array()
-});
-Ext.define('PVE.form.CacheTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.CacheTypeSelector'],
-    comboItems: [
-	['__default__', Proxmox.Utils.defaultText + " (" + gettext('No cache') + ")"],
-	['directsync', 'Direct sync'],
-	['writethrough', 'Write through'],
-	['writeback', 'Write back'],
-	['unsafe', 'Write back (' + gettext('unsafe') + ')'],
-	['none', gettext('No cache')]
-    ]
-});
-Ext.define('PVE.form.SnapshotSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.PVE.form.SnapshotSelector'],
-
-    valueField: 'name',
-    displayField: 'name',
-
-    loadStore: function(nodename, vmid) {
-	var me = this;
-
-	if (!nodename) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-        if (!vmid) {
-	    return;
-        }
-
-	me.vmid = vmid;
-
-	me.store.setProxy({
-	    type: 'proxmox',
-	    url: '/api2/json/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid +'/snapshot'
-	});
-
-	me.store.load();
-    },
-
-    initComponent: function() {
-	var me = this;
-
-        if (!me.nodename) {
-            throw "no node name specified";
-        }
-
-        if (!me.vmid) {
-            throw "no VM ID specified";
-        }
-
-	if (!me.guestType) {
-	    throw "no guest type specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'name'],
-	    filterOnLoad: true
-	});
-
-	Ext.apply(me, {
-	    store: store,
-            listConfig: {
-		columns: [
-		    {
-			header: gettext('Snapshot'),
-			dataIndex: 'name',
-			hideable: false,
-			flex: 1
-		    }
-		]
-	    }
-	});
-
-        me.callParent();
-
-	me.loadStore(me.nodename, me.vmid);
-    }
-});
-Ext.define('PVE.form.ContentTypeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveContentTypeSelector'],
-
-    cts: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	me.comboItems = [];
-
-	if (me.cts === undefined) {
-	    me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir', 'snippets'];
-	}
-
-	Ext.Array.each(me.cts, function(ct) {
-	    me.comboItems.push([ct, PVE.Utils.format_content_types(ct)]);
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.HotplugFeatureSelector', {
-    extend: 'Ext.form.CheckboxGroup',
-    alias: 'widget.pveHotplugFeatureSelector',
-
-    columns: 1,
-    vertical: true,
-
-    defaults: {
-	name: 'hotplug',
-	submitValue: false
-    },
-    items: [
-	{
-	    boxLabel: gettext('Disk'),
-	    inputValue: 'disk',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Network'),
-	    inputValue: 'network',
-	    checked: true
-	},
-	{
-	    boxLabel: 'USB',
-	    inputValue: 'usb',
-	    checked: true
-	},
-	{
-	    boxLabel: gettext('Memory'),
-	    inputValue: 'memory'
-	},
-	{
-	    boxLabel: gettext('CPU'),
-	    inputValue: 'cpu'
-	}
-    ],
-
-    setValue: function(value) {
-	var me = this;
-	var newVal = [];
-	if (value === '1') {
-	    newVal = ['disk', 'network', 'usb'];
-	} else if (value !== '0') {
-	    newVal = value.split(',');
-	}
-	me.callParent([{ hotplug: newVal }]);
-    },
-
-    // override framework function to
-    // assemble the hotplug value
-    getSubmitData: function() {
-	var me = this,
-	boxes = me.getBoxes(),
-	data = [];
-	Ext.Array.forEach(boxes, function(box){
-	    if (box.getValue()) {
-		data.push(box.inputValue);
-	    }
-	});
-
-	/* because above is hotplug an array */
-	/*jslint confusion: true*/
-	if (data.length === 0) {
-	    return { 'hotplug':'0' };
-	} else {
-	    return { 'hotplug': data.join(',') };
-	}
-    }
-
-});
-Ext.define('PVE.form.AgentFeatureSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: ['widget.pveAgentFeatureSelector'],
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    boxLabel: Ext.String.format(gettext('Use {0}'), 'QEMU Guest Agent'),
-	    name: 'enabled',
-	    reference: 'enabled',
-	    uncheckedValue: 0,
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    boxLabel: gettext('Run guest-trim after clone disk'),
-	    name: 'fstrim_cloned_disks',
-	    bind: {
-		disabled: '{!enabled.checked}',
-	    },
-	    disabled: true
-	},
-	{
-	    xtype: 'displayfield',
-	    userCls: 'pmx-hint',
-	    value: gettext('Make sure the QEMU Guest Agent is installed in the VM'),
-	    bind: {
-		hidden: '{!enabled.checked}',
-	    },
-	},
-    ],
-
-    advancedItems: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'type',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: 'Type',
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText + " (VirtIO)"],
-		['virtio', 'VirtIO'],
-		['isa', 'ISA'],
-	    ],
-	}
-    ],
-
-    onGetValues: function(values) {
-	var agentstr = PVE.Parser.printPropertyString(values, 'enabled');
-	return { agent: agentstr };
-    },
-
-    setValues: function(values) {
-	let res = PVE.Parser.parsePropertyString(values.agent, 'enabled');
-	this.callParent([res]);
-    }
-});
-Ext.define('PVE.form.iScsiProviderSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveiScsiProviderSelector'],
-    comboItems: [
-	['comstar', 'Comstar'],
-	[ 'istgt', 'istgt'],
-	[ 'iet', 'IET'],
-	[ 'LIO', 'LIO']
-    ]
-});
-Ext.define('PVE.form.DayOfWeekSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveDayOfWeekSelector'],
-    comboItems:[],
-    initComponent: function(){
-	var me = this;
-	me.comboItems = [
-	    ['mon', Ext.util.Format.htmlDecode(Ext.Date.dayNames[1])],
-	    ['tue', Ext.util.Format.htmlDecode(Ext.Date.dayNames[2])],
-	    ['wed', Ext.util.Format.htmlDecode(Ext.Date.dayNames[3])],
-	    ['thu', Ext.util.Format.htmlDecode(Ext.Date.dayNames[4])],
-	    ['fri', Ext.util.Format.htmlDecode(Ext.Date.dayNames[5])],
-	    ['sat', Ext.util.Format.htmlDecode(Ext.Date.dayNames[6])],
-	    ['sun', Ext.util.Format.htmlDecode(Ext.Date.dayNames[0])]
-	];
-	this.callParent();
-    }
-});
-Ext.define('PVE.form.BackupModeSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveBackupModeSelector'],
-    comboItems: [
-                ['snapshot', gettext('Snapshot')],
-                ['suspend', gettext('Suspend')],
-                ['stop', gettext('Stop')]
-    ]
-});
-Ext.define('PVE.form.ScsiHwSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveScsiHwSelector'],
-    comboItems: [
-	['__default__', PVE.Utils.render_scsihw('')],
-	['lsi', PVE.Utils.render_scsihw('lsi')],
-	['lsi53c810', PVE.Utils.render_scsihw('lsi53c810')],
-	['megasas', PVE.Utils.render_scsihw('megasas')],
-	['virtio-scsi-pci', PVE.Utils.render_scsihw('virtio-scsi-pci')],
-	['virtio-scsi-single', PVE.Utils.render_scsihw('virtio-scsi-single')],
-	['pvscsi', PVE.Utils.render_scsihw('pvscsi')]
-    ]
-});
-Ext.define('PVE.form.FirewallPolicySelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallPolicySelector'],
-    comboItems: [
-	    ['ACCEPT', 'ACCEPT'],
-	    ['REJECT', 'REJECT'],
-	    [ 'DROP', 'DROP']
-	]
-});
-/*
- *  This is a global search field
- *  it loads the /cluster/resources on focus
- *  and displays the result in a floating grid
- *
- *  it filters and sorts the objects by the algorithm in
- *  the customFilter function
- *
- *  also it does accept key up/down and enter for input
- *  and it opens to ctrl+shift+f and ctrl+space
- */
-Ext.define('PVE.form.GlobalSearchField', {
-    extend: 'Ext.form.field.Text',
-    alias: 'widget.pveGlobalSearchField',
-
-    emptyText: gettext('Search'),
-    enableKeyEvents: true,
-    selectOnFocus: true,
-    padding: '0 5 0 5',
-
-    grid: {
-	xtype: 'gridpanel',
-	focusOnToFront: false,
-	floating: true,
-	emptyText: Proxmox.Utils.noneText,
-	width: 600,
-	height: 400,
-	scrollable: {
-	    xtype: 'scroller',
-	    y: true,
-	    x:false
-	},
-	store: {
-	    model: 'PVEResources',
-	    proxy:{
-		type: 'proxmox',
-		url: '/api2/extjs/cluster/resources'
-	    }
-	},
-	plugins: {
-	    ptype: 'bufferedrenderer',
-	    trailingBufferZone: 20,
-	    leadingBufferZone: 20
-	},
-
-	hideMe: function() {
-	    var me = this;
-	    if (typeof me.ctxMenu !== 'undefined' && me.ctxMenu.isVisible()) {
-		return;
-	    }
-	    me.hasFocus = false;
-	    if (!me.textfield.hasFocus) {
-		me.hide();
-	    }
-	},
-
-	setFocus: function() {
-	    var me = this;
-	    me.hasFocus = true;
-	},
-
-	listeners: {
-	    rowclick: function(grid, record) {
-		var me = this;
-		me.textfield.selectAndHide(record.id);
-	    },
-	    itemcontextmenu: function(v, record, item, index, event) {
-		var me = this;
-		me.ctxMenu = PVE.Utils.createCmdMenu(v, record, item, index, event);
-	    },
-	    /* because of lint */
-	    focusleave: {
-		fn: 'hideMe'
-	    },
-	    focusenter: 'setFocus'
-	},
-
-	columns: [
-	    {
-		text: gettext('Type'),
-		dataIndex: 'type',
-		width: 100,
-		renderer: PVE.Utils.render_resource_type
-	    },
-	    {
-		text: gettext('Description'),
-		flex: 1,
-		dataIndex: 'text'
-	    },
-	    {
-		text: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		text: gettext('Pool'),
-		dataIndex: 'pool'
-	    }
-	]
-    },
-
-    customFilter: function(item) {
-	var me = this;
-	var match = 0;
-	var fieldArr = [];
-	var i,j, fields;
-
-	// different types of objects have different fields to search
-	// for example, a node will never have a pool and vice versa
-	switch (item.data.type) {
-	    case 'pool': fieldArr = ['type', 'pool', 'text']; break;
-	    case 'node': fieldArr = ['type', 'node', 'text']; break;
-	    case 'storage': fieldArr = ['type', 'pool', 'node', 'storage']; break;
-	    default: fieldArr = ['name', 'type', 'node', 'pool', 'vmid'];
-	}
-	if (me.filterVal === '') {
-	    item.data.relevance = 0;
-	    return true;
-	}
-
-	// all text is case insensitive and each word is
-	// searched alone
-	// for every partial match, the row gets
-	// 1 match point, for every exact match
-	// it gets 2 points
-	//
-	// results gets sorted by points (descending)
-	fields = me.filterVal.split(/\s+/);
-	for(i = 0; i < fieldArr.length; i++) {
-	    var v = item.data[fieldArr[i]];
-	    if (v !== undefined) {
-		v = v.toString().toLowerCase();
-		for(j = 0; j < fields.length; j++) {
-		    if (v.indexOf(fields[j]) !== -1) {
-			match++;
-			if(v === fields[j]) {
-			    match++;
-			}
-		    }
-		}
-	    }
-	}
-	// give the row the 'relevance' value
-	item.data.relevance = match;
-	return (match > 0);
-    },
-
-    updateFilter: function(field, newValue, oldValue) {
-	var me = this;
-	// parse input and filter store,
-	// show grid
-	me.grid.store.filterVal = newValue.toLowerCase().trim();
-	me.grid.store.clearFilter(true);
-	me.grid.store.filterBy(me.customFilter);
-	me.grid.getSelectionModel().select(0);
-    },
-
-    selectAndHide: function(id) {
-	var me = this;
-	me.tree.selectById(id);
-	me.grid.hide();
-	me.setValue('');
-	me.blur();
-    },
-
-    onKey: function(field, e) {
-	var me = this;
-	var key = e.getKey();
-
-	switch(key) {
-	    case Ext.event.Event.ENTER:
-		// go to first entry if there is one
-		if (me.grid.store.getCount() > 0) {
-		    me.selectAndHide(me.grid.getSelection()[0].data.id);
-		}
-		break;
-	    case Ext.event.Event.UP:
-		me.grid.getSelectionModel().selectPrevious();
-		break;
-	    case Ext.event.Event.DOWN:
-		me.grid.getSelectionModel().selectNext();
-		break;
-	    case Ext.event.Event.ESC:
-		me.grid.hide();
-		me.blur();
-		break;
-	}
-    },
-
-    loadValues: function(field) {
-	var me = this;
-	var records = [];
-
-	me.hasFocus = true;
-	me.grid.textfield = me;
-	me.grid.store.load();
-	me.grid.showBy(me, 'tl-bl');
-    },
-
-    hideGrid: function() {
-	var me = this;
-
-	me.hasFocus = false;
-	if (!me.grid.hasFocus) {
-	    me.grid.hide();
-	}
-    },
-
-    listeners: {
-	change: {
-	    fn: 'updateFilter',
-	    buffer: 250
-	},
-	specialkey: 'onKey',
-	focusenter: 'loadValues',
-	focusleave: {
-	    fn: 'hideGrid',
-	    delay: 100
-	}
-    },
-
-    toggleFocus: function() {
-	var me = this;
-	if (!me.hasFocus) {
-	    me.focus();
-	} else {
-	    me.blur();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.tree) {
-	    throw "no tree given";
-	}
-
-	me.grid = Ext.create(me.grid);
-
-	me.callParent();
-
-	/*jslint confusion: true*/
-	/*because shift is also a function*/
-	// bind ctrl+shift+f and ctrl+space
-	// to open/close the search
-	me.keymap = new Ext.KeyMap({
-	    target: Ext.get(document),
-	    binding: [{
-		key:'F',
-		ctrl: true,
-		shift: true,
-		fn: me.toggleFocus,
-		scope: me
-	    },{
-		key:' ',
-		ctrl: true,
-		fn: me.toggleFocus,
-		scope: me
-	    }]
-	});
-
-	// always select first item and
-	// sort by relevance after load
-	me.mon(me.grid.store, 'load', function() {
-	    me.grid.getSelectionModel().select(0);
-	    me.grid.store.sort({
-		property: 'relevance',
-		direction: 'DESC'
-	    });
-	});
-    }
-
-});
-Ext.define('PVE.form.QemuBiosSelector', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveQemuBiosSelector'],
-
-    initComponent: function() {
-	var me = this;
-
-        me.comboItems = [
-	    ['__default__', PVE.Utils.render_qemu_bios('')],
-	    ['seabios', PVE.Utils.render_qemu_bios('seabios')],
-	    ['ovmf', PVE.Utils.render_qemu_bios('ovmf')]
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-/* filter is a javascript builtin, but extjs calls it also filter */
-Ext.define('PVE.form.VMSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    allowBlank: true,
-    selectAll: false,
-    isFormField: true,
-
-    plugins: 'gridfilters',
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-    columns: [
-	{
-	    header: 'ID',
-	    dataIndex: 'vmid',
-	    width: 80,
-	    filter: {
-		type: 'number'
-	    }
-	},
-	{
-	    header: gettext('Node'),
-	    dataIndex: 'node'
-	},
-	{
-	    header: gettext('Status'),
-	    dataIndex: 'status',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1,
-	    filter: {
-		type: 'string'
-	    }
-	},
-	{
-	    header: gettext('Pool'),
-	    dataIndex: 'pool',
-	    filter: {
-		type: 'list'
-	    }
-	},
-	{
-	    header: gettext('Type'),
-	    dataIndex: 'type',
-	    width: 120,
-	    renderer: function(value) {
-		if (value === 'qemu') {
-		    return gettext('Virtual Machine');
-		} else if (value === 'lxc') {
-		    return gettext('LXC Container');
-		}
-
-		return '';
-	    },
-	    filter: {
-		type: 'list',
-		store: {
-		    data: [
-			{id: 'qemu', text: gettext('Virtual Machine')},
-			{id: 'lxc', text: gettext('LXC Container')}
-		    ],
-		    // due to EXTJS-18711
-		    // we have to do a static list via a store
-		    // but to avoid creating an object,
-		    // we have to have a pseudo un function
-		    un: function(){}
-		}
-	    }
-	},
-	{
-	    header: 'HA ' + gettext('Status'),
-	    dataIndex: 'hastate',
-	    flex: 1,
-	    filter: {
-		type: 'list'
-	    }
-	}
-    ],
-
-    selModel: {
-	selType: 'checkboxmodel',
-	mode: 'SIMPLE'
-    },
-
-    checkChangeEvents: [
-	'selectionchange',
-	'change'
-    ],
-
-    listeners: {
-	selectionchange: function() {
-	    // to trigger validity and error checks
-	    this.checkChange();
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	var selection = sm.getSelection();
-	var values = [];
-	var store = me.getStore();
-	selection.forEach(function(item) {
-	    // only add if not filtered
-	    if (store.findExact('vmid', item.data.vmid) !== -1) {
-		values.push(item.data.vmid);
-	    }
-	});
-	return values;
-    },
-
-    setValue: function(value) {
-	console.log(value);
-	var me = this;
-	var sm = me.getSelectionModel();
-	if (!Ext.isArray(value)) {
-	    value = value.split(',');
-	}
-	var selection = [];
-	var store = me.getStore();
-
-	value.forEach(function(item) {
-	    var rec = store.findRecord('vmid',item, 0, false, true, true);
-	    console.log(store);
-
-	    if (rec) {
-		console.log(rec);
-		selection.push(rec);
-	    }
-	});
-
-	sm.select(selection);
-
-	return me.mixins.field.setValue.call(me, value);
-    },
-
-    getErrors: function(value) {
-	var me = this;
-	if (me.allowBlank ===  false &&
-	    me.getSelectionModel().getCount() === 0) {
-	    me.addBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	    return [gettext('No VM selected')];
-	}
-
-	me.removeBodyCls(['x-form-trigger-wrap-default','x-form-trigger-wrap-invalid']);
-	return [];
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-
-	if (me.nodename) {
-	    me.store.filters.add({
-		property: 'node',
-		exactMatch: true,
-		value: me.nodename
-	    });
-	}
-
-	// only show the relevant guests by default
-	if (me.action) {
-	    var statusfilter = '';
-	    switch (me.action) {
-		case 'startall':
-		    statusfilter = 'stopped';
-		    break;
-		case 'stopall':
-		    statusfilter = 'running';
-		    break;
-	    }
-	    if (statusfilter !== '') {
-		me.store.filters.add({
-		    property: 'template',
-		    value: 0
-		},{
-		    id: 'x-gridfilter-status',
-		    operator: 'in',
-		    property: 'status',
-		    value: [statusfilter]
-		});
-	    }
-	}
-
-	var store = me.getStore();
-	var sm = me.getSelectionModel();
-
-	if (me.selectAll) {
-	    me.mon(store,'load', function(){
-		me.getSelectionModel().selectAll(false);
-	    });
-	}
-    }
-});
-
-
-Ext.define('PVE.form.VMComboSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.vmComboSelector',
-
-    valueField: 'vmid',
-    displayField: 'vmid',
-
-    autoSelect: false,
-    editable: true,
-    anyMatch: true,
-    forceSelection: true,
-
-    store: {
-	model: 'PVEResources',
-	autoLoad: true,
-	sorters: 'vmid',
-	filters: [{
-	    property: 'type',
-	    value: /lxc|qemu/
-	}]
-    },
-
-    listConfig: {
-	width: 600,
-	plugins: 'gridfilters',
-	columns: [
-	    {
-		header: 'ID',
-		dataIndex: 'vmid',
-		width: 80,
-		filter: {
-		    type: 'number'
-		}
-	    },
-	    {
-		header: gettext('Name'),
-		dataIndex: 'name',
-		flex: 1,
-		filter: {
-		    type: 'string'
-		}
-	    },
-	    {
-		header: gettext('Node'),
-		dataIndex: 'node'
-	    },
-	    {
-		header: gettext('Status'),
-		dataIndex: 'status',
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Pool'),
-		dataIndex: 'pool',
-		hidden: true,
-		filter: {
-		    type: 'list'
-		}
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		width: 120,
-		renderer: function(value) {
-		    if (value === 'qemu') {
-			return gettext('Virtual Machine');
-		    } else if (value === 'lxc') {
-			return gettext('LXC Container');
-		    }
-
-		    return '';
-		},
-		filter: {
-		    type: 'list',
-		    store: {
-			data: [
-			    {id: 'qemu', text: gettext('Virtual Machine')},
-			    {id: 'lxc', text: gettext('LXC Container')}
-			],
-			un: function(){} // due to EXTJS-18711
-		    }
-		}
-	    },
-	    {
-		header: 'HA ' + gettext('Status'),
-		dataIndex: 'hastate',
-		hidden: true,
-		flex: 1,
-		filter: {
-		    type: 'list'
-		}
-	    }
-	]
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.form.VMCPUFlagSelector', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.vmcpuflagselector',
-
-    mixins: {
-	field: 'Ext.form.field.Field'
-    },
-
-    disableSelection: true,
-    columnLines: false,
-    selectable: false,
-    hideHeaders: true,
-
-    scrollable: 'y',
-    height: 200,
-
-    unkownFlags: [],
-
-    store: {
-	type: 'store',
-	fields: ['flag', { name: 'state', defaultValue: '=' }, 'desc'],
-	data: [
-	    // FIXME: let qemu-server host this and autogenerate or get from API call??
-	    { flag: 'md-clear', desc: 'Required to let the guest OS know if MDS is mitigated correctly' },
-	    { flag: 'pcid', desc: 'Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs' },
-	    { flag: 'spec-ctrl', desc: 'Allows improved Spectre mitigation with Intel CPUs' },
-	    { flag: 'ssbd', desc: 'Protection for "Speculative Store Bypass" for Intel models' },
-	    { flag: 'ibpb', desc: 'Allows improved Spectre mitigation with AMD CPUs' },
-	    { flag: 'virt-ssbd', desc: 'Basis for "Speculative Store Bypass" protection for AMD models' },
-	    { flag: 'amd-ssbd', desc: 'Improves Spectre mitigation performance with AMD CPUs, best used with "virt-ssbd"' },
-	    { flag: 'amd-no-ssb', desc: 'Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs' },
-	    { flag: 'pdpe1gb', desc: 'Allow guest OS to use 1GB size pages, if host HW supports it' },
-	    { flag: 'hv-tlbflush', desc: 'Improve performance in overcommitted Windows guests. May lead to guest bluescreens on old CPUs.' },
-	    { flag: 'hv-evmcs', desc: 'Improve performance for nested virtualization. Only supported on Intel CPUs.' },
-	    { flag: 'aes', desc: 'Activate AES instruction set for HW acceleration.' }
-	],
-	listeners: {
-	    update: function() {
-		this.commitChanges();
-	    }
-	}
-    },
-
-    getValue: function() {
-	var me = this;
-	var store = me.getStore();
-	var flags = '';
-
-	// ExtJS does not has a nice getAllRecords interface for stores :/
-	store.queryBy(Ext.returnTrue).each(function(rec) {
-	    var s = rec.get('state');
-	    if (s && s !== '=') {
-		var f = rec.get('flag');
-		if (flags === '') {
-		    flags = s + f;
-		} else {
-		    flags += ';' + s + f;
-		}
-	    }
-	});
-
-	flags += me.unkownFlags.join(';');
-
-	return flags;
-    },
-
-    setValue: function(value) {
-	var me = this;
-	var store = me.getStore();
-
-	me.value = value || '';
-
-	me.unkownFlags = [];
-
-	me.getStore().queryBy(Ext.returnTrue).each(function(rec) {
-	    rec.set('state', '=');
-	});
-
-	var flags = value ? value.split(';') : [];
-	flags.forEach(function(flag) {
-	    var sign = flag.substr(0, 1);
-	    flag = flag.substr(1);
-
-	    var rec = store.findRecord('flag', flag);
-	    if (rec !== null) {
-		rec.set('state', sign);
-	    } else {
-		me.unkownFlags.push(flag);
-	    }
-	});
-	store.reload();
-
-	var res = me.mixins.field.setValue.call(me, value);
-
-	return res;
-    },
-    columns: [
-	{
-	    dataIndex: 'state',
-	    renderer: function(v) {
-		switch(v) {
-		    case '=': return 'Default';
-		    case '-': return 'Off';
-		    case '+': return 'On';
-		    default: return 'Unknown';
-		}
-	    },
-	    width: 65
-	},
-	{
-	    xtype: 'widgetcolumn',
-	    dataIndex: 'state',
-	    width: 95,
-	    onWidgetAttach: function (column, widget, record) {
-		var val = record.get('state') || '=';
-		widget.down('[inputValue=' + val + ']').setValue(true);
-		// TODO: disable if selected CPU model and flag are incompatible
-	    },
-	    widget: {
-		xtype: 'radiogroup',
-		hideLabel: true,
-		layout: 'hbox',
-		validateOnChange: false,
-		value: '=',
-		listeners: {
-		    change: function(f, value) {
-			var v = Object.values(value)[0];
-			f.getWidgetRecord().set('state', v);
-
-			var view = this.up('grid');
-			view.dirty = view.getValue() !== view.originalValue;
-			view.checkDirty();
-			//view.checkChange();
-		    }
-		},
-		items: [
-		    {
-			boxLabel: '-',
-			boxLabelAlign: 'before',
-			inputValue: '-'
-		    },
-		    {
-			checked: true,
-			inputValue: '='
-		    },
-		    {
-			boxLabel: '+',
-			inputValue: '+'
-		    }
-		]
-	    }
-	},
-	{
-	    dataIndex: 'flag',
-	    width: 100
-	},
-	{
-	    dataIndex: 'desc',
-	    cellWrap: true,
-	    flex: 1
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	// static class store, thus gets not recreated, so ensure defaults are set!
-	me.getStore().data.forEach(function(v) {
-	    v.state = '=';
-	});
-
-	me.value = me.originalValue = '';
-
-	me.callParent(arguments);
-    }
-});
-Ext.define('PVE.form.USBSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveUSBSelector'],
-
-    allowBlank: false,
-    autoSelect: false,
-    anyMatch: true,
-    displayField: 'product_and_id',
-    valueField: 'usbid',
-    editable: true,
-
-    validator: function(value) {
-	var me = this;
-	if (!value) {
-	    return true; // handled later by allowEmpty in the getErrors call chain
-	}
-	value = me.getValue(); // as the valueField is not the displayfield
-	if (me.type === 'device') {
-	    return (/^[a-f0-9]{4}\:[a-f0-9]{4}$/i).test(value);
-	} else if (me.type === 'port') {
-	    return (/^[0-9]+\-[0-9]+(\.[0-9]+)*$/).test(value);
-	}
-	return gettext("Invalid Value");
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	if (!nodename) {
-	    throw "no nodename specified";
-	}
-
-	if (me.type !== 'device' && me.type !== 'port') {
-	    throw "no valid type specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-usb-' + me.type,
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/scan/usb"
-	    },
-	    filters: [
-		function (item) {
-		    return !!item.data.usbpath && !!item.data.prodid && item.data['class'] != 9;
-		}
-	    ]
-	});
-	let emptyText = '';
-	if (me.type === 'device') {
-	    emptyText = gettext('Passthrough a specific device');
-	} else {
-	    emptyText = gettext('Passthrough a full port');
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    emptyText: emptyText,
-	    listConfig: {
-		width: 520,
-		columns: [
-		    {
-			header: (me.type === 'device')?gettext('Device'):gettext('Port'),
-			sortable: true,
-			dataIndex: 'usbid',
-			width: 80
-		    },
-		    {
-			header: gettext('Manufacturer'),
-			sortable: true,
-			dataIndex: 'manufacturer',
-			width: 150
-		    },
-		    {
-			header: gettext('Product'),
-			sortable: true,
-			dataIndex: 'product',
-			flex: 1
-		    },
-		    {
-			header: gettext('Speed'),
-			width: 75,
-			sortable: true,
-			dataIndex: 'speed',
-			renderer: function(value) {
-			    let speed_map = {
-				"10000"  : "USB 3.1",
-				 "5000"  : "USB 3.0",
-				  "480"  : "USB 2.0",
-				   "12"  : "USB 1.x",
-				    "1.5": "USB 1.x",
-			    };
-			    return speed_map[value] || value + " Mbps";
-			}
-		    }
-		]
-	    },
-	});
-
-        me.callParent();
-
-	store.load();
-    }
-
-}, function() {
-
-    Ext.define('pve-usb-device', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val, data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('vendid') + ':' + data.get('prodid');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' },
-	    {
-		name: 'product_and_id',
-		type: 'string',
-		convert: (v, rec) => {
-		    let res = rec.data.product || gettext('Unkown');
-		    res += " (" + rec.data.usbid + ")";
-		    return res;
-		},
-	    },
-	]
-    });
-
-    Ext.define('pve-usb-port', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    {
-		name: 'usbid',
-		convert: function(val,data) {
-		    if (val) {
-			return val;
-		    }
-		    return data.get('busnum') + '-' + data.get('usbpath');
-		}
-	    },
-	    'speed', 'product', 'manufacturer', 'vendid', 'prodid', 'usbpath',
-	    { name: 'port' , type: 'number' },
-	    { name: 'level' , type: 'number' },
-	    { name: 'class' , type: 'number' },
-	    { name: 'devnum' , type: 'number' },
-	    { name: 'busnum' , type: 'number' },
-	    {
-		name: 'product_and_id',
-		type: 'string',
-		convert: (v, rec) => {
-		    let res = rec.data.product || gettext('Unplugged');
-		    res += " (" + rec.data.usbid + ")";
-		    return res;
-		},
-	    },
-	]
-    });
-});
-Ext.define('PVE.form.CalendarEvent', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pveCalendarEvent',
-
-    editable: true,
-
-    valueField: 'value',
-    displayField: 'text',
-    queryMode: 'local',
-
-    store: {
-	field: [ 'value', 'text'],
-	data: [
-	    { value: '*/30', text: Ext.String.format(gettext("Every {0} minutes"), 30) },
-	    { value: '*/2:00', text: gettext("Every two hours")},
-	    { value: '2,22:30', text: gettext("Every day") + " 02:30, 22:30"},
-	    { value: 'mon..fri', text: gettext("Monday to Friday") + " 00:00"},
-	    { value: 'mon..fri */1:00', text: gettext("Monday to Friday") + ': ' +  gettext("hourly")},
-	    { value: 'sun 01:00', text: gettext("Sunday") + " 01:00"}
-	]
-    },
-
-    tpl: [
-	'<ul class="x-list-plain"><tpl for=".">',
-	    '<li role="option" class="x-boundlist-item">{text}</li>',
-	'</tpl></ul>'
-    ],
-
-    displayTpl: [
-	'<tpl for=".">',
-	'{value}',
-	'</tpl>'
-    ]
-
-});
-Ext.define('PVE.form.CephPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephPoolSelector',
-
-    allowBlank: false,
-    valueField: 'pool_name',
-    displayField: 'pool_name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/pools'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-        me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.form.PermPathSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    xtype: 'pvePermPathSelector',
-
-    valueField: 'value',
-    displayField: 'value',
-    typeAhead: true,
-    queryMode: 'local',
-    store: {
-	type: 'pvePermPath'
-    }
-});
-Ext.define('PVE.form.SpiceEnhancementSelector', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveSpiceEnhancementSelector',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'foldersharing',
-	    name: 'foldersharing',
-	    reference: 'foldersharing',
-	    fieldLabel: 'Folder Sharing',
-	    uncheckedValue: 0,
-	},
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    itemId: 'videostreaming',
-	    name: 'videostreaming',
-	    value: 'off',
-	    fieldLabel: 'Video Streaming',
-	    comboItems: [
-		['off', 'off'],
-		['all', 'all'],
-		['filter', 'filter'],
-	    ],
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'spicehint',
-	    userCls: 'pmx-hint',
-	    value: gettext('To use these features set the display to SPICE in the hardware settings of the VM.'),
-	    hidden: true,
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'spicefolderhint',
-	    userCls: 'pmx-hint',
-	    value: gettext('Make sure the SPICE WebDav daemon is installed in the VM.'),
-	    bind: {
-		hidden: '{!foldersharing.checked}',
-	    }
-	}
-    ],
-
-    onGetValues: function(values) {
-	var ret = {};
-
-	if (values.videostreaming !== "off") {
-	    ret.videostreaming = values.videostreaming;
-	}
-	if (values.foldersharing) {
-	    ret.foldersharing = 1;
-	}
-	if (Ext.Object.isEmpty(ret)) {
-	    return { 'delete': 'spice_enhancements' };
-	}
-	var enhancements = PVE.Parser.printPropertyString(ret);
-	return { spice_enhancements: enhancements };
-    },
-
-    setValues: function(values) {
-	var vga = PVE.Parser.parsePropertyString(values.vga, 'type');
-	if (!/^qxl\d?$/.test(vga.type)) {
-	    this.down('#spicehint').setVisible(true);
-	}
-	if (values.spice_enhancements) {
-	    var enhancements = PVE.Parser.parsePropertyString(values.spice_enhancements);
-	    enhancements['foldersharing'] = PVE.Parser.parseBoolean(enhancements['foldersharing'], 0);
-	    this.callParent([enhancements]);
-	}
-    },
-});
-/* This class defines the "Tasks" tab of the bottom status panel
- * Tasks are jobs with a start, end and log output
- */
-
-Ext.define('PVE.dc.Tasks', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterTasks'],
-
-    initComponent : function() {
-	var me = this;
-
-	var taskstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-tasks',
-	    model: 'proxmox-tasks',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/tasks'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: taskstore,
-	    sortAfterUpdate: true,
-	    appendAtStart: true,
-	    sorters: [
-		{
-		    property : 'pid',
-		    direction: 'DESC'
-		},
-		{
-		    property : 'starttime',
-		    direction: 'DESC'
-		}
-	    ]
-
-	});
-
-	var run_task_viewer = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('Proxmox.window.TaskViewer', {
-		upid: rec.data.upid
-	    });
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true, // does not work with getRowClass()
-
-		getRowClass: function(record, index) {
-		    var status = record.get('status');
-
-		    if (status && status != 'OK') {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{
-		    header: gettext("Start Time"),
-		    dataIndex: 'starttime',
-		    width: 150,
-		    renderer: function(value) {
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("End Time"),
-		    dataIndex: 'endtime',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type == "vncproxy" ||
-				record.data.type == "vncshell" ||
-				record.data.type == "spiceproxy") {
-				metaData.tdCls =  "x-grid-row-console";
-			    } else {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			return Ext.Date.format(value, "M d H:i:s");
-		    }
-		},
-		{
-		    header: gettext("Node"),
-		    dataIndex: 'node',
-		    width: 100
-		},
-		{
-		    header: gettext("User name"),
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{
-		    header: gettext("Description"),
-		    dataIndex: 'upid',
-		    flex: 1,
-		    renderer: Proxmox.Utils.render_upid
-		},
-		{
-		    header: gettext("Status"),
-		    dataIndex: 'status',
-		    width: 200,
-		    renderer: function(value, metaData, record) {
-			if (record.data.pid) {
-			    if (record.data.type != "vncproxy") {
-				metaData.tdCls =  "x-grid-row-loading";
-			    }
-			    return "";
-			}
-			if (value == 'OK') {
-			    return 'OK';
-			}
-			// metaData.attr = 'style="color:red;"';
-			return Proxmox.Utils.errorText + ': ' + value;
-		    }
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_task_viewer,
-		show: taskstore.startUpdate,
-		destroy: taskstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/* This class defines the "Cluster log" tab of the bottom status panel
- * A log entry is a timestamp associated with an action on a cluster
- */
-
-Ext.define('PVE.dc.Log', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveClusterLog'],
-
-    initComponent : function() {
-	var me = this;
-
-	var logstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-cluster-log',
-	    model: 'proxmox-cluster-log',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/log'
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: logstore,
-	    appendAtStart: true 
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-
-	    viewConfig: {
-		trackOver: false,
-		stripeRows: true,
- 
-		getRowClass: function(record, index) {
-		    var pri = record.get('pri');
-
-		    if (pri && pri <= 3) {
-			return "proxmox-invalid-row";
-		    }
-		}
-	    },
-	    sortableColumns: false,
-	    columns: [
-		{ 
-		    header: gettext("Time"), 
-		    dataIndex: 'time',
-		    width: 150,
-		    renderer: function(value) { 
-			return Ext.Date.format(value, "M d H:i:s"); 
-		    }
-		},
-		{ 
-		    header: gettext("Node"), 
-		    dataIndex: 'node',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Service"), 
-		    dataIndex: 'tag',
-		    width: 100
-		},
-		{ 
-		    header: "PID", 
-		    dataIndex: 'pid',
-		    width: 100 
-		},
-		{ 
-		    header: gettext("User name"), 
-		    dataIndex: 'user',
-		    width: 150
-		},
-		{ 
-		    header: gettext("Severity"), 
-		    dataIndex: 'pri',
-		    renderer: PVE.Utils.render_serverity,
-		    width: 100 
-		},
-		{ 
-		    header: gettext("Message"), 
-		    dataIndex: 'msg',
-		    flex: 1	  
-		}
-	    ],
-	    listeners: {
-		activate: logstore.startUpdate,
-		deactivate: logstore.stopUpdate,
-		destroy: logstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * This class describes the bottom panel
- */
-Ext.define('PVE.panel.StatusPanel', {
-    extend: 'Ext.tab.Panel',
-    alias: 'widget.pveStatusPanel',
-
-    
-    //title: "Logs",
-    //tabPosition: 'bottom',
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = 'ltab';
-	var sp = Ext.state.Manager.getProvider();
-
-	var state = sp.get(stateid);
-	if (state && state.value) {
-	    me.activeTab = state.value;
-	}
-
-	Ext.apply(me, {
-	    listeners: {
-		tabchange: function() {
-		    var atab = me.getActiveTab().itemId;
-		    var state = { value: atab };
-		    sp.set(stateid, state);
-		}
-	    },
-	    items: [
-		{
-		    itemId: 'tasks',
-		    title: gettext('Tasks'),
-		    xtype: 'pveClusterTasks'
-		},
-		{
-		    itemId: 'clog',
-		    title: gettext('Cluster log'),
-		    xtype: 'pveClusterLog'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.items.get(0).fireEvent('show', me.items.get(0));
-
-	var statechange = function(sp, key, state) {
-	    if (key === stateid) {
-		var atab = me.getActiveTab().itemId;
-		var ntab = state.value;
-		if (state && ntab && (atab != ntab)) {
-		    me.setActiveTab(ntab);
-		}
-	    }
-	};
-
-	sp.on('statechange', statechange);
-	me.on('destroy', function() {
-	    sp.un('statechange', statechange);		    
-	});
-
-    }
-});
-Ext.define('PVE.panel.StatusView', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStatusView',
-
-    layout: {
-	type: 'column'
-    },
-
-    title: gettext('Status'),
-
-    getRecordValue: function(key, store) {
-	if (!key) {
-	    throw "no key given";
-	}
-	var me = this;
-
-	if (store === undefined) {
-	    store = me.getStore();
-	}
-
-	var rec = store.getById(key);
-	if (rec) {
-	    return rec.data.value;
-	}
-
-	return '';
-    },
-
-    fieldRenderer: function(val,max) {
-	if (max === undefined) {
-	    return val;
-	}
-
-	if (!Ext.isNumeric(max) || max === 1) {
-	    return PVE.Utils.render_usage(val);
-	}
-	return PVE.Utils.render_size_usage(val,max);
-    },
-
-    fieldCalculator: function(used, max) {
-	if (!Ext.isNumeric(max) && Ext.isNumeric(used)) {
-	    return used;
-	} else if(!Ext.isNumeric(used)) {
-	    /* we come here if the field is from a node
-	     * where the records are not mem and maxmem
-	     * but mem.used and mem.total
-	     */
-	    if (used.used !== undefined &&
-		used.total !== undefined) {
-		return used.used/used.total;
-	    }
-	}
-
-	return used/max;
-    },
-
-    updateField: function(field) {
-	var me = this;
-	var text = '';
-	var renderer = me.fieldRenderer;
-	if (Ext.isFunction(field.renderer)) {
-	    renderer = field.renderer;
-	}
-	if (field.multiField === true) {
-	    field.updateValue(renderer.call(field, me.getStore().getRecord()));
-	} else if (field.textField !== undefined) {
-	    field.updateValue(renderer.call(field, me.getRecordValue(field.textField)));
-	} else if(field.valueField !== undefined) {
-	    var used = me.getRecordValue(field.valueField);
-	    /*jslint confusion: true*/
-	    /* string and int */
-	    var max = field.maxField !== undefined ? me.getRecordValue(field.maxField) : 1;
-
-	    var calculate = me.fieldCalculator;
-
-	    if (Ext.isFunction(field.calculate)) {
-		calculate = field.calculate;
-	    }
-	    field.updateValue(renderer.call(field, used,max), calculate(used,max));
-	}
-    },
-
-    getStore: function() {
-	var me = this;
-	if (!me.rstore) {
-	    throw "there is no rstore";
-	}
-
-	return me.rstore;
-    },
-
-    updateTitle: function() {
-	var me = this;
-	me.setTitle(me.getRecordValue('name'));
-    },
-
-    updateValues: function(store, records, success) {
-	if (!success) {
-	    return; // do not update if store load was not successful
-	}
-	var me = this;
-	var itemsToUpdate = me.query('pveInfoWidget');
-
-	itemsToUpdate.forEach(me.updateField, me);
-
-	me.updateTitle(store);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	if (!me.title) {
-	    throw "no title given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', 'updateValues');
-    }
-
-});
-Ext.define('PVE.panel.GuestStatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveGuestStatusView',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    height: 300,
-
-    cbindData: function (initialConfig) {
-	var me = this;
-	return {
-	    isQemu: me.pveSelNode.data.type === 'qemu',
-	    isLxc: me.pveSelNode.data.type === 'lxc'
-	};
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'status',
-	    title: gettext('Status'),
-	    iconCls: 'fa fa-info fa-fw',
-	    printBar: false,
-	    multiField: true,
-	    renderer: function(record) {
-		var me = this;
-		var text = record.data.status;
-		var qmpstatus = record.data.qmpstatus;
-		if (qmpstatus && qmpstatus !== record.data.status) {
-		    text += ' (' + qmpstatus + ')';
-		}
-		return text;
-	    }
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    xtype: 'pveInfoWidget',
-	    itemId: 'node',
-	    iconCls: 'fa fa-building fa-fw',
-	    title: gettext('Node'),
-	    cbind: {
-		text: '{pveSelNode.data.node}'
-	    },
-	    printBar: false
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpus',
-	    renderer: PVE.Utils.render_cpu_usage,
-	    // in this specific api call
-	    // we already have the correct value for the usage
-	    calculate: Ext.identityFn
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory usage'),
-	    valueField: 'mem',
-	    maxField: 'maxmem'
-	},
-	{
-	    itemId: 'swap',
-	    xtype: 'pveInfoWidget',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'maxswap',
-	    cbind: {
-		hidden: '{isQemu}',
-		disabled: '{isQemu}'
-	    }
-	},
-	{
-	    itemId: 'rootfs',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    valueField: 'disk',
-	    maxField: 'maxdisk',
-	    printBar: false,
-	    renderer: function(used, max) {
-		var me = this;
-		me.setPrintBar(used > 0);
-		if (used === 0) {
-		    return PVE.Utils.render_size(max);
-		} else {
-		    return PVE.Utils.render_size_usage(used,max);
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    height: 15
-	},
-	{
-	    itemId: 'ips',
-	    xtype: 'pveAgentIPView',
-	    cbind: {
-		rstore: '{rstore}',
-		pveSelNode: '{pveSelNode}',
-		hidden: '{isLxc}',
-		disabled: '{isLxc}'
-	    }
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = me.getRecordValue('uptime');
-
-	var text = "";
-	if (Number(uptime) > 0) {
-	    text = " (" + gettext('Uptime') + ': ' + Proxmox.Utils.format_duration_long(uptime)
-		+ ')';
-	}
-
-	me.setTitle(me.getRecordValue('name') + text);
-    }
-});
-/*
- * This is a running chart widget
- * you add time datapoints to it,
- * and we only show the last x of it
- * used for ceph performance charts
- */
-Ext.define('PVE.widget.RunningChart', {
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveRunningChart',
-
-    layout: {
-	type: 'hbox',
-	align: 'center'
-    },
-    items: [
-	{
-	    width: 80,
-	    xtype: 'box',
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}:</h3>'
-	},
-	{
-	    flex: 1,
-	    xtype: 'cartesian',
-	    height: '100%',
-	    itemId: 'chart',
-	    border: false,
-	    axes: [
-		{
-		    type: 'numeric',
-		    position: 'left',
-		    hidden: true,
-		    minimum: 0
-		},
-		{
-		    type: 'numeric',
-		    position: 'bottom',
-		    hidden: true
-		}
-	    ],
-
-	    store: {
-		data: {}
-	    },
-
-	    sprites: [{
-		id: 'valueSprite',
-		type: 'text',
-		text: '0 B/s',
-		textAlign: 'end',
-		textBaseline: 'middle',
-		fontSize: 14
-	    }],
-
-	    series: [{
-		type: 'line',
-		xField: 'time',
-		yField: 'val',
-		fill: 'true',
-		colors: ['#cfcfcf'],
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function( tooltip, record, ctx) {
-			var me = this.getChart();
-			var date = new Date(record.data.time);
-			var value = me.up().renderer(record.data.val);
-			tooltip.setHtml(
-			    me.up().title + ': ' + value + '<br />' +
-			    Ext.Date.format(date, 'H:i:s')
-			);
-		    }
-		},
-		style: {
-		    lineWidth: 1.5,
-		    opacity: 0.60
-		},
-		marker: {
-		    opacity: 0,
-		    scaling: 0.01,
-		    fx: {
-			duration: 200,
-			easing: 'easeOut'
-		    }
-		},
-		highlightCfg: {
-		    opacity: 1,
-		    scaling: 1.5
-		}
-	    }]
-	}
-    ],
-
-    // the renderer for the tooltip and last value,
-    // default just the value
-    renderer: Ext.identityFn,
-
-    // show the last x seconds
-    // default is 5 minutes
-    timeFrame: 5*60,
-
-    addDataPoint: function(value, time) {
-	var me = this.chart;
-	var panel = me.up();
-	var now = new Date();
-	var begin = new Date(now.getTime() - (1000*panel.timeFrame));
-
-	me.store.add({
-	    time: time || now.getTime(),
-	    val: value || 0
-	});
-
-	// delete all old records when we have 20 times more datapoints
-	// than seconds in our timeframe (so even a subsecond graph does
-	// not trigger this often)
-	//
-	// records in the store do not take much space, but like this,
-	// we prevent a memory leak when someone has the site open for a long time
-	// with minimal graphical glitches
-	if (me.store.count() > panel.timeFrame * 20) {
-	    var oldData = me.store.getData().createFiltered(function(item) {
-		return item.data.time < begin.getTime();
-	    });
-
-	    me.store.remove(oldData.getRange());
-	}
-
-	me.timeaxis.setMinimum(begin.getTime());
-	me.timeaxis.setMaximum(now.getTime());
-	me.valuesprite.setText(panel.renderer(value || 0).toString());
-	me.valuesprite.setAttributes({
-	    x: me.getWidth() - 15,
-	    y: me.getHeight()/2
-	}, true);
-	me.redraw();
-    },
-
-    setTitle: function(title) {
-	this.title = title;
-	var me = this.getComponent('title');
-	me.update({title: title});
-    },
-
-    initComponent: function(){
-	var me = this;
-	me.callParent();
-
-	if (me.title) {
-	    me.getComponent('title').update({title: me.title});
-	}
-	me.chart = me.getComponent('chart');
-	me.chart.timeaxis = me.chart.getAxes()[1];
-	me.chart.valuesprite = me.chart.getSurface('chart').get('valueSprite');
-	if (me.color) {
-	    me.chart.series[0].setStyle({
-		fill: me.color,
-		stroke: me.color
-	    });
-	}
-    }
-});
-Ext.define('PVE.widget.Info',{
-    extend: 'Ext.container.Container',
-    alias: 'widget.pveInfoWidget',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    value: 0,
-    maximum: 1,
-    printBar: true,
-    items: [
-	{
-	    xtype: 'component',
-	    itemId: 'label',
-	    data: {
-		title: '',
-		usage: '',
-		iconCls: undefined
-	    },
-	    tpl: [
-		'<div class="left-aligned">',
-		'<tpl if="iconCls">',
-		'<i class="{iconCls}"></i> ',
-		'</tpl>',
-		'{title}</div>&nbsp;<div class="right-aligned">{usage}</div>'
-	    ]
-	},
-	{
-	    height: 2,
-	    border: 0
-	},
-	{
-	    xtype: 'progressbar',
-	    itemId: 'progress',
-	    height: 5,
-	    value: 0,
-	    animate: true
-	}
-    ],
-
-    warningThreshold: 0.6,
-    criticalThreshold: 0.9,
-
-    setPrintBar: function(enable) {
-	var me = this;
-	me.printBar = enable;
-	me.getComponent('progress').setVisible(enable);
-    },
-
-    setIconCls: function(iconCls) {
-	var me = this;
-	me.getComponent('label').data.iconCls = iconCls;
-    },
-
-    updateValue: function(text, usage) {
-	var me = this;
-	var label = me.getComponent('label');
-	label.update(Ext.apply(label.data, {title: me.title, usage:text}));
-
-	if (usage !== undefined &&
-	    me.printBar &&
-	    Ext.isNumeric(usage) &&
-	    usage >= 0) {
-	    var progressBar = me.getComponent('progress');
-	    progressBar.updateProgress(usage, '');
-	    if (usage > me.criticalThreshold) {
-		progressBar.removeCls('warning');
-		progressBar.addCls('critical');
-	    } else if (usage > me.warningThreshold) {
-		progressBar.removeCls('critical');
-		progressBar.addCls('warning');
-	    } else {
-		progressBar.removeCls('warning');
-		progressBar.removeCls('critical');
-	    }
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.title) {
-	    throw "no title defined";
-	}
-
-	me.callParent();
-
-	me.getComponent('progress').setVisible(me.printBar);
-
-	me.updateValue(me.text, me.value);
-	me.setIconCls(me.iconCls);
-    }
-
-});
-Ext.define('PVE.panel.TemplateStatusView',{
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveTemplateStatusView',
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	printBar: false,
-	padding: '2 25'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'hamanaged',
-	    iconCls: 'fa fa-heartbeat fa-fw',
-	    title: gettext('HA State'),
-	    printBar: false,
-	    textField: 'ha',
-	    renderer: PVE.Utils.format_ha
-	},
-	{
-	    itemId: 'node',
-	    iconCls: 'fa fa-fw fa-building',
-	    title: gettext('Node')
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	},
-	{
-	    itemId: 'cpus',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('Processors'),
-	    textField: 'cpus'
-	},
-	{
-	    itemId: 'memory',
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    title: gettext('Memory'),
-	    textField: 'maxmem',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'swap',
-	    iconCls: 'fa fa-refresh fa-fw',
-	    title: gettext('Swap'),
-	    textField: 'maxswap',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    itemId: 'disk',
-	    iconCls: 'fa fa-hdd-o fa-fw',
-	    title: gettext('Bootdisk size'),
-	    textField: 'maxdisk',
-	    renderer: PVE.Utils.render_size
-	},
-	{
-	    xtype: 'box',
-	    height: 20
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	var name = me.pveSelNode.data.name;
-	if (!name) {
-	    throw "no name specified";
-	}
-
-	me.title = name;
-
-	me.callParent();
-	if (me.pveSelNode.data.type !== 'lxc') {
-	    me.remove(me.getComponent('swap'));
-	}
-	me.getComponent('node').updateValue(me.pveSelNode.data.node);
-    }
-});
-Ext.define('PVE.widget.HealthWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveHealthWidget',
-
-    data: {
-	iconCls: PVE.Utils.get_health_icon(undefined, true),
-	text: '',
-	title: ''
-    },
-
-    style: {
-	'text-align':'center'
-    },
-
-    tpl: [
-	'<h3>{title}</h3>',
-	'<i class="fa fa-5x {iconCls}"></i>',
-	'<br /><br/>',
-	'{text}'
-    ],
-
-    updateHealth: function(data) {
-	var me = this;
-	me.update(Ext.apply(me.data, data));
-    },
-
-    initComponent: function(){
-	var me = this;
-
-	if (me.title) {
-	    me.config.data.title = me.title;
-	}
-
-	me.callParent();
-    }
-
-});
-Ext.define('PVE.qemu.Summary', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveGuestSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.workspace) {
-	    throw "no workspace specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	var template = !!me.pveSelNode.data.template;
-	var rstore = me.statusStore;
-
-	var items = [
-	    {
-		xtype: template ? 'pveTemplateStatusView' : 'pveGuestStatusView',
-		flex: 1,
-		padding: template ? '5' : '0 5 0 0',
-		itemId: 'gueststatus',
-		pveSelNode: me.pveSelNode,
-		rstore: rstore
-	    },
-	    {
-		xtype: 'pveNotesView',
-		flex: 1,
-		padding: template ? '5' : '0 0 0 5',
-		itemId: 'notesview',
-		pveSelNode: me.pveSelNode,
-	    },
-	];
-
-	var rrdstore;
-	if (!template) {
-
-	    // in non-template mode put the two panels always together
-	    items = [
-		{
-		    xtype: 'container',
-		    layout: {
-			type: 'hbox',
-			align: 'stretch',
-		    },
-		    items: items
-		}
-	    ];
-
-	    rrdstore = Ext.create('Proxmox.data.RRDStore', {
-		rrdurl: `/api2/json/nodes/${nodename}/${type}/${vmid}/rrddata`,
-		model: 'pve-rrd-guest'
-	    });
-
-	    items.push(
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('CPU usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['cpu'],
-		    fieldTitles: [gettext('CPU usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Memory usage'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['maxmem', 'mem'],
-		    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Network traffic'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['netin','netout'],
-		    store: rrdstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Disk IO'),
-		    pveSelNode: me.pveSelNode,
-		    fields: ['diskread','diskwrite'],
-		    store: rrdstore
-		}
-	    );
-
-	}
-
-	Ext.apply(me, {
-	    tbar: [ '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    itemId: 'itemcontainer',
-		    layout: {
-			type: 'column'
-		    },
-		    minWidth: 700,
-		    defaults: {
-			minHeight: 330,
-			padding: 5,
-		    },
-		    items: items,
-		    listeners: {
-			resize: function(container) {
-			    PVE.Utils.updateColumns(container);
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-	if (!template) {
-	    rrdstore.startUpdate();
-	    me.on('destroy', rrdstore.stopUpdate);
-	}
-	let sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', function(provider, key, value) {
-	    if (key !== 'summarycolumns') {
-		return;
-	    }
-	    PVE.Utils.updateColumns(me.getComponent('itemcontainer'));
-	});
-    }
-});
-/*global u2f*/
-Ext.define('PVE.window.LoginWindow', {
-    extend: 'Ext.window.Window',
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onLogon: function() {
-	    var me = this;
-
-	    var form = this.lookupReference('loginForm');
-	    var unField = this.lookupReference('usernameField');
-	    var saveunField = this.lookupReference('saveunField');
-	    var view = this.getView();
-
-	    if (!form.isValid()) {
-		return;
-	    }
-
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-
-	    // set or clear username
-	    var sp = Ext.state.Manager.getProvider();
-	    if (saveunField.getValue() === true) {
-		sp.set(unField.getStateId(), unField.getValue());
-	    } else {
-		sp.clear(unField.getStateId());
-	    }
-	    sp.set(saveunField.getStateId(), saveunField.getValue());
-
-	    form.submit({
-		failure: function(f, resp){
-		    me.failure(resp);
-		},
-		success: function(f, resp){
-		    view.el.unmask();
-
-		    var data = resp.result.data;
-		    if (Ext.isDefined(data.NeedTFA)) {
-			// Store first factor login information first:
-			data.LoggedOut = true;
-			Proxmox.Utils.setAuthData(data);
-
-			if (Ext.isDefined(data.U2FChallenge)) {
-			    me.perform_u2f(data);
-			} else {
-			    me.perform_otp();
-			}
-		    } else {
-			me.success(data);
-		    }
-		}
-	    });
-
-	},
-	failure: function(resp) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.unmask();
-	    var handler = function() {
-		var uf = me.lookupReference('usernameField');
-		uf.focus(true, true);
-	    };
-
-	    let emsg = gettext("Login failed. Please try again");
-
-	    if (resp.failureType === "connect") {
-		emsg = gettext("Connection failure. Network error or Proxmox VE services not running?");
-	    }
-
-	    Ext.MessageBox.alert(gettext('Error'), emsg, handler);
-	},
-	success: function(data) {
-	    var me = this;
-	    var view = me.getView();
-	    var handler = view.handler || Ext.emptyFn;
-	    handler.call(me, data);
-	    view.close();
-	},
-
-	perform_otp: function() {
-	    var me = this;
-	    var win = Ext.create('PVE.window.TFALoginWindow', {
-		onLogin: function(value) {
-		    me.finish_tfa(value);
-		},
-		onCancel: function() {
-		    Proxmox.LoggedOut = false;
-		    Proxmox.Utils.authClear();
-		    me.getView().show();
-		}
-	    });
-	    win.show();
-	},
-
-	perform_u2f: function(data) {
-	    var me = this;
-	    // Show the message:
-	    var msg = Ext.Msg.show({
-		title: 'U2F: '+gettext('Verification'),
-		message: gettext('Please press the button on your U2F Device'),
-		buttons: []
-	    });
-	    var chlg = data.U2FChallenge;
-	    var key = {
-		version: chlg.version,
-		keyHandle: chlg.keyHandle
-	    };
-	    u2f.sign(chlg.appId, chlg.challenge, [key], function(res) {
-		msg.close();
-		if (res.errorCode) {
-		    Proxmox.Utils.authClear();
-		    Ext.Msg.alert(gettext('Error'), PVE.Utils.render_u2f_error(res.errorCode));
-		    return;
-		}
-		delete res.errorCode;
-		me.finish_tfa(JSON.stringify(res));
-	    });
-	},
-	finish_tfa: function(res) {
-	    var me = this;
-	    var view = me.getView();
-	    view.el.mask(gettext('Please wait...'), 'x-mask-loading');
-	    var params = { response: res };
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'POST',
-		timeout: 5000, // it'll delay both success & failure
-		success: function(resp, opts) {
-		    view.el.unmask();
-		    // Fill in what we copy over from the 1st factor:
-		    var data = resp.result.data;
-		    data.CSRFPreventionToken = Proxmox.CSRFPreventionToken;
-		    data.username = Proxmox.UserName;
-		    // Finish logging in:
-		    me.success(data);
-		},
-		failure: function(resp, opts) {
-		    Proxmox.Utils.authClear();
-		    me.failure(resp);
-		}
-	    });
-	},
-
-	control: {
-	    'field[name=username]': {
-		specialkey: function(f, e) {
-		    if (e.getKey() === e.ENTER) {
-			var pf = this.lookupReference('passwordField');
-			if (!pf.getValue()) {
-			    pf.focus(false);
-			}
-		    }
-		}
-	    },
-	    'field[name=lang]': {
-		change: function(f, value) {
-		    var dt = Ext.Date.add(new Date(), Ext.Date.YEAR, 10);
-		    Ext.util.Cookies.set('PVELangCookie', value, dt);
-		    this.getView().mask(gettext('Please wait...'), 'x-mask-loading');
-		    window.location.reload();
-		}
-	    },
-            'button[reference=loginButton]': {
-		click: 'onLogon'
-            },
-	    '#': {
-		show: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    var checkboxField = this.lookupReference('saveunField');
-		    var unField = this.lookupReference('usernameField');
-
-		    var checked = sp.get(checkboxField.getStateId());
-		    checkboxField.setValue(checked);
-
-		    if(checked === true) {
-			var username = sp.get(unField.getStateId());
-			unField.setValue(username);
-			var pwField = this.lookupReference('passwordField');
-			pwField.focus();
-		    }
-		}
-	    }
-	}
-    },
-
-    width: 400,
-    modal: true,
-    border: false,
-    draggable: true,
-    closable: false,
-    resizable: false,
-    layout: 'auto',
-
-    title: gettext('Proxmox VE Login'),
-
-    defaultFocus: 'usernameField',
-    defaultButton: 'loginButton',
-
-    items: [{
-	xtype: 'form',
-	layout: 'form',
-	url: '/api2/extjs/access/ticket',
-	reference: 'loginForm',
-
-	fieldDefaults: {
-	    labelAlign: 'right',
-	    allowBlank: false
-	},
-
-	items: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('User name'),
-		name: 'username',
-		itemId: 'usernameField',
-		reference: 'usernameField',
-		stateId: 'login-username'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		fieldLabel: gettext('Password'),
-		name: 'password',
-		reference: 'passwordField'
-	    },
-	    {
-		xtype: 'pveRealmComboBox',
-		name: 'realm'
-	    },
-	    {
-		xtype: 'proxmoxLanguageSelector',
-		fieldLabel: gettext('Language'),
-		value: Ext.util.Cookies.get('PVELangCookie') || Proxmox.defaultLang || 'en',
-		name: 'lang',
-		reference: 'langField',
-		submitValue: false
-	    }
-	],
-	buttons: [
-	    {
-		xtype: 'checkbox',
-		fieldLabel: gettext('Save User name'),
-		name: 'saveusername',
-		reference: 'saveunField',
-		stateId: 'login-saveusername',
-		labelWidth: 250,
-		labelAlign: 'right',
-		submitValue: false
-	    },
-	    {
-		text: gettext('Login'),
-		reference: 'loginButton'
-	    }
-	]
-    }]
- });
-Ext.define('PVE.window.TFALoginWindow', {
-    extend: 'Ext.window.Window',
-
-    modal: true,
-    resizable: false,
-    title: 'Two-Factor Authentication',
-    layout: 'form',
-    defaultButton: 'loginButton',
-    defaultFocus: 'otpField',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	login: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onLogin(me.lookup('otpField').getValue());
-	    view.close();
-	},
-	cancel: function() {
-	    var me = this;
-	    var view = me.getView();
-	    view.onCancel();
-	    view.close();
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Please enter your OTP verification code:'),
-	    name: 'otp',
-	    itemId: 'otpField',
-	    reference: 'otpField',
-	    allowBlank: false
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Login'),
-	    reference: 'loginButton',
-	    handler: 'login'
-	},
-	{
-	    text: gettext('Cancel'),
-	    handler: 'cancel'
-	}
-    ]
-});
-Ext.define('PVE.window.Wizard', {
-    extend: 'Ext.window.Window',
-
-    activeTitle: '', // used for automated testing
-
-    width: 700,
-    height: 510,
-
-    modal: true,
-    border: false,
-
-    draggable: true,
-    closable: true,
-    resizable: false,
-
-    layout: 'border',
-
-    getValues: function(dirtyOnly) {
-	var me = this;
-
-        var values = {};
-
-	var form = me.down('form').getForm();
-
-        form.getFields().each(function(field) {
-            if (!field.up('inputpanel') && (!dirtyOnly || field.isDirty())) {
-                Proxmox.Utils.assemble_field_data(values, field.getSubmitData());
-            }
-        });
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    Proxmox.Utils.assemble_field_data(values, panel.getValues(dirtyOnly));
-	});
-
-        return values;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var tabs = me.items || [];
-	delete me.items;
-	
-	/* 
-	 * Items may have the following functions:
-	 * validator(): per tab custom validation
-	 * onSubmit(): submit handler
-	 * onGetValues(): overwrite getValues results
-	 */
-
-	Ext.Array.each(tabs, function(tab) {
-	    tab.disabled = true;
-	});
-	tabs[0].disabled = false;
-
-	var maxidx = 0;
-	var curidx = 0;
-
-	var check_card = function(card) {
-	    var valid = true;
-	    var fields = card.query('field, fieldcontainer');
-	    if (card.isXType('fieldcontainer')) {
-		fields.unshift(card);
-	    }
-	    Ext.Array.each(fields, function(field) {
-		// Note: not all fielcontainer have isValid()
-		if (Ext.isFunction(field.isValid) && !field.isValid()) {
-		    valid = false;
-		}
-	    });
-
-	    if (Ext.isFunction(card.validator)) {
-		return card.validator();
-	    }
-
-	    return valid;
-	};
-
-	var disable_at = function(card) {
-	    var tp = me.down('#wizcontent');
-	    var idx = tp.items.indexOf(card);
-	    for(;idx < tp.items.getCount();idx++) {
-		var nc = tp.items.getAt(idx);
-		if (nc) {
-		    nc.disable();
-		}
-	    }
-	};
-
-	var tabchange = function(tp, newcard, oldcard) {
-	    if (newcard.onSubmit) {
-		me.down('#next').setVisible(false);
-		me.down('#submit').setVisible(true); 
-	    } else {
-		me.down('#next').setVisible(true);
-		me.down('#submit').setVisible(false); 
-	    }
-	    var valid = check_card(newcard);
-	    me.down('#next').setDisabled(!valid);    
-	    me.down('#submit').setDisabled(!valid);    
-	    me.down('#back').setDisabled(tp.items.indexOf(newcard) == 0);
-
-	    var idx = tp.items.indexOf(newcard);
-	    if (idx > maxidx) {
-		maxidx = idx;
-	    }
-	    curidx = idx;
-
-	    var next = idx + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (valid && ntab && !newcard.onSubmit) {
-		ntab.enable();
-	    }
-	};
-
-	if (me.subject && !me.title) {
-	    me.title = Proxmox.Utils.dialog_title(me.subject, true, false);
-	}
-
-	var sp = Ext.state.Manager.getProvider();
-	var advchecked = sp.get('proxmox-advanced-cb');
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'form',
-		    region: 'center',
-		    layout: 'fit',
-		    border: false,
-		    margins: '5 5 0 5',
-		    fieldDefaults: {
-			labelWidth: 100,
-			anchor: '100%'
-		    },
-		    items: [{
-			itemId: 'wizcontent',
-			xtype: 'tabpanel',
-			activeItem: 0,
-			bodyPadding: 10,
-			listeners: {
-			    afterrender: function(tp) {
-				var atab = this.getActiveTab();
-				tabchange(tp, atab);
-			    },
-			    tabchange: function(tp, newcard, oldcard) {
-				tabchange(tp, newcard, oldcard);
-			    }
-			},
-			items: tabs
-		    }]
-		}
-	    ],
-	    fbar: [
-		{
-		    xtype: 'proxmoxHelpButton',
-		    itemId: 'help'
-		},
-		'->',
-		{
-		    xtype: 'proxmoxcheckbox',
-		    boxLabelAlign: 'before',
-		    boxLabel: gettext('Advanced'),
-		    value: advchecked,
-		    listeners: {
-			change: function(cb, val) {
-			    var tp = me.down('#wizcontent');
-			    tp.query('inputpanel').forEach(function(ip) {
-				ip.setAdvancedVisible(val);
-			    });
-
-			    sp.set('proxmox-advanced-cb', val);
-			}
-		    }
-		},
-		{
-		    text: gettext('Back'),
-		    disabled: true,
-		    itemId: 'back',
-		    minWidth: 60,
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			var prev = tp.items.indexOf(atab) - 1;
-			if (prev < 0) {
-			    return;
-			}
-			var ntab = tp.items.getAt(prev);
-			if (ntab) {
-			    tp.setActiveTab(ntab);
-			}
-		    }
-		},
-		{
-		    text: gettext('Next'),
-		    disabled: true,
-		    itemId: 'next',
-		    minWidth: 60,
-		    handler: function() {
-
-			var form = me.down('form').getForm();
-
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			if (!check_card(atab)) {
-			    return;
-			}
-
-			var next = tp.items.indexOf(atab) + 1;
-			var ntab = tp.items.getAt(next);
-			if (ntab) {
-			    ntab.enable();
-			    tp.setActiveTab(ntab);
-			}
-
-		    }
-		},
-		{
-		    text: gettext('Finish'),
-		    minWidth: 60,
-		    hidden: true,
-		    itemId: 'submit',
-		    handler: function() {
-			var tp = me.down('#wizcontent');
-			var atab = tp.getActiveTab();
-			atab.onSubmit();
-		    }
-		}
-	    ]
-	});
-	me.callParent();
-
-	Ext.Array.each(me.query('inputpanel'), function(panel) {
-	    panel.setAdvancedVisible(advchecked);
-	});
-
-	Ext.Array.each(me.query('field'), function(field) {
-	    var validcheck = function() {
-		var tp = me.down('#wizcontent');
-
-		// check tabs from current to the last enabled for validity
-		// since we might have changed a validity on a later one
-		var i;
-		for (i = curidx; i <= maxidx && i < tp.items.getCount(); i++) {
-		    var tab = tp.items.getAt(i);
-		    var valid = check_card(tab);
-
-		    // only set the buttons on the current panel
-		    if (i === curidx) {
-			me.down('#next').setDisabled(!valid);
-			me.down('#submit').setDisabled(!valid);
-		    }
-
-		    // if a panel is invalid, then disable it and all following,
-		    // else enable it and go to the next
-		    var ntab = tp.items.getAt(i + 1);
-		    if (!valid) {
-			disable_at(ntab);
-			return;
-		    } else if (ntab && !tab.onSubmit) {
-			ntab.enable();
-		    }
-		}
-	    };
-	    field.on('change', validcheck);
-	    field.on('validitychange', validcheck);
-	});
-    }
-});
-Ext.define('PVE.window.NotesEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    title: gettext('Notes'),
-	    width: 600,
-	    height: '400px',
-	    resizable: true,
-	    layout: 'fit',
-	    defaultButton: undefined,
-	    items: {
-		xtype: 'textarea',
-		name: 'description',
-		height: '100%',
-		value: '',
-		hideLabel: true
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.window.Backup', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: me.storage,
-	    fieldLabel: gettext('Storage'),
-	    storageContent: 'backup',
-	    allowBlank: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		storagesel,
-		{
-		    xtype: 'pveBackupModeSelector',
-		    fieldLabel: gettext('Mode'),
-		    value: 'snapshot',
-		    name: 'mode'
-		},
-		{
-		    xtype: 'pveCompressionSelector',
-		    name: 'compress',
-		    value: 'lzo',
-		    fieldLabel: gettext('Compression')
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Send email to'),
-		    name: 'mailto',
-		    emptyText: Proxmox.Utils.noneText
-		}
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Backup'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid,
-		    mode: values.mode,
-		    remove: 0
-		};
-
-		if ( values.mailto ) {
-		    params.mailto = values.mailto;
-		}
-
-		if (values.compress) {
-		    params.compress = values.compress;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/vzdump',
-		    params: params,
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error',response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			// close later so we reload the grid
-			// after the task has completed
-			me.hide();
-
-			var upid = response.result.data;
-			
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				close: function() {
-				    me.close();
-				}
-			    }
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	var helpBtn = Ext.create('Proxmox.button.Help', {
-	    onlineHelp: 'chapter_vzdump',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	});
-
-	var title = gettext('Backup') + " " + 
-	    ((me.vmtype === 'lxc') ? "CT" : "VM") +
-	    " " + me.vmid;
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 350,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ helpBtn, '->', submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.Restore', {
-    extend: 'Ext.window.Window', // fixme: Proxmox.window.Edit?
-
-    resizable: false,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.volid) {
-	    throw "no volume ID specified";
-	}
-
-	if (!me.vmtype) {
-	    throw "no vmtype specified";
-	}
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: me.nodename,
-	    name: 'storage',
-	    value: '',
-	    fieldLabel: gettext('Storage'),
-	    storageContent: (me.vmtype === 'lxc') ? 'rootdir' : 'images',
-	    allowBlank: true
-	});
-
-	var IDfield;
-	if (me.vmid) {
-	    IDfield = Ext.create('Ext.form.field.Display', {
-		name: 'vmid',
-		value: me.vmid,
-		fieldLabel: (me.vmtype === 'lxc') ? 'CT' : 'VM'
-	    });
-	} else {
-	    IDfield = Ext.create('PVE.form.GuestIDSelector', {
-		name: 'vmid',
-		guestType: me.vmtype,
-		loadNextFreeID: true,
-		validateExists: false
-	    });
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		value: me.volidText || me.volid,
-		fieldLabel: gettext('Source')
-	    },
-	    storagesel,
-	    IDfield,
-	    {
-		xtype: 'pveBandwidthField',
-		name: 'bwlimit',
-		backendUnit: 'KiB',
-		fieldLabel: gettext('Read Limit'),
-		emptyText: gettext('Defaults to target storage restore limit'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext("Use '0' to disable all bandwidth limits.")
-		}
-	    },
-	    {
-		xtype: 'fieldcontainer',
-		layout: 'hbox',
-		items: [{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unique',
-		    fieldLabel: gettext('Unique'),
-		    hidden: !!me.vmid,
-		    flex: 1,
-		    autoEl: {
-			tag: 'div',
-			'data-qtip': gettext('Autogenerate unique properties, e.g., MAC addresses')
-		    },
-		    checked: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    flex: 1,
-		    fieldLabel: gettext('Start after restore'),
-		    labelWidth: 105,
-		    checked: false
-		}],
-	    },
-	];
-
-	/*jslint confusion: true*/
-	if (me.vmtype === 'lxc') {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'unprivileged',
-		value: true,
-		fieldLabel: gettext('Unprivileged container')
-	    });
-	}
-	/*jslint confusion: false*/
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doRestore = function(url, params) {
-	    Proxmox.Utils.API2Request({
-		url: url,
-		params: params,
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    
-		    var win = Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid
-		    });
-		    win.show();
-		    me.close();
-		}
-	    });
-	};
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Restore'),
-	    handler: function(){
-		var storage = storagesel.getValue();
-		var values = form.getValues();
-
-		var params = {
-		    storage: storage,
-		    vmid: me.vmid || values.vmid,
-		    force: me.vmid ? 1 : 0
-		};
-		if (values.unique) { params.unique = 1; }
-		if (values.start) { params.start = 1; }
-
-		if (values.bwlimit !== undefined) {
-		    params.bwlimit = values.bwlimit;
-		}
-
-		var url;
-		var msg;
-		if (me.vmtype === 'lxc') {
-		    url = '/nodes/' + me.nodename + '/lxc';
-		    params.ostemplate = me.volid;
-		    params.restore = 1;
-		    if (values.unprivileged) { params.unprivileged = 1; }
-		    msg = Proxmox.Utils.format_task_description('vzrestore', params.vmid);
-		} else if (me.vmtype === 'qemu') {
-		    url = '/nodes/' + me.nodename + '/qemu';
-		    params.archive = me.volid;
-		    msg = Proxmox.Utils.format_task_description('qmrestore', params.vmid);
-		} else {
-		    throw 'unknown VM type';
-		}
-
-		if (me.vmid) {
-		    msg += '. ' + gettext('This will permanently erase current VM data.');
-		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRestore(url, params);
-		    });
-		} else {
-		    doRestore(url, params);
-		}
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-	var title =  gettext('Restore') + ": " + (
-	    (me.vmtype === 'lxc') ? 'CT' : 'VM');
-
-	if (me.vmid) {
-	    title += " " + me.vmid;
-	}
-
-	Ext.apply(me, {
-	    title: title,
-	    width: 500,
-	    modal: true,
-	    layout: 'auto',
-	    border: false,
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-/* Popup a message window
- * where the user has to manually enter the resource ID
- * to enable the destroy button
- */
-Ext.define('PVE.window.SafeDestroy', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSafeDestroy',
-
-    title: gettext('Confirm'),
-    modal: true,
-    buttonAlign: 'center',
-    bodyPadding: 10,
-    width: 450,
-    layout: { type:'hbox' },
-    defaultFocus: 'confirmField',
-    showProgress: false,
-
-    config: {
-	item: {
-	    id: undefined,
-	    type: undefined
-	},
-	url: undefined,
-	params: {}
-    },
-
-    getParams: function() {
-	var me = this;
-	var purgeCheckbox = me.lookupReference('purgeCheckbox');
-	if (purgeCheckbox.checked) {
-	    me.params.purge = 1;
-	}
-	if (Ext.Object.isEmpty(me.params)) {
-	    return '';
-	}
-	return '?' + Ext.Object.toQueryString(me.params);
-    },
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=confirm]': {
-		change: function(f, value) {
-		    var view = this.getView();
-		    var removeButton = this.lookupReference('removeButton');
-		    if (value === view.getItem().id.toString()) {
-			removeButton.enable();
-		    } else {
-			removeButton.disable();
-		    }
-		},
-		specialkey: function (field, event) {
-		    var removeButton = this.lookupReference('removeButton');
-		    if (!removeButton.isDisabled() && event.getKey() == event.ENTER) {
-			removeButton.fireEvent('click', removeButton, event);
-		    }
-		}
-	    },
-           'button[reference=removeButton]': {
-		click: function() {
-		    var view = this.getView();
-		    Proxmox.Utils.API2Request({
-			url: view.getUrl() + view.getParams(),
-			method: 'DELETE',
-			waitMsgTarget: view,
-			failure: function(response, opts) {
-			    view.close();
-			    Ext.Msg.alert('Error', response.htmlStatus);
-			},
-			success: function(response, options) {
-			    var hasProgressBar = view.showProgress &&
-				response.result.data ? true : false;
-
-			    if (hasProgressBar) {
-				// stay around so we can trigger our close events
-				// when background action is completed
-				view.hide();
-
-				var upid = response.result.data;
-				var win = Ext.create('Proxmox.window.TaskProgress', {
-				    upid: upid,
-				    listeners: {
-					destroy: function () {
-					    view.close();
-					}
-				    }
-				});
-				win.show();
-			    } else {
-				view.close();
-			    }
-			}
-		    });
-		}
-            }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    cls: [ Ext.baseCSSPrefix + 'message-box-icon',
-		   Ext.baseCSSPrefix + 'message-box-warning',
-		   Ext.baseCSSPrefix + 'dlg-icon']
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    xtype: 'component',
-		    reference: 'messageCmp'
-		},
-		{
-		    itemId: 'confirmField',
-		    reference: 'confirmField',
-		    xtype: 'textfield',
-		    name: 'confirm',
-		    labelWidth: 300,
-		    hideTrigger: true,
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'purge',
-		    reference: 'purgeCheckbox',
-		    boxLabel: gettext('Purge'),
-		    checked: false,
-		    autoEl: {
-			tag: 'div',
-			'data-qtip': gettext('Remove from replication and backup jobs')
-		    }
-		}
-	    ]
-	}
-    ],
-    buttons: [
-	{
-	    reference: 'removeButton',
-	    text: gettext('Remove'),
-	    disabled: true
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	var item = me.getItem();
-
-	if (!Ext.isDefined(item.id)) {
-	    throw "no ID specified";
-	}
-
-	if (!Ext.isDefined(item.type)) {
-	    throw "no VM type specified";
-	}
-
-	var messageCmp = me.lookupReference('messageCmp');
-	var msg;
-
-	if (item.type === 'VM') {
-	    msg = Proxmox.Utils.format_task_description('qmdestroy', item.id);
-	} else if (item.type === 'CT') {
-	    msg = Proxmox.Utils.format_task_description('vzdestroy', item.id);
-	} else if (item.type === 'CephPool') {
-	    msg = Proxmox.Utils.format_task_description('cephdestroypool', item.id);
-	} else if (item.type === 'Image') {
-	    msg = Proxmox.Utils.format_task_description('unknownimgdel', item.id);
-	} else {
-	    throw "unknown item type specified";
-	}
-
-	messageCmp.setHtml(msg);
-
-	if (!(item.type === 'VM' || item.type === 'CT')) {
-	    let purgeCheckbox = me.lookupReference('purgeCheckbox');
-	    purgeCheckbox.setDisabled(true);
-	    purgeCheckbox.setHidden(true);
-	}
-
-	var confirmField = me.lookupReference('confirmField');
-	msg = gettext('Please enter the ID to confirm') +
-	    ' (' + item.id + ')';
-	confirmField.setFieldLabel(msg);
-    }
-});
-Ext.define('PVE.window.BackupConfig', {
-    extend: 'Ext.window.Window',
-    title: gettext('Configuration'),
-    width: 600,
-    height: 400,
-    layout: 'fit',
-    modal: true,
-    items: {
-	xtype: 'component',
-	itemId: 'configtext',
-	autoScroll: true,
-	style: {
-	    'background-color': 'white',
-	    'white-space': 'pre',
-	    'font-family': 'monospace',
-	    padding: '5px'
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.volume) {
-	    throw "no volume specified";
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.callParent();
-
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + nodename + "/vzdump/extractconfig",
-	    method: 'GET',
-	    params: {
-		volume: me.volume
-	    },
-	    failure: function(response, opts) {
-		me.close();
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response,options) {
-		me.show();
-		me.down('#configtext').update(Ext.htmlEncode(response.result.data));
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.Settings', {
-    extend: 'Ext.window.Window',
-
-    width: '800px',
-    title: gettext('My Settings'),
-    iconCls: 'fa fa-gear',
-    modal: true,
-    bodyPadding: 10,
-    resizable: false,
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    onlineHelp: 'gui_my_settings',
-	    hidden: false
-	},
-	'->',
-	{
-	    text: gettext('Close'),
-	    handler: function() {
-		this.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'column',
-	align: 'top'
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    var me = this;
-	    var sp = Ext.state.Manager.getProvider();
-
-	    var username = sp.get('login-username') || Proxmox.Utils.noneText;
-	    me.lookupReference('savedUserName').setValue(username);
-	    var vncMode = sp.get('novnc-scaling');
-	    if (vncMode !== undefined) {
-		me.lookupReference('noVNCScalingGroup').setValue({ noVNCScalingField: vncMode });
-	    }
-
-	    let summarycolumns = sp.get('summarycolumns', 'auto');
-	    me.lookup('summarycolumns').setValue(summarycolumns);
-
-	    me.lookup('guestNotesCollapse').setValue(sp.get('guest-notes-collapse', 'never'));
-
-	    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-	    settings.forEach(function(setting) {
-		var val = localStorage.getItem('pve-xterm-' + setting);
-		if (val !== undefined && val !== null) {
-		    var field = me.lookup(setting);
-		    field.setValue(val);
-		    field.resetOriginalValue();
-		}
-	    });
-	},
-
-	set_button_status: function() {
-	    var me = this;
-
-	    var form = me.lookup('xtermform');
-	    var valid = form.isValid();
-	    var dirty = form.isDirty();
-
-	    var hasvalues = false;
-	    var values = form.getValues();
-	    Ext.Object.eachValue(values, function(value) {
-		if (value) {
-		    hasvalues = true;
-		    return false;
-		}
-	    });
-
-	    me.lookup('xtermsave').setDisabled(!dirty || !valid);
-	    me.lookup('xtermreset').setDisabled(!hasvalues);
-	},
-
-	control: {
-	    '#xtermjs form': {
-		dirtychange: 'set_button_status',
-		validitychange: 'set_button_status'
-	    },
-	    '#xtermjs button': {
-		click: function(button) {
-		    var me = this;
-		    var settings = ['fontSize', 'fontFamily', 'letterSpacing', 'lineHeight'];
-		    settings.forEach(function(setting) {
-			var field = me.lookup(setting);
-			if (button.reference === 'xtermsave') {
-			    var value = field.getValue();
-			    if (value) {
-				localStorage.setItem('pve-xterm-' + setting, value);
-			    } else {
-				localStorage.removeItem('pve-xterm-' + setting);
-			    }
-			} else if (button.reference === 'xtermreset') {
-			    field.setValue(undefined);
-			    localStorage.removeItem('pve-xterm-' + setting);
-			}
-			field.resetOriginalValue();
-		    });
-		    me.set_button_status();
-		}
-	    },
-	    'button[name=reset]': {
-		click: function () {
-		    var blacklist = ['GuiCap', 'login-username', 'dash-storages'];
-		    var sp = Ext.state.Manager.getProvider();
-		    var state;
-		    for (state in sp.state) {
-			if (sp.state.hasOwnProperty(state)) {
-			    if (blacklist.indexOf(state) !== -1) {
-				continue;
-			    }
-
-			    sp.clear(state);
-			}
-		    }
-
-		    window.location.reload();
-		}
-	    },
-	    'button[name=clear-username]': {
-		click: function () {
-		    var me = this;
-		    var usernamefield = me.lookupReference('savedUserName');
-		    var sp = Ext.state.Manager.getProvider();
-
-		    usernamefield.setValue(Proxmox.Utils.noneText);
-		    sp.clear('login-username');
-		}
-	    },
-	    'grid[reference=dashboard-storages]': {
-		selectionchange: function(grid, selected) {
-		    var me = this;
-		    var sp = Ext.state.Manager.getProvider();
-
-		    // saves the selected storageids as
-		    // "id1,id2,id3,..."
-		    // or clears the variable
-		    if (selected.length > 0) {
-			sp.set('dash-storages',
-			    Ext.Array.pluck(selected, 'id').join(','));
-		    } else {
-			sp.clear('dash-storages');
-		    }
-		},
-		afterrender: function(grid) {
-		    var me = grid;
-		    var sp = Ext.state.Manager.getProvider();
-		    var store = me.getStore();
-		    var items = [];
-		    me.suspendEvent('selectionchange');
-		    var storages = sp.get('dash-storages') || '';
-		    storages.split(',').forEach(function(storage){
-			// we have to get the records
-			// to be able to select them
-			if (storage !== '') {
-			    var item = store.getById(storage);
-			    if (item) {
-				items.push(item);
-			    }
-			}
-		    });
-		    me.getSelectionModel().select(items);
-		    me.resumeEvent('selectionchange');
-		}
-	    },
-	    'field[reference=summarycolumns]': {
-		change: function(el, newValue) {
-		    var sp = Ext.state.Manager.getProvider();
-		    sp.set('summarycolumns', newValue);
-		}
-	    },
-	    'field[reference=guestNotesCollapse]': {
-		change: function(e, v) {
-		    Ext.state.Manager.getProvider().set('guest-notes-collapse', v);
-		},
-	    },
-	}
-    },
-
-    items: [{
-	xtype: 'fieldset',
-	columnWidth: 0.5,
-	title: gettext('Webinterface Settings'),
-	margin: '5',
-	layout: {
-	    type: 'vbox',
-	    align: 'left'
-	},
-	defaults: {
-	    width: '100%',
-	    margin: '0 0 10 0'
-	},
-	items: [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Dashboard Storages'),
-		labelAlign: 'left',
-		labelWidth: '50%'
-	    },
-	    {
-		xtype: 'grid',
-		maxHeight: 150,
-		reference: 'dashboard-storages',
-		selModel: {
-		    selType: 'checkboxmodel'
-		},
-		columns: [{
-		    header: gettext('Name'),
-		    dataIndex: 'storage',
-		    flex: 1
-		},{
-		    header: gettext('Node'),
-		    dataIndex: 'node',
-		    flex: 1
-		}],
-		store: {
-		    type: 'diff',
-		    field: ['type', 'storage', 'id', 'node'],
-		    rstore: PVE.data.ResourceStore,
-		    filters: [{
-			property: 'type',
-			value: 'storage'
-		    }],
-		    sorters: [ 'node','storage']
-		}
-	    },
-	    {
-		xtype: 'box',
-		autoEl: { tag: 'hr'}
-	    },
-	    {
-		xtype: 'container',
-		layout:  'hbox',
-		items: [
-		    {
-			xtype: 'displayfield',
-			fieldLabel: gettext('Saved User Name') + ':',
-			labelWidth: '150',
-			stateId: 'login-username',
-			reference: 'savedUserName',
-			flex: 1,
-			value: ''
-		    },
-		    {
-			xtype: 'button',
-			cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-			text: gettext('Reset'),
-			name: 'clear-username',
-		    },
-		]
-	    },
-	    {
-		xtype: 'box',
-		autoEl: { tag: 'hr'}
-	    },
-	    {
-		xtype: 'container',
-		layout: 'hbox',
-		items: [
-		    {
-			xtype: 'displayfield',
-			fieldLabel: gettext('Layout') + ':',
-			flex: 1,
-		    },
-		    {
-			xtype: 'button',
-			cls: 'x-btn-default-toolbar-small proxmox-inline-button',
-			text: gettext('Reset'),
-			tooltip: gettext('Reset all layout changes (for example, column widths)'),
-			name: 'reset',
-		    },
-		]
-	    },
-	    {
-		xtype: 'box',
-		autoEl: { tag: 'hr'}
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		fieldLabel: gettext('Summary columns') + ':',
-		labelWidth: 150,
-		stateId: 'summarycolumns',
-		reference: 'summarycolumns',
-		comboItems: [
-		    ['auto', 'auto'],
-		    ['1', '1'],
-		    ['2', '2'],
-		    ['3', '3'],
-		],
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		fieldLabel: gettext('Guest Notes') + ':',
-		labelWidth: 150,
-		stateId: 'guest-notes-collapse',
-		reference: 'guestNotesCollapse',
-		comboItems: [
-		    ['never', 'Show by default'],
-		    ['always', 'Collapse by default'],
-		    ['auto', 'auto (Collapse if empty)'],
-		],
-	    },
-	]
-    },
-    {
-	xtype: 'container',
-	layout: 'vbox',
-	columnWidth: 0.5,
-	margin: '5',
-	defaults: {
-	    width: '100%',
-	    // right margin ensures that the right border of the fieldsets
-	    // is shown
-	    margin: '0 2 10 0'
-	},
-	items:[
-	    {
-		xtype: 'fieldset',
-		itemId: 'xtermjs',
-		title: gettext('xterm.js Settings'),
-		items: [{
-		    xtype: 'form',
-		    reference: 'xtermform',
-		    border: false,
-		    layout: {
-			type: 'vbox',
-			algin: 'left'
-		    },
-		    defaults: {
-			width: '100%',
-			margin: '0 0 10 0',
-		    },
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'fontFamily',
-			    reference: 'fontFamily',
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('Font-Family')
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    emptyText: Proxmox.Utils.defaultText,
-			    name: 'fontSize',
-			    reference: 'fontSize',
-			    minValue: 1,
-			    fieldLabel: gettext('Font-Size')
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'letterSpacing',
-			    reference: 'letterSpacing',
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('Letter Spacing')
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'lineHeight',
-			    minValue: 0.1,
-			    reference: 'lineHeight',
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('Line Height')
-			},
-			{
-			    xtype: 'container',
-			    layout: {
-				type: 'hbox',
-				pack: 'end'
-			    },
-			    defaults: {
-				margin: '0 0 0 5',
-			    },
-			    items: [
-				{
-				    xtype: 'button',
-				    reference: 'xtermreset',
-				    disabled: true,
-				    text: gettext('Reset')
-				},
-				{
-				    xtype: 'button',
-				    reference: 'xtermsave',
-				    disabled: true,
-				    text: gettext('Save')
-				}
-			    ]
-			}
-		    ]
-		}]
-	    },{
-		xtype: 'fieldset',
-		title: gettext('noVNC Settings'),
-		items: [
-		    {
-			xtype: 'radiogroup',
-			fieldLabel: gettext('Scaling mode'),
-			reference: 'noVNCScalingGroup',
-			height: '15px', // renders faster with value assigned
-			layout: {
-			    type: 'hbox',
-			},
-			items: [
-			    {
-				xtype: 'radiofield',
-				name: 'noVNCScalingField',
-				inputValue: 'scale',
-				boxLabel: 'Local Scaling',
-				checked: true,
-			    },{
-				xtype: 'radiofield',
-				name: 'noVNCScalingField',
-				inputValue: 'off',
-				boxLabel: 'Off',
-				margin: '0 0 0 10',
-			    }
-			],
-			listeners: {
-			    change: function(el, newValue, undefined) {
-				var sp = Ext.state.Manager.getProvider();
-				sp.set('novnc-scaling', newValue.noVNCScalingField);
-			    }
-			},
-		    },
-		]
-	    },
-	]
-    }],
-});
-Ext.define('PVE.panel.StartupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'qm_startup_and_shutdown',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = PVE.Parser.printStartup(values);
-
-	if (res === undefined || res === '') {
-	    return { 'delete': 'startup' };
-	}
-
-	return { startup: res };
-    },
-
-    setStartup: function(value) {
-	var me = this;
-
-	var startup = PVE.Parser.parseStartup(value);
-	if (startup) {
-	    me.setValues(startup);
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.items = [
-	    {
-		xtype: 'textfield',
-		name: 'order',
-		defaultValue: '',
-		emptyText: 'any',
-		fieldLabel: gettext('Start/Shutdown order')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'up',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Startup delay')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'down',
-		defaultValue: '',
-		emptyText: 'default',
-		fieldLabel: gettext('Shutdown timeout')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.window.StartupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveWindowStartupEdit',
-    onlineHelp: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-	var ipanelConfig = me.onlineHelp ? {onlineHelp: me.onlineHelp} : {};
-	var ipanel = Ext.create('PVE.panel.StartupInputPanel', ipanelConfig);
-
-	Ext.applyIf(me, {
-	    subject: gettext('Start/Shutdown order'),
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		ipanel.setStartup(me.vmconfig.startup);		    
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.Install', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveCephInstallWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 220,
-    header: false,
-    resizable: false,
-    draggable: false,
-    modal: true,
-    nodename: undefined,
-    shadow: false,
-    border: false,
-    bodyBorder: false,
-    closable: false,
-    cls: 'install-mask',
-    bodyCls: 'install-mask',
-    layout: {
-        align: 'stretch',
-        pack: 'center',
-	type: 'vbox'
-    },
-    viewModel: {
-	data: {
-	      cephVersion: 'nautilus',
-	      isInstalled: false
-	},
-	formulas: {
-	    buttonText: function (get){
-		if (get('isInstalled')) {
-		    return gettext('Configure Ceph');
-		} else {
-		    return gettext('Install Ceph-') + get('cephVersion');
-		}
-	    },
-	    windowText: function (get) {
-		if (get('isInstalled')) {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not initialized.'), 'Ceph') + ' '+
-		    gettext('You need to create a initial config once.') + '</p>';
-		} else {
-		    return '<p class="install-mask">' +
-		    Ext.String.format(gettext('{0} is not installed on this node.'), 'Ceph') + '<br>' +
-		    gettext('Would you like to install it now?') + '</p>';
-		}
-	    }
-	}
-    },
-    items: [
-	{
-	    bind: {
-		html: '{windowText}'
-	    },
-	    border: false,
-	    padding: 5,
-	    bodyCls: 'install-mask'
-
-	},
-	{
-	    xtype: 'button',
-	    bind: {
-		text: '{buttonText}'
-	    },
-	    viewModel: {},
-	    cbind: {
-		nodename: '{nodename}'
-	    },
-	    handler: function() {
-		var me = this.up('pveCephInstallWindow');
-		var win = Ext.create('PVE.ceph.CephInstallWizard',{
-		    nodename: me.nodename
-		});
-		win.getViewModel().set('isInstalled', this.getViewModel().get('isInstalled'));
-		win.show();
-		me.mon(win,'beforeClose', function(){
-		    me.fireEvent("cephInstallWindowClosed");
-		    me.close();
-		});
-
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallEnableEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveFirewallEnableEdit'],
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    subject: gettext('Firewall'),
-    cbindData: {
-	defaultValue: 0
-    },
-    width: 350,
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    uncheckedValue: 0,
-	    cbind: {
-		defaultValue: '{defaultValue}',
-		checked: '{defaultValue}'
-	    },
-	    deleteDefaultValue: false,
-	    fieldLabel: gettext('Firewall')
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'warning',
-	    userCls: 'pmx-hint',
-	    value: gettext('Warning: Firewall still disabled at datacenter level!'),
-	    hidden: true
-	}
-    ],
-
-    beforeShow: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/cluster/firewall/options',
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		if (!response.result.data.enable) {
-		    me.down('displayfield[name=warning]').setVisible(true);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.FirewallLograteInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveFirewallLograteInputPanel',
-
-    viewModel: {},
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'enable',
-	    reference: 'enable',
-	    fieldLabel: gettext('Enable'),
-	    value: true
-	},
-	{
-	    layout: 'hbox',
-	    border: false,
-	    items: [
-		{
-		    xtype: 'numberfield',
-		    name: 'rate',
-		    fieldLabel: gettext('Log rate limit'),
-		    minValue: 1,
-		    maxValue: 99,
-		    allowBlank: false,
-		    flex: 2,
-		    value: 1
-		},
-		{
-		    xtype: 'box',
-		    html: '<div style="margin: auto; padding: 2.5px;"><b>/</b></div>'
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    name: 'unit',
-		    comboItems: [['second', 'second'], ['minute', 'minute'],
-			['hour', 'hour'], ['day', 'day']],
-		    allowBlank: false,
-		    flex: 1,
-		    value: 'second'
-		}
-	    ]
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'burst',
-	    fieldLabel: gettext('Log burst limit'),
-	    minValue: 1,
-	    maxValue: 99,
-	    value: 5
-	}
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var vals = {};
-	vals.enable = values.enable !== undefined ? 1 : 0;
-	vals.rate = values.rate + '/' + values.unit;
-	vals.burst = values.burst;
-	var properties = PVE.Parser.printPropertyString(vals, undefined);
-	if (properties == '') {
-	    return { 'delete': 'log_ratelimit' };
-	}
-	return { log_ratelimit: properties };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	var properties = {};
-	if (values.log_ratelimit !== undefined) {
-	    properties = PVE.Parser.parsePropertyString(values.log_ratelimit, 'enable');
-	    if (properties.rate) {
-		var matches = properties.rate.match(/^(\d+)\/(second|minute|hour|day)$/);
-		if (matches) {
-		    properties.rate = matches[1];
-		    properties.unit = matches[2];
-		}
-	    }
-	}
-	me.callParent([properties]);
-    }
-});
-
-Ext.define('PVE.FirewallLograteEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveFirewallLograteEdit',
-
-    subject: gettext('Log rate limit'),
-
-    items: [{
-	xtype: 'pveFirewallLograteInputPanel'
-    }],
-    autoLoad: true
-});
-Ext.define('PVE.panel.NotesView', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNotesView',
-
-    title: gettext("Notes"),
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 10,
-    scrollable: true,
-    animCollapse: false,
-
-    tbar: {
-	itemId: 'tbar',
-	hidden: true,
-	items: [
-	    {
-		text: gettext('Edit'),
-		handler: function() {
-		    var me = this.up('panel');
-		    me.run_editor();
-		}
-	    }
-	]
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create('PVE.window.NotesEdit', {
-	    pveSelNode: me.pveSelNode,
-	    url: me.url
-	});
-	win.show();
-	win.on('destroy', me.load, me);
-    },
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		me.setCollapsed(false);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data.description || '';
-		me.update(Ext.htmlEncode(data));
-
-		if (me.collapsible && me.collapseMode === 'auto') {
-		    me.setCollapsed(data === '');
-		}
-	    }
-	});
-    },
-
-    listeners: {
-	render: function(c) {
-	    var me = this;
-	    me.getEl().on('dblclick', me.run_editor, me);
-	},
-	afterlayout: function() {
-	    let me = this;
-	    if (me.collapsible && !me.getCollapsed() && me.collapseMode === 'always') {
-		me.setCollapsed(true);
-		me.collapseMode = ''; // only once, on initial load!
-	    }
-	},
-    },
-
-    tools: [{
-	type: 'gear',
-	handler: function() {
-	    var me = this.up('panel');
-	    me.run_editor();
-	}
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var type = me.pveSelNode.data.type;
-	if (!Ext.Array.contains(['node', 'qemu', 'lxc'], type)) {
-	    throw 'invalid type specified';
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid && type !== 'node') {
-	    throw "no VM ID specified";
-	}
-
-	me.url = '/api2/extjs/nodes/' + nodename + '/';
-
-	// add the type specific path if qemu/lxc
-	if (type === 'qemu' || type === 'lxc') {
-	    me.url += type + '/' + vmid + '/';
-	}
-
-	me.url += 'config';
-
-	me.callParent();
-	if (type === 'node') {
-	    me.down('#tbar').setVisible(true);
-	} else {
-	    me.setCollapsible(true);
-	    me.collapseDirection = 'right';
-
-	    let sp = Ext.state.Manager.getProvider();
-	    me.collapseMode = sp.get('guest-notes-collapse', 'never');
-
-	    if (me.collapseMode === 'auto') {
-		me.setCollapsed(true);
-	    }
-	}
-	me.load();
-    }
-});
-Ext.define('PVE.grid.ResourceGrid', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveResourceGrid'],
-
-    border: false,
-    defaultSorter: {
-	property: 'type',
-	direction: 'ASC'
-    },
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	var coldef = rstore.defaultColumns();
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: me.defaultSorter,
-	    proxy: { type: 'memory' }
-	});
-
-	var textfilter = '';
-
-	var textfilter_match = function(item) {
-	    var match = false;
-	    Ext.each(['name', 'storage', 'node', 'type', 'text'], function(field) {
-		var v = item.data[field];
-		if (v !== undefined) {
-		    v = v.toLowerCase();
-		    if (v.indexOf(textfilter) >= 0) {
-			match = true;
-			return false;
-		    }
-		}
-	    });
-	    return match;
-	};
-
-	var updateGrid = function() {
-
-	    var filterfn = me.viewFilter ? me.viewFilter.filterfn : null;
-	    
-	    //console.log("START GRID UPDATE " +  me.viewFilter);
-
-	    store.suspendEvents();
-
-	    var nodeidx = {};
-	    var gather_child_nodes = function(cn) {
-		if (!cn) {
-		    return;
-		}
-                var cs = cn.childNodes;
-		if (!cs) {
-		    return;
-		}
-		var len = cs.length, i = 0, n, res;
-
-                for (; i < len; i++) {
-		    var child = cs[i];
-		    var orgnode = rstore.data.get(child.data.id);
-		    if (orgnode) {
-			if ((!filterfn || filterfn(child)) &&
-			    (!textfilter || textfilter_match(child))) {
-			    nodeidx[child.data.id] = orgnode;
-			}
-		    }
-		    gather_child_nodes(child);
-		}
-	    };
-	    gather_child_nodes(me.pveSelNode);
-
-	    // remove vanished items
-	    var rmlist = [];
-	    store.each(function(olditem) {
-		var item = nodeidx[olditem.data.id];
-		if (!item) {
-		    //console.log("GRID REM UID: " + olditem.data.id);
-		    rmlist.push(olditem);
-		}
-	    });
-
-	    if (rmlist.length) {
-		store.remove(rmlist);
-	    }
-
-	    // add new items
-	    var addlist = [];
-	    var key;
-	    for (key in nodeidx) {
-		if (nodeidx.hasOwnProperty(key)) {
-		    var item = nodeidx[key];
-		
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var olditem = store.getById(item.data.id);
-		    var olditem = store.data.get(item.data.id);
-
-		    if (!olditem) {
-			//console.log("GRID ADD UID: " + item.data.id);
-			var info = Ext.apply({}, item.data);
-			var child = Ext.create(store.model, info);
-			addlist.push(item);
-			continue;
-		    }
-		    // try to detect changes
-		    var changes = false;
-		    var fieldkeys = PVE.data.ResourceStore.fieldNames;
-		    var fieldcount = fieldkeys.length;
-		    var fieldind;
-		    for (fieldind = 0; fieldind < fieldcount; fieldind++) {
-			var field = fieldkeys[fieldind];
-			if (field != 'id' && item.data[field] != olditem.data[field]) {
-			    changes = true;
-			    //console.log("changed item " + item.id + " " + field + " " + item.data[field] + " != " + olditem.data[field]);
-			    olditem.beginEdit();
-			    olditem.set(field, item.data[field]);
-			}
-		    }
-		    if (changes) {
-			olditem.endEdit(true);
-			olditem.commit(true); 
-		    }
-		}
-	    }
-
-	    if (addlist.length) {
-		store.add(addlist);
-	    }
-
-	    store.sort();
-
-	    store.resumeEvents();
-
-	    store.fireEvent('refresh', store);
-
-	    //console.log("END GRID UPDATE");
-	};
-
-	var filter_task = new Ext.util.DelayedTask(function(){
-	    updateGrid();
-	});
-
-	var load_cb = function() { 
-	    updateGrid(); 
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: true,
-	    stateId: 'grid-resource',
-	    tbar: [
-		'->', 
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    value: textfilter,
-		    enableKeyEvents: true,
-		    listeners: {
-			keyup: function(field, e) {
-			    var v = field.getValue();
-			    textfilter = v.toLowerCase();
-			    filter_task.delay(500);
-			}
-		    }
-		}
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		destroy: function() {
-		    rstore.un("load", load_cb);
-		}
-	    },
-            columns: coldef
-	});
-	me.callParent();
-	updateGrid();
-	rstore.on("load", load_cb);
-    }
-});
-Ext.define('PVE.pool.AddVM', {
-    extend: 'Proxmox.window.Edit',
-    width: 600,
-    height: 400,
-    isAdd: true,
-    isCreate: true,
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	var vmsField = Ext.create('Ext.form.field.Text', {
-	    name: 'vms',
-	    hidden: true,
-	    allowBlank: false
-	});
-
-	var vmStore = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property: 'vmid',
-		    order: 'ASC'
-		}
-	    ],
-	    filters: [
-		function(item) {
-		    return ((item.data.type === 'lxc' || item.data.type === 'qemu') && item.data.pool === '');
-		}
-	    ]
-	});
-
-	var vmGrid = Ext.create('widget.grid',{
-	    store: vmStore,
-	    border: true,
-	    height: 300,
-	    scrollable: true,
-	    selModel: {
-		selType: 'checkboxmodel',
-		mode: 'SIMPLE',
-		listeners: {
-		    selectionchange: function(model, selected, opts) {
-			var selectedVms = [];
-			selected.forEach(function(vm) {
-			    selectedVms.push(vm.data.vmid);
-			});
-			vmsField.setValue(selectedVms);
-		    }
-		}
-	    },
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-	Ext.apply(me, {
-	    subject: gettext('Virtual Machine'),
-	    items: [ vmsField, vmGrid ]
-	});
-
-	me.callParent();
-	vmStore.load();
-    }
-});
-
-Ext.define('PVE.pool.AddStorage', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	me.isCreate = true;
-	me.isAdd = true;
-	me.url = "/pools/" + me.pool;
-	me.method = 'PUT';
-
-	Ext.apply(me, {
-	    subject: gettext('Storage'),
-	    width: 350,
-	    items: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'storage',
-		    nodename: 'localhost',
-		    autoSelect: false,
-		    value:  '',
-		    fieldLabel: gettext("Storage")
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.grid.PoolMembers', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pvePoolMembers'],
-
-    // fixme: dynamic status update ?
-
-    stateful: true,
-    stateId: 'grid-pool-members',
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.pool) {
-	    throw "no pool specified";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    model: 'PVEResources',
-	    sorters: [
-		{
-		    property : 'type',
-		    direction: 'ASC'
-		}
-	    ],
-	    proxy: {
-		type: 'proxmox',
-		root: 'data.members',
-		url: "/api2/json/pools/" + me.pool
-	    }
-	});
-
-	var coldef = PVE.data.ResourceStore.defaultColumns();
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		var params = { 'delete': 1 };
-		if (rec.data.type === 'storage') {
-		    params.storage = rec.data.storage;
-		} else if (rec.data.type === 'qemu' || rec.data.type === 'lxc' || rec.data.type === 'openvz') {
-		    params.vms = rec.data.vmid;
-		} else {
-		    throw "unknown resource type";
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/pools/' + me.pool,
-		    method: 'PUT',
-		    params: params,
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Virtual Machine'),
-				iconCls: 'pve-itype-icon-qemu',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddVM', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Storage'),
-				iconCls: 'pve-itype-icon-storage',
-				handler: function() {
-				    var win = Ext.create('PVE.pool.AddStorage', { pool: me.pool });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		stripeRows: true
-            },
-            columns: coldef,
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		itemdblclick: function(v, record) {
-		    var ws = me.up('pveStdWorkspace');
-		    ws.selectById(record.data.id);
-		},
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.form.FWMacroSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: 'widget.pveFWMacroSelector',
-    allowBlank: true,
-    autoSelect: false,
-    valueField: 'macro',
-    displayField: 'macro',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		hideable: false,
-		width: 100
-	    },
-	    {
-		header: gettext('Description'),
-		renderer: Ext.String.htmlEncode,
-		flex: 1,
-		dataIndex: 'descr'
-	    }
-	]
-    },
-    initComponent: function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: true,
-	    fields: [ 'macro', 'descr' ],
-	    idProperty: 'macro',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json/cluster/firewall/macros"
-	    },
-	    sorters: {
-		property: 'macro',
-		order: 'DESC'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRulePanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    allow_iface: false,
-
-    list_refs_url: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	// hack: editable ComboGrid returns nothing when empty, so we need to set ''
-	// Also, disabled text fields return nothing, so we need to set ''
-
-	Ext.Array.each(['source', 'dest', 'macro', 'proto', 'sport', 'dport', 'log'], function(key) {
-	    if (values[key] === undefined) {
-		values[key] = '';
-	    }
-	});
-
-	delete values.modified_marker;
- 
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.column1 = [
-	    {
-		// hack: we use this field to mark the form 'dirty' when the
-		// record has errors- so that the user can safe the unmodified 
-		// form again.
-		xtype: 'hiddenfield',
-		name: 'modified_marker',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'type',
-		value: 'in',
-		comboItems: [['in', 'in'], ['out', 'out']],
-		fieldLabel: gettext('Direction'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'action',
-		value: 'ACCEPT',
-		comboItems: [['ACCEPT', 'ACCEPT'], ['DROP', 'DROP'], ['REJECT', 'REJECT']],
-		fieldLabel: gettext('Action'),
-		allowBlank: false
-	    }
-        ];
-
-	if (me.allow_iface) {
-	    me.column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		fieldLabel: '',
-		value: ''
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'source',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Source')
-
-	    },
-	    {
-		xtype: 'pveIPRefSelector',
-		name: 'dest',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('Destination')
-	    }
-	);
-
-	
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    },
-	    {
-		xtype: 'pveFWMacroSelector',
-		name: 'macro',
-		fieldLabel: gettext('Macro'),
-		editable: true,
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-                        if (value === null) {
-			    me.down('field[name=proto]').setDisabled(false);
-			    me.down('field[name=sport]').setDisabled(false);
-			    me.down('field[name=dport]').setDisabled(false);
-                        } else {
-			    me.down('field[name=proto]').setDisabled(true);
-			    me.down('field[name=proto]').setValue('');
-			    me.down('field[name=sport]').setDisabled(true);
-			    me.down('field[name=sport]').setValue('');
-			    me.down('field[name=dport]').setDisabled(true);
-			    me.down('field[name=dport]').setValue('');
-                       }
-                    }
-                }
-	    },
-	    {
-		xtype: 'pveIPProtocolSelector',
-		name: 'proto',
-		autoSelect: false,
-		editable: true,
-		value: '',
-		fieldLabel: gettext('Protocol')
-	    },
-	    {
-		xtype: 'displayfield',
-		fieldLabel: '',
-		height: 7,
-		value: ''
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'sport',
-		value: '',
-		fieldLabel: gettext('Source port')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'dport',
-		value: '',
-		fieldLabel: gettext('Dest. port')
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'pveFirewallLogLevels'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.FirewallRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "no base_url specified";
-	}
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.FirewallRulePanel', {
-	    isCreate: me.isCreate,
-	    list_refs_url: me.list_refs_url,
-	    allow_iface: me.allow_iface,
-	    rule_pos: me.rule_pos
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		    if (values.errors) {
-			var field = me.query('[isFormField][name=modified_marker]')[0];
-			field.setValue(1);
-			Ext.Function.defer(function() {
-			    var form = ipanel.up('form').getForm();
-			    form.markInvalid(values.errors);
-			}, 100);
-		    }
-		}
-	    });
-	} else if (me.rec) {
-	    ipanel.setValues(me.rec.data);
-	}
-    }
-});
-
-Ext.define('PVE.FirewallGroupRuleEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    allow_iface: false,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.rule_pos === undefined);
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.rule_pos.toString();
-            me.method = 'PUT';
-        }
-
-	var column1 = [
-	    {
-		xtype: 'hiddenfield',
-		name: 'type',
-		value: 'group'
-	    },
-	    {
-		xtype: 'pveSecurityGroupsSelector',
-		name: 'action',
-		value: '',
-		fieldLabel: gettext('Security Group'),
-		allowBlank: false
-	    }
-	];
-
-	if (me.allow_iface) {
-	    column1.push({
-		xtype: 'proxmoxtextfield',
-		name: 'iface',
-		deleteEmpty: !me.isCreate,
-		value: '',
-		fieldLabel: gettext('Interface')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'enable',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: gettext('Enable')
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Rule'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.FirewallRules', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveFirewallRules',
-
-    onlineHelp: 'chapter_pve_firewall',
-
-    stateful: true,
-    stateId: 'grid-firewall-rules',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-    groupBtn: undefined,
-
-    tbar_prefix: undefined,
-
-    allow_groups: true,
-    allow_iface: false,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(true);
-	    }
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    if (me.groupBtn) {
-		me.groupBtn.setDisabled(false);
-	    }
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    moveRule: function(from, to) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + "/" + from,
-	    method: 'PUT',
-	    params: { moveto: to },
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-    updateRule: function(rule) {
-        var me = this;
-
-	if (!me.base_url) { 
-	    return;
-	}
-
-	rule.enable = rule.enable ? 1 : 0;
-
-	var pos = rule.pos;
-	delete rule.pos;
-	delete rule.errors;
-
-	Proxmox.Utils.API2Request({
-	    url: me.base_url + '/' + pos.toString(),
-	    method: 'PUT',
-	    params: rule,
-	    waitMsgTarget: me,
-	    failure: function(response, options) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-    },
-
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-fw-rule'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-	    var editor;
-	    if (type === 'in' || type === 'out') {
-		editor = 'PVE.FirewallRuleEdit';
-	    } else if (type === 'group') {
-		editor = 'PVE.FirewallGroupRuleEdit';
-	    } else {
-		return;
-	    }
-
-	    var win = Ext.create(editor, {
-		digest: rec.data.digest,
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rule_pos: rec.data.pos
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallRuleEdit', {
-		    allow_iface: me.allow_iface,
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var run_copy_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type;
-
-
-	    if (!(type === 'in' || type === 'out')) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallRuleEdit', {
-		allow_iface: me.allow_iface,
-		base_url: me.base_url,
-		list_refs_url: me.list_refs_url,
-		rec: rec
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.copyBtn = Ext.create('Proxmox.button.Button',{
-	    text: gettext('Copy'),
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return (rec.data.type === 'in' || rec.data.type === 'out');
-	    },
-	    disabled: true,
-	    handler: run_copy_editor
-	});
-
-	if (me.allow_groups) {
-	    me.groupBtn =  Ext.create('Ext.Button', {
-		text: gettext('Insert') + ': ' + 
-		    gettext('Security Group'),
-		disabled: true,
-		handler: function() {
-		    var win = Ext.create('PVE.FirewallGroupRuleEdit', {
-			allow_iface: me.allow_iface,
-			base_url: me.base_url
-		    });
-		    win.on('destroy', reload);
-		    win.show();
-		}
-	    });
-	}
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    confirmMsg: false,
-	    getRecordName: function(rec) {
-		var rule = rec.data;
-		return rule.pos.toString() +
-		    '?digest=' + encodeURIComponent(rule.digest);
-	    },
-	    callback: function() {
-		me.store.load();
-	    }
-	});
-
-	var tbar = me.tbar_prefix ? [ me.tbar_prefix ] : [];
-	tbar.push(me.addBtn, me.copyBtn);
-	if (me.groupBtn) {
-	    tbar.push(me.groupBtn);
-	}
-	tbar.push(me.removeBtn, me.editBtn);
-
-	var render_errors = function(name, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors && errors[name]) {
-		metaData.tdCls = 'proxmox-invalid-row';
-		var html = '<p>' +  Ext.htmlEncode(errors[name]) + '</p>';
-		metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-		    html.replace(/\"/g,'&quot;') + '"';
-	    }
-	    return value;
-	};
-
-	var columns = [
-	    {
-		// similar to xtype: 'rownumberer',
-		dataIndex: 'pos',
-		resizable: false,
-		width: 23,
-		sortable: false,
-		align: 'right',
-		hideable: false,
-		menuDisabled: true,
-		renderer: function(value, metaData, record, rowIdx, colIdx, store) {
-		    metaData.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
-		    if (value >= 0) {
-			return value;
-		    }
-		    return '';
-		}
-	    },
-	    {
-		xtype: 'checkcolumn',
-		header: gettext('Enable'),
-		dataIndex: 'enable',
-		listeners: {
-		    checkchange: function(column, recordIndex, checked) {
-			var record = me.getStore().getData().items[recordIndex];
-			record.commit();
-			var data = {};
-			Ext.Array.forEach(record.getFields(), function(field) {
-			    data[field.name] = record.get(field.name);
-			});
-			if (!me.allow_iface || !data.iface) {
-			    delete data.iface;
-			}
-			me.updateRule(data);
-		    }
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Type'),
-		dataIndex: 'type',
-		renderer: function(value, metaData, record) {
-		    return render_errors('type', value, metaData, record);
-		},
-		width: 50
-	    },
-	    {
-		header: gettext('Action'),
-		dataIndex: 'action',
-		renderer: function(value, metaData, record) {
-		    return render_errors('action', value, metaData, record);
-		},
-		width: 80
-	    },
-	    {
-		header: gettext('Macro'),
-		dataIndex: 'macro',
-		renderer: function(value, metaData, record) {
-		    return render_errors('macro', value, metaData, record);
-		},
-		width: 80
-	    }
-	];
-
-	if (me.allow_iface) {
-	    columns.push({
-		header: gettext('Interface'),
-		dataIndex: 'iface',
-		renderer: function(value, metaData, record) {
-		    return render_errors('iface', value, metaData, record);
-		},
-		width: 80
-	    });
-	}
-
-	columns.push(
-	    {
-		header: gettext('Source'),
-		dataIndex: 'source',
-		renderer: function(value, metaData, record) {
-		    return render_errors('source', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Destination'),
-		dataIndex: 'dest',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dest', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Protocol'),
-		dataIndex: 'proto',
-		renderer: function(value, metaData, record) {
-		    return render_errors('proto', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Dest. port'),
-		dataIndex: 'dport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('dport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Source port'),
-		dataIndex: 'sport',
-		renderer: function(value, metaData, record) {
-		    return render_errors('sport', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Log level'),
-		dataIndex: 'log',
-		renderer: function(value, metaData, record) {
-		    return render_errors('log', value, metaData, record);
-		},
-		width: 100
-	    },
-	    {
-		header: gettext('Comment'),
-		dataIndex: 'comment',
-		flex: 1,
-		renderer: function(value, metaData, record) {
-		    return render_errors('comment', Ext.util.Format.htmlEncode(value), metaData, record);
-		}
-	    }
-	);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-            viewConfig: {
-		plugins: [
-		    {
-			ptype: 'gridviewdragdrop',
-			dragGroup: 'FWRuleDDGroup',
-			dropGroup: 'FWRuleDDGroup'
-		    }
-		],
-		listeners: {
-                    beforedrop: function(node, data, dropRec, dropPosition) {
-			if (!dropRec) {
-			    return false; // empty view
-			}
-			var moveto = dropRec.get('pos');
-			if (dropPosition === 'after') {
-			    moveto++;
-			}
-			var pos = data.records[0].get('pos');
-			me.moveRule(pos, moveto);
-			return 0;
-                    },
-		    itemdblclick: run_editor
-		}
-	    },
-	    sortableColumns: false,
-	    columns: columns
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-fw-rule', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'enable', type: 'boolean' },
-		  'type', 'action', 'macro', 'source', 'dest', 'proto', 'iface',
-		  'dport', 'sport', 'comment', 'pos', 'digest', 'errors' ],
-	idProperty: 'pos'
-    });
-
-});
-Ext.define('PVE.FirewallAliasEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: undefined,
-
-    alias_name: undefined,
-
-    width: 400,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.alias_name === undefined);
-
-	if (me.isCreate) {
-	    me.url = '/api2/extjs' + me.base_url;
-	    me.method = 'POST';
-	} else {
-	    me.url = '/api2/extjs' + me.base_url + '/' + me.alias_name;
-	    me.method = 'PUT';
-	}
-
-	var items =  [
-	    {
-		xtype: 'textfield',
-		name: me.isCreate ? 'name' : 'rename',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'cidr',
-		fieldLabel: gettext('IP/CIDR'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    items: items
-	});
-
-	Ext.apply(me, {
-            subject: gettext('Alias'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-		    values.rename = values.name;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('pve-fw-aliases', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'name', 'cidr', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.FirewallAliases', {
-    extend: 'Ext.grid.Panel',
-    alias: ['widget.pveFirewallAliases'],
-
-    onlineHelp: 'pve_firewall_ip_aliases',
-
-    stateful: true,
-    stateId: 'grid-firewall-aliases',
-
-    base_url: undefined,
-
-    title: gettext('Alias'),
-
-    initComponent : function() {
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-aliases',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.FirewallAliasEdit', {
-		base_url: me.base_url,
-		alias_name: rec.data.name
-	    });
-
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn =  Ext.create('Ext.Button', {
-	    text: gettext('Add'),
-	    handler: function() {
-		var win = Ext.create('PVE.FirewallAliasEdit', {
-		    base_url: me.base_url
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1,
-		},
-		{
-		    header:  gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    flex: 1,
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 3,
-		}
-	    ],
-	    listeners: {
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-	me.on('activate', reload);
-    }
-});
-Ext.define('PVE.FirewallOptions', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveFirewallOptions'],
-
-    fwtype: undefined, // 'dc', 'node' or 'vm'
-
-    base_url: undefined,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	if (!me.base_url) {
-	    throw "missing base_url configuration";
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'node' || me.fwtype === 'vm') {
-	    if (me.fwtype === 'node') {
-		me.cwidth1 = 250;
-	    }
-	} else {
-	    throw "unknown firewall option type";
-	}
-
-	me.rows = {};
-
-	var add_boolean_row = function(name, text, defaultValue) {
-	    me.add_boolean_row(name, text, { defaultValue: defaultValue });
-	};
-	var add_integer_row = function(name, text, minValue, labelWidth) {
-	    me.add_integer_row(name, text, {
-		minValue: minValue,
-		deleteEmpty: true,
-		labelWidth: labelWidth,
-		renderer: function(value) {
-		    if (value === undefined) {
-			return Proxmox.Utils.defaultText;
-		    }
-
-		    return value;
-		}
-	    });
-	};
-
-	var add_log_row = function(name, labelWidth) {
-	    me.rows[name] = {
-		header: name,
-		required: true,
-		defaultValue: 'nolog',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: name,
-		    fieldDefaults: { labelWidth: labelWidth || 100 },
-		    items: {
-			xtype: 'pveFirewallLogLevels',
-			name: name,
-			fieldLabel: name
-		    }
-		}
-	    };
-	};
-
-	if (me.fwtype === 'node') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 1,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 1
-		}
-	    };
-	    add_boolean_row('nosmurfs', gettext('SMURFS filter'), 1);
-	    add_boolean_row('tcpflags', gettext('TCP flags filter'), 0);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_integer_row('nf_conntrack_max', 'nf_conntrack_max', 32768, 120);
-	    add_integer_row('nf_conntrack_tcp_timeout_established',
-			    'nf_conntrack_tcp_timeout_established', 7875, 250);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	    add_log_row('tcp_flags_log_level', 120);
-	    add_log_row('smurf_log_level');
-	} else if (me.fwtype === 'vm') {
-	    me.rows.enable = {
-		required: true,
-		defaultValue: 0,
-		header: gettext('Firewall'),
-		renderer: Proxmox.Utils.format_boolean,
-		editor: {
-		    xtype: 'pveFirewallEnableEdit',
-		    defaultValue: 0
-		}
-	    };
-	    add_boolean_row('dhcp', 'DHCP', 1);
-	    add_boolean_row('ndp', 'NDP', 1);
-	    add_boolean_row('radv', gettext('Router Advertisement'), 0);
-	    add_boolean_row('macfilter', gettext('MAC filter'), 1);
-	    add_boolean_row('ipfilter', gettext('IP filter'), 0);
-	    add_log_row('log_level_in');
-	    add_log_row('log_level_out');
-	} else if (me.fwtype === 'dc') {
-	    add_boolean_row('enable', gettext('Firewall'), 0);
-	    add_boolean_row('ebtables', 'ebtables', 1);
-	    me.rows.log_ratelimit = {
-		header: gettext('Log rate limit'),
-		required: true,
-		defaultValue: gettext('Default') + ' (enable=1,rate1/second,burst=5)',
-		editor: {
-		    xtype: 'pveFirewallLograteEdit',
-		    defaultValue: 'enable=1'
-		}
-	    };
-	}
-
-	if (me.fwtype === 'dc' || me.fwtype === 'vm') {
-	    me.rows.policy_in = {
-		header: gettext('Input Policy'),
-		required: true,
-		defaultValue: 'DROP',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Input Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_in',
-			value: 'DROP',
-			fieldLabel: gettext('Input Policy')
-		    }
-		}
-	    };
-
-	    me.rows.policy_out = {
-		header: gettext('Output Policy'),
-		required: true,
-		defaultValue: 'ACCEPT',
-		editor: {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Output Policy'),
-		    items: {
-			xtype: 'pveFirewallPolicySelector',
-			name: 'policy_out',
-			value: 'ACCEPT',
-			fieldLabel: gettext('Output Policy')
-		    }
-		}
-	    };
-	}
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    var rowdef = me.rows[rec.data.key];
-	    edit_btn.setDisabled(!rowdef.editor);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json" + me.base_url,
-	    tbar: [ edit_btn ],
-	    editorConfig: {
-		url: '/api2/extjs/' + me.base_url
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-
-
-Ext.define('PVE.FirewallLogLevels', {
-    extend: 'Proxmox.form.KVComboBox',
-    alias: ['widget.pveFirewallLogLevels'],
-
-    name: 'log',
-    fieldLabel: gettext('Log level'),
-    value: 'nolog',
-    comboItems: [['nolog', 'nolog'], ['emerg', 'emerg'], ['alert', 'alert'],
-	['crit', 'crit'], ['err', 'err'], ['warning', 'warning'],
-	['notice', 'notice'], ['info', 'info'], ['debug', 'debug']]
-});
-/*
- * Left Treepanel, containing all the resources we manage in this datacenter: server nodes, server storages, VMs and Containers
- */
-Ext.define('PVE.tree.ResourceTree', {
-    extend: 'Ext.tree.TreePanel',
-    alias: ['widget.pveResourceTree'],
-
-    statics: {
-	typeDefaults: {
-	    node: { 
-		iconCls: 'fa fa-building',
-		text: gettext('Nodes')
-	    },
-	    pool: { 
-		iconCls: 'fa fa-tags',
-		text: gettext('Resource Pool')
-	    },
-	    storage: {
-		iconCls: 'fa fa-database',
-		text: gettext('Storage')
-	    },
-	    qemu: {
-		iconCls: 'fa fa-desktop',
-		text: gettext('Virtual Machine')
-	    },
-	    lxc: {
-		//iconCls: 'x-tree-node-lxc',
-		iconCls: 'fa fa-cube',
-		text: gettext('LXC Container')
-	    },
-	    template: {
-		iconCls: 'fa fa-file-o'
-	    }
-	}
-    },
-
-    useArrows: true,
-
-    // private
-    nodeSortFn: function(node1, node2) {
-	var n1 = node1.data;
-	var n2 = node2.data;
-
-	if ((n1.groupbyid && n2.groupbyid) ||
-	    !(n1.groupbyid || n2.groupbyid)) {
-
-	    var tcmp;
-
-	    var v1 = n1.type;
-	    var v2 = n2.type;
-
-	    if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		return tcmp;
-	    }
-
-	    // numeric compare for VM IDs
-	    // sort templates after regular VMs
-	    if (v1 === 'qemu' || v1 === 'lxc') {
-		if (n1.template && !n2.template) {
-		    return 1;
-		} else if (n2.template && !n1.template) {
-		    return -1;
-		}
-		v1 = n1.vmid;
-		v2 = n2.vmid;
-		if ((tcmp = v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)) != 0) {
-		    return tcmp;
-		}
-	    }
-
-	    return n1.id > n2.id ? 1 : (n1.id < n2.id ? -1 : 0);
-	} else if (n1.groupbyid) {
-	    return -1;
-	} else if (n2.groupbyid) {
-	    return 1;
-	}
-    },
-
-    // private: fast binary search
-    findInsertIndex: function(node, child, start, end) {
-	var me = this;
-
-	var diff = end - start;
-
-	var mid = start + (diff>>1);
-
-	if (diff <= 0) {
-	    return start;
-	}
-
-	var res = me.nodeSortFn(child, node.childNodes[mid]);
-	if (res <= 0) {
-	    return me.findInsertIndex(node, child, start, mid);
-	} else {
-	    return me.findInsertIndex(node, child, mid + 1, end);
-	}
-    },
-
-    setIconCls: function(info) {
-	var me = this;
-
-	var cls = PVE.Utils.get_object_icon_class(info.type, info);
-
-	if (cls !== '') {
-	    info.iconCls = cls;
-	}
-    },
-
-    // add additional elements to text
-    // at the moment only the usage indicator for storages
-    setText: function(info) {
-	var me = this;
-
-	var status = '';
-	if (info.type === 'storage') {
-	    var maxdisk = info.maxdisk;
-	    var disk = info.disk;
-	    var usage = disk/maxdisk;
-	    var cls = '';
-	    if (usage <= 1.0 && usage >= 0.0) {
-		var height = (usage*100).toFixed(0);
-		var neg_height = (100-usage*100).toFixed(0);
-		status = '<div class="usage-wrapper">';
-		status += '<div class="usage-negative" style="height: ';
-		status += neg_height + '%"></div>';
-		status += '<div class="usage" style="height: '+ height +'%"></div>';
-		status += '</div> ';
-	    }
-	}
-
-	info.text = status + info.text;
-    },
-
-    setToolTip: function(info) {
-	if (info.type === 'pool' || info.groupbyid !== undefined) {
-	    return;
-	}
-
-	var qtips = [gettext('Status') + ': ' + (info.qmpstatus || info.status)];
-	if (info.lock) {
-	    qtips.push('Config locked (' + info.lock + ')');
-	}
-	if (info.hastate != 'unmanaged') {
-	    qtips.push(gettext('HA State') + ": " + info.hastate);
-	}
-
-	info.qtip = qtips.join(', ');
-    },
-
-    // private
-    addChildSorted: function(node, info) {
-	var me = this;
-
-	me.setIconCls(info);
-	me.setText(info);
-	me.setToolTip(info);
-
-	var defaults;
-	if (info.groupbyid) {
-	    info.text = info.groupbyid;
-	    if (info.type === 'type') {
-		defaults = PVE.tree.ResourceTree.typeDefaults[info.groupbyid];
-		if (defaults && defaults.text) {
-		    info.text = defaults.text;
-		}
-	    }
-	}
-	var child = Ext.create('PVETree', info);
-
-        var cs = node.childNodes;
-	var pos;
-	if (cs) {
-	    pos = cs[me.findInsertIndex(node, child, 0, cs.length)];
-	}
-
-	node.insertBefore(child, pos);
-
-	return child;
-    },
-
-    // private
-    groupChild: function(node, info, groups, level) {
-	var me = this;
-
-	var groupby = groups[level];
-	var v = info[groupby];
-
-	if (v) {
-            var group = node.findChild('groupbyid', v);
-	    if (!group) {
-		var groupinfo;
-		if (info.type === groupby) {
-		    groupinfo = info;
-		} else {
-		    groupinfo = {
-			type: groupby,
-			id : groupby + "/" + v
-		    };
-		    if (groupby !== 'type') {
-			groupinfo[groupby] = v;
-		    }
-		}
-		groupinfo.leaf = false;
-		groupinfo.groupbyid = v; 
-		group = me.addChildSorted(node, groupinfo);
-	    }
-	    if (info.type === groupby) {
-		return group;
-	    }
-	    if (group) {
-		return me.groupChild(group, info, groups, level + 1);
-	    }
-	}
-
-	return me.addChildSorted(node, info);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var rstore = PVE.data.ResourceStore;
-	var sp = Ext.state.Manager.getProvider();
-
-	if (!me.viewFilter) {
-	    me.viewFilter = {};
-	}
-
-	var pdata = {
-	    dataIndex: {},
-	    updateCount: 0
-	};
-
-	var store = Ext.create('Ext.data.TreeStore', {
-	    model: 'PVETree',
-	    root: {
-		expanded: true,
-		id: 'root',
-		text: gettext('Datacenter'),
-		iconCls: 'fa fa-server'
-	    }
-	});
-
-	var stateid = 'rid';
-
-	var updateTree = function() {
-	    var tmp;
-
-	    store.suspendEvents();
-
-	    var rootnode = me.store.getRootNode();
-	    // remember selected node (and all parents)
-	    var sm = me.getSelectionModel();
-
-	    var lastsel = sm.getSelection()[0];
-	    var reselect = false;
-	    var parents = [];
-	    var p = lastsel;
-	    while (p && !!(p = p.parentNode)) {
-		parents.push(p);
-	    }
-
-	    var index = pdata.dataIndex;
-
-	    var groups = me.viewFilter.groups || [];
-	    var filterfn = me.viewFilter.filterfn;
-
-	    // remove vanished or moved items
-	    // update in place changed items
-	    var key;
-	    for (key in index) {
-		if (index.hasOwnProperty(key)) {
-		    var olditem = index[key];
-
-		    // getById() use find(), which is slow (ExtJS4 DP5) 
-		    //var item = rstore.getById(olditem.data.id);
-		    var item = rstore.data.get(olditem.data.id);
-
-		    var changed = false;
-		    var moved = false;
-		    if (item) {
-			// test if any grouping attributes changed
-			// this will also catch migrated nodes
-			// in server view
-			var i, len;
-			for (i = 0, len = groups.length; i < len; i++) {
-			    var attr = groups[i];
-			    if (item.data[attr] != olditem.data[attr]) {
-				//console.log("changed " + attr);
-				moved = true;
-				break;
-			    }
-			}
-
-			// explicitly check for node, since
-			// in some views, node is not a grouping
-			// attribute
-			if (!moved && item.data.node !== olditem.data.node) {
-			    moved = true;
-			}
-
-			// tree item has been updated
-			var fields = [
-			    'text', 'running', 'template', 'status',
-			    'qmpstatus', 'hastate', 'lock'
-			];
-
-			var field;
-			for (i = 0; i < fields.length; i++) {
-			    field = fields[i];
-			    if (item.data[field] !== olditem.data[field]) {
-				changed = true;
-				break;
-			    }
-			}
-
-			// fixme: also test filterfn()?
-		    }
-
-		    if (changed) {
-			olditem.beginEdit();
-			//console.log("REM UPDATE UID: " + key + " ITEM " + item.data.running);
-			var info = olditem.data;
-			Ext.apply(info, item.data);
-			me.setIconCls(info);
-			me.setText(info);
-			me.setToolTip(info);
-			olditem.commit();
-		    }
-		    if ((!item || moved) && olditem.isLeaf()) {
-			//console.log("REM UID: " + key + " ITEM " + olditem.data.id);
-			delete index[key];
-			var parentNode = olditem.parentNode;
-			// when the selected item disappears,
-			// we have to deselect it here, and reselect it
-			// later
-			if (lastsel && olditem.data.id === lastsel.data.id) {
-			    reselect = true;
-			    sm.deselect(olditem);
-			}
-			// since the store events are suspended, we
-			// manually remove the item from the store also
-			store.remove(olditem);
-			parentNode.removeChild(olditem, true);
-		    }
-		}
-	    }
-
-	    // add new items
-            rstore.each(function(item) {
-		var olditem = index[item.data.id];
-		if (olditem) {
-		    return;
-		}
-
-		if (filterfn && !filterfn(item)) {
-		    return;
-		}
-
-		//console.log("ADD UID: " + item.data.id);
-
-		var info = Ext.apply({ leaf: true }, item.data);
-
-		var child = me.groupChild(rootnode, info, groups, 0);
-		if (child) {
-		    index[item.data.id] = child;
-		}
-	    });
-
-	    store.resumeEvents();
-	    store.fireEvent('refresh', store);
-
-	    // select parent node is selection vanished
-	    if (lastsel && !rootnode.findChild('id', lastsel.data.id, true)) {
-		lastsel = rootnode;
-		while (!!(p = parents.shift())) {
-		    if (!!(tmp = rootnode.findChild('id', p.data.id, true))) {
-			lastsel = tmp;
-			break;
-		    }
-		}
-		me.selectById(lastsel.data.id);
-	    } else if (lastsel && reselect) {
-		me.selectById(lastsel.data.id);
-	    }
-
-	    // on first tree load set the selection from the stateful provider
-	    if (!pdata.updateCount) {
-		rootnode.expand();
-		me.applyState(sp.get(stateid));
-	    }
-
-	    pdata.updateCount++;
-	};
-
-	var statechange = function(sp, key, value) {
-	    if (key === stateid) {
-		me.applyState(value);
-	    }
-	};
-
-	sp.on('statechange', statechange);
-
-	Ext.apply(me, {
-	    allowSelection: true,
-	    store: store,
-	    viewConfig: {
-		// note: animate cause problems with applyState
-		animate: false
-	    },
-	    //useArrows: true,
-            //rootVisible: false,
-            //title: 'Resource Tree',
-	    listeners: {
-		itemcontextmenu: PVE.Utils.createCmdMenu,
-		destroy: function() {
-		    rstore.un("load", updateTree);
-		},
-		beforecellmousedown: function (tree, td, cellIndex, record, tr, rowIndex, ev) {
-		    var sm = me.getSelectionModel();
-		    // disable selection when right clicking
-		    // except the record is already selected
-		    me.allowSelection = (ev.button !== 2) || sm.isSelected(record);
-		},
-		beforeselect: function (tree, record, index, eopts) {
-		    var allow = me.allowSelection;
-		    me.allowSelection = true;
-		    return allow;
-		},
-		itemdblclick: PVE.Utils.openTreeConsole
-	    },
-	    setViewFilter: function(view) {
-		me.viewFilter = view;
-		me.clearTree();
-		updateTree();
-	    },
-	    setDatacenterText: function(clustername) {
-		var rootnode = me.store.getRootNode();
-
-		var rnodeText = gettext('Datacenter');
-		if (clustername !== undefined) {
-		    rnodeText += ' (' + clustername + ')';
-		}
-
-		rootnode.beginEdit();
-		rootnode.data.text = rnodeText;
-		rootnode.commit();
-	    },
-	    clearTree: function() {
-		pdata.updateCount = 0;
-		var rootnode = me.store.getRootNode();
-		rootnode.collapse();
-		rootnode.removeAll();
-		pdata.dataIndex = {};
-		me.getSelectionModel().deselectAll();
-	    },
-	    selectExpand: function(node) {
-		var sm = me.getSelectionModel();
-		if (!sm.isSelected(node)) {
-		    sm.select(node);
-		    var cn = node;
-		    while (!!(cn = cn.parentNode)) {
-			if (!cn.isExpanded()) {
-			    cn.expand();
-			}
-		    }
-		    me.getView().focusRow(node);
-		}
-	    },
-	    selectById: function(nodeid) {
-		var rootnode = me.store.getRootNode();
-		var sm = me.getSelectionModel();
-		var node;
-		if (nodeid === 'root') {
-		    node = rootnode;
-		} else {
-		    node = rootnode.findChild('id', nodeid, true);
-		}
-		if (node) {
-		    me.selectExpand(node);
-		}
-		return node;
-	    },
-	    applyState : function(state) {
-		var sm = me.getSelectionModel();
-		if (state && state.value) {
-		    me.selectById(state.value);
-		} else {
-		    sm.deselectAll();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	var sm = me.getSelectionModel();
-	sm.on('select', function(sm, n) {		    
-	    sp.set(stateid, { value: n.data.id});
-	});
-
-	rstore.on("load", updateTree);
-	rstore.startUpdate();
-	//rstore.stopUpdate();
-    }
-
-});
-Ext.define('PVE.guest.SnapshotTree', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveGuestSnapshotTree',
-
-    stateful: true,
-    stateId: 'grid-snapshots',
-
-    viewModel: {
-	data: {
-	    // should be 'qemu' or 'lxc'
-	    type: undefined,
-	    nodename: undefined,
-	    vmid: undefined,
-	    snapshotAllowed: false,
-	    rollbackAllowed: false,
-	    snapshotFeature: false,
-	    running: false,
-	    selected: '',
-	    load_delay: 3000,
-	},
-	formulas: {
-	    canSnapshot: (get) => get('snapshotAllowed') && get('snapshotFeature'),
-	    canRollback: (get) => get('rollbackAllowed') && get('isSnapshot'),
-	    canRemove: (get) => get('snapshotAllowed') && get('isSnapshot'),
-	    isSnapshot: (get) => get('selected') && get('selected') !== 'current',
-	    buttonText: (get) => get('snapshotAllowed') ? gettext('Edit') : gettext('View'),
-	    showMemory: (get) => get('type') === 'qemu',
-	},
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	newSnapshot: function() {
-	    this.run_editor(false);
-	},
-
-	editSnapshot: function() {
-	    this.run_editor(true);
-	},
-
-	run_editor: function(edit) {
-	    let me = this;
-	    let vm = me.getViewModel();
-	    let snapname;
-	    if (edit) {
-		snapname = vm.get('selected');
-		if (!snapname || snapname === 'current') { return; }
-	    }
-	    let win = Ext.create('PVE.window.Snapshot', {
-		nodename: vm.get('nodename'),
-		vmid: vm.get('vmid'),
-		viewonly: !vm.get('snapshotAllowed'),
-		type: vm.get('type'),
-		isCreate: !edit,
-		submitText: !edit ? gettext('Take Snapshot') : undefined,
-		snapname: snapname,
-		running: vm.get('running'),
-	    });
-	    win.show();
-	    me.mon(win, 'destroy', me.reload, me);
-	},
-
-	snapshotAction: function(action, method) {
-	    let me = this;
-	    let view = me.getView();
-	    let vm = me.getViewModel();
-	    let snapname = vm.get('selected');
-	    if (!snapname) { return; }
-
-	    let nodename = vm.get('nodename');
-	    let type = vm.get('type');
-	    let vmid = vm.get('vmid');
-
-	    Proxmox.Utils.API2Request({
-		url: `/nodes/${nodename}/${type}/${vmid}/snapshot/${snapname}/${action}`,
-		method: method,
-		waitMsgTarget: view,
-		callback: function() {
-		    me.reload();
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
-		    win.show();
-		}
-	    });
-	},
-
-	rollback: function() {
-	    this.snapshotAction('rollback', 'POST');
-	},
-	remove: function() {
-	    this.snapshotAction('', 'DELETE');
-	},
-	cancel: function() {
-	    this.load_task.cancel();
-	},
-
-	reload: function() {
-	    let me = this;
-	    let view = me.getView();
-	    let vm = me.getViewModel();
-	    let nodename = vm.get('nodename');
-	    let vmid = vm.get('vmid');
-	    let type = vm.get('type');
-	    let load_delay = vm.get('load_delay');
-
-	    Proxmox.Utils.API2Request({
-		url: `/nodes/${nodename}/${type}/${vmid}/snapshot`,
-		method: 'GET',
-		failure: function(response, opts) {
-		    if (me.destroyed) return;
-		    Proxmox.Utils.setErrorMask(view, response.htmlStatus);
-		    me.load_task.delay(load_delay);
-		},
-		success: function(response, opts) {
-		    if (me.destroyed) {
-			// this is in a delayed task, avoid dragons if view has
-			// been destroyed already and go home.
-			return;
-		    }
-		    Proxmox.Utils.setErrorMask(view, false);
-		    var digest = 'invalid';
-		    var idhash = {};
-		    var root = { name: '__root', expanded: true, children: [] };
-		    Ext.Array.each(response.result.data, function(item) {
-			item.leaf = true;
-			item.children = [];
-			if (item.name === 'current') {
-			    vm.set('running', !!item.running);
-			    digest = item.digest + item.running;
-			    item.iconCls = PVE.Utils.get_object_icon_class(vm.get('type'), item);
-			} else {
-			    item.iconCls = 'fa fa-fw fa-history x-fa-tree';
-			}
-			idhash[item.name] = item;
-		    });
-
-		    if (digest !== me.old_digest) {
-			me.old_digest = digest;
-
-			Ext.Array.each(response.result.data, function(item) {
-			    if (item.parent && idhash[item.parent]) {
-				var parent_item = idhash[item.parent];
-				parent_item.children.push(item);
-				parent_item.leaf = false;
-				parent_item.expanded = true;
-				parent_item.expandable = false;
-			    } else {
-				root.children.push(item);
-			    }
-			});
-
-			me.getView().setRootNode(root);
-		    }
-
-		    me.load_task.delay(load_delay);
-		}
-	    });
-
-	    // if we do not have the permissions, we don't have to check
-	    // if we can create a snapshot, since the butten stays disabled
-	    if (!vm.get('snapshotAllowed')) {
-		return;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: `/nodes/${nodename}/${type}/${vmid}/feature`,
-		params: { feature: 'snapshot' },
-		method: 'GET',
-		success: function(response, options) {
-		    if (me.destroyed) {
-			// this is in a delayed task, the current view could been
-			// destroyed already; then we mustn't do viemodel set
-			return;
-		    }
-		    let res = response.result.data;
-		    vm.set('snapshotFeature', !!res.hasFeature);
-		}
-	    });
-	},
-
-	select: function(grid, val) {
-	    let vm = this.getViewModel();
-	    if (val.length < 1) {
-		vm.set('selected', '');
-		return;
-	    }
-	    vm.set('selected', val[0].data.name);
-	},
-
-	init: function(view) {
-	    let me = this;
-	    let vm = me.getViewModel();
-	    me.load_task = new Ext.util.DelayedTask(me.reload, me);
-
-	    if (!view.type) {
-		throw 'guest type not set';
-	    }
-	    vm.set('type', view.type);
-
-	    if (!view.pveSelNode.data.node) {
-		throw "no node name specified";
-	    }
-	    vm.set('nodename', view.pveSelNode.data.node);
-
-	    if (!view.pveSelNode.data.vmid) {
-		throw "no VM ID specified";
-	    }
-	    vm.set('vmid', view.pveSelNode.data.vmid);
-
-	    let caps = Ext.state.Manager.get('GuiCap');
-	    vm.set('snapshotAllowed', !!caps.vms['VM.Snapshot']);
-	    vm.set('rollbackAllowed', !!caps.vms['VM.Snapshot.Rollback']);
-
-	    view.getStore().sorters.add({
-		property: 'order',
-		direction: 'ASC',
-	    });
-
-	    me.reload();
-	},
-    },
-
-    listeners: {
-	selectionchange: 'select',
-	itemdblclick: 'editSnapshot',
-	destroy: 'cancel',
-    },
-
-    layout: 'fit',
-    rootVisible: false,
-    animate: false,
-    sortableColumns: false,
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Take Snapshot'),
-	    disabled: true,
-	    bind: {
-		disabled: "{!canSnapshot}",
-	    },
-	    handler: 'newSnapshot',
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Rollback'),
-	    disabled: true,
-	    bind: {
-		disabled: '{!canRollback}',
-	    },
-	    confirmMsg: function() {
-		let view = this.up('treepanel');
-		let rec = view.getSelection()[0];
-		let vmid = view.getViewModel().get('vmid');
-		return Proxmox.Utils.format_task_description('qmrollback', vmid) +
-		    " '" +  rec.data.name + "'";
-	    },
-	    handler: 'rollback',
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Remove'),
-	    disabled: true,
-	    bind: {
-		disabled: '{!canRemove}',
-	    },
-	    confirmMsg: function() {
-		let view = this.up('treepanel');
-		let rec = view.getSelection()[0];
-		return Ext.String.format(
-		    gettext('Are you sure you want to remove entry {0}'),
-		    `'${rec.data.name}'`
-		);
-	    },
-	    handler: 'remove',
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    bind: {
-		text: '{buttonText}',
-		disabled: '{!isSnapshot}',
-	    },
-	    disabled: true,
-	    edit: true,
-	    handler: 'editSnapshot',
-	},
-	{
-	    xtype: 'label',
-	    text: gettext("The current guest configuration does not support taking new snapshots"),
-	    hidden: true,
-	    bind: {
-		hidden: "{canSnapshot}",
-	    },
-	},
-    ],
-
-    columnLines: true,
-
-    fields: [
-	'name', 'description', 'snapstate', 'vmstate', 'running',
-	{ name: 'snaptime', type: 'date', dateFormat: 'timestamp' },
-	{
-	    name: 'order',
-	    calculate: function(data) {
-		return data.snaptime || (data.name === 'current' ? 'ZZZ' : data.snapstate);
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    width: 200,
-	    renderer: function(value, metaData, record) {
-		if (value === 'current') {
-		    return gettext('NOW');
-		} else {
-		    return value;
-		}
-	    }
-	},
-	{
-	    text: gettext('RAM'),
-	    hidden: true,
-	    bind: {
-		hidden: '{!showMemory}',
-	    },
-	    align: 'center',
-	    resizable: false,
-	    dataIndex: 'vmstate',
-	    width: 50,
-	    renderer: function(value, metaData, record) {
-		if (record.data.name !== 'current') {
-		    return Proxmox.Utils.format_boolean(value);
-		}
-	    }
-	},
-	{
-	    text: gettext('Date') + "/" + gettext("Status"),
-	    dataIndex: 'snaptime',
-	    width: 150,
-	    renderer: function(value, metaData, record) {
-		if (record.data.snapstate) {
-		    return record.data.snapstate;
-		}
-		if (value) {
-		    return Ext.Date.format(value,'Y-m-d H:i:s');
-		}
-	    }
-	},
-	{
-	    text: gettext('Description'),
-	    dataIndex: 'description',
-	    flex: 1,
-	    renderer: function(value, metaData, record) {
-		if (record.data.name === 'current') {
-		    return gettext("You are here!");
-		} else {
-		    return Ext.String.htmlEncode(value);
-		}
-	    }
-	}
-    ],
-
-});
-Ext.define('pve-fw-ipsets', {
-    extend: 'Ext.data.Model',
-    fields: [ 'name', 'comment', 'digest' ],
-    idProperty: 'name'
-});
-
-Ext.define('PVE.IPSetList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetList',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsetlist',
-
-    ipset_panel: undefined,
-
-    base_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    initComponent: function() {
-
-        var me = this;
-
-	if (me.ipset_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-fw-ipsets',
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + me.base_url
-	    },
-	    sorters: {
-		property: 'name',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('name', oldrec.data.name);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('Proxmox.window.Edit', {
-		subject: "IPSet '" + rec.data.name + "'",
-		url: me.base_url,
-		method: 'POST',
-		digest: rec.data.digest,
-		items: [
-		    {
-			xtype: 'hiddenfield',
-			name: 'rename',
-			value: rec.data.name
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'name',
-			value: rec.data.name,
-			fieldLabel: gettext('Name'),
-			allowBlank: false
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'comment',
-			value: rec.data.comment,
-			fieldLabel: gettext('Comment')
-		    }
-		]
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('Proxmox.window.Edit', {
-		    subject: 'IPSet',
-		    url: me.base_url,
-		    method: 'POST',
-		    items: [
-			{
-			    xtype: 'textfield',
-			    name: 'name',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'textfield',
-			    name: 'comment',
-			    value: '',
-			    fieldLabel: gettext('Comment')
-			}
-		    ]
-		});
-		win.show();
-		win.on('destroy', reload);
-
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>IPSet:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: 'IPSet', dataIndex: 'name', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = me.base_url + '/' + rec.data.name;
-		    me.ipset_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.ipset_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.IPSetCidrEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    cidr: undefined,
-
-    initComponent : function() {
-
-	var me = this;
-
-	me.isCreate = (me.cidr === undefined);
-
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs' + me.base_url;
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs' + me.base_url + '/' + me.cidr;
-            me.method = 'PUT';
-        }
-
-	var column1 = [];
-
-	if (me.isCreate) {
-	    if (!me.list_refs_url) {
-		throw "no alias_base_url specified";
-	    }
-
-	    column1.push({
-		xtype: 'pveIPRefSelector',
-		name: 'cidr',
-		ref_type: 'alias',
-		autoSelect: false,
-		editable: true,
-		base_url: me.list_refs_url,
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	} else {
-	    column1.push({
-		xtype: 'displayfield',
-		name: 'cidr',
-		value: '',
-		fieldLabel: gettext('IP/CIDR')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    isCreate: me.isCreate,
-	    column1: column1,
-	    column2: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'nomatch',
-		    checked: false,
-		    uncheckedValue: 0,
-		    fieldLabel: 'nomatch'
-		}
-	    ],
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    value: '',
-		    fieldLabel: gettext('Comment')
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('IP/CIDR'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-Ext.define('PVE.IPSetGrid', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveIPSetGrid',
-
-    stateful: true,
-    stateId: 'grid-firewall-ipsets',
-
-    base_url: undefined,
-    list_refs_url: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    setBaseUrl: function(url) {
-        var me = this;
-
-	me.base_url = url;
-
-	if (url === undefined) {
-	    me.addBtn.setDisabled(true);
-	    me.store.removeAll();
-	} else {
-	    me.addBtn.setDisabled(false);
-	    me.removeBtn.baseurl = url + '/';
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: '/api2/json' + url
-	    });
-
-	    me.store.load();
-	}
-    },
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no1 list_refs_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ipset'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.IPSetCidrEdit', {
-		base_url: me.base_url,
-		cidr: rec.data.cidr
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Add'),
-	    disabled: true,
-	    handler: function() {
-		if (!me.base_url) {
-		    return;
-		}
-		var win = Ext.create('PVE.IPSetCidrEdit', {
-		    base_url: me.base_url,
-		    list_refs_url: me.list_refs_url
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    callback: reload
-	});
-
-	var render_errors = function(value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors.cidr || errors.nomatch;
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	Ext.apply(me, {
-	    tbar: [ '<b>IP/CIDR:</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    store: store,
-	    selModel: sm,
-	    listeners: {
-		itemdblclick: run_editor
-	    },
-	    columns: [
-		{
-		    xtype: 'rownumberer'
-		},
-		{
-		    header: gettext('IP/CIDR'),
-		    dataIndex: 'cidr',
-		    width: 150,
-		    renderer: function(value, metaData, record) {
-			value = render_errors(value, metaData, record);
-			if (record.data.nomatch) {
-			    return '<b>! </b>' + value;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Comment'),
-		    dataIndex: 'comment',
-		    flex: 1,
-		    renderer: function(value) {
-			return Ext.util.Format.htmlEncode(value);
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (me.base_url) {
-	    me.setBaseUrl(me.base_url); // load
-	}
-    }
-}, function() {
-
-    Ext.define('pve-ipset', {
-	extend: 'Ext.data.Model',
-	fields: [ { name: 'nomatch', type: 'boolean' },
-		  'cidr', 'comment', 'errors' ],
-	idProperty: 'cidr'
-    });
-
-});
-
-Ext.define('PVE.IPSet', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveIPSet',
-
-    title: 'IPSet',
-
-    onlineHelp: 'pve_firewall_ip_sets',
-
-    list_refs_url: undefined,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.list_refs_url) {
-	    throw "no list_refs_url specified";
-	}
-
-	var ipset_panel = Ext.createWidget('pveIPSetGrid', {
-	    region: 'center',
-	    list_refs_url: me.list_refs_url,
-	    border: false
-	});
-
-	var ipset_list = Ext.createWidget('pveIPSetList', {
-	    region: 'west',
-	    ipset_panel: ipset_panel,
-	    base_url: me.base_url,
-	    width: '50%',
-	    border: false,
-	    split: true
-	});
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ ipset_list, ipset_panel ],
-	    listeners: {
-		show: function() {
-		    ipset_list.fireEvent('show', ipset_list);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Base class for all the multitab config panels
- *
- * How to use this:
- *
- * You create a subclass of this, and then define your wanted tabs
- * as items like this:
- *
- * items: [{
- *  title: "myTitle",
- *  xytpe: "somextype",
- *  iconCls: 'fa fa-icon',
- *  groups: ['somegroup'],
- *  expandedOnInit: true,
- *  itemId: 'someId'
- * }]
- *
- * this has to be in the declarative syntax, else we
- * cannot save them for later
- * (so no Ext.create or Ext.apply of an item in the subclass)
- *
- * the groups array expects the itemids of the items
- * which are the parents, which have to come before they
- * are used
- *
- * if you want following the tree:
- *
- * Option1
- * Option2
- *   -> SubOption1
- *	-> SubSubOption1
- *
- * the suboption1 group array has to look like this:
- * groups: ['itemid-of-option2']
- *
- * and of subsuboption1:
- * groups: ['itemid-of-option2', 'itemid-of-suboption1']
- *
- * setting the expandedOnInit determines if the item/group is expanded
- * initially (false by default)
- */
-Ext.define('PVE.panel.Config', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePanelConfig',
-
-    showSearch: true, // add a resource grid with a search button as first tab
-    viewFilter: undefined, // a filter to pass to that resource grid
-
-    tbarSpacing: true, // if true, adds a spacer after the title in tbar
-
-    dockedItems: [{
-	// this is needed for the overflow handler
-	xtype: 'toolbar',
-	overflowHandler: 'scroller',
-	dock: 'left',
-	style: {
-	    backgroundColor: '#f5f5f5',
-	    padding: 0,
-	    margin: 0
-	},
-	items: {
-	    xtype: 'treelist',
-	    itemId: 'menu',
-	    ui: 'nav',
-	    expanderOnly: true,
-	    expanderFirst: false,
-	    animation: false,
-	    singleExpand: false,
-	    listeners: {
-		selectionchange: function(treeList, selection) {
-		    var me = this.up('panel');
-		    me.suspendLayout = true;
-		    me.activateCard(selection.data.id);
-		    me.suspendLayout = false;
-		    me.updateLayout();
-		},
-		itemclick: function(treelist, info) {
-		    var olditem = treelist.getSelection();
-		    var newitem = info.node;
-
-		    // when clicking on the expand arrow,
-		    // we don't select items, but still want
-		    // the original behaviour
-		    if (info.select === false) {
-			return;
-		    }
-
-		    // if you click on a different item which is open,
-		    // leave it open
-		    // else toggle the clicked item
-		    if (olditem.data.id !== newitem.data.id &&
-			newitem.data.expanded === true) {
-			info.toggle = false;
-		    } else {
-			info.toggle = true;
-		    }
-		}
-	    }
-	}
-    },
-    {
-	xtype: 'toolbar',
-	itemId: 'toolbar',
-	dock: 'top',
-	height: 36,
-	overflowHandler: 'scroller'
-    }],
-
-    firstItem: '',
-    layout: 'card',
-    border: 0,
-
-    // used for automated test
-    selectById: function(cardid) {
-	var me = this;
-
-	var root = me.store.getRoot();
-	var selection = root.findChild('id', cardid, true);
-
-	if (selection) {
-	    selection.expand();
-	    var menu = me.down('#menu');
-	    menu.setSelection(selection);
-	    return cardid;
-	}
-    },
-
-    activateCard: function(cardid) {
-	var me = this;
-	if (me.savedItems[cardid]) {
-	    var curcard = me.getLayout().getActiveItem();
-	    var newcard = me.add(me.savedItems[cardid]);
-	    me.helpButton.setOnlineHelp(newcard.onlineHelp || me.onlineHelp);
-	    if (curcard) {
-		me.setActiveItem(cardid);
-		me.remove(curcard, true);
-
-		// trigger state change
-
-		var ncard = cardid;
-		// Note: '' is alias for first tab.
-		// First tab can be 'search' or something else
-		if (cardid === me.firstItem) {
-		    ncard = '';
-		}
-		if (me.hstateid) {
-		   me.sp.set(me.hstateid, { value: ncard });
-		}
-	    }
-	}
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var stateid = me.hstateid;
-
-	me.sp = Ext.state.Manager.getProvider();
-
-	var activeTab; // leaving this undefined means items[0] will be the default tab
-
-	if (stateid) {
-	    var state = me.sp.get(stateid);
-	    if (state && state.value) {
-		// if this tab does not exist, it chooses the first
-		activeTab = state.value;
-	    }
-	}
-
-	// get title
-	var title = me.title || me.pveSelNode.data.text;
-	me.title = undefined;
-
-	// create toolbar
-	var tbar = me.tbar || [];
-	me.tbar = undefined;
-
-	if (!me.onlineHelp) {
-	    switch(me.pveSelNode.data.id) {
-		case 'type/storage':me.onlineHelp = 'chapter-pvesm.html'; break;
-		case 'type/qemu':me.onlineHelp = 'chapter-qm.html'; break;
-		case 'type/lxc':me.onlineHelp = 'chapter-pct.html'; break;
-		case 'type/pool':me.onlineHelp = 'chapter-pveum.html#_pools'; break;
-		case 'type/node':me.onlineHelp = 'chapter-sysadmin.html'; break;
-	    }
-	}
-
-	if (me.tbarSpacing) {
-	    tbar.unshift('->');
-	}
-	tbar.unshift({
-	    xtype: 'tbtext',
-	    text: title,
-	    baseCls: 'x-panel-header-text'
-	});
-
-	me.helpButton = Ext.create('Proxmox.button.Help', {
-	    hidden: false,
-	    listenToGlobalEvent: false,
-	    onlineHelp: me.onlineHelp || undefined
-	});
-
-	tbar.push(me.helpButton);
-
-	me.dockedItems[1].items = tbar;
-
-	// include search tab
-	me.items = me.items || [];
-	if (me.showSearch) {
-	    me.items.unshift({
-		itemId: 'search',
-		title: gettext('Search'),
-		iconCls: 'fa fa-search',
-		xtype: 'pveResourceGrid',
-		pveSelNode: me.pveSelNode
-	    });
-	}
-
-	me.savedItems = {};
-	/*jslint confusion:true*/
-	if (me.items[0]) {
-	    me.firstItem = me.items[0].itemId;
-	}
-	/*jslint confusion:false*/
-
-	me.store = Ext.create('Ext.data.TreeStore', {
-	    root: {
-		expanded: true
-	    }
-	});
-	var root = me.store.getRoot();
-	me.items.forEach(function(item){
-	    var treeitem = Ext.create('Ext.data.TreeModel',{
-		id: item.itemId,
-		text: item.title,
-		iconCls: item.iconCls,
-		leaf: true,
-		expanded: item.expandedOnInit
-	    });
-	    item.header = false;
-	    if (me.savedItems[item.itemId] !== undefined) {
-		throw "itemId already exists, please use another";
-	    }
-	    me.savedItems[item.itemId] = item;
-
-	    var group;
-	    var curnode = root;
-
-	    // get/create the group items
-	    while (Ext.isArray(item.groups) && item.groups.length > 0) {
-		group = item.groups.shift();
-
-		var child = curnode.findChild('id', group);
-		if (child === null) {
-		    // did not find the group item
-		    // so add it where we are
-		    break;
-		}
-		curnode = child;
-	    }
-
-	    // insert the item
-
-	    // lets see if it already exists
-	    var node = curnode.findChild('id', item.itemId);
-
-	    if (node === null) {
-		curnode.appendChild(treeitem);
-	    } else {
-		// should not happen!
-		throw "id already exists";
-	    }
-	});
-
-	delete me.items;
-	me.defaults = me.defaults || {};
-	Ext.apply(me.defaults, {
-	    pveSelNode: me.pveSelNode,
-	    viewFilter: me.viewFilter,
-	    workspace: me.workspace,
-	    border: 0
-	});
-
-	me.callParent();
-
-	var menu = me.down('#menu');
-	var selection = root.findChild('id', activeTab, true) || root.firstChild;
-	var node = selection;
-	while (node !== root) {
-	    node.expand();
-	    node = node.parentNode;
-	}
-	menu.setStore(me.store);
-	menu.setSelection(selection);
-
-	// on a state change,
-	// select the new item
-	var statechange = function(sp, key, state) {
-	    // it the state change is for this panel
-	    if (stateid && (key === stateid) && state) {
-		// get active item
-		var acard = me.getLayout().getActiveItem().itemId;
-		// get the itemid of the new value
-		var ncard = state.value || me.firstItem;
-		if (ncard && (acard != ncard)) {
-		    // select the chosen item
-		    menu.setSelection(root.findChild('id', ncard, true) || root.firstChild);
-		}
-	    }
-	};
-
-	if (stateid) {
-	    me.mon(me.sp, 'statechange', statechange);
-	}
-    }
-});
-Ext.define('PVE.grid.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    stateful: true,
-    stateId: 'grid-guest-backup',
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var vmtype = me.pveSelNode.data.type;
-	if (!vmtype) {
-	    throw "no VM type specified";
-	}
-
-	var vmtypeFilter;
-	if (vmtype === 'lxc' || vmtype === 'openvz') {
-	    vmtypeFilter = function(item) {
-		return PVE.Utils.volume_is_lxc_backup(item.data.volid, item.data.format);
-	    };
-	} else if (vmtype === 'qemu') {
-	    vmtypeFilter = function(item) {
-		return PVE.Utils.volume_is_qemu_backup(item.data.volid, item.data.format);
-	    };
-	} else {
-	    throw "unsupported VM type '" + vmtype + "'";
-	}
-
-	var searchFilter = {
-	    property: 'volid',
-	// on initial store display only our vmid backups
-	// surround with minus sign to prevent the 2016 VMID bug
-	    value: vmtype + '-' + vmid + '-',
-	    anyMatch: true,
-	    caseSensitive: false
-	};
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'pve-storage-content',
-	    sorters: { 
-		property: 'volid', 
-		order: 'DESC' 
-	    },
-	    filters: [
-	        vmtypeFilter,
-		searchFilter
-		]
-	});
-
-	var reload = Ext.Function.createBuffered(function() {
-	    if (me.store) {
-		me.store.load();
-	    }
-	}, 100);
-
-	var setStorage = function(storage) {
-	    var url = '/api2/json/nodes/' + nodename + '/storage/' + storage + '/content';
-	    url += '?content=backup';
-
-	    me.store.setProxy({
-		type: 'proxmox',
-		url: url
-	    });
-
-	    reload();
-	};
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    nodename: nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    setStorage(value);
-		}
-	    }
-	});
-
-	var storagefilter = Ext.create('Ext.form.field.Text', {
-	    fieldLabel: gettext('Search'),
-	    labelWidth: 50,
-	    labelAlign: 'right',
-	    enableKeyEvents: true,
-	    value: searchFilter.value,
-	    listeners: {
-		buffer: 500,
-		keyup: function(field) {
-		    me.store.clearFilter(true);
-		    searchFilter.value = field.getValue();
-		    me.store.filter([
-			vmtypeFilter,
-			searchFilter
-		    ]);
-		}
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var backup_btn = Ext.create('Ext.button.Button', {
-	    text: gettext('Backup now'),
-	    handler: function() {
-		var win = Ext.create('PVE.window.Backup', { 
-		    nodename: nodename,
-		    vmid: vmid,
-		    vmtype: vmtype,
-		    storage: storagesel.getValue(),
-		    listeners : {
-			close: function() {
-			    reload();
-			}
-		    }
-		});
-		win.show();
-	    }
-	});
-
-	var restore_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Restore'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var volid = rec.data.volid;
-
-		var win = Ext.create('PVE.window.Restore', {
-		    nodename: nodename,
-		    vmid: vmid,
-		    volid: rec.data.volid,
-		    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-		    vmtype: vmtype
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var delete_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    dangerous: true,
-	    delay: 5,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + rec.data.volid + "'");
-		msg += " " + gettext('This will permanently erase all data.');
-
-		return msg;
-	    },
-	    getUrl: function(rec) {
-		var storage = storagesel.getValue();
-		return '/nodes/' + nodename + '/storage/' + storage + '/content/' + rec.data.volid;
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	var config_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show Configuration'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!rec;
-	    },
-	    handler: function(b, e, rec) {
-		var storage = storagesel.getValue();
-		if (!storage) {
-		    return;
-		}
-
-		var win = Ext.create('PVE.window.BackupConfig', {
-		    volume: rec.data.volid,
-		    pveSelNode: me.pveSelNode
-		});
-
-		win.show();
-	    }
-	});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    tbar: [ backup_btn, restore_btn, delete_btn,config_btn, '->', storagesel, storagefilter ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'volid'
-		},
-		{
-		    header: gettext('Date'),
-		    width: 150,
-		    dataIndex: 'vdate'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.CephCreateService', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateService',
-
-    showProgress: true,
-
-    setNode: function(nodename) {
-        var me = this;
-
-	me.nodename = nodename;
-        me.url = "/nodes/" + nodename + "/ceph/" + me.type + "/" + nodename;
-    },
-
-    method: 'POST',
-    isCreate: true,
-
-    items: [
-	{
-	    xtype: 'pveNodeSelector',
-	    submitValue: false,
-	    fieldLabel: gettext('Host'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    listeners: {
-		change: function(f, value) {
-		    var me = this.up('pveCephCreateService');
-		    me.setNode(value);
-		}
-	    }
-	}
-    ],
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.type) {
-	    throw "no type specified";
-	}
-
-	me.setNode(me.nodename);
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephServiceList', {
-    extend: 'Ext.grid.GridPanel',
-    xtype: 'pveNodeCephServiceList',
-
-    onlineHelp: 'chapter_pveceph',
-    emptyText: gettext('No such service configured.'),
-
-    stateful: true,
-
-    // will be called when the store loads
-    storeLoadCallback: Ext.emptyFn,
-
-    // if set to true, does shows the ceph install mask if needed
-    showCephInstallMask: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	init: function(view) {
-	    if (view.pveSelNode) {
-		view.nodename = view.pveSelNode.data.node;
-	    }
-	    if (!view.nodename) {
-		throw "no node name specified";
-	    }
-
-	    if (!view.type) {
-		throw "no type specified";
-	    }
-
-	    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-		autoLoad: true,
-		autoStart: true,
-		interval: 3000,
-		storeid: 'ceph-' + view.type + '-list' + view.nodename,
-		model: 'ceph-service-list',
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + view.nodename + "/ceph/" + view.type
-		}
-	    });
-
-	    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-		rstore: view.rstore,
-		sorters: [{ property: 'name' }]
-	    }));
-
-	    if (view.storeLoadCallback) {
-		view.rstore.on('load', view.storeLoadCallback, this);
-	    }
-	    view.on('destroy', view.rstore.stopUpdate);
-
-	    if (view.showCephInstallMask) {
-		var regex = new RegExp("not (installed|initialized)", "i");
-		PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error) {
-		    view.rstore.stopUpdate();
-		    PVE.Utils.showCephInstallOrMask(view.ownerCt, error.statusText, view.nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', function(){
-				view.rstore.startUpdate();
-			    });
-			}
-		    );
-		});
-	    }
-	},
-
-	service_cmd: function(rec, cmd) {
-	    var view = this.getView();
-	    if (!rec.data.host) {
-		Ext.Msg.alert(gettext('Error'), "entry has no host");
-		return;
-	    }
-	    Proxmox.Utils.API2Request({
-		url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
-		method: 'POST',
-		params: { service: view.type + '.' + rec.data.name },
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: function() {
-			    view.rstore.load();
-			}
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-	onChangeService: function(btn) {
-	    var me = this;
-	    var view = this.getView();
-	    var cmd = btn.action;
-	    var rec = view.getSelection()[0];
-	    me.service_cmd(rec, cmd);
-	},
-
-	showSyslog: function() {
-	    var view = this.getView();
-	    var rec = view.getSelection()[0];
-	    var servicename = 'ceph-' + view.type + '@' + rec.data.name;
-	    var url = "/api2/extjs/nodes/" + rec.data.host + "/syslog?service=" +  encodeURIComponent(servicename);
-	    var win = Ext.create('Ext.window.Window', {
-		title: gettext('Syslog') + ': ' + servicename,
-		modal: true,
-		width: 800,
-		height: 400,
-		layout: 'fit',
-		items: [{
-		    xtype: 'proxmoxLogView',
-		    url: url,
-		    log_select_timespan: 1
-		}]
-	    });
-	    win.show();
-	},
-
-	onCreate: function() {
-	    var view = this.getView();
-	    var win = Ext.create('PVE.CephCreateService', {
-		autoShow: true,
-		nodename: view.nodename,
-		subject: view.getTitle(),
-		type: view.type,
-		taskDone: function() {
-		    view.rstore.load();
-		}
-	    });
-	}
-    },
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Start'),
-	    iconCls: 'fa fa-play',
-	    action: 'start',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state === 'stopped' ||
-		  rec.data.state === 'unknown';
-	    },
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Stop'),
-	    iconCls: 'fa fa-stop',
-	    action: 'stop',
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    disabled: true,
-	    handler: 'onChangeService'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Restart'),
-	    iconCls: 'fa fa-refresh',
-	    action: 'restart',
-	    disabled: true,
-	    enableFn: function(rec) {
-		return rec.data.state !== 'stopped';
-	    },
-	    handler: 'onChangeService'
-	},
-	'-',
-	{
-	    text: gettext('Create'),
-	    reference: 'createButton',
-	    handler: 'onCreate'
-	},
-	{
-	    text: gettext('Destroy'),
-	    xtype: 'proxmoxStdRemoveButton',
-	    getUrl: function(rec) {
-		var view = this.up('grid');
-		if (!rec.data.host) {
-		    Ext.Msg.alert(gettext('Error'), "entry has no host");
-		    return;
-		}
-		return "/nodes/" + rec.data.host + "/ceph/" + view.type + "/" + rec.data.name;
-	    },
-	    callback: function(options, success, response) {
-		var view = this.up('grid');
-		if (!success) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    return;
-		}
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskProgress', {
-		    upid: upid,
-		    taskDone: function() {
-			view.rstore.load();
-		    }
-		});
-		win.show();
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Syslog'),
-	    disabled: true,
-	    handler: 'showSyslog'
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return this.type + '.' + v;
-	    },
-	    dataIndex: 'name'
-	},
-	{
-	    header: gettext('Host'),
-	    flex: 1,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'host'
-	},
-	{
-	    header: gettext('Status'),
-	    flex: 1,
-	    sortable: false,
-	    dataIndex: 'state'
-	},
-	{
-	    header: gettext('Address'),
-	    flex: 3,
-	    sortable: true,
-	    renderer: function(v) {
-		return v || Proxmox.Utils.unknownText;
-	    },
-	    dataIndex: 'addr'
-	},
-	{
-	    header: gettext('Version'),
-	    flex: 3,
-	    sortable: true,
-	    dataIndex: 'version'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (me.additionalColumns) {
-	    me.columns = me.columns.concat(me.additionalColumns);
-	}
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('ceph-service-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'addr', 'name', 'rank', 'host', 'quorum', 'state',
-	    'ceph_version', 'ceph_version_short',
-	    { type: 'string', name: 'version', calculate: function(data) {
-		return PVE.Utils.parse_ceph_version(data);
-	    } }
-	],
-	idProperty: 'name'
-    });
-});
-/*jslint confusion: true */
-Ext.define('PVE.CephCreateFS', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreateFS',
-
-    showTaskViewer: true,
-    onlineHelp: 'pveceph_fs_create',
-
-    subject: 'Ceph FS',
-    isCreate: true,
-    method: 'POST',
-
-    setFSName: function(fsName) {
-	var me = this;
-
-	if (fsName === '' || fsName === undefined) {
-	    fsName = 'cephfs';
-	}
-
-	me.url = "/nodes/" + me.nodename + "/ceph/fs/" + fsName;
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    value: 'cephfs',
-	    listeners: {
-		change: function(f, value) {
-		    this.up('pveCephCreateFS').setFSName(value);
-		}
-	    },
-	    submitValue: false, // already encoded in apicall URL
-	    emptyText: 'cephfs'
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'Placement Groups',
-	    name: 'pg_num',
-	    value: 128,
-	    emptyText: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add-storage',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new CephFS to the cluster storage configuration.'),
-	    },
-	}
-    ],
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	me.setFSName();
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.NodeCephFSPanel', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveNodeCephFSPanel',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    title: gettext('CephFS'),
-    onlineHelp: 'pveceph_fs',
-
-    border: false,
-    defaults: {
-	border: false,
-	cbind: {
-	    nodename: '{nodename}'
-	}
-    },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    cephfsConfigured: false,
-	    mdsCount: 0
-	},
-	formulas: {
-	    canCreateFS: function(get) {
-		return (!get('cephfsConfigured') && get('mdsCount') > 0);
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'grid',
-	    emptyText: Ext.String.format(gettext('No {0} configured.'), 'CephFS'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-ceph-fs',
-			proxy: {
-			    type: 'proxmox',
-			    url: '/api2/json/nodes/' + view.nodename + '/ceph/fs'
-			},
-			model: 'pve-ceph-fs'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'name',
-			    order: 'DESC'
-			}
-		    }));
-		    var regex = new RegExp("not (installed|initialized)", "i");
-		    PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error){
-			me.rstore.stopUpdate();
-			PVE.Utils.showCephInstallOrMask(me.ownerCt, error.statusText, view.nodename,
-			    function(win){
-				me.mon(win, 'cephInstallWindowClosed', function(){
-				    me.rstore.startUpdate();
-				});
-			    }
-			);
-		    });
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.rstore.stopUpdate();
-		    var win = Ext.create('PVE.CephCreateFS', {
-			autoShow: true,
-			nodename: view.nodename,
-			listeners: {
-			    destroy: function() {
-				view.rstore.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!(success && records && records.length > 0)) {
-			vm.set('cephfsConfigured', false);
-			return;
-		    }
-		    vm.set('cephfsConfigured', true);
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create CephFS'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			// only one CephFS per Ceph cluster makes sense for now
-			disabled: '{!canCreateFS}'
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    dataIndex: 'name'
-		},
-		{
-		    header: 'Data Pool',
-		    flex: 1,
-		    dataIndex: 'data_pool'
-		},
-		{
-		    header: 'Metadata Pool',
-		    flex: 1,
-		    dataIndex: 'metadata_pool'
-		}
-	    ],
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    title: gettext('Metadata Servers'),
-	    stateId: 'grid-ceph-mds',
-	    type: 'mds',
-	    storeLoadCallback: function(store, records, success) {
-		var vm = this.getViewModel();
-		if (!success || !records) {
-		    vm.set('mdsCount', 0);
-		    return;
-		}
-		vm.set('mdsCount', records.length);
-	    },
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-}, function() {
-    Ext.define('pve-ceph-fs', {
-	extend: 'Ext.data.Model',
-	fields: [ 'name', 'data_pool', 'metadata_pool' ],
-	proxy: {
-	    type: 'proxmox',
-	    url: "/api2/json/nodes/localhost/ceph/fs"
-	},
-	idProperty: 'name'
-    });
-});
-Ext.define('PVE.CephCreatePool', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveCephCreatePool',
-
-    showProgress: true,
-    onlineHelp: 'pve_ceph_pools',
-
-    subject: 'Ceph Pool',
-    isCreate: true,
-    method: 'POST',
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'name',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Size'),
-	    name: 'size',
-	    value: 3,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: gettext('Min. Size'),
-	    name: 'min_size',
-	    value: 2,
-	    minValue: 1,
-	    maxValue: 7,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'pveCephRuleSelector',
-	    fieldLabel: 'Crush Rule', // do not localize
-	    name: 'crush_rule',
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    fieldLabel: 'pg_num',
-	    name: 'pg_num',
-	    value: 128,
-	    minValue: 8,
-	    maxValue: 32768,
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Add as Storage'),
-	    value: true,
-	    name: 'add_storages',
-	    autoEl: {
-		tag: 'div',
-		 'data-qtip': gettext('Add the new pool to the cluster storage configuration.'),
-	    },
-	}
-    ],
-    initComponent : function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.apply(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/pools",
-	    defaults: {
-		nodename: me.nodename
-	    }
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.CephPoolList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeCephPoolList',
-
-    onlineHelp: 'chapter_pveceph',
-
-    stateful: true,
-    stateId: 'grid-ceph-pools',
-    bufferedRenderer: false,
-
-    features: [ { ftype: 'summary'} ],
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    width: 120,
-	    sortable: true,
-	    dataIndex: 'pool_name'
-	},
-	{
-	    header: gettext('Size') + '/min',
-	    width: 100,
-	    align: 'right',
-	    renderer: function(v, meta, rec) {
-		return v + '/' + rec.data.min_size;
-	    },
-	    dataIndex: 'size'
-	},
-	{
-	    text: '# Placement Groups', // pg_num',
-	    width: 180,
-	    align: 'right',
-	    dataIndex: 'pg_num'
-	},
-	{
-	    text: 'CRUSH Rule',
-	    columns: [
-		{
-		    text: 'ID',
-		    align: 'right',
-		    width: 50,
-		    dataIndex: 'crush_rule'
-		},
-		{
-		    text: gettext('Name'),
-		    width: 150,
-		    dataIndex: 'crush_rule_name',
-		},
-	    ]
-	},
-	{
-	    text: gettext('Used'),
-	    columns: [
-		{
-		    text: '%',
-		    width: 100,
-		    sortable: true,
-		    align: 'right',
-		    renderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		    dataIndex: 'percent_used',
-		    summaryType: 'sum',
-		    summaryRenderer: function(val) {
-			return Ext.util.Format.percent(val, '0.00');
-		    },
-		},
-		{
-		    text: gettext('Total'),
-		    width: 100,
-		    sortable: true,
-		    renderer: PVE.Utils.render_size,
-		    align: 'right',
-		    dataIndex: 'bytes_used',
-		    summaryType: 'sum',
-		    summaryRenderer: PVE.Utils.render_size
-		}
-	    ]
-	}
-    ],
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'ceph-pool-list' + nodename,
-	    model: 'ceph-pool-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/ceph/pools"
-	    }
-	});
-
-	var store = Ext.create('Proxmox.data.DiffStore', { rstore: rstore });
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
-	    me.store.rstore.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.rstore.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	var create_btn = new Ext.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		var win = Ext.create('PVE.CephCreatePool', {
-                    nodename: nodename
-		});
-		win.show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	var destroy_btn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Destroy'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		if (!rec.data.pool_name) {
-		    return;
-		}
-		var base_url = '/nodes/' + nodename + '/ceph/pools/' +
-		    rec.data.pool_name;
-
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    showProgress: true,
-		    url: base_url,
-		    params: {
-			remove_storages: 1
-		    },
-		    item: { type: 'CephPool', id: rec.data.pool_name }
-		}).show();
-		win.on('destroy', function() {
-		    rstore.load();
-		});
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ create_btn, destroy_btn ],
-	    listeners: {
-		activate: rstore.startUpdate,
-		destroy: rstore.stopUpdate
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('ceph-pool-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'pool_name',
-		  { name: 'pool', type: 'integer'},
-		  { name: 'size', type: 'integer'},
-		  { name: 'min_size', type: 'integer'},
-		  { name: 'pg_num', type: 'integer'},
-		  { name: 'bytes_used', type: 'integer'},
-		  { name: 'percent_used', type: 'number'},
-		  { name: 'crush_rule', type: 'integer'},
-		  { name: 'crush_rule_name', type: 'string'}
-		],
-	idProperty: 'pool_name'
-    });
-});
-
-Ext.define('PVE.form.CephRuleSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCephRuleSelector',
-
-    allowBlank: false,
-    valueField: 'name',
-    displayField: 'name',
-    editable: false,
-    queryMode: 'local',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['name'],
-	    sorters: 'name',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/ceph/rules'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-
-	store.load({
-	    callback: function(rec, op, success){
-		if (success && rec.length > 0) {
-		    me.select(rec[0]);
-		}
-	    }
-	});
-    }
-
-});
-Ext.define('PVE.CephCreateOsd', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephCreateOsd',
-
-    subject: 'Ceph OSD',
-
-    showProgress: true,
-
-    onlineHelp: 'pve_ceph_osds',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			Object.keys(values || {}).forEach(function(name) {
-			    if (values[name] === '') {
-				delete values[name];
-			    }
-			});
-
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'dev',
-			    nodename: me.nodename,
-			    diskType: 'unused',
-			    fieldLabel: gettext('Disk'),
-			    allowBlank: false
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'db_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('DB Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=db_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'db_size',
-			    fieldLabel: gettext('DB size') + ' (GiB)',
-			    minValue: 1,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ],
-		    advancedColumn1: [
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'encrypted',
-			    fieldLabel: gettext('Encrypt OSD')
-			},
-		    ],
-		    advancedColumn2: [
-			{
-			    xtype: 'pveDiskSelector',
-			    name: 'wal_dev',
-			    nodename: me.nodename,
-			    diskType: 'journal_disks',
-			    fieldLabel: gettext('WAL Disk'),
-			    value: '',
-			    autoSelect: false,
-			    allowBlank: true,
-			    emptyText: 'use OSD/DB disk',
-			    listeners: {
-				change: function(field, val) {
-				    me.down('field[name=wal_size]').setDisabled(!val);
-				}
-			    }
-			},
-			{
-			    xtype: 'numberfield',
-			    name: 'wal_size',
-			    fieldLabel: gettext('WAL size') + ' (GiB)',
-			    minValue: 0.5,
-			    maxValue: 128*1024,
-			    decimalPrecision: 2,
-			    allowBlank: true,
-			    disabled: true,
-			    emptyText: gettext('Automatic')
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pmx-hint',
-		    value: 'Note: Ceph is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_pveceph') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.CephRemoveOsd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveCephRemoveOsd'],
-
-    isRemove: true,
-
-    showProgress: true,
-    method: 'DELETE',
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cleanup',
-	    checked: true,
-	    labelWidth: 130,
-	    fieldLabel: gettext('Cleanup Disks')
-	}
-    ],
-    initComponent : function() {
-
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (me.osdid === undefined || me.osdid < 0) {
-	    throw "no osdid specified";
-	}
-
-	me.isCreate = true;
-
-	me.title = gettext('Destroy') + ': Ceph OSD osd.' + me.osdid.toString();
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/ceph/osd/" + me.osdid.toString()
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.CephSetFlags', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCephSetFlags',
-
-    showProgress: true,
-
-    width: 720,
-    layout: 'fit',
-
-    onlineHelp: 'pve_ceph_osds',
-    isCreate: true,
-    title: Ext.String.format(gettext('Manage {0}'), 'Global OSD Flags'),
-    submitText: gettext('Apply'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    onGetValues: function(values) {
-		var me = this;
-		var val = {};
-		var data = me.down('#flaggrid').getStore().each((rec) => {
-		    val[rec.data.name] = rec.data.value ? 1 : 0;
-		});
-
-		return val;
-	    },
-	    items: [
-		{
-		    xtype: 'grid',
-		    itemId: 'flaggrid',
-		    store: {
-			listeners: {
-			    update: function() {
-				this.commitChanges();
-			    }
-			}
-		    },
-
-		    columns: [
-			{
-			    text: gettext('Enable'),
-			    xtype: 'checkcolumn',
-			    width: 75,
-			    dataIndex: 'value',
-			},
-			{
-			    text: 'Name',
-			    dataIndex: 'name',
-			},
-			{
-			    text: 'Description',
-			    flex: 1,
-			    dataIndex: 'description',
-			},
-		    ]
-		},
-	    ],
-	},
-    ],
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-        Ext.applyIf(me, {
-	    url: "/cluster/ceph/flags",
-	    method: 'PUT',
-	});
-
-	me.callParent();
-
-	var grid = me.down('#flaggrid');
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		grid.getStore().setData(data);
-		// re-align after store load, else the window is not centered
-		me.alignTo(Ext.getBody(), 'c-c');
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CephOsdTree', {
-    extend: 'Ext.tree.Panel',
-    alias: ['widget.pveNodeCephOsdTree'],
-    onlineHelp: 'chapter_pveceph',
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    flags: [],
-	    maxversion: '0',
-	    mixedversions: false,
-	    versions: {},
-	    isOsd: false,
-	    downOsd: false,
-	    upOsd: false,
-	    inOsd: false,
-	    outOsd: false,
-	    osdid: '',
-	    osdhost: '',
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	reload: function() {
-	    var me = this.getView();
-	    var vm = this.getViewModel();
-	    var nodename = vm.get('nodename');
-	    var sm = me.getSelectionModel();
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + nodename + "/ceph/osd",
-		waitMsgTarget: me,
-		method: 'GET',
-		failure: function(response, opts) {
-		    var msg = response.htmlStatus;
-		    PVE.Utils.showCephInstallOrMask(me, msg, nodename,
-			function(win){
-			    me.mon(win, 'cephInstallWindowClosed', this.reload);
-			}
-		    );
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-		    var selected = me.getSelection();
-		    var name;
-		    if (selected.length) {
-			name = selected[0].data.name;
-		    }
-		    vm.set('versions', data.versions);
-		    // extract max version
-		    var maxversion = "0";
-		    var mixedversions = false;
-		    var traverse;
-		    traverse = function(node, fn) {
-			fn(node);
-			if (Array.isArray(node.children)) {
-			    node.children.forEach(c => { traverse(c, fn); });
-			}
-		    };
-		    traverse(data.root, node => {
-			// compatibility for old api call
-			if (node.type === 'host' && !node.version) {
-			    node.version = data.versions[node.name];
-			}
-
-			if (node.version === undefined) {
-			    return;
-			}
-
-			if (node.version !== maxversion && maxversion !== "0") {
-			    mixedversions = true;
-			}
-
-			if (PVE.Utils.compare_ceph_versions(node.version, maxversion) > 0) {
-			    maxversion = node.version;
-			}
-
-		    });
-		    vm.set('maxversion', maxversion);
-		    vm.set('mixedversions', mixedversions);
-		    sm.deselectAll();
-		    me.setRootNode(data.root);
-		    me.expandAll();
-		    if (name) {
-			var node = me.getRootNode().findChild('name', name, true);
-			if (node) {
-			    me.setSelection([node]);
-			}
-		    }
-
-		    var flags = data.flags.split(',');
-		    vm.set('flags', flags);
-		}
-	    });
-	},
-
-	osd_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd;
-	    var params = comp.params || {};
-	    var osdid = vm.get('osdid');
-
-	    var doRequest = function() {
-		Proxmox.Utils.API2Request({
-		    url: "/nodes/" + vm.get('osdhost') + "/ceph/osd/" + osdid + '/' + cmd,
-		    waitMsgTarget: me.getView(),
-		    method: 'POST',
-		    params: params,
-		    success: () => { me.reload(); },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    };
-
-	    if (cmd === 'scrub') {
-		Ext.MessageBox.defaultButton = params.deep === 1 ? 2 : 1;
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: params.deep === 1 ? Ext.Msg.WARNING : Ext.Msg.QUESTION,
-		    msg: params.deep !== 1 ?
-		       Ext.String.format(gettext("Scrub OSD.{0}"), osdid) :
-		       Ext.String.format(gettext("Deep Scrub OSD.{0}"), osdid) +
-			   "<br>Caution: This can reduce performance while it is running.",
-		    buttons: Ext.Msg.YESNO,
-		    callback: function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			doRequest();
-		    }
-		});
-	    } else {
-		doRequest();
-	    }
-	},
-
-	create_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephCreateOsd', {
-		nodename: vm.get('nodename'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	destroy_osd: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephRemoveOsd', {
-		nodename: vm.get('osdhost'),
-		osdid: vm.get('osdid'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	set_flags: function() {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    Ext.create('PVE.CephSetFlags', {
-		nodename: vm.get('nodename'),
-		taskDone: () => { me.reload(); }
-	    }).show();
-	},
-
-	service_cmd: function(comp) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    var cmd = comp.cmd || comp;
-	    Proxmox.Utils.API2Request({
-                url: "/nodes/" + vm.get('osdhost') + "/ceph/" + cmd,
-		params: { service: "osd." + vm.get('osdid') },
-		waitMsgTarget: me.getView(),
-		method: 'POST',
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var win = Ext.create('Proxmox.window.TaskProgress', {
-			upid: upid,
-			taskDone: () => { me.reload(); }
-		    });
-		    win.show();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	set_selection_status: function(tp, selection) {
-	    if (selection.length < 1) {
-		return;
-	    }
-	    var rec = selection[0];
-	    var vm = this.getViewModel();
-
-	    var isOsd = (rec.data.host && (rec.data.type === 'osd') && (rec.data.id >= 0));
-
-	    vm.set('isOsd', isOsd);
-	    vm.set('downOsd', isOsd && rec.data.status === 'down');
-	    vm.set('upOsd', isOsd && rec.data.status !== 'down');
-	    vm.set('inOsd', isOsd && rec.data.in);
-	    vm.set('outOsd', isOsd && !rec.data.in);
-	    vm.set('osdid', isOsd ? rec.data.id : undefined);
-	    vm.set('osdhost', isOsd ? rec.data.host : undefined);
-	},
-
-	render_status: function(value, metaData, rec) {
-	    if (!value) {
-		return value;
-	    }
-	    var inout = rec.data['in'] ? 'in' : 'out';
-	    var updownicon = value === 'up' ? 'good fa-arrow-circle-up' :
-		'critical fa-arrow-circle-down';
-
-	    var inouticon = rec.data['in'] ? 'good fa-circle' :
-		'warning fa-circle-o';
-
-	    var text = value + ' <i class="fa ' + updownicon + '"></i> / ' +
-		inout + ' <i class="fa ' + inouticon + '"></i>';
-
-	    return text;
-	},
-
-	render_wal: function(value, metaData, rec) {
-	    if (!value &&
-		rec.data.osdtype === 'bluestore' &&
-		rec.data.type === 'osd') {
-		return 'N/A';
-	    }
-	    return value;
-	},
-
-	render_version: function(value, metadata, rec) {
-	    var vm = this.getViewModel();
-	    var versions = vm.get('versions');
-	    var icon = "";
-	    var version = value || "";
-	    var maxversion = vm.get('maxversion');
-	    if (value && value != maxversion) {
-		if (rec.data.type === 'host' || versions[rec.data.host] !== maxversion) {
-		    icon = PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE');
-		} else {
-		    icon = PVE.Utils.get_ceph_icon_html('HEALTH_OLD');
-		}
-	    } else if (value && vm.get('mixedversions')) {
-		icon = PVE.Utils.get_ceph_icon_html('HEALTH_OK');
-	    }
-
-	    return icon + version;
-	},
-
-	render_osd_val: function(value, metaData, rec) {
-	    return (rec.data.type === 'osd') ? value : '';
-	},
-	render_osd_weight: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    return Ext.util.Format.number(value, '0.00###');
-	},
-
-	render_osd_latency: function(value, metaData, rec) {
-	    if (rec.data.type !== 'osd') {
-		return '';
-	    }
-	    let commit_ms = rec.data.commit_latency_ms,
-	        apply_ms = rec.data.apply_latency_ms;
-	    return apply_ms + ' / ' + commit_ms;
-	},
-
-	render_osd_size: function(value, metaData, rec) {
-	    return this.render_osd_val(PVE.Utils.render_size(value), metaData, rec);
-	},
-
-	control: {
-	    '#': {
-		selectionchange: 'set_selection_status'
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-
-	    if (!view.pveSelNode.data.node) {
-		throw "no node name specified";
-	    }
-
-	    vm.set('nodename', view.pveSelNode.data.node);
-
-	    me.callParent();
-	    me.reload();
-	}
-    },
-
-    stateful: true,
-    stateId: 'grid-ceph-osd',
-    rootVisible: false,
-    useArrows: true,
-
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: 'Name',
-	    dataIndex: 'name',
-	    width: 150
-	},
-	{
-	    text: 'Type',
-	    dataIndex: 'type',
-	    hidden: true,
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: gettext("Class"),
-	    dataIndex: 'device_class',
-	    align: 'right',
-	    width: 75
-	},
-	{
-	    text: "OSD Type",
-	    dataIndex: 'osdtype',
-	    align: 'right',
-	    width: 100
-	},
-	{
-	    text: "Bluestore Device",
-	    dataIndex: 'blfsdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "DB Device",
-	    dataIndex: 'dbdev',
-	    align: 'right',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: "WAL Device",
-	    dataIndex: 'waldev',
-	    align: 'right',
-	    renderer: 'render_wal',
-	    width: 75,
-	    hidden: true
-	},
-	{
-	    text: 'Status',
-	    dataIndex: 'status',
-	    align: 'right',
-	    renderer: 'render_status',
-	    width: 120
-	},
-	{
-	    text: gettext('Version'),
-	    dataIndex: 'version',
-	    align: 'right',
-	    renderer: 'render_version'
-	},
-	{
-	    text: 'weight',
-	    dataIndex: 'crush_weight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: 'reweight',
-	    dataIndex: 'reweight',
-	    align: 'right',
-	    renderer: 'render_osd_weight',
-	    width: 90
-	},
-	{
-	    text: gettext('Used') + ' (%)',
-	    dataIndex: 'percent_used',
-	    align: 'right',
-	    renderer: function(value, metaData, rec) {
-		if (rec.data.type !== 'osd') {
-		    return '';
-		}
-		return Ext.util.Format.number(value, '0.00');
-	    },
-	    width: 100
-	},
-	{
-	    text: gettext('Total'),
-	    dataIndex: 'total_space',
-	    align: 'right',
-	    renderer: 'render_osd_size',
-	    width: 100
-	},
-	{
-	    text: 'Apply/Commit<br>Latency (ms)',
-	    dataIndex: 'apply_latency_ms',
-	    align: 'right',
-	    renderer: 'render_osd_latency',
-	    width: 120
-	}
-    ],
-
-
-    tbar: {
-	items: [
-	    {
-		text: gettext('Reload'),
-		iconCls: 'fa fa-refresh',
-		handler: 'reload'
-	    },
-	    '-',
-	    {
-		text: gettext('Create') + ': OSD',
-		handler: 'create_osd',
-	    },
-	    {
-		text: Ext.String.format(gettext('Manage {0}'), 'Global Flags'),
-		handler: 'set_flags',
-	    },
-	    '->',
-	    {
-		xtype: 'tbtext',
-		data: {
-		    osd: undefined
-		},
-		bind: {
-		    data: {
-			osd: "{osdid}"
-		    }
-		},
-		tpl: [
-		    '<tpl if="osd">',
-		    'osd.{osd}:',
-		    '<tpl else>',
-		    gettext('No OSD selected'),
-		    '</tpl>'
-		]
-	    },
-	    {
-		text: gettext('Start'),
-		iconCls: 'fa fa-play',
-		disabled: true,
-		bind: {
-		    disabled: '{!downOsd}'
-		},
-		cmd: 'start',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Stop'),
-		iconCls: 'fa fa-stop',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'stop',
-		handler: 'service_cmd'
-	    },
-	    {
-		text: gettext('Restart'),
-		iconCls: 'fa fa-refresh',
-		disabled: true,
-		bind: {
-		    disabled: '{!upOsd}'
-		},
-		cmd: 'restart',
-		handler: 'service_cmd'
-	    },
-	    '-',
-	    {
-		text: 'Out',
-		iconCls: 'fa fa-circle-o',
-		disabled: true,
-		bind: {
-		    disabled: '{!inOsd}'
-		},
-		cmd: 'out',
-		handler: 'osd_cmd'
-	    },
-	    {
-		text: 'In',
-		iconCls: 'fa fa-circle',
-		disabled: true,
-		bind: {
-		    disabled: '{!outOsd}'
-		},
-		cmd: 'in',
-		handler: 'osd_cmd'
-	    },
-	    '-',
-	    {
-		text: gettext('More'),
-		iconCls: 'fa fa-bars',
-		disabled: true,
-		bind: {
-		    disabled: '{!isOsd}'
-		},
-		menu: [
-		    {
-			text: gettext('Scrub'),
-			iconCls: 'fa fa-shower',
-			cmd: 'scrub',
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Deep Scrub'),
-			iconCls: 'fa fa-bath',
-			cmd: 'scrub',
-			params: {
-			    deep: 1,
-			},
-			handler: 'osd_cmd'
-		    },
-		    {
-			text: gettext('Destroy'),
-			itemId: 'remove',
-			iconCls: 'fa fa-fw fa-trash-o',
-			bind: {
-			    disabled: '{!downOsd}'
-			},
-			handler: 'destroy_osd'
-		    }
-		],
-	    }
-	]
-    },
-
-    fields: [
-	'name', 'type', 'status', 'host', 'in', 'id' ,
-	{ type: 'number', name: 'reweight' },
-	{ type: 'number', name: 'percent_used' },
-	{ type: 'integer', name: 'bytes_used' },
-	{ type: 'integer', name: 'total_space' },
-	{ type: 'integer', name: 'apply_latency_ms' },
-	{ type: 'integer', name: 'commit_latency_ms' },
-	{ type: 'string', name: 'device_class' },
-	{ type: 'string', name: 'osdtype' },
-	{ type: 'string', name: 'blfsdev' },
-	{ type: 'string', name: 'dbdev' },
-	{ type: 'string', name: 'waldev' },
-	{ type: 'string', name: 'version', calculate: function(data) {
-	    return PVE.Utils.parse_ceph_version(data);
-	} },
-	{ type: 'string', name: 'iconCls', calculate: function(data) {
-	    var iconMap = {
-		host: 'fa-building',
-		osd: 'fa-hdd-o',
-		root: 'fa-server',
-	    };
-	    return 'fa x-fa-tree ' + iconMap[data.type];
-	} },
-	{ type: 'number', name: 'crush_weight' }
-    ],
-});
-Ext.define('PVE.node.CephMonMgrList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveNodeCephMonMgr',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    onlineHelp: 'chapter_pveceph',
-
-    defaults: {
-	border: false,
-	onlineHelp: 'chapter_pveceph',
-	flex: 1
-    },
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    items: [
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    type: 'mon',
-	    additionalColumns: [
-		{
-		    header: gettext('Quorum'),
-		    width: 70,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'quorum'
-		}
-	    ],
-	    stateId: 'grid-ceph-monitor',
-	    showCephInstallMask: true,
-	    title: gettext('Monitor')
-	},
-	{
-	    xtype: 'pveNodeCephServiceList',
-	    type: 'mgr',
-	    stateId: 'grid-ceph-manager',
-	    cbind: { pveSelNode: '{pveSelNode}' },
-	    title: gettext('Manager')
-	}
-    ]
-});
-Ext.define('PVE.node.CephCrushMap', {
-    extend: 'Ext.panel.Panel',
-    alias: ['widget.pveNodeCephCrushMap'],
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    stateful: true,
-    stateId: 'layout-ceph-crush',
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/crush',
-
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.node.CephStatus', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephStatus',
-
-    onlineHelp: 'chapter_pveceph',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: {
-	type: 'column'
-    },
-
-    defaults: {
-	padding: 5
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Health'),
-	    bodyPadding: 10,
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    minHeight: 230,
-		    columnWidth: 1
-		},
-		'width >= 1900': {
-		    minHeight: 500,
-		    columnWidth: 0.5
-		}
-	    },
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    itemId: 'overallhealth',
-		    xtype: 'pveHealthWidget',
-		    title: gettext('Status')
-		},
-		{
-		    flex: 2,
-		    itemId: 'warnings',
-		    stateful: true,
-		    stateId: 'ceph-status-warnings',
-		    xtype: 'grid',
-		    // since we load the store manually,
-		    // to show the emptytext, we have to
-		    // specify an empty store
-		    store: { data:[] },
-		    emptyText: gettext('No Warnings/Errors'),
-		    columns: [
-			{
-			    dataIndex: 'severity',
-			    header: gettext('Severity'),
-			    align: 'center',
-			    width: 70,
-			    renderer: function(value) {
-				var health = PVE.Utils.map_ceph_health[value];
-				var classes = PVE.Utils.get_health_icon(health);
-
-				return '<i class="fa fa-fw ' + classes + '"></i>';
-			    },
-			    sorter: {
-				sorterFn: function(a,b) {
-				    var healthArr = ['HEALTH_ERR', 'HEALTH_WARN', 'HEALTH_OK'];
-				    return healthArr.indexOf(b.data.severity) - healthArr.indexOf(a.data.severity);
-				}
-			    }
-			},
-			{
-			    dataIndex: 'summary',
-			    header: gettext('Summary'),
-			    flex: 1
-			},
-			{
-			    xtype: 'actioncolumn',
-			    width: 40,
-			    align: 'center',
-			    tooltip: gettext('Detail'),
-			    items: [
-				{
-				    iconCls: 'x-fa fa-info-circle',
-				    handler: function(grid, rowindex, colindex, item, e, record) {
-					var win = Ext.create('Ext.window.Window', {
-					    title: gettext('Detail'),
-					    resizable: true,
-					    modal: true,
-					    width: 650,
-					    height: 400,
-					    layout: {
-						type: 'fit'
-					    },
-					    items: [{
-						scrollable: true,
-						padding: 10,
-						xtype: 'box',
-						html: [
-						    '<span>' + Ext.htmlEncode(record.data.summary) + '</span>',
-						    '<pre>' + Ext.htmlEncode(record.data.detail) + '</pre>'
-						]
-					    }]
-					});
-					win.show();
-				    }
-				}
-			    ]
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveCephStatusDetail',
-	    itemId: 'statusdetail',
-	    plugins: 'responsive',
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 250
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 300
-		}
-	    },
-	    title: gettext('Status')
-	},
-	{
-	    title: gettext('Services'),
-	    xtype: 'pveCephServices',
-	    itemId: 'services',
-	    plugins: 'responsive',
-	    layout: {
-		type: 'hbox',
-		align: 'stretch'
-	    },
-	    responsiveConfig: {
-		'width < 1900': {
-		    columnWidth: 1,
-		    minHeight: 200
-		},
-		'width >= 1900': {
-		    columnWidth: 0.5,
-		    minHeight: 200
-		}
-	    }
-	},
-	{
-	    xtype: 'panel',
-	    title: gettext('Performance'),
-	    columnWidth: 1,
-	    bodyPadding: 5,
-	    layout: {
-		type: 'hbox',
-		align: 'center'
-	    },
-	    items: [
-		{
-		    flex: 1,
-		    xtype: 'proxmoxGauge',
-		    itemId: 'space',
-		    title: gettext('Usage')
-		},
-		{
-		    flex: 2,
-		    xtype: 'container',
-		    defaults: {
-			padding: 0,
-			height: 100
-		    },
-		    items: [
-			{
-			    itemId: 'reads',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Reads'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'writes',
-			    xtype: 'pveRunningChart',
-			    title: gettext('Writes'),
-			    renderer: PVE.Utils.render_bandwidth
-			},
-			{
-			    itemId: 'iops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS', // do not localize
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'readiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Reads'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			},
-			{
-			    itemId: 'writeiops',
-			    xtype: 'pveRunningChart',
-			    hidden: true,
-			    title: 'IOPS: ' + gettext('Writes'),
-			    renderer: Ext.util.Format.numberRenderer('0,000')
-			}
-		    ]
-		}
-	    ]
-	}
-    ],
-
-    generateCheckData: function(health) {
-	var result = [];
-	var checks = health.checks || {};
-	var keys = Ext.Object.getKeys(checks).sort();
-
-	Ext.Array.forEach(keys, function(key) {
-	    var details = checks[key].detail || [];
-	    result.push({
-		id: key,
-		summary: checks[key].summary.message,
-		detail: Ext.Array.reduce(
-			    checks[key].detail,
-			    function(first, second) {
-				return first + '\n' + second.message;
-			    },
-			    ''
-			),
-		severity: checks[key].severity
-	    });
-	});
-
-	return result;
-    },
-
-    updateAll: function(store, records, success) {
-	if (!success || records.length === 0) {
-	    return;
-	}
-
-	var me = this;
-	var rec = records[0];
-	me.status = rec.data;
-
-	// add health panel
-	me.down('#overallhealth').updateHealth(PVE.Utils.render_ceph_health(rec.data.health || {}));
-	// add errors to gridstore
-	me.down('#warnings').getStore().loadRawData(me.generateCheckData(rec.data.health || {}), false);
-
-	// update services
-	me.getComponent('services').updateAll(me.metadata || {}, rec.data);
-
-	// update detailstatus panel
-	me.getComponent('statusdetail').updateAll(me.metadata || {}, rec.data);
-
-	// add performance data
-	var used = rec.data.pgmap.bytes_used;
-	var total = rec.data.pgmap.bytes_total;
-
-	var text = Ext.String.format(gettext('{0} of {1}'),
-	    PVE.Utils.render_size(used),
-	    PVE.Utils.render_size(total)
-	);
-
-	// update the usage widget
-	me.down('#space').updateValue(used/total, text);
-
-	// TODO: logic for jewel (iops split in read/write)
-
-	var iops = rec.data.pgmap.op_per_sec;
-	var readiops = rec.data.pgmap.read_op_per_sec;
-	var writeiops = rec.data.pgmap.write_op_per_sec;
-	var reads = rec.data.pgmap.read_bytes_sec || 0;
-	var writes = rec.data.pgmap.write_bytes_sec || 0;
-
-	if (iops !== undefined && me.version !== 'hammer') {
-	    me.change_version('hammer');
-	} else if((readiops !== undefined || writeiops !== undefined) && me.version !== 'jewel') {
-	    me.change_version('jewel');
-	}
-	// update the graphs
-	me.reads.addDataPoint(reads);
-	me.writes.addDataPoint(writes);
-	me.iops.addDataPoint(iops);
-	me.readiops.addDataPoint(readiops);
-	me.writeiops.addDataPoint(writeiops);
-    },
-
-    change_version: function(version) {
-	var me = this;
-	me.version = version;
-	me.sp.set('ceph-version', version);
-	me.iops.setVisible(version === 'hammer');
-	me.readiops.setVisible(version === 'jewel');
-	me.writeiops.setVisible(version === 'jewel');
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-
-	me.callParent();
-	var baseurl = '/api2/json' + (nodename ? '/nodes/' + nodename : '/cluster') + '/ceph';
-	me.store = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-status-' + (nodename || 'cluster'),
-	    interval: 5000,
-	    proxy: {
-		type: 'proxmox',
-		url: baseurl + '/status'
-	    }
-	});
-
-	me.metadatastore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'ceph-metadata-' + (nodename || 'cluster'),
-	    interval: 15*1000,
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/cluster/ceph/metadata'
-	    }
-	});
-
-	// save references for the updatefunction
-	me.iops = me.down('#iops');
-	me.readiops = me.down('#readiops');
-	me.writeiops = me.down('#writeiops');
-	me.reads = me.down('#reads');
-	me.writes = me.down('#writes');
-
-	// get ceph version
-	me.sp = Ext.state.Manager.getProvider();
-	me.version = me.sp.get('ceph-version');
-	me.change_version(me.version);
-
-	var regex = new RegExp("not (installed|initialized)", "i");
-	PVE.Utils.handleStoreErrorOrMask(me, me.store, regex, function(me, error){
-	    me.store.stopUpdate();
-	    PVE.Utils.showCephInstallOrMask(me, error.statusText, (nodename || 'localhost'),
-		function(win){
-		    me.mon(win, 'cephInstallWindowClosed', function(){
-			me.store.startUpdate();
-		    });
-		}
-	    );
-	});
-
-	me.mon(me.store, 'load', me.updateAll, me);
-	me.mon(me.metadatastore, 'load', function(store, records, success) {
-	    if (!success || records.length < 1) {
-		return;
-	    }
-	    var rec = records[0];
-	    me.metadata = rec.data;
-
-	    // update services
-	    me.getComponent('services').updateAll(rec.data, me.status || {});
-
-	    // update detailstatus panel
-	    me.getComponent('statusdetail').updateAll(rec.data, me.status || {});
-
-	}, me);
-
-	me.on('destroy', me.store.stopUpdate);
-	me.on('destroy', me.metadatastore.stopUpdate);
-	me.store.startUpdate();
-	me.metadatastore.startUpdate();
-    }
-
-});
-Ext.define('PVE.ceph.StatusDetail', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephStatusDetail',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [{
-	flex: 1,
-	itemId: 'osds',
-	maxHeight: 250,
-	scrollable: true,
-	padding: '0 10 5 10',
-	data: {
-	    total: 0,
-	    upin: 0,
-	    upout: 0,
-	    downin: 0,
-	    downout: 0,
-	    oldosds: []
-	},
-	tpl: [
-	    '<h3>' + 'OSDs' + '</h3>',
-	    '<table class="osds">',
-	    '<tr><td></td>',
-	    '<td><i class="fa fa-fw good fa-circle"></i>',
-	    gettext('In'),
-	    '</td>',
-	    '<td><i class="fa fa-fw warning fa-circle-o"></i>',
-	    gettext('Out'),
-	    '</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw good fa-arrow-circle-up"></i>',
-	    gettext('Up'),
-	    '</td>',
-	    '<td>{upin}</td>',
-	    '<td>{upout}</td>',
-	    '</tr>',
-	    '<tr>',
-	    '<td><i class="fa fa-fw critical fa-arrow-circle-down"></i>',
-	    gettext('Down'),
-	    '</td>',
-	    '<td>{downin}</td>',
-	    '<td>{downout}</td>',
-	    '</tr>',
-	    '</table>',
-	    '<br /><div>',
-	    gettext('Total'),
-	    ': {total}',
-	    '</div><br />',
-	    '<tpl if="oldosds.length &gt; 0">',
-	    '<i class="fa fa-refresh warning"></i> ' + gettext('Outdated OSDs') + "<br>",
-	    '<div class="osds">',
-	    '<tpl for="oldosds">',
-	    '<div class="left-aligned">osd.{id}:</div>',
-	    '<div class="right-aligned">{version}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>',
-	    '</div>',
-	    '</tpl>'
-	]
-    },
-    {
-	flex: 1,
-	border: false,
-	itemId: 'pgchart',
-	xtype: 'polar',
-	height: 184,
-	innerPadding: 5,
-	insetPadding: 5,
-	colors: [
-	    '#CFCFCF',
-	    '#21BF4B',
-	    '#FFCC00',
-	    '#FF6C59'
-	],
-	store: { },
-	series: [
-	    {
-		type: 'pie',
-		donut: 60,
-		angleField: 'count',
-		tooltip: {
-		    trackMouse: true,
-		    renderer: function(tooltip, record, ctx) {
-			var html = record.get('text');
-			html += '<br>';
-			record.get('states').forEach(function(state) {
-			    html += '<br>' +
-				state.state_name + ': ' + state.count.toString();
-			});
-			tooltip.setHtml(html);
-		    }
-		},
-		subStyle: {
-		    strokeStyle: false
-		}
-	    }
-	]
-    },
-    {
-	flex: 1.6,
-	itemId: 'pgs',
-	padding: '0 10',
-	maxHeight: 250,
-	scrollable: true,
-	data: {
-	    states: []
-	},
-	tpl: [
-	    '<h3>' + 'PGs' + '</h3>',
-	    '<tpl for="states">',
-	    '<div class="left-aligned"><i class ="fa fa-circle {cls}"></i> {state_name}:</div>',
-	    '<div class="right-aligned">{count}</div><br />',
-	    '<div style="clear:both"></div>',
-	    '</tpl>'
-	]
-    }],
-
-    // similar to mgr dashboard
-    pgstates: {
-	// clean
-	clean: 1,
-	active: 1,
-
-	// working
-	activating: 2,
-	backfill_wait: 2,
-	backfilling: 2,
-	creating: 2,
-	deep: 2,
-	degraded: 2,
-	forced_backfill: 2,
-	forced_recovery: 2,
-	peered: 2,
-	peering: 2,
-	recovering: 2,
-	recovery_wait: 2,
-	repair: 2,
-	scrubbing: 2,
-	snaptrim: 2,
-	snaptrim_wait: 2,
-
-	// error
-	backfill_toofull: 3,
-	backfill_unfound: 3,
-	down: 3,
-	incomplete: 3,
-	inconsistent: 3,
-	recovery_toofull: 3,
-	recovery_unfound: 3,
-	remapped: 3,
-	snaptrim_error: 3,
-	stale: 3,
-	undersized: 3
-    },
-
-    statecategories: [
-	{
-	    text: gettext('Unknown'),
-	    count: 0,
-	    states: [],
-	    cls: 'faded'
-	},
-	{
-	    text: gettext('Clean'),
-	    cls: 'good'
-	},
-	{
-	    text: gettext('Working'),
-	    cls: 'warning'
-	},
-	{
-	    text: gettext('Error'),
-	    cls: 'critical'
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var maxversion = "0";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-
-	var oldosds = [];
-
-	if (metadata.osd) {
-	    metadata.osd.forEach(function(osd) {
-		var version = PVE.Utils.parse_ceph_version(osd);
-		if (version != maxversion) {
-		    oldosds.push({
-			id: osd.id,
-			version: version
-		    });
-		}
-	    });
-	}
-
-	var pgmap = status.pgmap || {};
-	var health = status.health || {};
-	var osdmap = status.osdmap || { osdmap: {} };
-
-
-	// update pgs sorted
-	var pgs_by_state = pgmap.pgs_by_state || [];
-	pgs_by_state.sort(function(a,b){
-	    return (a.state_name < b.state_name)?-1:(a.state_name === b.state_name)?0:1;
-	});
-
-	me.statecategories.forEach(function(cat) {
-	    cat.count = 0;
-	    cat.states = [];
-	});
-
-	pgs_by_state.forEach(function(state) {
-	    var i;
-	    var states = state.state_name.split(/[^a-z]+/);
-	    var result = 0;
-	    for (i = 0; i < states.length; i++) {
-		if (me.pgstates[states[i]] > result) {
-		    result = me.pgstates[states[i]];
-		}
-	    }
-	    // for the list
-	    state.cls = me.statecategories[result].cls;
-
-	    me.statecategories[result].count += state.count;
-	    me.statecategories[result].states.push(state);
-	});
-
-	me.getComponent('pgchart').getStore().setData(me.statecategories);
-	me.getComponent('pgs').update({states: pgs_by_state});
-
-	var downinregex = /(\d+) osds down/;
-	var downin_osds = 0;
-
-	// we collect monitor/osd information from the checks
-	Ext.Object.each(health.checks, function(key, value, obj) {
-	    var found = null;
-	    if (key === 'OSD_DOWN') {
-		found = value.summary.message.match(downinregex);
-		if (found !== null) {
-		    downin_osds = parseInt(found[1],10);
-		}
-	    }
-	});
-
-	// update osds counts
-
-	var total_osds = osdmap.osdmap.num_osds || 0;
-	var in_osds = osdmap.osdmap.num_in_osds || 0;
-	var up_osds = osdmap.osdmap.num_up_osds || 0;
-	var out_osds = total_osds - in_osds;
-	var down_osds = total_osds - up_osds;
-
-	var downout_osds = down_osds - downin_osds;
-	var upin_osds = in_osds - downin_osds;
-	var upout_osds = up_osds - upin_osds;
-	var osds = {
-	    total: total_osds,
-	    upin: upin_osds,
-	    upout: upout_osds,
-	    downin: downin_osds,
-	    downout: downout_osds,
-	    oldosds: oldosds
-	};
-	var osdcomponent = me.getComponent('osds');
-	osdcomponent.update(Ext.apply(osdcomponent.data, osds));
-
-	me.suspendLayout = false;
-	me.updateLayout();
-    }
-});
-
-Ext.define('PVE.ceph.Services', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveCephServices',
-
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    bodyPadding: '0 5 20',
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mons',
-	    title: gettext('Monitors')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mgrs',
-	    title: gettext('Managers')
-	},
-	{
-	    flex: 1,
-	    xtype: 'pveCephServiceList',
-	    itemId: 'mdss',
-	    title: gettext('Meta Data Servers')
-	}
-    ],
-
-    updateAll: function(metadata, status) {
-	var me = this;
-
-	var healthstates = {
-	    'HEALTH_UNKNOWN': 0,
-	    'HEALTH_ERR': 1,
-	    'HEALTH_WARN': 2,
-	    'HEALTH_UPGRADE': 3,
-	    'HEALTH_OLD': 4,
-	    'HEALTH_OK': 5
-	};
-	var healthmap = [
-	    'HEALTH_UNKNOWN',
-	    'HEALTH_ERR',
-	    'HEALTH_WARN',
-	    'HEALTH_UPGRADE',
-	    'HEALTH_OLD',
-	    'HEALTH_OK'
-	];
-	var reduceFn = function(first, second) {
-	    return first + '\n' + second.message;
-	};
-	var maxversion = "00.0.00";
-	Object.values(metadata.version || {}).forEach(function(version) {
-	    if (PVE.Utils.compare_ceph_versions(version, maxversion) > 0) {
-		maxversion = version;
-	    }
-	});
-	var i;
-	var quorummap = (status && status.quorum_names) ? status.quorum_names : [];
-	var monmessages = {};
-	var mgrmessages = {};
-	var mdsmessages = {};
-	if (status) {
-	    if (status.health) {
-		Ext.Object.each(status.health.checks, function(key, value, obj) {
-		    if (!Ext.String.startsWith(key, "MON_")) {
-			return;
-		    }
-
-		    var i;
-		    for (i = 0; i < value.detail.length; i++) {
-			var match = value.detail[i].message.match(/mon.([a-zA-Z0-9\-\.]+)/);
-			if (!match) {
-			    continue;
-			}
-			var monid = match[1];
-
-			if (!monmessages[monid]) {
-			    monmessages[monid] = {
-				worstSeverity: healthstates.HEALTH_OK,
-				messages: []
-			    };
-			}
-
-
-			monmessages[monid].messages.push(
-							 PVE.Utils.get_ceph_icon_html(value.severity, true) +
-							 Ext.Array.reduce(value.detail, reduceFn, '')
-			);
-			if (healthstates[value.severity] < monmessages[monid].worstSeverity) {
-			    monmessages[monid].worstSeverity = healthstates[value.severity];
-			}
-		    }
-		});
-	    }
-
-	    if (status.mgrmap) {
-		mgrmessages[status.mgrmap.active_name] = "active";
-		status.mgrmap.standbys.forEach(function(mgr) {
-		    mgrmessages[mgr.name] = "standby";
-		});
-	    }
-
-	    if (status.fsmap) {
-		status.fsmap.by_rank.forEach(function(mds) {
-		    mdsmessages[mds.name] = 'rank: ' + mds.rank + "; " + mds.status;
-		});
-	    }
-	}
-
-	var checks = {
-	    mon: function(mon) {
-		if (quorummap.indexOf(mon.name) !== -1) {
-		    mon.health = healthstates.HEALTH_OK;
-		} else {
-		    mon.health = healthstates.HEALTH_ERR;
-		}
-		if (monmessages[mon.name]) {
-		    if (monmessages[mon.name].worstSeverity < mon.health) {
-			mon.health = monmessages[mon.name].worstSeverity;
-		    }
-		    Array.prototype.push.apply(mon.messages, monmessages[mon.name].messages);
-		}
-		return mon;
-	    },
-	    mgr: function(mgr) {
-		if (mgrmessages[mgr.name] === 'active') {
-		    mgr.title = '<b>' + mgr.title + '</b>';
-		    mgr.statuses.push(gettext('Status') + ': <b>active</b>');
-		} else if (mgrmessages[mgr.name] === 'standby') {
-		    mgr.statuses.push(gettext('Status') + ': standby');
-		} else if (mgr.health > healthstates.HEALTH_WARN) {
-		    mgr.health = healthstates.HEALTH_WARN;
-		}
-
-		return mgr;
-	    },
-	    mds: function(mds) {
-		if (mdsmessages[mds.name]) {
-		    mds.title = '<b>' + mds.title + '</b>';
-		    mds.statuses.push(gettext('Status') + ': <b>' + mdsmessages[mds.name]+"</b>");
-		} else if (mds.addr !== Proxmox.Utils.unknownText) {
-		    mds.statuses.push(gettext('Status') + ': standby');
-		}
-
-		return mds;
-	    }
-	};
-
-	for (let type of ['mon', 'mgr', 'mds']) {
-	    var ids = Object.keys(metadata[type] || {});
-	    me[type] = {};
-
-	    for (let id of ids) {
-		var tmp = id.split('@');
-		var name = tmp[0];
-		var host = tmp[1];
-		var result = {
-		    id: id,
-		    health: healthstates.HEALTH_OK,
-		    statuses: [],
-		    messages: [],
-		    name: name,
-		    title: metadata[type][id].name || name,
-		    host: host,
-		    version: PVE.Utils.parse_ceph_version(metadata[type][id]),
-		    service: metadata[type][id].service,
-		    addr: metadata[type][id].addr || metadata[type][id].addrs || Proxmox.Utils.unknownText
-		};
-
-		result.statuses = [
-		    gettext('Host') + ": " + result.host,
-		    gettext('Address') + ": " + result.addr
-		];
-
-		if (checks[type]) {
-		    result = checks[type](result);
-		}
-
-		if (result.service && !result.version) {
-		    result.messages.push(
-			PVE.Utils.get_ceph_icon_html('HEALTH_UNKNOWN', true) +
-			gettext('Stopped')
-		    );
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (!result.version && result.addr === Proxmox.Utils.unknownText) {
-		    result.health = healthstates.HEALTH_UNKNOWN;
-		}
-
-		if (result.version) {
-		    result.statuses.push(gettext('Version') + ": " + result.version);
-
-		    if (result.version != maxversion) {
-			if (metadata.version[result.host] === maxversion) {
-			    if (result.health > healthstates.HEALTH_OLD) {
-				result.health = healthstates.HEALTH_OLD;
-			    }
-			    result.messages.push(
-				PVE.Utils.get_ceph_icon_html('HEALTH_OLD', true) +
-				gettext('A newer version was installed but old version still running, please restart')
-			    );
-			} else {
-			    if (result.health > healthstates.HEALTH_UPGRADE) {
-				result.health = healthstates.HEALTH_UPGRADE;
-			    }
-			    result.messages.push(
-				PVE.Utils.get_ceph_icon_html('HEALTH_UPGRADE', true) +
-				gettext('Other cluster members use a newer version of this service, please upgrade and restart')
-			    );
-			}
-		    }
-		}
-
-		result.statuses.push(''); // empty line
-		result.text = result.statuses.concat(result.messages).join('<br>');
-
-		result.health = healthmap[result.health];
-
-		me[type][id] = result;
-	    }
-	}
-
-	me.getComponent('mons').updateAll(Object.values(me.mon));
-	me.getComponent('mgrs').updateAll(Object.values(me.mgr));
-	me.getComponent('mdss').updateAll(Object.values(me.mds));
-    }
-});
-
-Ext.define('PVE.ceph.ServiceList', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCephServiceList',
-
-    style: {
-	'text-align':'center'
-    },
-    defaults: {
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'title',
-	    data: {
-		title: ''
-	    },
-	    tpl: '<h3>{title}</h3>'
-	}
-    ],
-
-    updateAll: function(list) {
-	var me = this;
-	me.suspendLayout = true;
-
-	var i;
-	list.sort((a, b) => a.id > b.id ? 1 : a.id < b.id ? -1 : 0);
-	var ids = {};
-	if (me.ids) {
-	    me.ids.forEach(id => ids[id] = true);
-	}
-	for (i = 0; i < list.length; i++) {
-	    var service = me.getComponent(list[i].id);
-	    if (!service) {
-		// since services are already sorted, and
-		// we always have a sorted list
-		// we can add it at the service+1 position (because of the title)
-		service = me.insert(i+1, {
-		    xtype: 'pveCephServiceWidget',
-		    itemId: list[i].id
-		});
-		if (!me.ids) {
-		    me.ids = [];
-		}
-		me.ids.push(list[i].id);
-	    } else {
-		delete ids[list[i].id];
-	    }
-	    service.updateService(list[i].title, list[i].text, list[i].health);
-	}
-
-	Object.keys(ids).forEach(function(id) {
-	    me.remove(id);
-	});
-	me.suspendLayout = false;
-	me.updateLayout();
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getComponent('title').update({
-	    title: me.title
-	});
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.ServiceWidget', {
-    extend: 'Ext.Component',
-    alias: 'widget.pveCephServiceWidget',
-
-    userCls: 'monitor inline-block',
-    data: {
-	title: '0',
-	health: 'HEALTH_ERR',
-	text: '',
-	iconCls: PVE.Utils.get_health_icon()
-    },
-
-    tpl: [
-	'{title}: ',
-	'<i class="fa fa-fw {iconCls}"></i>'
-    ],
-
-    updateService: function(title, text, health) {
-	var me = this;
-
-	me.update(Ext.apply(me.data, {
-	    health: health,
-	    text: text,
-	    title: title,
-	    iconCls: PVE.Utils.get_health_icon(PVE.Utils.map_ceph_health[health])
-	}));
-
-	if (me.tooltip) {
-	    me.tooltip.setHtml(text);
-	}
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    if (me.tooltip) {
-		me.tooltip.destroy();
-		delete me.tooltip;
-	    }
-	},
-	mouseenter: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (!me) {
-		    return;
-		}
-		if (!me.tooltip) {
-		    me.tooltip = Ext.create('Ext.tip.ToolTip', {
-			target: me.el,
-			trackMouse: true,
-			dismissDelay: 0,
-			renderTo: Ext.getBody(),
-			html: me.data.text
-		    });
-		}
-		me.tooltip.show();
-	    }
-	},
-	mouseleave: {
-	    element: 'el',
-	    fn: function(events, element) {
-		var me = this.component;
-		if (me.tooltip) {
-		    me.tooltip.destroy();
-		    delete me.tooltip;
-		}
-	    }
-	}
-    }
-});
-Ext.define('PVE.node.CephConfigDb', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveNodeCephConfigDb',
-
-    border: false,
-    store: {
-	proxy: {
-	    type: 'proxmox'
-	}
-    },
-
-    columns: [
-	{
-	    dataIndex: 'section',
-	    text: 'WHO',
-	    width: 100,
-	},
-	{
-	    dataIndex: 'mask',
-	    text: 'MASK',
-	    hidden: true,
-	    width: 80,
-	},
-	{
-	    dataIndex: 'level',
-	    hidden: true,
-	    text: 'LEVEL',
-	},
-	{
-	    dataIndex: 'name',
-	    flex: 1,
-	    text: 'OPTION',
-	},
-	{
-	    dataIndex: 'value',
-	    flex: 1,
-	    text: 'VALUE',
-	},
-	{
-	    dataIndex: 'can_update_at_runtime',
-	    text: 'Runtime Updatable',
-	    hidden: true,
-	    width: 80,
-	    renderer: Proxmox.Utils.format_boolean
-	},
-    ],
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.store.proxy.url = '/api2/json/nodes/' + nodename + '/ceph/configdb';
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore());
-	me.getStore().load();
-    }
-});
-Ext.define('PVE.node.CephConfig', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfig',
-
-    bodyStyle: 'white-space:pre',
-    bodyPadding: 5,
-    border: false,
-    scrollable: true,
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    waitMsgTarget: me,
-	    failure: function(response, opts) {
-		me.update(gettext('Error') + " " + response.htmlStatus);
-		var msg = response.htmlStatus;
-		PVE.Utils.showCephInstallOrMask(me.ownerCt, msg, me.pveSelNode.data.node,
-		    function(win){
-			me.mon(win, 'cephInstallWindowClosed', function(){
-			    me.load();
-			});
-		    }
-		);
-
-	    },
-	    success: function(response, opts) {
-		var data = response.result.data;
-		me.update(Ext.htmlEncode(data));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    url: '/nodes/' + nodename + '/ceph/config',
-	    listeners: {
-		activate: function() {
-		    me.load();
-		}
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.CephConfigCrush', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeCephConfigCrush',
-
-    onlineHelp: 'chapter_pveceph',
-
-    layout: 'border',
-    items: [{
-	    title: gettext('Configuration'),
-	    xtype: 'pveNodeCephConfig',
-	    region: 'center'
-	},
-	{
-	    title: 'Crush Map', // do not localize
-	    xtype: 'pveNodeCephCrushMap',
-	    region: 'east',
-	    split: true,
-	    width: '50%'
-	},
-	{
-	    title: gettext('Configuration Database'),
-	    xtype: 'pveNodeCephConfigDb',
-	    region: 'south',
-	    split: true,
-	    weight: -30,
-	    height: '50%'
-    }],
-
-    initComponent: function() {
-	var me = this;
-	me.defaults = {
-	    pveSelNode: me.pveSelNode
-	};
-	me.callParent();
-    }
-});
-Ext.define('PVE.ceph.Log', {
-    extend: 'Proxmox.panel.LogView',
-    xtype: 'cephLogView',
-    nodename: undefined,
-    failCallback: function(response) {
-	var me = this;
-	var msg = response.htmlStatus;
-	var windowShow = PVE.Utils.showCephInstallOrMask(me, msg, me.nodename,
-	    function(win){
-		me.mon(win, 'cephInstallWindowClosed', function(){
-		    me.loadTask.delay(200);
-		});
-	    }
-	);
-	if (!windowShow) {
-	    Proxmox.Utils.setErrorMask(me, msg);
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ceph.CephInstallWizard', {
-	extend: 'PVE.window.Wizard',
-	alias: 'widget.pveCephInstallWizard',
-	mixins: ['Proxmox.Mixin.CBind'],
-	resizable: false,
-	nodename: undefined,
-	viewModel: {
-	    data: {
-		nodename: '',
-		configuration: true,
-		isInstalled: false
-	    }
-	},
-	cbindData: {
-	    nodename: undefined
-	},
-	title: gettext('Setup'),
-	navigateNext: function() {
-	    var tp = this.down('#wizcontent');
-	    var atab = tp.getActiveTab();
-
-	    var next = tp.items.indexOf(atab) + 1;
-	    var ntab = tp.items.getAt(next);
-	    if (ntab) {
-		ntab.enable();
-		tp.setActiveTab(ntab);
-	    }
-	},
-	setInitialTab: function (index) {
-	    var tp = this.down('#wizcontent');
-	    var initialTab = tp.items.getAt(index);
-	    initialTab.enable();
-	    tp.setActiveTab(initialTab);
-	},
-	onShow: function() {
-		this.callParent(arguments);
-		var isInstalled = this.getViewModel().get('isInstalled');
-		if (isInstalled) {
-		    this.getViewModel().set('configuration', false);
-		    this.setInitialTab(2);
-		}
-	},
-	items: [
-	    {
-		title: gettext('Info'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'chapter_pveceph',
-		html: '<h3>Ceph?</h3>'+
-		'<blockquote cite="https://ceph.com/"><p>"<b>Ceph</b> is a unified, distributed storage system designed for excellent performance, reliability and scalability."</p></blockquote>'+
-		'<p><b>Ceph</b> is currently <b>not installed</b> on this node, click on the next button below to start the installation.'+
-		' This wizard will guide you through the necessary steps, after the initial installation you will be offered to create an initial configuration.'+
-		' The configuration step is only needed once per cluster and will be skipped if a config is already present.</p>'+
-		'<p>Please take a look at our documentation, by clicking the help button below, before starting the installation, '+
-		'if you want to gain deeper knowledge about Ceph visit <a target="_blank" href="http://docs.ceph.com/docs/master/">ceph.com</a>.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#back').hide(true);
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Start installation'));
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-			this.up('pveCephInstallWizard').down('#next').setText(gettext('Next'));
-		    }
-		}
-	    },
-	    {
-		title: gettext('Installation'),
-		xtype: 'panel',
-		layout: 'fit',
-		cbind:{
-		    nodename: '{nodename}'
-		},
-		viewModel: {}, // needed to inherit parent viewModel data
-		listeners: {
-		    afterrender: function() {
-			var me = this;
-			if (this.getViewModel().get('isInstalled')) {
-			    this.mask("Ceph is already installed, click next to create your configuration.",['pve-static-mask']);
-			} else {
-			    me.down('pveNoVncConsole').fireEvent('activate');
-			}
-		    },
-		    activate: function() {
-			var me = this;
-			var nodename = me.nodename;
-			me.updateStore = Ext.create('Proxmox.data.UpdateStore', {
-				storeid: 'ceph-status-' + nodename,
-				interval: 1000,
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + nodename + '/ceph/status'
-				},
-				listeners: {
-				    load: function(rec, response, success, operation) {
-
-					if (success) {
-					    me.updateStore.stopUpdate();
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("not initialized", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',false);
-					    me.down('textfield').setValue('success');
-					} else if (operation.error.statusText.match("rados_connect failed", "i")) {
-					    me.updateStore.stopUpdate();
-					    me.up('pveCephInstallWizard').getViewModel().set('configuration',true);
-					    me.down('textfield').setValue('success');
-					} else if (!operation.error.statusText.match("not installed", "i")) {
-					    Proxmox.Utils.setErrorMask(me, operation.error.statusText);
-					}
-				    }
-				}
-			});
-			me.updateStore.startUpdate();
-		    },
-		    destroy: function() {
-			var me = this;
-			if (me.updateStore) {
-			    me.updateStore.stopUpdate();
-			}
-		    }
-		},
-		items: [
-		    {
-			itemId: 'jsconsole',
-			consoleType: 'cmd',
-			xtermjs: true,
-			xtype: 'pveNoVncConsole',
-			cbind:{
-			    nodename: '{nodename}'
-			},
-			cmd: 'ceph_install'
-		    },
-		    {
-			xtype: 'textfield',
-			name: 'installSuccess',
-			value: '',
-			allowBlank: false,
-			submitValue: false,
-			hidden: true
-		    }
-		]
-	    },
-	    {
-		xtype: 'inputpanel',
-		title: gettext('Configuration'),
-		onlineHelp: 'chapter_pveceph',
-		cbind: {
-		    nodename: '{nodename}'
-		},
-		viewModel: {
-		    data: {
-			replicas: undefined,
-			minreplicas: undefined
-		    }
-		},
-		listeners: {
-		    activate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Next'));
-		    },
-		    beforeshow: function() {
-			if (this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			    this.mask("Configuration already initialized",['pve-static-mask']);
-			} else {
-			    this.unmask();
-			}
-		    },
-		    deactivate: function() {
-			this.up('pveCephInstallWizard').down('#submit').setText(gettext('Finish'));
-		    }
-		},
-		column1: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('Ceph cluster configuration') + ':'
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'network',
-			value: '',
-			fieldLabel: 'Public Network IP/CIDR',
-			bind: {
-			    allowBlank: '{configuration}'
-			},
-			cbind: {
-			    nodename: '{nodename}'
-			}
-		    },
-		    {
-			xtype: 'proxmoxNetworkSelector',
-			name: 'cluster-network',
-			fieldLabel: 'Cluster Network IP/CIDR',
-			allowBlank: true,
-			autoSelect: false,
-			emptyText: gettext('Same as Public Network'),
-			cbind: {
-			    nodename: '{nodename}'
-			}
-		    }
-		    // FIXME: add hint about cluster network and/or reference user to docs??
-		],
-		column2: [
-		    {
-			xtype: 'displayfield',
-			value: gettext('First Ceph monitor') + ':'
-		    },
-		    {
-			xtype: 'pveNodeSelector',
-			fieldLabel: gettext('Monitor node'),
-			name: 'mon-node',
-			selectCurNode: true,
-			allowBlank: false
-		    },
-		    {
-			xtype: 'displayfield',
-			value: gettext('Additional monitors are recommended. They can be created at any time in the Monitor tab.'),
-			userCls: 'pmx-hint'
-		    }
-		],
-		advancedColumn1: [
-		    {
-			xtype: 'numberfield',
-			name: 'size',
-			fieldLabel: 'Number of replicas',
-			bind: {
-			    value: '{replicas}'
-			},
-			maxValue: 7,
-			minValue: 2,
-			emptyText: '3'
-		    },
-		    {
-			xtype: 'numberfield',
-			name: 'min_size',
-			fieldLabel: 'Minimum replicas',
-			bind: {
-			    maxValue: '{replicas}',
-			    value: '{minreplicas}'
-			},
-			minValue: 2,
-			maxValue: 3,
-			setMaxValue: function(value) {
-			    this.maxValue = Ext.Number.from(value, 2);
-			    // allow enough to avoid split brains with max 'size', but more makes simply no sense
-			    if (this.maxValue > 4) {
-				this.maxValue = 4;
-			    }
-			    this.toggleSpinners();
-			    this.validate();
-			},
-			emptyText: '2'
-		    }
-		],
-		onGetValues: function(values) {
-		    ['cluster-network', 'size', 'min_size'].forEach(function(field) {
-			if (!values[field]) {
-			    delete values[field];
-			}
-		    });
-		    return values;
-		},
-		onSubmit: function() {
-		    var me = this;
-		    if (!this.up('pveCephInstallWizard').getViewModel().get('configuration')) {
-			var wizard = me.up('window');
-			var kv = wizard.getValues();
-			delete kv['delete'];
-			var monNode = kv['mon-node'];
-			delete kv['mon-node'];
-			var nodename = me.nodename;
-			delete kv.nodename;
-			Proxmox.Utils.API2Request({
-			    url: '/nodes/' + nodename + '/ceph/init',
-			    waitMsgTarget: wizard,
-			    method: 'POST',
-			    params: kv,
-			    success: function() {
-				Proxmox.Utils.API2Request({
-				    url: '/nodes/' + monNode + '/ceph/mon/' + monNode,
-				    waitMsgTarget: wizard,
-				    method: 'POST',
-				    success: function() {
-					me.up('pveCephInstallWizard').navigateNext();
-				    },
-				    failure: function(response, opts) {
-					Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-				    }
-				});
-			    },
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    }
-			});
-
-		    } else {
-			me.up('pveCephInstallWizard').navigateNext();
-		    }
-		}
-	    },
-	    {
-		title: gettext('Success'),
-		xtype: 'panel',
-		border: false,
-		bodyBorder: false,
-		onlineHelp: 'pve_ceph_install',
-		html: '<h3>Installation successful!</h3>'+
-		'<p>The basic installation and configuration is completed, depending on your setup some of the following steps are required to start using Ceph:</p>'+
-		    '<ol><li>Install Ceph on other nodes</li>'+
-		    '<li>Create additional Ceph Monitors</li>'+
-		    '<li>Create Ceph OSDs</li>'+
-		    '<li>Create Ceph Pools</li></ol>'+
-		'<p>To learn more click on the help button below.</p>',
-		listeners: {
-		    activate: function() {
-			// notify owning container that it should display a help button
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxShowHelp', this.onlineHelp);
-			}
-
-			var tp = this.up('#wizcontent');
-			var idx = tp.items.indexOf(this)-1;
-			for(;idx >= 0;idx--) {
-			    var nc = tp.items.getAt(idx);
-			    if (nc) {
-				nc.disable();
-			    }
-			}
-		    },
-		    deactivate: function() {
-			if (this.onlineHelp) {
-			    Ext.GlobalEvents.fireEvent('proxmoxHideHelp', this.onlineHelp);
-			}
-		    }
-		},
-		onSubmit: function() {
-		    var wizard = this.up('pveCephInstallWizard');
-		    wizard.close();
-		}
-	    }
-	]
-    });
-Ext.define('PVE.node.DiskList', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveNodeDiskList',
-
-    emptyText: gettext('No Disks found'),
-
-    stateful: true,
-    stateId: 'grid-node-disks',
-
-    columns: [
-	{
-	    header: gettext('Device'),
-	    width: 150,
-	    sortable: true,
-	    dataIndex: 'devpath'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 80,
-	    sortable: true,
-	    dataIndex: 'type',
-	    renderer: function(v) {
-		if (v === 'ssd') {
-		    return 'SSD';
-		} else if (v === 'hdd') {
-		    return 'Hard Disk';
-		} else if (v === 'usb'){
-		    return 'USB';
-		} else {
-		    return gettext('Unknown');
-		}
-	    }
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 150,
-	    sortable: false,
-	    renderer: function(v, metaData, rec) {
-		if (rec) {
-		    if (rec.data.osdid >= 0) {
-			var bluestore = '';
-			if (rec.data.bluestore === 1) {
-			    bluestore = ' (Bluestore)';
-			}
-			return "Ceph osd." + rec.data.osdid.toString() + bluestore;
-		    }
-
-		    var types = [];
-		    if (rec.data.journals > 0) {
-			types.push('Journal');
-		    }
-
-		    if (rec.data.db > 0) {
-			types.push('DB');
-		    }
-
-		    if (rec.data.wal > 0) {
-			types.push('WAL');
-		    }
-
-		    if (types.length > 0) {
-			return 'Ceph (' + types.join(', ') + ')';
-		    }
-		}
-
-		return v || Proxmox.Utils.noText;
-	    },
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: 'GPT',
-	    width: 60,
-	    align: 'right',
-	    renderer: Proxmox.Utils.format_boolean,
-	    dataIndex: 'gpt'
-	},
-	{
-	    header: gettext('Vendor'),
-	    width: 100,
-	    sortable: true,
-	    hidden: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'vendor'
-	},
-	{
-	    header: gettext('Model'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'model'
-	},
-	{
-	    header: gettext('Serial'),
-	    width: 200,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'serial'
-	},
-	{
-	    header: 'S.M.A.R.T.',
-	    width: 100,
-	    sortable: true,
-	    renderer: Ext.String.htmlEncode,
-	    dataIndex: 'health'
-	},
-	{
-	    header: 'Wearout',
-	    width: 90,
-	    sortable: true,
-	    align: 'right',
-	    dataIndex: 'wearout',
-	    renderer: function(value) {
-		if (Ext.isNumeric(value)) {
-		    return (100 - value).toString() + '%';
-		}
-		return 'N/A';
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var store = Ext.create('Ext.data.Store', {
-	    storeid: 'node-disk-list' + nodename,
-	    model: 'node-disk-list',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/list"
-	    },
-	    sorters: [
-		{
-		    property : 'dev',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var reloadButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reload'),
-	    handler: function() {
-		me.store.load();
-	    }
-	});
-
-	var smartButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Show S.M.A.R.T. values'),
-	    selModel: sm,
-	    enableFn: function() {
-		return !!sm.getSelection().length;
-	    },
-	    disabled: true,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-
-		var win = Ext.create('PVE.DiskSmartWindow', {
-                    nodename: nodename,
-		    dev: rec.data.devpath
-		});
-		win.show();
-	    }
-	});
-
-	var initButton = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Initialize Disk with GPT'),
-	    selModel: sm,
-	    enableFn: function() {
-		var selection = sm.getSelection();
-
-		if (!selection.length || selection[0].data.used) {
-		    return false;
-		} else {
-		    return true;
-		}
-	    },
-	    disabled: true,
-
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/nodes/' + nodename + '/disks/initgpt',
-		    waitMsgTarget: me,
-		    method: 'POST',
-		    params: { disk: rec.data.devpath},
-		    failure: function(response, options) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-			var win = Ext.create('Proxmox.window.TaskProgress', {
-			    upid: upid
-			});
-			win.show();
-		    }
-		});
-	    }
-	});
-
-	me.loadCount = 1; // avoid duplicate loadmask
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [ reloadButton, smartButton, initButton ],
-	    listeners: {
-		itemdblclick: function() {
-		    var rec = sm.getSelection()[0];
-
-		    var win = Ext.create('PVE.DiskSmartWindow', {
-			nodename: nodename,
-			dev: rec.data.devpath
-		    });
-		    win.show();
-		}
-	    }
-	});
-
-
-	me.callParent();
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('node-disk-list', {
-	extend: 'Ext.data.Model',
-	fields: [ 'devpath', 'used', { name: 'size', type: 'number'},
-		  {name: 'osdid', type: 'number'},
-		  'vendor', 'model', 'serial', 'rpm', 'type', 'health', 'wearout' ],
-	idProperty: 'devpath'
-    });
-});
-
-Ext.define('PVE.DiskSmartWindow', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveSmartWindow',
-
-    modal: true,
-
-    items: [
-	{
-	    xtype: 'gridpanel',
-	    layout: {
-		type: 'fit'
-	    },
-	    emptyText: gettext('No S.M.A.R.T. Values'),
-	    scrollable: true,
-	    flex: 1,
-	    itemId: 'smarts',
-	    reserveScrollbar: true,
-	    columns: [
-	    { text: 'ID', dataIndex: 'id', width: 50 },
-	    { text: gettext('Attribute'), flex: 1, dataIndex: 'name', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Value'), dataIndex: 'raw', renderer: Ext.String.htmlEncode },
-	    { text: gettext('Normalized'), dataIndex: 'value', width: 60},
-	    { text: gettext('Threshold'), dataIndex: 'threshold', width: 60},
-	    { text: gettext('Worst'), dataIndex: 'worst', width: 60},
-	    { text: gettext('Flags'), dataIndex: 'flags'},
-	    { text: gettext('Failing'), dataIndex: 'fail', renderer: Ext.String.htmlEncode }
-	    ]
-	},
-	{
-	    xtype: 'component',
-	    itemId: 'text',
-	    layout: {
-		type: 'fit'
-	    },
-	    hidden: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	}
-    ],
-
-    buttons: [
-	{
-	    text: gettext('Reload'),
-	    name: 'reload',
-	    handler: function() {
-		var me = this;
-		me.up('window').store.reload();
-	    }
-	},
-	{
-	    text: gettext('Close'),
-	    name: 'close',
-	    handler: function() {
-		var me = this;
-		me.up('window').close();
-	    }
-	}
-    ],
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    width: 800,
-    height: 500,
-    minWidth: 600,
-    minHeight: 400,
-    bodyPadding: 5,
-    title: gettext('S.M.A.R.T. Values'),
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.nodename;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var dev = me.dev;
-	if (!dev) {
-	    throw "no device specified";
-	}
-
-	me.store = Ext.create('Ext.data.Store', {
-	    model: 'disk-smart',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/nodes/" + nodename + "/disks/smart?disk=" + dev
-	    }
-	});
-
-	me.callParent();
-	var grid = me.down('#smarts');
-	var text = me.down('#text');
-
-	Proxmox.Utils.monStoreErrors(grid, me.store);
-	me.mon(me.store, 'load', function(s, records, success) {
-	    if (success && records.length > 0) {
-		var rec = records[0];
-		switch (rec.data.type) {
-		    case 'text':
-			grid.setVisible(false);
-			text.setVisible(true);
-			text.setHtml(Ext.String.htmlEncode(rec.data.text));
-			break;
-		    default:
-			// includes 'ata'
-			// cannot use empty case because
-			// of jslint
-			grid.setVisible(true);
-			text.setVisible(false);
-			grid.setStore(rec.attributes());
-			break;
-		}
-	    }
-	});
-
-	me.store.load();
-    }
-}, function() {
-
-    Ext.define('disk-smart', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'health'},
-	    { name:'type'},
-	    { name:'text'}
-	],
-	hasMany: {model: 'smart-attribute', name: 'attributes'}
-    });
-    Ext.define('smart-attribute', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    { name:'id', type:'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw'
-	]
-    });
-});
-Ext.define('PVE.node.CreateLVM', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVM',
-
-    subject: 'LVM Volume Group',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMList', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveLVMList',
-    emptyText: gettext('No Volume Groups found'),
-    stateful: true,
-    stateId: 'grid-node-lvm',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Number of LVs'),
-	    dataIndex: 'lvcount',
-	    width: 150,
-	    align: 'right'
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Volume Group',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVM', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/lvm",
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'size', 'free',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			txt += (data.leaf) ? 'hdd-o' : 'object-group';
-			return txt;
-		    }
-		},
-		{
-		    type: 'number',
-		    name: 'usage',
-		    calculate: function(data) {
-			return ((data.size-data.free)/data.size);
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateLVMThin', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateLVMThin',
-
-    subject: 'LVM Thinpool',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_lvm',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/lvmthin",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.LVMThinList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveLVMThinList',
-
-    emptyText: gettext('No thinpools found'),
-    stateful: true,
-    stateId: 'grid-node-lvmthin',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'lv',
-	    flex: 1
-	},
-	{
-	    header: gettext('Usage'),
-	    width: 110,
-	    dataIndex: 'usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Size'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'lv_size'
-	},
-	{
-	    header: gettext('Used'),
-	    width: 100,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'used'
-	},
-	{
-	    header: gettext('Metadata Usage'),
-	    width: 120,
-	    dataIndex: 'metadata_usage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Metadata Size'),
-	    width: 120,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_size'
-	},
-	{
-	    header: gettext('Metadata Used'),
-	    width: 125,
-	    align: 'right',
-	    sortable: true,
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'metadata_used'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Thinpool',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateLVMThin', {
-		    nodename: me.nodename,
-		    taskDone: function() {
-			me.reload();
-		    }
-		}).show();
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['lv', 'lv_size', 'used', 'metadata_size', 'metadata_used',
-		    {
-			type: 'number',
-			name: 'usage',
-			calculate: function(data) {
-			    return data.used/data.lv_size;
-			}
-		    },
-		    {
-			type: 'number',
-			name: 'metadata_usage',
-			calculate: function(data) {
-			    return data.metadata_used/data.metadata_size;
-			}
-		    }
-		],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/lvmthin'
-		},
-		sorters: 'lv'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.CreateDirectory', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateDirectory',
-
-    subject: Proxmox.Utils.directoryText,
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-        Ext.applyIf(me, {
-	    url: "/nodes/" + me.nodename + "/disks/directory",
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'pveDiskSelector',
-		    name: 'device',
-		    nodename: me.nodename,
-		    diskType: 'unused',
-		    fieldLabel: gettext('Disk'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxKVComboBox',
-		    comboItems: [
-			['ext4', 'ext4'],
-			['xfs', 'xfs']
-		    ],
-		    fieldLabel: gettext('Filesystem'),
-		    name: 'filesystem',
-		    value: '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'name',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'add_storage',
-		    fieldLabel: gettext('Add Storage'),
-		    value: '1'
-		}
-            ]
-        });
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.node.Directorylist', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveDirectoryList',
-
-    stateful: true,
-    stateId: 'grid-node-directory',
-    columns: [
-	{
-	    text: gettext('Path'),
-	    dataIndex: 'path',
-	    flex: 1
-	},
-	{
-	    header: gettext('Device'),
-	    flex: 1,
-	    dataIndex: 'device'
-	},
-	{
-	    header: gettext('Type'),
-	    width: 100,
-	    dataIndex: 'type'
-	},
-	{
-	    header: gettext('Options'),
-	    width: 100,
-	    dataIndex: 'options'
-	},
-	{
-	    header: gettext('Unit File'),
-	    hidden: true,
-	    dataIndex: 'unitfile'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': Directory',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateDirectory', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['path', 'device', 'type', 'options', 'unitfile' ],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/directory'
-		},
-		sorters: 'path'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-/*jslint confusion: true*/
-Ext.define('PVE.node.CreateZFS', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCreateZFS',
-
-    subject: 'ZFS',
-
-    showProgress: true,
-
-    onlineHelp: 'chapter_zfs',
-
-    initComponent : function() {
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = true;
-
-	var update_disklist = function() {
-	    var grid = me.down('#disklist');
-	    var disks = grid.getSelection();
-
-	    var val = [];
-	    disks.sort(function(a,b) {
-		var aorder = a.get('order') || 0;
-		var border = b.get('order') || 0;
-		return (aorder - border);
-	    });
-
-	    disks.forEach(function(disk) {
-		val.push(disk.get('devpath'));
-	    });
-
-	    me.down('field[name=devices]').setValue(val.join(','));
-	};
-
-	Ext.apply(me, {
-	    url: '/nodes/' + me.nodename + '/disks/zfs',
-	    method: 'POST',
-	    items: [
-		{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			return values;
-		    },
-		    column1: [
-			{
-			    xtype: 'textfield',
-			    hidden: true,
-			    name: 'devices',
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxtextfield',
-			    name: 'name',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: false
-			},
-			{
-			    xtype: 'proxmoxcheckbox',
-			    name: 'add_storage',
-			    fieldLabel: gettext('Add Storage'),
-			    value: '1'
-			}
-		    ],
-		    column2: [
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('RAID Level'),
-			    name: 'raidlevel',
-			    value: 'single',
-			    comboItems: [
-				['single', gettext('Single Disk')],
-				['mirror', 'Mirror'],
-				['raid10', 'RAID10'],
-				['raidz', 'RAIDZ'],
-				['raidz2', 'RAIDZ2'],
-				['raidz3', 'RAIDZ3']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxKVComboBox',
-			    fieldLabel: gettext('Compression'),
-			    name: 'compression',
-			    value: 'on',
-			    comboItems: [
-				['on', 'on'],
-				['off', 'off'],
-				['gzip', 'gzip'],
-				['lz4', 'lz4'],
-				['lzjb', 'lzjb'],
-				['zle', 'zle']
-			    ]
-			},
-			{
-			    xtype: 'proxmoxintegerfield',
-			    fieldLabel: gettext('ashift'),
-			    minValue: 9,
-			    maxValue: 16,
-			    value: '12',
-			    name: 'ashift'
-			}
-		    ],
-		    columnB: [
-			{
-			    xtype: 'grid',
-			    height: 200,
-			    emptyText: gettext('No Disks unused'),
-			    itemId: 'disklist',
-			    selModel: 'checkboxmodel',
-			    listeners: {
-				selectionchange: update_disklist
-			    },
-			    store: {
-				proxy: {
-				    type: 'proxmox',
-				    url: '/api2/json/nodes/' + me.nodename + '/disks/list?type=unused'
-				}
-			    },
-			    columns: [
-				{
-				    text: gettext('Device'),
-				    dataIndex: 'devpath',
-				    flex: 1
-				},
-				{
-				    text: gettext('Serial'),
-				    dataIndex: 'serial'
-				},
-				{
-				    text: gettext('Size'),
-				    dataIndex: 'size',
-				    renderer: PVE.Utils.render_size
-				},
-				{
-				    header: gettext('Order'),
-				    xtype: 'widgetcolumn',
-				    dataIndex: 'order',
-				    sortable: true,
-				    widget: {
-					xtype: 'proxmoxintegerfield',
-					minValue: 1,
-					isFormField: false,
-					listeners: {
-					    change: function(numberfield, value, old_value) {
-						var record = numberfield.getWidgetRecord();
-						record.set('order', value);
-						update_disklist(record);
-					    }
-					}
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    xtype: 'displayfield',
-		    padding: '5 0 0 0',
-		    userCls: 'pmx-hint',
-		    value: 'Note: ZFS is not compatible with disks backed by a hardware ' +
-			   'RAID controller. For details see ' +
-			   '<a target="_blank" href="' + Proxmox.Utils.get_help_link('chapter_zfs') + '">the reference documentation</a>.',
-		}
-	    ]
-	});
-
-        me.callParent();
-	me.down('#disklist').getStore().load();
-    }
-});
-
-Ext.define('PVE.node.ZFSDevices', {
-    extend: 'Ext.tree.Panel',
-    xtype: 'pveZFSDevices',
-    stateful: true,
-    stateId: 'grid-node-zfsstatus',
-    columns: [
-	{
-	    xtype: 'treecolumn',
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    text: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'state'
-	},
-	{
-	    text: 'READ',
-	    dataIndex: 'read'
-	},
-	{
-	    text: 'WRITE',
-	    dataIndex: 'write'
-	},
-	{
-	    text: 'CKSUM',
-	    dataIndex: 'cksum'
-	},
-	{
-	    text: gettext('Message'),
-	    dataIndex: 'msg'
-	}
-    ],
-
-    rootVisible: true,
-
-    reload: function() {
-	var me = this;
-	var sm = me.getSelectionModel();
-	Proxmox.Utils.API2Request({
-	    url: "/nodes/" + me.nodename + "/disks/zfs/" + me.zpool,
-	    waitMsgTarget: me,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		sm.deselectAll();
-		me.setRootNode(response.result.data);
-		me.expandAll();
-	    }
-	});
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	var sm = Ext.create('Ext.selection.TreeModel', {});
-
-	Ext.apply(me, {
-	    selModel: sm,
-	    fields: ['name', 'status',
-		{
-		    type: 'string',
-		    name: 'iconCls',
-		    calculate: function(data) {
-			var txt = 'fa x-fa-tree fa-';
-			if (data.leaf) {
-			    return txt + 'hdd-o';
-			}
-		    }
-		}
-	    ],
-	    sorters: 'name'
-	});
-
-	me.callParent();
-
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSStatus', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveZFSStatus',
-    layout: 'fit',
-    border: false,
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.zpool) {
-	    throw "no zpool specified";
-	}
-
-	me.url = "/api2/extjs/nodes/" + me.nodename + "/disks/zfs/" + me.zpool;
-
-	me.rows = {
-	    scan: {
-		header: gettext('Scan')
-	    },
-	    status: {
-		header: gettext('Status')
-	    },
-	    action: {
-		header: gettext('Action')
-	    },
-	    errors: {
-		header: gettext('Errors')
-	    }
-	};
-
-	me.callParent();
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.ZFSList', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveZFSList',
-
-    stateful: true,
-    stateId: 'grid-node-zfs',
-    columns: [
-	{
-	    text: gettext('Name'),
-	    dataIndex: 'name',
-	    flex: 1
-	},
-	{
-	    header: gettext('Size'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'size'
-	},
-	{
-	    header: gettext('Free'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'free'
-	},
-	{
-	    header: gettext('Allocated'),
-	    renderer: Proxmox.Utils.format_size,
-	    dataIndex: 'alloc'
-	},
-	{
-	    header: gettext('Fragmentation'),
-	    renderer: function(value) {
-		return value.toString() + '%';
-	    },
-	    dataIndex: 'frag'
-	},
-	{
-	    header: gettext('Health'),
-	    renderer: PVE.Utils.render_zfs_health,
-	    dataIndex: 'health'
-	},
-	{
-	    header: gettext('Deduplication'),
-	    hidden: true,
-	    renderer: function(value) {
-		return value.toFixed(2).toString() + 'x';
-	    },
-	    dataIndex: 'dedup'
-	}
-    ],
-
-    rootVisible: false,
-    useArrows: true,
-
-    tbar: [
-	{
-	    text: gettext('Reload'),
-	    iconCls: 'fa fa-refresh',
-	    handler: function() {
-		var me = this.up('panel');
-		me.reload();
-	    }
-	},
-	{
-	    text: gettext('Create') + ': ZFS',
-	    handler: function() {
-		var me = this.up('panel');
-		var win = Ext.create('PVE.node.CreateZFS', {
-		    nodename: me.nodename
-		}).show();
-		win.on('destroy', function() { me.reload(); });
-	    }
-	},
-	{
-	    text: gettext('Detail'),
-	    itemId: 'detailbtn',
-	    disabled: true,
-	    handler: function() {
-		var me = this.up('panel');
-		var selection = me.getSelection();
-		if (selection.length < 1) {
-		    return;
-		}
-		me.show_detail(selection[0].get('name'));
-	    }
-	}
-    ],
-
-    show_detail: function(zpool) {
-	var me = this;
-
-	var detailsgrid = Ext.create('PVE.node.ZFSStatus', {
-	    layout: 'fit',
-	    nodename: me.nodename,
-	    flex: 0,
-	    zpool: zpool
-	});
-
-	var devicetree = Ext.create('PVE.node.ZFSDevices', {
-	    title: gettext('Devices'),
-	    nodename: me.nodename,
-	    flex: 1,
-	    zpool: zpool
-	});
-
-
-	var win = Ext.create('Ext.window.Window', {
-	    modal: true,
-	    width: 800,
-	    height: 400,
-	    resizable: true,
-	    layout: 'fit',
-	    title: gettext('Status') + ': ' + zpool,
-	    items:[{
-		xtype: 'panel',
-		region: 'center',
-		layout: {
-		    type: 'vbox',
-		    align: 'stretch'
-		},
-		items: [detailsgrid, devicetree],
-		tbar: [{
-		    text: gettext('Reload'),
-		    iconCls: 'fa fa-refresh',
-		    handler: function() {
-
-			devicetree.reload();
-			detailsgrid.reload();
-		    }
-		}]
-	    }]
-	}).show();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var selection = me.getSelection();
-	me.down('#detailbtn').setDisabled(selection.length === 0);
-    },
-
-    reload: function() {
-	var me = this;
-	me.store.load();
-	me.store.sort();
-    },
-
-    listeners: {
-	activate: function() {
-	    var me = this;
-	    me.reload();
-	},
-	selectionchange: function() {
-	    this.set_button_status();
-	},
-	itemdblclick: function(grid, record) {
-	    var me = this;
-	    me.show_detail(record.get('name'));
-	}
-    },
-
-    initComponent: function() {
-	 /*jslint confusion: true */
-        var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	Ext.apply(me, {
-	    store: {
-		fields: ['name', 'size', 'free', 'alloc', 'dedup', 'frag', 'health'],
-		proxy: {
-		    type: 'proxmox',
-		    url: "/api2/json/nodes/" + me.nodename + '/disks/zfs'
-		},
-		sorters: 'name'
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, me.getStore(), true);
-	me.reload();
-    }
-});
-
-Ext.define('PVE.node.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveNodeStatus',
-
-    height: 300,
-    bodyPadding: '20 15 20 15',
-
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 15 5 15'
-    },
-
-    items: [
-	{
-	    itemId: 'cpu',
-	    iconCls: 'fa fa-fw pve-itype-icon-processor pve-icon',
-	    title: gettext('CPU usage'),
-	    valueField: 'cpu',
-	    maxField: 'cpuinfo',
-	    renderer: PVE.Utils.render_node_cpu_usage
-	},
-	{
-	    itemId: 'wait',
-	    iconCls: 'fa fa-fw fa-clock-o',
-	    title: gettext('IO delay'),
-	    valueField: 'wait',
-	    rowspan: 2
-	},
-	{
-	    itemId: 'load',
-	    iconCls: 'fa fa-fw fa-tasks',
-	    title: gettext('Load average'),
-	    printBar: false,
-	    textField: 'loadavg'
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    iconCls: 'fa fa-fw pve-itype-icon-memory pve-icon',
-	    itemId: 'memory',
-	    title: gettext('RAM usage'),
-	    valueField: 'memory',
-	    maxField: 'memory',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    itemId: 'ksm',
-	    printBar: false,
-	    title: gettext('KSM sharing'),
-	    textField: 'ksm',
-	    renderer: function(record) {
-		return PVE.Utils.render_size(record.shared);
-	    },
-	    padding: '0 15 10 15'
-	},
-	{
-	    iconCls: 'fa fa-fw fa-hdd-o',
-	    itemId: 'rootfs',
-	    title: gettext('HD space') + '(root)',
-	    valueField: 'rootfs',
-	    maxField: 'rootfs',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    iconCls: 'fa fa-fw fa-refresh',
-	    itemId: 'swap',
-	    printSize: true,
-	    title: gettext('SWAP usage'),
-	    valueField: 'swap',
-	    maxField: 'swap',
-	    renderer: PVE.Utils.render_node_size_usage
-	},
-	{
-	    xtype: 'box',
-	    colspan: 2,
-	    padding: '0 0 20 0'
-	},
-	{
-	    itemId: 'cpus',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('CPU(s)'),
-	    textField: 'cpuinfo',
-	    renderer: function(cpuinfo) {
-		return cpuinfo.cpus + " x " + cpuinfo.model + " (" +
-		cpuinfo.sockets.toString() + " " +
-		(cpuinfo.sockets > 1 ?
-		    gettext('Sockets') :
-		    gettext('Socket')
-		) + ")";
-	    },
-	    value: ''
-	},
-	{
-	    itemId: 'kversion',
-	    colspan: 2,
-	    title: gettext('Kernel Version'),
-	    printBar: false,
-	    textField: 'kversion',
-	    value: ''
-	},
-	{
-	    itemId: 'version',
-	    colspan: 2,
-	    printBar: false,
-	    title: gettext('PVE Manager Version'),
-	    textField: 'pveversion',
-	    value: ''
-	}
-    ],
-
-    updateTitle: function() {
-	var me = this;
-	var uptime = Proxmox.Utils.render_uptime(me.getRecordValue('uptime'));
-	me.setTitle(me.pveSelNode.data.node + ' (' + gettext('Uptime') + ': ' + uptime + ')');
-    }
-
-});
-Ext.define('PVE.node.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveNodeSummary',
-
-    scrollable: true,
-    bodyPadding: 5,
-
-    showVersions: function() {
-	var me = this;
-
-	// Note: we use simply text/html here, because ExtJS grid has problems
-	// with cut&paste
-
-	var nodename = me.pveSelNode.data.node;
-
-	var view = Ext.createWidget('component', {
-	    autoScroll: true,
-	    padding: 5,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace'
-	    }
-	});
-
-	var win = Ext.create('Ext.window.Window', {
-	    title: gettext('Package versions'),
-	    width: 600,
-	    height: 400,
-	    layout: 'fit',
-	    modal: true,
-	    items: [ view ]
-	});
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: "/nodes/" + nodename + "/apt/versions",
-	    method: 'GET',
-	    failure: function(response, opts) {
-		win.close();
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		win.show();
-		var text = '';
-
-		Ext.Array.each(response.result.data, function(rec) {
-		    var version = "not correctly installed";
-		    var pkg = rec.Package;
-		    if (rec.OldVersion && rec.CurrentState === 'Installed') {
-			version = rec.OldVersion;
-		    }
-		    if (rec.RunningKernel) {
-			text += pkg + ': ' + version + ' (running kernel: ' +
-			    rec.RunningKernel + ')\n';
-		    } else if (rec.ManagerVersion) {
-			text += pkg + ': ' + version + ' (running version: ' +
-			    rec.ManagerVersion + ')\n';
-		    } else {
-			text += pkg + ': ' + version + '\n';
-		    }
-		});
-
-		view.update(Ext.htmlEncode(text));
-	    }
-	});
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.statusStore) {
-	    throw "no status storage specified";
-	}
-
-	var rstore = me.statusStore;
-
-	var version_btn = new Ext.Button({
-	    text: gettext('Package versions'),
-	    handler: function(){
-		Proxmox.Utils.checked_command(function() { me.showVersions(); });
-	    }
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl: "/api2/json/nodes/" + nodename + "/rrddata",
-	    model: 'pve-rrd-node'
-	});
-
-	Ext.apply(me, {
-	    tbar: [version_btn, '->', { xtype: 'proxmoxRRDTypeSelector' } ],
-	    items: [
-		{
-		    xtype: 'container',
-		    itemId: 'itemcontainer',
-		    layout: 'column',
-		    minWidth: 700,
-		    defaults: {
-			minHeight: 320,
-			padding: 5,
-			columnWidth: 1
-		    },
-		    items: [
-			{
-			    xtype: 'pveNodeStatus',
-			    rstore: rstore,
-			    width: 770,
-			    pveSelNode: me.pveSelNode
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('CPU usage'),
-			    fields: ['cpu','iowait'],
-			    fieldTitles: [gettext('CPU usage'), gettext('IO delay')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Server load'),
-			    fields: ['loadavg'],
-			    fieldTitles: [gettext('Load average')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Memory usage'),
-			    fields: ['memtotal','memused'],
-			    fieldTitles: [gettext('Total'), gettext('RAM usage')],
-			    store: rrdstore
-			},
-			{
-			    xtype: 'proxmoxRRDChart',
-			    title: gettext('Network traffic'),
-			    fields: ['netin','netout'],
-			    store: rrdstore
-			}
-		    ],
-		    listeners: {
-			resize: function(panel) {
-			    PVE.Utils.updateColumns(panel);
-			},
-		    },
-		},
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-
-	let sp = Ext.state.Manager.getProvider();
-	me.mon(sp, 'statechange', function(provider, key, value) {
-	    if (key !== 'summarycolumns') {
-		return;
-	    }
-	    PVE.Utils.updateColumns(me.getComponent('itemcontainer'));
-	});
-    }
-});
-/*global Blob*/
-Ext.define('PVE.node.SubscriptionKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-    title: gettext('Upload Subscription Key'),
-    width: 300,
-    items: {
-	xtype: 'textfield',
-	name: 'key',
-	value: '',
-	fieldLabel: gettext('Subscription Key')
-    },
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.node.Subscription', {
-    extend: 'Proxmox.grid.ObjectGrid',
-
-    alias: ['widget.pveNodeSubscription'],
-
-    onlineHelp: 'getting_help',
-
-    viewConfig: {
-	enableTextSelection: true
-    },
-
-    showReport: function() {
-	var me = this;
-	var nodename = me.pveSelNode.data.node;
-
-	var getReportFileName = function() {
-	    var now = Ext.Date.format(new Date(), 'D-d-F-Y-G-i');
-	    return me.nodename + '-report-'  + now + '.txt';
-	};
-
-	var view = Ext.createWidget('component', {
-	    itemId: 'system-report-view',
-	    scrollable: true,
-	    style: {
-		'background-color': 'white',
-		'white-space': 'pre',
-		'font-family': 'monospace',
-		padding: '5px'
-	    }
-	});
-
-	var reportWindow = Ext.create('Ext.window.Window', {
-	    title: gettext('System Report'),
-	    width: 1024,
-	    height: 600,
-	    layout: 'fit',
-	    modal: true,
-	    buttons: [
-		        '->',
-			{
-			    text: gettext('Download'),
-			    handler: function() {
-				var fileContent = Ext.String.htmlDecode(reportWindow.getComponent('system-report-view').html);
-				var fileName = getReportFileName();
-
-				// Internet Explorer
-				if (window.navigator.msSaveOrOpenBlob) {
-				    navigator.msSaveOrOpenBlob(new Blob([fileContent]), fileName);
-				} else {
-				    var element = document.createElement('a');
-				    element.setAttribute('href', 'data:text/plain;charset=utf-8,'
-				      + encodeURIComponent(fileContent));
-				    element.setAttribute('download', fileName);
-				    element.style.display = 'none';
-				    document.body.appendChild(element);
-				    element.click();
-				    document.body.removeChild(element);
-				}
-			    }
-			}
-		],
-	    items: view
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/nodes/' + me.nodename + '/report',
-	    method: 'GET',
-	    waitMsgTarget: me,
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var report = Ext.htmlEncode(response.result.data);
-		reportWindow.show();
-		view.update(report);
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var baseurl = '/nodes/' + me.nodename + '/subscription';
-
-	var render_status = function(value) {
-
-	    var message = me.getObjectValue('message');
-
-	    if (message) {
-		return value + ": " + message;
-	    }
-	    return value;
-	};
-
-	var rows = {
-	    productname: {
-		header: gettext('Type')
-	    },
-	    key: {
-		header: gettext('Subscription Key')
-	    },
-	    status: {
-		header: gettext('Status'),
-		renderer: render_status
-	    },
-	    message: {
-		visible: false
-	    },
-	    serverid: {
-		header: gettext('Server ID')
-	    },
-	    sockets: {
-		header: gettext('Sockets')
-	    },
-	    checktime: {
-		header: gettext('Last checked'),
-		renderer: Proxmox.Utils.render_timestamp
-	    },
-	    nextduedate: {
-		header: gettext('Next due date')
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json' + baseurl,
-	    cwidth1: 170,
-	    tbar: [ 
-		{
-		    text: gettext('Upload Subscription Key'),
-		    handler: function() {
-			var win = Ext.create('PVE.node.SubscriptionKeyEdit', {
-			    url: '/api2/extjs/' + baseurl 
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		{
-		    text: gettext('Check'),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    params: { force: 1 },
-			    url: baseurl,
-			    method: 'POST',
-			    waitMsgTarget: me,
-			    failure: function(response, opts) {
-				Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			    },
-			    callback: reload
-			});
-		    }
-		},
-		{
-		    text: gettext('System Report'),
-		    handler: function() {
-			Proxmox.Utils.checked_command(function (){ me.showReport(); });
-		    }
-		}
-	    ],
-	    rows: rows,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.node.CertificateView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveCertificatesView',
-
-    onlineHelp: 'sysadmin_certificate_management',
-
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    items: [
-	{
-	    xtype: 'pveCertView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	},
-	{
-	    xtype: 'pveACMEView',
-	    border: 0,
-	    cbind: {
-		nodename: '{nodename}'
-	    }
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.CertificateViewer', {
-    extend: 'Proxmox.window.Edit',
-
-    title: gettext('Certificate'),
-
-    fieldDefaults: {
-	labelWidth: 120
-    },
-    width: 800,
-    resizable: true,
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Name'),
-	    name: 'filename'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Fingerprint'),
-	    name: 'fingerprint'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Issuer'),
-	    name: 'issuer'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject'),
-	    name: 'subject'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Public Key Type'),
-	    name: 'public-key-type'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Public Key Size'),
-	    name: 'public-key-bits'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Valid Since'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notbefore'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Expires'),
-	    renderer: Proxmox.Utils.render_timestamp,
-	    name: 'notafter'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Subject Alternative Names'),
-	    name: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    xtype: 'textarea',
-	    editable: false,
-	    grow: true,
-	    growMax: 200,
-	    fieldLabel: gettext('Certificate'),
-	    name: 'pem'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.cert) {
-	    throw "no cert given";
-	}
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/info';
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		if (Ext.isArray(response.result.data)) {
-		    Ext.Array.each(response.result.data, function(item) {
-			if (item.filename === me.cert) {
-			    me.setValues(item);
-			    return false;
-			}
-		    });
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.CertUpload', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCertUpload',
-
-    title: gettext('Upload Custom Certificate'),
-    resizable: false,
-    isCreate: true,
-    submitText: gettext('Upload'),
-    method: 'POST',
-    width: 600,
-
-    apiCallDone: function(success, response, options) {
-	if (!success) {
-	    return;
-	}
-
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    items: [
-	{
-	    fieldLabel: gettext('Private Key (Optional)'),
-	    labelAlign: 'top',
-	    emptyText: gettext('No change'),
-	    name: 'key',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=key]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'box',
-	    autoEl: 'hr'
-	},
-	{
-	    fieldLabel: gettext('Certificate Chain'),
-	    labelAlign: 'top',
-	    allowBlank: false,
-	    name: 'certificates',
-	    xtype: 'textarea'
-	},
-	{
-	    xtype: 'filebutton',
-	    text: gettext('From File'),
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('form');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    me.down('field[name=certificates]').setValue(res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'restart',
-	    value: '1'
-	},
-	{
-	    xtype: 'hidden',
-	    name: 'force',
-	    value: '1'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/nodes/' + me.nodename + '/certificates/custom';
-
-	me.callParent();
-    }
-});
-
-Ext.define('pve-certificate', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'filename', 'fingerprint', 'issuer', 'notafter', 'notbefore', 'subject', 'san', 'public-key-bits', 'public-key-type' ],
-    idProperty: 'filename'
-});
-
-Ext.define('PVE.node.Certificates', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveCertView',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    text: gettext('Upload Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.CertUpload', {
-		    nodename: me.nodename
-		});
-		win.show();
-		win.on('destroy', me.reload, me);
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'deletebtn',
-	    text: gettext('Delete Custom Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/certificates/custom?restart=1',
-		    method: 'DELETE',
-		    success: function(response, opt) {
-			var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-			Ext.getBody().mask(txt, ['pve-static-mask']);
-			// reload after 10 seconds automatically
-			Ext.defer(function() {
-			    window.location.reload(true);
-			}, 10000);
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	},
-	'-',
-	{
-	    xtype: 'proxmoxButton',
-	    itemId: 'viewbtn',
-	    disabled: true,
-	    text: gettext('View Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-		me.view_certificate();
-	    }
-	}
-    ],
-
-    columns: [
-	{
-	    header: gettext('File'),
-	    width: 150,
-	    dataIndex: 'filename'
-	},
-	{
-	    header: gettext('Issuer'),
-	    flex: 1,
-	    dataIndex: 'issuer'
-	},
-	{
-	    header: gettext('Subject'),
-	    flex: 1,
-	    dataIndex: 'subject'
-	},
-	{
-	    header: gettext('Public Key Alogrithm'),
-	    flex: 1,
-	    dataIndex: 'public-key-type',
-	    hidden: true
-	},
-	{
-	    header: gettext('Public Key Size'),
-	    flex: 1,
-	    dataIndex: 'public-key-bits',
-	    hidden: true
-	},
-	{
-	    header: gettext('Valid Since'),
-	    width: 150,
-	    dataIndex: 'notbefore',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Expires'),
-	    width: 150,
-	    dataIndex: 'notafter',
-	    renderer: Proxmox.Utils.render_timestamp
-	},
-	{
-	    header: gettext('Subject Alternative Names'),
-	    flex: 1,
-	    dataIndex: 'san',
-	    renderer: PVE.Utils.render_san
-	},
-	{
-	    header: gettext('Fingerprint'),
-	    dataIndex: 'fingerprint',
-	    hidden: true
-	},
-	{
-	    header: gettext('PEM'),
-	    dataIndex: 'pem',
-	    hidden: true
-	}
-    ],
-
-    reload: function() {
-	var me = this;
-	me.rstore.load();
-    },
-
-    set_button_status: function() {
-	var me = this;
-	var rec = me.rstore.getById('pveproxy-ssl.pem');
-
-	me.down('#deletebtn').setDisabled(!rec);
-    },
-
-    view_certificate: function() {
-	var me = this;
-	var selection = me.getSelection();
-	if (!selection || selection.length < 1) {
-	    return;
-	}
-	var win = Ext.create('PVE.node.CertificateViewer', {
-	    cert: selection[0].data.filename,
-	    nodename : me.nodename
-	});
-	win.show();
-    },
-
-    listeners: {
-	itemdblclick: 'view_certificate'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'certs-' + me.nodename,
-	    model: 'pve-certificate',
-	    proxy: {
-		type: 'proxmox',
-		    url: '/api2/json/nodes/' + me.nodename + '/certificates/info'
-	    }
-	});
-
-	me.store = {
-	    type: 'diff',
-	    rstore: me.rstore
-	};
-
-	me.callParent();
-
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-    }
-});
-Ext.define('PVE.node.ACMEEditor', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveACMEEditor',
-
-    subject: gettext('Domains'),
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    items: [
-		{
-		    xtype: 'textarea',
-		    fieldLabel: gettext('Domains'),
-		    emptyText: "domain1.example.com\ndomain2.example.com",
-		    name: 'domains'
-		}
-	    ],
-	    onGetValues: function(values) {
-		if (!values.domains) {
-		    return {
-			'delete': 'acme'
-		    };
-		}
-		var domains = values.domains.split(/\n/).join(';');
-		return {
-		    'acme': 'domains=' + domains
-		};
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		var res = PVE.Parser.parseACME(response.result.data.acme);
-		if (res) {
-		    res.domains = res.domains.join(' ');
-		    me.setValues(res);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACMEAccountCreate', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-    title: gettext('Register Account'),
-    isCreate: true,
-    method: 'POST',
-    submitText: gettext('Register'),
-    url: '/cluster/acme/account',
-    showTaskViewer: true,
-
-    items: [
-	{
-	    xtype: 'proxmoxComboGrid',
-	    name: 'directory',
-	    allowBlank: false,
-	    valueField: 'url',
-	    displayField: 'name',
-	    fieldLabel: gettext('ACME Directory'),
-	    store: {
-		autoLoad: true,
-		fields: ['name', 'url'],
-		idProperty: ['name'],
-		proxy: {
-		    type: 'proxmox',
-		    url: '/api2/json/cluster/acme/directories'
-		},
-		sorters: {
-		    property: 'name',
-		    order: 'ASC'
-		}
-	    },
-	    listConfig: {
-		columns: [
-		    {
-			header: gettext('Name'),
-			dataIndex: 'name',
-			flex: 1
-		    },
-		    {
-			header: gettext('URL'),
-			dataIndex: 'url',
-			flex: 1
-		    }
-		]
-	    },
-	    listeners: {
-		change: function(combogrid, value) {
-		    var me = this;
-		    if (!value) {
-			return;
-		    }
-
-		    var disp = me.up('window').down('#tos_url_display');
-		    var field = me.up('window').down('#tos_url');
-		    var checkbox = me.up('window').down('#tos_checkbox');
-
-		    disp.setValue(gettext('Loading'));
-		    field.setValue(undefined);
-		    checkbox.setValue(undefined);
-
-		    Proxmox.Utils.API2Request({
-			url: '/cluster/acme/tos',
-			method: 'GET',
-			params: {
-			    directory: value
-			},
-			success: function(response, opt) {
-			    me.up('window').down('#tos_url').setValue(response.result.data);
-			    me.up('window').down('#tos_url_display').setValue(response.result.data);
-			},
-			failure: function(response, opt) {
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-		}
-	    }
-	},
-	{
-	    xtype: 'displayfield',
-	    itemId: 'tos_url_display',
-	    fieldLabel: gettext('Terms of Service'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos_url_display'
-	},
-	{
-	    xtype: 'hidden',
-	    itemId: 'tos_url',
-	    name: 'tos_url'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    itemId: 'tos_checkbox',
-	    fieldLabel: gettext('Accept TOS'),
-	    submitValue: false,
-	    validateValue: function(value) {
-		if (value && this.checked) {
-		    return true;
-		}
-		return false;
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'contact',
-	    vtype: 'email',
-	    allowBlank: false,
-	    fieldLabel: gettext('E-Mail')
-	}
-    ]
-
-});
-
-Ext.define('PVE.node.ACMEAccountView', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 600,
-    fieldDefaults: {
-	labelWidth: 140
-    },
-
-    title: gettext('Account'),
-
-    items: [
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('E-Mail'),
-	    name: 'email'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Created'),
-	    name: 'createdAt'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Status'),
-	    name: 'status'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Directory'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'directory'
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Terms of Services'),
-	    renderer: PVE.Utils.render_optional_url,
-	    name: 'tos'
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.accountname) {
-	    throw "no account name defined";
-	}
-
-	me.url = '/cluster/acme/account/' + me.accountname;
-
-	me.callParent();
-
-	// hide OK/Reset button, because we just want to show data
-	me.down('toolbar[dock=bottom]').setVisible(false);
-
-	me.load({
-	    success: function(response) {
-		var data = response.result.data;
-		data.email = data.account.contact[0];
-		data.createdAt = data.account.createdAt;
-		data.status = data.account.status;
-		me.setValues(data);
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.node.ACME', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    xtype: 'pveACMEView',
-
-    margin: '10 0 0 0',
-    title: 'ACME',
-
-    tbar: [
-	{
-	    xtype: 'button',
-	    itemId: 'edit',
-	    text: gettext('Edit Domains'),
-	    handler: function() {
-		this.up('grid').run_editor();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'createaccount',
-	    text: gettext('Register Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountCreate', {
-		    taskDone: function() {
-			me.load_account();
-			me.reload();
-		    }
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'viewaccount',
-	    text: gettext('View Account'),
-	    handler: function() {
-		var me = this.up('grid');
-		var win = Ext.create('PVE.node.ACMEAccountView', {
-		    accountname: 'default'
-		});
-		win.show();
-	    }
-	},
-	{
-	    xtype: 'button',
-	    itemId: 'order',
-	    text: gettext('Order Certificate'),
-	    handler: function() {
-		var me = this.up('grid');
-
-		Proxmox.Utils.API2Request({
-		    method: 'POST',
-		    params: {
-			force: 1
-		    },
-		    url: '/nodes/' + me.nodename + '/certificates/acme/certificate',
-		    success: function(response, opt) {
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: response.result.data,
-			    taskDone: function(success) {
-				me.certificate_order_finished(success);
-			    }
-			});
-			win.show();
-		    },
-		    failure: function(response, opt) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ],
-
-    certificate_order_finished: function(success) {
-	if (!success) {
-	    return;
-	}
-	var txt = gettext('pveproxy will be restarted with new certificates, please reload the GUI!');
-	Ext.getBody().mask(txt, ['pve-static-mask']);
-	// reload after 10 seconds automatically
-	Ext.defer(function() {
-	    window.location.reload(true);
-	}, 10000);
-    },
-
-    set_button_status: function() {
-	var me = this;
-
-	var account = !!me.account;
-	var acmeObj = PVE.Parser.parseACME(me.getObjectValue('acme'));
-	var domains = acmeObj ? acmeObj.domains.length : 0;
-
-	var order = me.down('#order');
-	order.setVisible(account);
-	order.setDisabled(!account || !domains);
-
-	me.down('#createaccount').setVisible(!account);
-	me.down('#viewaccount').setVisible(account);
-    },
-
-    load_account: function() {
-	var me = this;
-
-	// for now we only use the 'default' account
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/acme/account/default',
-	    success: function(response, opt) {
-		me.account = response.result.data;
-		me.set_button_status();
-	    },
-	    failure: function(response, opt) {
-		me.account = undefined;
-		me.set_button_status();
-	    }
-	});
-    },
-
-    run_editor: function() {
-	var me = this;
-	var win = Ext.create(me.rows.acme.editor, me.editorConfig);
-	win.show();
-	win.on('destroy', me.reload, me);
-    },
-
-    listeners: {
-	itemdblclick: 'run_editor'
-    },
-
-    // account data gets loaded here
-    account: undefined,
-
-    disableSelection: true,
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no nodename given";
-	}
-
-	me.url = '/api2/json/nodes/' + me.nodename + '/config';
-
-	me.editorConfig = {
-	    url: '/api2/extjs/nodes/' + me.nodename + '/config'
-	};
-	/*jslint confusion: true*/
-	/*acme is a string above*/
-	me.rows = {
-	    acme: {
-		defaultValue: '',
-		header: gettext('Domains'),
-		editor: 'PVE.node.ACMEEditor',
-		renderer: function(value) {
-		    var acmeObj = PVE.Parser.parseACME(value);
-		    if (acmeObj) {
-			return acmeObj.domains.join('<br>');
-		    }
-		    return Proxmox.Utils.noneText;
-		}
-	    }
-	};
-	/*jslint confusion: false*/
-
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-	me.rstore.startUpdate();
-	me.load_account();
-    }
-});
-Ext.define('PVE.node.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.node.Config',
-
-    onlineHelp: 'chapter_system_administration',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/status",
-	    interval: 1000
-	});
-
-	var node_command = function(cmd) {
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/status',
-		method: 'POST',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	};
-
-	var actionBtn = Ext.create('Ext.Button', {
-	    text: gettext('Bulk Actions'),
-	    iconCls: 'fa fa-fw fa-ellipsis-v',
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    menu: new Ext.menu.Menu({
-		items: [
-		    {
-			text: gettext('Bulk Start'),
-			iconCls: 'fa fa-fw fa-play',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Start'),
-				btnText: gettext('Start'),
-				action: 'startall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Stop'),
-			iconCls: 'fa fa-fw fa-stop',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Stop'),
-				btnText: gettext('Stop'),
-				action: 'stopall'
-			    });
-			    win.show();
-			}
-		    },
-		    {
-			text: gettext('Bulk Migrate'),
-			iconCls: 'fa fa-fw fa-send-o',
-			handler: function() {
-			    var win = Ext.create('PVE.window.BulkAction', {
-				nodename: nodename,
-				title: gettext('Bulk Migrate'),
-				btnText: gettext('Migrate'),
-				action: 'migrateall'
-			    });
-			    win.show();
-			}
-		    }
-		]
-	    })
-	});
-
-	var restartBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Reboot'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Reboot node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('reboot');
-	    },
-	    iconCls: 'fa fa-undo'
-	});
-
-	var shutdownBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.nodes['Sys.PowerMgmt'],
-	    dangerous: true,
-	    confirmMsg: Ext.String.format(gettext("Shutdown node '{0}'?"), nodename),
-	    handler: function() {
-		node_command('shutdown');
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var shellBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.nodes['Sys.Console'],
-	    text: gettext('Shell'),
-	    consoleType: 'shell',
-	    nodename: nodename
-	});
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext('Node') + " '" + nodename + "'",
-	    hstateid: 'nodetab',
-	    defaults: { statusStore: me.statusStore },
-	    tbar: [ restartBtn, shutdownBtn, shellBtn, actionBtn]
-	});
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary',
-		    xtype: 'pveNodeSummary'
-		},
-		{
-		    title: gettext('Notes'),
-		    iconCls: 'fa fa-sticky-note-o',
-		    itemId: 'notes',
-		    xtype: 'pveNotesView'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Console']) {
-	    me.items.push(
-		{
-		    title: gettext('Shell'),
-		    iconCls: 'fa fa-terminal',
-		    itemId: 'jsconsole',
-		    xtype: 'pveNoVncConsole',
-		    consoleType: 'shell',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('System'),
-		    iconCls: 'fa fa-cogs',
-		    itemId: 'services',
-		    expandedOnInit: true,
-		    startOnlyServices: {
-			'pveproxy': true,
-			'pvedaemon': true,
-			'pve-cluster': true
-		    },
-		    nodename: nodename,
-		    onlineHelp: 'pve_service_daemons',
-		    xtype: 'proxmoxNodeServiceView'
-		},
-		{
-		    title: gettext('Network'),
-		    iconCls: 'fa fa-exchange',
-		    itemId: 'network',
-		    showApplyBtn: true,
-		    groups: ['services'],
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeNetworkView'
-		},
-		{
-		    title: gettext('Certificates'),
-		    iconCls: 'fa fa-certificate',
-		    itemId: 'certificates',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'pveCertificatesView'
-		},
-		{
-		    title: gettext('DNS'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'dns',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeDNSView'
-		},
-		{
-		    title: gettext('Hosts'),
-		    iconCls: 'fa fa-globe',
-		    groups: ['services'],
-		    itemId: 'hosts',
-		    nodename: nodename,
-		    onlineHelp: 'sysadmin_network_configuration',
-		    xtype: 'proxmoxNodeHostsView'
-		},
-		{
-		    title: gettext('Time'),
-		    itemId: 'time',
-		    groups: ['services'],
-		    nodename: nodename,
-		    xtype: 'proxmoxNodeTimeView',
-		    iconCls: 'fa fa-clock-o'
-		});
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push({
-		title: 'Syslog',
-		iconCls: 'fa fa-list',
-		groups: ['services'],
-		disabled: !caps.nodes['Sys.Syslog'],
-		itemId: 'syslog',
-		xtype: 'proxmoxJournalView',
-		url: "/api2/extjs/nodes/" + nodename + "/journal"
-	    });
-
-	    if (caps.nodes['Sys.Modify']) {
-		me.items.push({
-		    title: gettext('Updates'),
-		    iconCls: 'fa fa-refresh',
-		    disabled: !caps.nodes['Sys.Console'],
-		    // do we want to link to system updates instead?
-		    itemId: 'apt',
-		    xtype: 'proxmoxNodeAPT',
-		    upgradeBtn: {
-			xtype: 'pveConsoleButton',
-			disabled: Proxmox.UserName !== 'root@pam',
-			text: gettext('Upgrade'),
-			consoleType: 'upgrade',
-			nodename: nodename
-		    },
-		    nodename: nodename
-		});
-	    }
-	}
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    iconCls: 'fa fa-shield',
-		    title: gettext('Firewall'),
-		    allow_iface: true,
-		    base_url: '/nodes/' + nodename + '/firewall/rules',
-		    list_refs_url: '/cluster/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    title: gettext('Options'),
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_host_specific_configuration',
-		    groups: ['firewall'],
-		    base_url: '/nodes/' + nodename + '/firewall/options',
-		    fwtype: 'node',
-		    itemId: 'firewall-options'
-		});
-	}
-
-
-	if (caps.nodes['Sys.Audit']) {
-	    me.items.push(
-		{
-		    title: gettext('Disks'),
-		    itemId: 'storage',
-		    expandedOnInit: true,
-		    iconCls: 'fa fa-hdd-o',
-		    xtype: 'pveNodeDiskList'
-		},
-		{
-		    title: 'LVM',
-		    itemId: 'lvm',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square',
-		    groups: ['storage'],
-		    xtype: 'pveLVMList'
-		},
-		{
-		    title: 'LVM-Thin',
-		    itemId: 'lvmthin',
-		    onlineHelp: 'chapter_lvm',
-		    iconCls: 'fa fa-square-o',
-		    groups: ['storage'],
-		    xtype: 'pveLVMThinList'
-		},
-		{
-		    title: Proxmox.Utils.directoryText,
-		    itemId: 'directory',
-		    onlineHelp: 'chapter_storage',
-		    iconCls: 'fa fa-folder',
-		    groups: ['storage'],
-		    xtype: 'pveDirectoryList'
-		},
-		{
-		    title: 'ZFS',
-		    itemId: 'zfs',
-		    onlineHelp: 'chapter_zfs',
-		    iconCls: 'fa fa-th-large',
-		    groups: ['storage'],
-		    xtype: 'pveZFSList'
-		},
-		{
-		    title: 'Ceph',
-		    itemId: 'ceph',
-		    iconCls: 'fa fa-ceph',
-		    xtype: 'pveNodeCephStatus'
-		},
-		{
-		    xtype: 'pveReplicaView',
-		    iconCls: 'fa fa-retweet',
-		    title: gettext('Replication'),
-		    itemId: 'replication'
-		},
-		{
-		    xtype: 'pveNodeCephConfigCrush',
-		    title: gettext('Configuration'),
-		    iconCls: 'fa fa-gear',
-		    groups: ['ceph'],
-		    itemId: 'ceph-config'
-		},
-		{
-		    xtype: 'pveNodeCephMonMgr',
-		    title: gettext('Monitor'),
-		    iconCls: 'fa fa-tv',
-		    groups: ['ceph'],
-		    itemId: 'ceph-monlist'
-		},
-		{
-		    xtype: 'pveNodeCephOsdTree',
-		    title: 'OSD',
-		    iconCls: 'fa fa-hdd-o',
-		    groups: ['ceph'],
-		    itemId: 'ceph-osdtree'
-		},
-		{
-		    xtype: 'pveNodeCephFSPanel',
-		    title: 'CephFS',
-		    iconCls: 'fa fa-folder',
-		    groups: ['ceph'],
-		    nodename: nodename,
-		    itemId: 'ceph-cephfspanel'
-		},
-		{
-		    xtype: 'pveNodeCephPoolList',
-		    title: 'Pools',
-		    iconCls: 'fa fa-sitemap',
-		    groups: ['ceph'],
-		    itemId: 'ceph-pools'
-		}
-	    );
-	}
-
-	if (caps.nodes['Sys.Syslog']) {
-	    me.items.push(
-		{
-		    xtype: 'proxmoxLogView',
-		    title: gettext('Log'),
-		    iconCls: 'fa fa-list',
-		    groups: ['firewall'],
-		    onlineHelp: 'chapter_pve_firewall',
-		    url: '/api2/extjs/nodes/' + nodename + '/firewall/log',
-		    itemId: 'firewall-fwlog'
-		},
-		{
-		    title: gettext('Log'),
-		    itemId: 'ceph-log',
-		    iconCls: 'fa fa-list',
-		    groups: ['ceph'],
-		    onlineHelp: 'chapter_pveceph',
-		    xtype: 'cephLogView',
-		    url: "/api2/extjs/nodes/" + nodename + "/ceph/log",
-		    nodename: nodename
-		});
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Task History'),
-		iconCls: 'fa fa-list',
-		itemId: 'tasks',
-		nodename: nodename,
-		xtype: 'proxmoxNodeTasks'
-	    },
-	    {
-		title: gettext('Subscription'),
-		iconCls: 'fa fa-support',
-		itemId: 'support',
-		xtype: 'pveNodeSubscription',
-		nodename: nodename
-	    }
-	);
-
-	me.callParent();
-
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var uptimerec = s.data.get('uptime');
-	    var powermgmt = uptimerec ? uptimerec.data.value : false;
-	    if (!caps.nodes['Sys.PowerMgmt']) {
-		powermgmt = false;
-	    }
-	    restartBtn.setDisabled(!powermgmt);
-	    shutdownBtn.setDisabled(!powermgmt);
-	    shellBtn.setDisabled(!powermgmt);
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.window.Migrate', {
-    extend: 'Ext.window.Window',
-
-    vmtype: undefined,
-    nodename: undefined,
-    vmid: undefined,
-
-    viewModel: {
-	data: {
-	    vmid: undefined,
-	    nodename: undefined,
-	    vmtype: undefined,
-	    running: false,
-	    qemu: {
-		onlineHelp: 'qm_migration',
-		commonName: 'VM'
-	    },
-	    lxc: {
-		onlineHelp: 'pct_migration',
-		commonName: 'CT'
-	    },
-	    migration: {
-		possible: true,
-		preconditions: [],
-		'with-local-disks': 0,
-		mode: undefined,
-		allowedNodes: undefined,
-		overwriteLocalResourceCheck: false,
-		hasLocalResources: false
-	    }
-
-	},
-
-	formulas: {
-	    setMigrationMode: function(get) {
-		if (get('running')){
-		    if (get('vmtype') === 'qemu') {
-			return gettext('Online');
-		    } else {
-			return gettext('Restart Mode');
-		    }
-		} else {
-		    return gettext('Offline');
-		}
-	    },
-	    setStorageselectorHidden: function(get) {
-		    if (get('migration.with-local-disks') && get('running')) {
-			return false;
-		    } else {
-			return true;
-		    }
-	    },
-	    setLocalResourceCheckboxHidden: function(get) {
-		if (get('running') || !get('migration.hasLocalResources') ||
-		    Proxmox.UserName !== 'root@pam') {
-		    return true;
-		} else {
-		    return false;
-		}
-	    }
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=formPanel]': {
-		validityChange: function(panel, isValid) {
-		    this.getViewModel().set('migration.possible', isValid);
-		    this.checkMigratePreconditions();
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this,
-		vm = view.getViewModel();
-
-	    if (!view.nodename) {
-		throw "missing custom view config: nodename";
-	    }
-	    vm.set('nodename', view.nodename);
-
-	    if (!view.vmid) {
-		throw "missing custom view config: vmid";
-	    }
-	    vm.set('vmid', view.vmid);
-
-	    if (!view.vmtype) {
-		throw "missing custom view config: vmtype";
-	    }
-	    vm.set('vmtype', view.vmtype);
-
-
-	    view.setTitle(
-		Ext.String.format('{0} {1} {2}', gettext('Migrate'), vm.get(view.vmtype).commonName, view.vmid)
-	    );
-	    me.lookup('proxmoxHelpButton').setHelpConfig({
-		onlineHelp: vm.get(view.vmtype).onlineHelp
-	    });
-	    me.checkMigratePreconditions();
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	onTargetChange: function (nodeSelector) {
-	    //Always display the storages of the currently seleceted migration target
-	    this.lookup('pveDiskStorageSelector').setNodename(nodeSelector.value);
-	    this.checkMigratePreconditions();
-	},
-
-	startMigration: function() {
-	    var me = this,
-		view = me.getView(),
-		vm = me.getViewModel();
-
-	    var values = me.lookup('formPanel').getValues();
-	    var params = {
-		target: values.target
-	    };
-
-	    if (vm.get('migration.mode')) {
-		params[vm.get('migration.mode')] = 1;
-	    }
-	    if (vm.get('migration.with-local-disks')) {
-		params['with-local-disks'] = 1;
-	    }
-	    //only submit targetstorage if vm is running, storage migration to different storage is only possible online
-	    if (vm.get('migration.with-local-disks') && vm.get('running')) {
-		params.targetstorage = values.targetstorage;
-	    }
-
-	    if (vm.get('migration.overwriteLocalResourceCheck')) {
-		params['force'] = 1;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		waitMsgTarget: view,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    var upid = response.result.data;
-		    var extraTitle = Ext.String.format(' ({0} ---> {1})', vm.get('nodename'), params.target);
-
-		    Ext.create('Proxmox.window.TaskViewer', {
-			upid: upid,
-			extraTitle: extraTitle
-		    }).show();
-
-		    view.close();
-		}
-	    });
-
-	},
-
-	checkMigratePreconditions: function(resetMigrationPossible) {
-	    var me = this,
-		vm = me.getViewModel();
-
-	    var vmrec = PVE.data.ResourceStore.findRecord('vmid', vm.get('vmid'),
-			0, false, false, true);
-	    if (vmrec && vmrec.data && vmrec.data.running) {
-		vm.set('running', true);
-	    }
-
-	    if (vm.get('vmtype') === 'qemu') {
-		me.checkQemuPreconditions(resetMigrationPossible);
-	    } else {
-		me.checkLxcPreconditions(resetMigrationPossible);
-	    }
-	    me.lookup('pveNodeSelector').disallowedNodes = [vm.get('nodename')];
-
-	    // Only allow nodes where the local storage is available in case of offline migration
-	    // where storage migration is not possible
-	    me.lookup('pveNodeSelector').allowedNodes = vm.get('migration.allowedNodes');
-
-	    me.lookup('formPanel').isValid();
-
-	},
-
-	checkQemuPreconditions: function(resetMigrationPossible) {
-	    var me = this,
-		vm = me.getViewModel(),
-		migrateStats;
-
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'online');
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + vm.get('nodename') + '/' + vm.get('vmtype') + '/' + vm.get('vmid') + '/migrate',
-		method: 'GET',
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		},
-		success: function(response, options) {
-		    migrateStats = response.result.data;
-		    if (migrateStats.running) {
-			vm.set('running', true);
-		    }
-		    // Get migration object from viewmodel to prevent
-		    // to many bind callbacks
-		    var migration = vm.get('migration');
-		    if (resetMigrationPossible) migration.possible = true;
-		    migration.preconditions = [];
-
-		    if (migrateStats.allowed_nodes) {
-			migration.allowedNodes = migrateStats.allowed_nodes;
-			var target = me.lookup('pveNodeSelector').value;
-			if (target.length && !migrateStats.allowed_nodes.includes(target)) {
-			    let disallowed = migrateStats.not_allowed_nodes[target];
-			    let missing_storages = disallowed.unavailable_storages.join(', ');
-
-			    migration.possible = false;
-			    migration.preconditions.push({
-				text: 'Storage (' + missing_storages + ') not available on selected target. ' +
-				  'Start VM to use live storage migration or select other target node',
-				severity: 'error'
-			    });
-			}
-		    }
-
-		    if (migrateStats.local_resources.length) {
-			migration.hasLocalResources = true;
-			if(!migration.overwriteLocalResourceCheck || vm.get('running')){
-			    migration.possible = false;
-			    migration.preconditions.push({
-				text: Ext.String.format('Can\'t migrate VM with local resources: {0}',
-				migrateStats.local_resources.join(', ')),
-				severity: 'error'
-			    });
-			} else {
-			    migration.preconditions.push({
-				text: Ext.String.format('Migrate VM with local resources: {0}. ' +
-				'This might fail if resources aren\'t available on the target node.',
-				migrateStats.local_resources.join(', ')),
-				severity: 'warning'
-			    });
-			}
-		    }
-
-		    if (migrateStats.local_disks.length) {
-
-			migrateStats.local_disks.forEach(function (disk) {
-			    if (disk.cdrom && disk.cdrom === 1) {
-				if (disk.volid.includes('vm-'+vm.get('vmid')+'-cloudinit')) {
-				    if (migrateStats.running) {
-					migration.possible = false;
-					migration.preconditions.push({
-					     text: "Can't live migrate VM with local cloudinit disk, use shared storage instead",
-					     severity: 'error'
-					});
-				    } else {
-					return;
-				    }
-				} else {
-				    migration.possible = false;
-				    migration.preconditions.push({
-					text: "Can't migrate VM with local CD/DVD",
-					severity: 'error'
-				    });
-				}
-
-			    } else if (!disk.referenced_in_config) {
-				migration.possible = false;
-				migration.preconditions.push({
-				    text: 'Found not referenced/unused disk via storage: '+ disk.volid,
-				    severity: 'error'
-				});
-			    } else {
-				migration['with-local-disks'] = 1;
-				migration.preconditions.push({
-				    text:'Migration with local disk might take long: ' + disk.volid
-					+' (' + PVE.Utils.render_size(disk.size) + ')',
-				    severity: 'warning'
-				});
-			    }
-			});
-
-		    }
-
-		    vm.set('migration', migration);
-
-		}
-	    });
-	},
-	checkLxcPreconditions: function(resetMigrationPossible) {
-	    var me = this,
-		vm = me.getViewModel();
-	    if (vm.get('running')) {
-		vm.set('migration.mode', 'restart');
-	    }
-	}
-
-
-    },
-
-    width: 600,
-    modal: true,
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-    border: false,
-    items: [
-	{
-	    xtype: 'form',
-	    reference: 'formPanel',
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'column'
-	    },
-	    items: [
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'displayfield',
-			name: 'source',
-			fieldLabel: gettext('Source node'),
-			bind: {
-			    value: '{nodename}'
-			}
-		    },
-		    {
-			xtype: 'displayfield',
-			reference: 'migrationMode',
-			fieldLabel: gettext('Mode'),
-			bind: {
-			    value: '{setMigrationMode}'
-			}
-		    }]
-		},
-		{
-		    xtype: 'container',
-		    columnWidth: 0.5,
-		    items: [{
-			xtype: 'pveNodeSelector',
-			reference: 'pveNodeSelector',
-			name: 'target',
-			fieldLabel: gettext('Target node'),
-			allowBlank: false,
-			disallowedNodes: undefined,
-			onlineValidator: true,
-			listeners: {
-			    change: 'onTargetChange'
-			}
-		    },
-		    {
-			    xtype: 'pveStorageSelector',
-			    reference: 'pveDiskStorageSelector',
-			    name: 'targetstorage',
-			    fieldLabel: gettext('Target storage'),
-			    storageContent: 'images',
-			    bind: {
-				hidden: '{setStorageselectorHidden}'
-			    }
-		    },
-		    {
-			xtype: 'proxmoxcheckbox',
-			name: 'overwriteLocalResourceCheck',
-			fieldLabel: gettext('Force'),
-			autoEl: {
-			    tag: 'div',
-			    'data-qtip': 'Overwrite local resources unavailable check'
-			},
-			bind: {
-			    hidden: '{setLocalResourceCheckboxHidden}',
-			    value: '{migration.overwriteLocalResourceCheck}'
-			},
-			listeners: {
-			    change: {fn: 'checkMigratePreconditions', extraArg: true}
-			}
-		}]
-		}
-	    ]
-	},
-	{
-	    xtype: 'gridpanel',
-	    reference: 'preconditionGrid',
-	    selectable: false,
-	    flex: 1,
-	    columns: [{
-		text: '',
-		dataIndex: 'severity',
-		renderer: function(v) {
-		    switch (v) {
-			case 'warning':
-			    return '<i class="fa fa-exclamation-triangle warning"></i> ';
-			case 'error':
-			    return '<i class="fa fa-times critical"></i>';
-			default:
-			    return v;
-		    }
-		},
-		width: 35
-	    },
-	    {
-		text: 'Info',
-		dataIndex: 'text',
-		cellWrap: true,
-		flex: 1
-	    }],
-	    bind: {
-		hidden: '{!migration.preconditions.length}',
-		store: {
-		    fields: ['severity','text'],
-		    data: '{migration.preconditions}'
-		}
-	    }
-	}
-
-    ],
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton',
-	    reference: 'proxmoxHelpButton',
-	    onlineHelp: 'pct_migration',
-	    listenToGlobalEvent: false,
-	    hidden: false
-	},
-	'->',
-	{
-	    xtype: 'button',
-	    reference: 'submitButton',
-	    text: gettext('Migrate'),
-	    handler: 'startMigration',
-	    bind: {
-		disabled: '{!migration.possible}'
-	    }
-	}
-    ]
-});
-Ext.define('PVE.window.BulkAction', {
-    extend: 'Ext.window.Window',
-
-    resizable: true,
-    width: 800,
-    modal: true,
-    layout: {
-	type: 'fit'
-    },
-    border: false,
-
-    // the action to be set
-    // currently there are
-    // startall
-    // migrateall
-    // stopall
-    action: undefined,
-
-    submit: function(params) {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.action,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		me.hide();
-		win.on('destroy', function() {
-		    me.close();
-		});
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-	if (!me.action) {
-	    throw "no action specified";
-	}
-	if (!me.btnText) {
-	    throw "no button text specified";
-	}
-	if (!me.title) {
-	    throw "no title specified";
-	}
-
-	var items = [];
-
-	if (me.action === 'migrateall') {
-	    /*jslint confusion: true*/
-	    /*value is string and number*/
-	    items.push(
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'target',
-		    disallowedNodes: [me.nodename],
-		    fieldLabel: gettext('Target node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'proxmoxintegerfield',
-		    name: 'maxworkers',
-		    minValue: 1,
-		    maxValue: 100,
-		    value: 1,
-		    fieldLabel: gettext('Parallel jobs'),
-		    allowBlank: false
-		},
-		{
-		    xtype: 'fieldcontainer',
-		    fieldLabel: gettext('Allow local disk migration'),
-		    layout: 'hbox',
-		    items: [{
-			xtype: 'proxmoxcheckbox',
-			name: 'with-local-disks',
-			checked: true,
-			uncheckedValue: 0,
-			listeners: {
-			    change: (cb, val) => me.down('#localdiskwarning').setVisible(val),
-			}
-
-		    },
-		    {
-			itemId: 'localdiskwarning',
-			xtype: 'displayfield',
-			flex: 1,
-			padding: '0 0 0 10',
-			userCls: 'pmx-hint',
-			value: 'Note: Migration with local disks might take long.',
-		    }],
-		},
-		{
-		    itemId: 'lxcwarning',
-		    xtype: 'displayfield',
-		    userCls: 'pmx-hint',
-		    value: 'Warning: Running CTs will be migrated in Restart Mode.',
-		    hidden: true // only visible if running container chosen
-		}
-	    );
-	    /*jslint confusion: false*/
-	} else if (me.action === 'startall') {
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'force',
-		value: 1
-	    });
-	}
-
-	items.push({
-	    xtype: 'vmselector',
-	    itemId: 'vms',
-	    name: 'vms',
-	    flex: 1,
-	    height: 300,
-	    selectAll: true,
-	    allowBlank: false,
-	    nodename: me.nodename,
-	    action: me.action,
-	    listeners: {
-		selectionchange: function(vmselector, records) {
-		    if (me.action == 'migrateall') {
-			var showWarning = records.some(function(item) {
-			    return (item.data.type == 'lxc' &&
-				item.data.status == 'running');
-			});
-			me.down('#lxcwarning').setVisible(showWarning);
-		    }
-		}
-	    }
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    layout: {
-		type: 'vbox',
-		align: 'stretch'
-	    },
-	    fieldDefaults: {
-		labelWidth: 300,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: me.btnText,
-	    handler: function() {
-		form.isValid();
-		me.submit(form.getValues());
-	    }
-	});
-
-	Ext.apply(me, {
-	    items: [ me.formPanel ],
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-
-	form.on('validitychange', function() {
-	    var valid = form.isValid();
-	    submitBtn.setDisabled(!valid);
-	});
-	form.isValid();
-    }
-});
-Ext.define('PVE.window.Clone', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    isTemplate: false,
-
-    onlineHelp: 'qm_copy_and_clone',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'panel[reference=cloneform]': {
-		validitychange: 'disableSubmit'
-	    }
-	},
-	disableSubmit: function(form) {
-	    this.lookupReference('submitBtn').setDisabled(!form.isValid());
-	}
-    },
-
-    statics: {
-	// display a snapshot selector only if needed
-	wrap: function(nodename, vmid, isTemplate, guestType) {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/' + nodename + '/' + guestType + '/' + vmid +'/snapshot',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var snapshotList = response.result.data;
-		    var hasSnapshots = snapshotList.length === 1 &&
-			snapshotList[0].name === 'current' ? false : true;
-
-		    Ext.create('PVE.window.Clone', {
-			nodename: nodename,
-			guestType: guestType,
-			vmid: vmid,
-			isTemplate: isTemplate,
-			hasSnapshots: hasSnapshots
-		    }).show();
-		}
-	    });
-	}
-    },
-
-    create_clone: function(values) {
-	var me = this;
-
-	var params = { newid: values.newvmid };
-
-	if (values.snapname && values.snapname !== 'current') {
-	    params.snapname = values.snapname;
-	}
-
-	if (values.pool) {
-	    params.pool = values.pool;
-	}
-
-	if (values.name) {
-	    if (me.guestType === 'lxc') {
-		params.hostname = values.name;
-	    } else {
-		params.name = values.name;
-	    }
-	}
-
-	if (values.target) {
-	    params.target = values.target;
-	}
-
-	if (values.clonemode === 'copy') {
-	    params.full = 1;
-	    if (values.hdstorage) {
-		params.storage = values.hdstorage;
-		if (values.diskformat && me.guestType !== 'lxc') {
-		    params.format = values.diskformat;
-		}
-	    }
-	}
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/clone',
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-
-    },
-
-    // disable the Storage selector when clone mode is linked clone
-    updateVisibility: function() {
-	var me = this;
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-	var disksel = me.lookup('diskselector');
-	disksel.setDisabled(clonemode === 'clone');
-    },
-
-    // add to the list of valid nodes each node where
-    // all the VM disks are available
-    verifyFeature: function() {
-	var me = this;
-
-	var snapname = me.lookupReference('snapshotsel').getValue();
-	var clonemode = me.lookupReference('clonemodesel').getValue();
-
-	var params = { feature: clonemode };
-	if (snapname !== 'current') {
-	    params.snapname = snapname;
-	}
-
-	Proxmox.Utils.API2Request({
-	    waitMsgTarget: me,
-	    url: '/nodes/' + me.nodename + '/' + me.guestType + '/' + me.vmid + '/feature',
-	    params: params,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		me.lookupReference('submitBtn').setDisabled(true);
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var res = response.result.data;
-
-		me.lookupReference('targetsel').allowedNodes = res.nodes;
-		me.lookupReference('targetsel').validate();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.snapname) {
-	    me.snapname = 'current';
-	}
-
-	if (!me.guestType) {
-	    throw "no Guest Type specified";
-	}
-
-	var titletext = me.guestType === 'lxc' ? 'CT' : 'VM';
-	if (me.isTemplate) {
-	    titletext += ' Template';
-	}
-	me.title = "Clone " + titletext + " " + me.vmid;
-
-	var col1 = [];
-	var col2 = [];
-
-	col1.push({
-	    xtype: 'pveNodeSelector',
-	    name: 'target',
-	    reference: 'targetsel',
-	    fieldLabel: gettext('Target node'),
-	    selectCurNode: true,
-	    allowBlank: false,
-	    onlineValidator: true,
-	    listeners: {
-		change: function(f, value) {
-		    me.lookupReference('hdstorage').setTargetNode(value);
-		}
-	    }
-	});
-
-	var modelist = [['copy', gettext('Full Clone')]];
-	if (me.isTemplate) {
-	    modelist.push(['clone', gettext('Linked Clone')]);
-	}
-
-	col1.push({
-	    xtype: 'pveGuestIDSelector',
-	    name: 'newvmid',
-	    guestType: me.guestType,
-	    value: '',
-	    loadNextFreeID: true,
-	    validateExists: false
-	},
-	{
-	    xtype: 'textfield',
-	    name: 'name',
-	    allowBlank: true,
-	    fieldLabel: me.guestType === 'lxc' ? gettext('Hostname') : gettext('Name')
-	},
-	{
-	    xtype: 'pvePoolSelector',
-	    fieldLabel: gettext('Resource Pool'),
-	    name: 'pool',
-	    value: '',
-	    allowBlank: true
-	}
-	);
-
-	col2.push({
-	    xtype: 'proxmoxKVComboBox',
-	    fieldLabel: gettext('Mode'),
-	    name: 'clonemode',
-	    reference: 'clonemodesel',
-	    allowBlank: false,
-	    hidden: !me.isTemplate,
-	    value: me.isTemplate ? 'clone' : 'copy',
-		    comboItems: modelist,
-		    listeners: {
-			change: function(t, value) {
-			    me.updateVisibility();
-			    me.verifyFeature();
-			}
-		    }
-	},
-	{
-	    xtype: 'PVE.form.SnapshotSelector',
-	    name: 'snapname',
-	    reference: 'snapshotsel',
-	    fieldLabel: gettext('Snapshot'),
-	    nodename: me.nodename,
-	    guestType: me.guestType,
-	    vmid: me.vmid,
-	    hidden: me.isTemplate || !me.hasSnapshots ? true : false,
-	    disabled: false,
-	    allowBlank: false,
-	    value : me.snapname,
-	    listeners: {
-		change: function(f, value) {
-		    me.verifyFeature();
-		}
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    reference: 'diskselector',
-	    nodename: me.nodename,
-	    autoSelect: false,
-	    hideSize: true,
-	    hideSelection: true,
-	    storageLabel: gettext('Target Storage'),
-	    allowBlank: true,
-	    storageContent: me.guestType === 'qemu' ? 'images' : 'rootdir',
-	    emptyText: gettext('Same as source'),
-	    disabled: me.isTemplate ? true : false // because default mode is clone for templates
-	});
-
-	var formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    reference: 'cloneform',
-	    border: false,
-	    layout: 'column',
-	    defaultType: 'container',
-	    columns: 2,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: [
-		{
-		    columnWidth: 0.5,
-		    padding: '0 10 0 0',
-		    layout: 'anchor',
-		    items: col1
-		},
-		{
-		    columnWidth: 0.5,
-		    padding: '0 0 0 10',
-		    layout: 'anchor',
-		    items: col2
-		}
-	    ]
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 600,
-	    height: 250,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ {
-		xtype: 'proxmoxHelpButton',
-		listenToGlobalEvent: false,
-		hidden: false,
-		onlineHelp: me.onlineHelp
-	    },
-	    '->',
-	    {
-		reference: 'submitBtn',
-		text: gettext('Clone'),
-		disabled: true,
-		handler: function() {
-		    var cloneForm = me.lookupReference('cloneform');
-		    if (cloneForm.isValid()) {
-			me.create_clone(cloneForm.getValues());
-		    }
-		}
-	    } ],
-	    items: [ formPanel ]
-	});
-
-	me.callParent();
-
-	me.verifyFeature();
-    }
-});
-Ext.define('PVE.window.Snapshot', {
-    extend: 'Proxmox.window.Edit',
-
-    viewModel: {
-	data: {
-	    type: undefined,
-	    isCreate: undefined,
-	    running: false,
-	    guestAgentEnabled: false,
-	},
-	formulas: {
-	    runningWithoutGuestAgent: (get) => get('type') === 'qemu' && get('running') && !get('guestAgentEnabled'),
-	    shouldWarnAboutFS: (get) => get('isCreate') && get('runningWithoutGuestAgent') && get('!vmstate.checked'),
-	},
-    },
-
-    onGetValues: function(values) {
-	let me = this;
-
-	if (me.type === 'lxc') {
-	    delete values.vmstate;
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var vm = me.getViewModel();
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    throw "no type specified";
-	}
-
-	vm.set('type', me.type);
-	vm.set('running', me.running);
-	vm.set('isCreate', me.isCreate);
-
-	if (me.type === 'qemu' && me.isCreate) {
-	    Proxmox.Utils.API2Request({
-		url: `/nodes/${me.nodename}/${me.type}/${me.vmid}/config`,
-		params: { 'current': '1' },
-		method: 'GET',
-		success: function(response, options) {
-		    let res = response.result.data;
-		    let enabled = PVE.Parser.parsePropertyString(res.agent, 'enabled');
-		    vm.set('guestAgentEnabled', !!PVE.Parser.parseBoolean(enabled.enabled));
-		}
-	    });
-	}
-
-	me.items = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'snapname',
-		value: me.snapname,
-		fieldLabel: gettext('Name'),
-		vtype: 'ConfigId',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		hidden: me.isCreate,
-		disabled: me.isCreate,
-		name: 'snaptime',
-		renderer: PVE.Utils.render_timestamp_human_readable,
-		fieldLabel: gettext('Timestamp')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		hidden: me.type !== 'qemu' || !me.isCreate || !me.running,
-		disabled: me.type !== 'qemu' || !me.isCreate || !me.running,
-		name: 'vmstate',
-		reference: 'vmstate',
-		uncheckedValue: 0,
-		defaultValue: 0,
-		checked: 1,
-		fieldLabel: gettext('Include RAM')
-	    },
-	    {
-		xtype: 'textareafield',
-		grow: true,
-		editable: !me.viewonly,
-		name: 'description',
-		fieldLabel: gettext('Description')
-	    },
-	    {
-		xtype: 'displayfield',
-		userCls: 'pmx-hint',
-		name: 'fswarning',
-		hidden: true,
-		value: gettext('It is recommended to either include the RAM or use the QEMU Guest Agent when taking a snapshot of a running VM to avoid inconsistencies.'),
-		bind: {
-		    hidden: '{!shouldWarnAboutFS}',
-		},
-	    },
-	    {
-		title: gettext('Settings'),
-		hidden: me.isCreate,
-		xtype: 'grid',
-		itemId: 'summary',
-		border: true,
-		height: 200,
-		store: {
-		    model: 'KeyValue',
-		    sorters: [
-			{
-			    property : 'key',
-			    direction: 'ASC'
-			}
-		    ]
-		},
-		columns: [
-		    {
-			header: gettext('Key'),
-			width: 150,
-			dataIndex: 'key',
-		    },
-		    {
-			header: gettext('Value'),
-			flex: 1,
-			dataIndex: 'value',
-		    }
-		]
-	    }
-	];
-
-	me.url = `/nodes/${me.nodename}/${me.type}/${me.vmid}/snapshot`;
-
-	let subject;
-	if (me.isCreate) {
-	    subject = (me.type === 'qemu' ? 'VM' : 'CT') + me.vmid + ' ' + gettext('Snapshot');
-	    me.method = 'POST';
-	    me.showProgress = true;
-	} else {
-	    subject = `${gettext('Snapshot')} ${me.snapname}`;
-	    me.url += `/${me.snapname}/config`;
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    width: me.isCreate ? 450 : 620,
-	    height: me.isCreate ? undefined : 420,
-	});
-
-	me.callParent();
-
-	if (!me.snapname) {
-	    return;
-	}
-
-	me.load({
-	    success: function(response) {
-		let kvarray = [];
-		Ext.Object.each(response.result.data, function(key, value) {
-		    if (key === 'description' || key === 'snaptime') {
-			return;
-		    }
-		    kvarray.push({ key: key, value: value });
-		});
-
-		let summarystore = me.down('#summary').getStore();
-		summarystore.suspendEvents();
-		summarystore.add(kvarray);
-		summarystore.sort();
-		summarystore.resumeEvents();
-		summarystore.fireEvent('refresh', summarystore);
-
-		me.setValues(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Monitor', {
-    extend: 'Ext.panel.Panel',
-
-    alias: 'widget.pveQemuMonitor',
-
-    maxLines: 500,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var history = [];
-	var histNum = -1;
-	var lines = [];
-
-	var textbox = Ext.createWidget('panel', {
-	    region: 'center',
-	    xtype: 'panel',
-	    autoScroll: true,
-	    border: true,
-	    margins: '5 5 5 5',
-	    bodyStyle: 'font-family: monospace;'
-	});
-
-	var scrollToEnd = function() {
-	    var el = textbox.getTargetEl();
-	    var dom = Ext.getDom(el);
-
-	    var clientHeight = dom.clientHeight;
-	    // BrowserBug: clientHeight reports 0 in IE9 StrictMode
-            // Instead we are using offsetHeight and hardcoding borders
-            if (Ext.isIE9 && Ext.isStrict) {
-		clientHeight = dom.offsetHeight + 2;
-            }
-	    dom.scrollTop = dom.scrollHeight - clientHeight;
-	};
-
-	var refresh = function() {
-	    textbox.update('<pre>' + lines.join('\n') + '</pre>');
-	    scrollToEnd();
-	};
-
-	var addLine = function(line) {
-	    lines.push(line);
-	    if (lines.length > me.maxLines) {
-		lines.shift();
-	    }
-	};
-
-	var executeCmd = function(cmd) {
-	    addLine("# " + Ext.htmlEncode(cmd));
-	    if (cmd) {
-		history.unshift(cmd);
-		if (history.length > 20) {
-		    history.splice(20);
-		}
-	    }
-	    histNum = -1;
-
-	    refresh();
-	    Proxmox.Utils.API2Request({
-		params: { command: cmd },
-		url: '/nodes/' + nodename + '/qemu/' + vmid + "/monitor",
-		method: 'POST',
-		waitMsgTarget: me,
-		success: function(response, opts) {
-		    var res = response.result.data; 
-		    Ext.Array.each(res.split('\n'), function(line) {
-			addLine(Ext.htmlEncode(line));
-		    });
-		    refresh();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		textbox,
-		{
-		    region: 'south',
-		    margins:'0 5 5 5',
-		    border: false,
-		    xtype: 'textfield',
-		    name: 'cmd',
-		    value: '',
-		    fieldStyle: 'font-family: monospace;',
-		    allowBlank: true,
-		    listeners: {
-			afterrender: function(f) {
-			    f.focus(false);
-			    addLine("Type 'help' for help.");
-			    refresh();
-			},
-			specialkey: function(f, e) {
-			    var key = e.getKey();
-			    switch (key) {
-				case e.ENTER:
-				    var cmd = f.getValue();
-				    f.setValue('');
-				    executeCmd(cmd);
-				    break;
-				case e.PAGE_UP:
-				    textbox.scrollBy(0, -0.9*textbox.getHeight(), false);
-				    break;
-				case e.PAGE_DOWN:
-				    textbox.scrollBy(0, 0.9*textbox.getHeight(), false);
-				    break;
-				case e.UP:
-				    if (histNum + 1 < history.length) {
-					f.setValue(history[++histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				case e.DOWN:
-				    if (histNum > 0) {
-					f.setValue(history[--histNum]);
-				    }
-				    e.preventDefault();
-				    break;
-				default:
-				    break;
-			    }
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		show: function() {
-		    var field = me.query('textfield[name="cmd"]')[0];
-		    field.focus(false, true);
-		}
-	    }
-	});		
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.OSTypeInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuOSTypePanel',
-    onlineHelp: 'qm_os_settings',
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'combobox[name=osbase]': {
-		change: 'onOSBaseChange'
-	    },
-	    'combobox[name=ostype]': {
-		afterrender: 'onOSTypeChange',
-		change: 'onOSTypeChange'
-	    }
-	},
-	onOSBaseChange: function(field, value) {
-	    this.lookup('ostype').getStore().setData(PVE.Utils.kvm_ostypes[value]);
-	},
-	onOSTypeChange: function(field) {
-	    var me = this, ostype = field.getValue();
-	    if (!me.getView().insideWizard) {
-		return;
-	    }
-	    var targetValues = PVE.qemu.OSDefaults.getDefaults(ostype);
-
-	    me.setWidget('pveBusSelector', targetValues.busType);
-	    me.setWidget('pveNetworkCardSelector', targetValues.networkCard);
-	    var scsihw = targetValues.scsihw || '__default__';
-	    this.getViewModel().set('current.scsihw', scsihw);
-	},
-	setWidget: function(widget, newValue) {
-	    // changing a widget is safe only if ComponentQuery.query returns us
-	    // a single value array
-	    var widgets = Ext.ComponentQuery.query('pveQemuCreateWizard ' + widget);
-	    if (widgets.length === 1) {
-		widgets[0].setValue(newValue);
-	    } else {
-		throw 'non unique widget :' + widget + ' in Wizard';
-	    }
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	/*jslint confusion: true */
-	me.items = [
-	    {
-		xtype: 'displayfield',
-		value: gettext('Guest OS') + ':',
-		hidden: !me.insideWizard
-	    },
-	    {
-		xtype: 'combobox',
-		submitValue: false,
-		name: 'osbase',
-		fieldLabel: gettext('Type'),
-		editable: false,
-		queryMode: 'local',
-		value: 'Linux',
-		store: Object.keys(PVE.Utils.kvm_ostypes)
-	    },
-	    {
-		xtype: 'combobox',
-		name: 'ostype',
-		reference: 'ostype',
-		fieldLabel: gettext('Version'),
-		value: 'l26',
-		allowBlank : false,
-		editable: false,
-		queryMode: 'local',
-		valueField: 'val',
-		displayField: 'desc',
-		store: {
-		    fields: ['desc', 'val'],
-		    data: PVE.Utils.kvm_ostypes.Linux,
-		    listeners: {
-			datachanged: function (store) {
-			    var ostype = me.lookup('ostype');
-			    var old_val = ostype.getValue();
-			    if (!me.insideWizard && old_val && store.find('val', old_val) != -1) {
-				ostype.setValue(old_val);
-			    } else {
-				ostype.setValue(store.getAt(0));
-			    }
-			}
-		    }
-		}
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.OSTypeEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: 'OS Type',
-
-    items: [{ xtype: 'pveQemuOSTypePanel' }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var value = response.result.data.ostype || 'other';
-		var osinfo = PVE.Utils.get_kvm_osinfo(value);
-		me.setValues({ ostype: value, osbase: osinfo.base });
-	    }
-	});
-    }
-});
-/*
- * This class holds performance *recommended* settings for the PVE Qemu wizards
- * the *mandatory* settings are set in the PVE::QemuServer
- * config_to_command sub
- * We store this here until we get the data from the API server
-*/
-
-// this is how you would add an hypothetic FreeBSD > 10 entry
-//
-//virtio-blk is stable but virtIO net still
-//   problematic as of 10.3
-// see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=165059
-//	addOS({
-//	    parent: 'generic', // inherits defaults
-//	    pveOS: 'freebsd10', // must match a radiofield in OSTypeEdit.js
-//	    busType: 'virtio' // must match a pveBusController value
-//			    // networkCard muss match a pveNetworkCardSelector
-
-
-Ext.define('PVE.qemu.OSDefaults', {
-    singleton: true, // will also force creation when loaded
-
-    constructor: function() {
-	var me = this;
-
-	var addOS = function(settings) {
-		if (me.hasOwnProperty(settings.parent)) {
-		    var child = Ext.clone(me[settings.parent]);
-		    me[settings.pveOS] = Ext.apply(child, settings);
-
-		} else {
-		    throw("Could not find your genitor");
-		}
-	    };
-
-	// default values
-	me.generic = {
-	    busType: 'ide',
-	    networkCard: 'e1000',
-	    busPriority: {
-		    ide: 4,
-		    sata: 3,
-		    scsi: 2,
-		    virtio: 1
-	    },
-	    scsihw: 'virtio-scsi-pci'
-	};
-
-       // virtio-net is in kernel since 2.6.25
-       // virtio-scsi since 3.2 but backported in RHEL with 2.6 kernel
-	addOS({
-	    pveOS: 'l26',
-	    parent : 'generic',
-	    busType: 'scsi',
-	    busPriority: {
-		    scsi: 4,
-		    virtio: 3,
-		    sata: 2,
-		    ide: 1
-	    },
-	    networkCard: 'virtio'
-	});
-
-	// recommandation from http://wiki.qemu.org/Windows2000
-	addOS({
-	    pveOS: 'w2k',
-	    parent : 'generic',
-	    networkCard: 'rtl8139',
-	    scsihw: ''
-	});
-	// https://pve.proxmox.com/wiki/Windows_XP_Guest_Notes
-	addOS({
-	    pveOS: 'wxp',
-	    parent : 'w2k'
-	});
-
-	me.getDefaults = function(ostype) {
-	    if (PVE.qemu.OSDefaults[ostype]) {
-		return PVE.qemu.OSDefaults[ostype];
-	    } else {
-		return PVE.qemu.OSDefaults.generic;
-	    }
-	};
-    }
-});
-Ext.define('PVE.qemu.ProcessorInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuProcessorPanel',
-    onlineHelp: 'qm_cpu',
-
-    insideWizard: false,
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	updateCores: function() {
-	    var me = this.getView();
-	    var sockets = me.down('field[name=sockets]').getValue();
-	    var cores = me.down('field[name=cores]').getValue();
-	    me.down('field[name=totalcores]').setValue(sockets*cores);
-	    var vcpus = me.down('field[name=vcpus]');
-	    vcpus.setMaxValue(sockets*cores);
-	    vcpus.setEmptyText(sockets*cores);
-	    vcpus.validate();
-	},
-
-	control: {
-	    'field[name=sockets]': {
-		change: 'updateCores'
-	    },
-	    'field[name=cores]': {
-		change: 'updateCores'
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (Array.isArray(values['delete'])) {
-	    values['delete'] = values['delete'].join(',');
-	}
-
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	// build the cpu options:
-	me.cpu.cputype = values.cputype;
-
-	if (values.flags) {
-	    me.cpu.flags = values.flags;
-	} else {
-	    delete me.cpu.flags;
-	}
-
-	delete values.cputype;
-	delete values.flags;
-	var cpustring = PVE.Parser.printQemuCpu(me.cpu);
-
-	// remove cputype delete request:
-	var del = values['delete'];
-	delete values['delete'];
-	if (del) {
-	    del = del.split(',');
-	    Ext.Array.remove(del, 'cputype');
-	} else {
-	    del = [];
-	}
-
-	if (cpustring) {
-	    values.cpu = cpustring;
-	} else {
-	    del.push('cpu');
-	}
-
-	var delarr = del.join(',');
-	if (delarr) {
-	    values['delete'] = delarr;
-	}
-
-	return values;
-    },
-
-    cpu: {},
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'sockets',
-	    minValue: 1,
-	    maxValue: 4,
-	    value: '1',
-	    fieldLabel: gettext('Sockets'),
-	    allowBlank: false
-	},
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cores',
-	    minValue: 1,
-	    maxValue: 128,
-	    value: '1',
-	    fieldLabel: gettext('Cores'),
-	    allowBlank: false
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'CPUModelSelector',
-	    name: 'cputype',
-	    fieldLabel: gettext('Type')
-	},
-	{
-	    xtype: 'displayfield',
-	    fieldLabel: gettext('Total cores'),
-	    name: 'totalcores',
-	    value: '1'
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'vcpus',
-	    minValue: 1,
-	    maxValue: 1,
-	    value: '',
-	    fieldLabel: gettext('VCPUs'),
-	    deleteEmpty: true,
-	    allowBlank: true,
-	    emptyText: '1'
-	},
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    maxValue: 128, // api maximum
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    minValue: 8,
-	    maxValue: 500000,
-	    value: '1024',
-	    deleteEmpty: true,
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Enable NUMA'),
-	    name: 'numa',
-	    uncheckedValue: 0
-	}
-    ],
-    advancedColumnB: [
-	{
-	    xtype: 'label',
-	    text: 'Extra CPU Flags:'
-	},
-	{
-	    xtype: 'vmcpuflagselector',
-	    name: 'flags'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.ProcessorEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 700,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.ProcessorInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Processors'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-		var value = data.cpu;
-		if (value) {
-		    var cpu = PVE.Parser.parseQemuCpu(value);
-		    ipanel.cpu = cpu;
-		    data.cputype = cpu.cputype;
-		    if (cpu.flags) {
-			data.flags = cpu.flags;
-		    }
-		}
-		me.setValues(data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.BootOrderPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuBootOrderPanel',
-    vmconfig: {}, // store loaded vm config
-
-    bootdisk: undefined,
-    selection: [],
-    list: [],
-    comboboxes: [],
-
-    isBootDisk: function(value) {
-	return PVE.Utils.bus_match.test(value);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-	var order = me.vmconfig.boot || 'cdn';
-	me.bootdisk = me.vmconfig.bootdisk || undefined;
-
-	// get the first 3 characters
-	// ignore the rest (there should never be more than 3)
-	me.selection = order.split('').slice(0,3);
-
-	// build bootdev list
-	me.list = [];
-	Ext.Object.each(me.vmconfig, function(key, value) {
-	    if (me.isBootDisk(key) &&
-		!(/media=cdrom/).test(value)) {
-		me.list.push([key, "Disk '" + key + "'"]);
-	    }
-	});
-
-	me.list.push(['d', 'CD-ROM']);
-	me.list.push(['n', gettext('Network')]);
-	me.list.push(['__none__', Proxmox.Utils.noneText]);
-
-	me.recomputeList();
-
-	me.comboboxes.forEach(function(box) {
-	    box.resetOriginalValue();
-	});
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var order = me.selection.join('');
-	var res = { boot: order };
-
-	if  (me.bootdisk && order.indexOf('c') !== -1) {
-	    res.bootdisk = me.bootdisk;
-	} else {
-	    res['delete'] = 'bootdisk';
-	}
-
-	return res;
-    },
-
-    recomputeSelection: function(combobox, newVal, oldVal) {
-	var me = this.up('#inputpanel');
-	me.selection = [];
-	me.comboboxes.forEach(function(item) {
-	    var val = item.getValue();
-
-	    // when selecting an already selected item,
-	    // switch it around
-	    if ((val === newVal || (me.isBootDisk(val) && me.isBootDisk(newVal))) &&
-		item.name !== combobox.name &&
-		newVal !== '__none__') {
-		// swap items
-		val = oldVal;
-	    }
-
-	    // push 'c','d' or 'n' in the array
-	    if (me.isBootDisk(val)) {
-		me.selection.push('c');
-		me.bootdisk = val;
-	    } else if (val === 'd' ||
-		       val === 'n') {
-		me.selection.push(val);
-	    }
-	});
-
-	me.recomputeList();
-    },
-
-    recomputeList: function(){
-	var me = this;
-	// set the correct values in the kvcomboboxes
-	var cnt = 0;
-	me.comboboxes.forEach(function(item) {
-	    if (cnt === 0) {
-		// never show 'none' on first combobox
-		item.store.loadData(me.list.slice(0, me.list.length-1));
-	    } else {
-		item.store.loadData(me.list);
-	    }
-	    item.suspendEvent('change');
-	    if (cnt < me.selection.length) {
-		item.setValue((me.selection[cnt] !== 'c')?me.selection[cnt]:me.bootdisk);
-	    } else if (cnt === 0){
-		item.setValue('');
-	    } else {
-		item.setValue('__none__');
-	    }
-	    cnt++;
-	    item.resumeEvent('change');
-	    item.validate();
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	// this has to be done here, because of
-	// the way our inputPanel class handles items
-	me.comboboxes = [
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 1",
-		labelWidth: 120,
-		name: 'bd1',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 2",
-		labelWidth: 120,
-		name: 'bd2',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    }),
-		Ext.createWidget('proxmoxKVComboBox', {
-		fieldLabel: gettext('Boot device') + " 3",
-		labelWidth: 120,
-		name: 'bd3',
-		allowBlank: false,
-		listeners: {
-		    change: me.recomputeSelection
-		}
-	    })
-	];
-	Ext.apply(me, { items: me.comboboxes });
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.BootOrderEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    items: [{
-	xtype: 'pveQemuBootOrderPanel',
-	itemId: 'inputpanel'
-    }],
-
-    subject: gettext('Boot Order'),
-
-    initComponent : function() {
-	var me = this;
-	me.callParent();
-	me.load({
-	    success: function(response, options) {
-		me.down('#inputpanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuMemoryPanel',
-    onlineHelp: 'qm_memory',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var res = {};
-
-	res.memory = values.memory;
-	res.balloon = values.balloon;
-
-	if (!values.ballooning) {
-	    res.balloon = 0;
-	    res['delete'] = 'shares';
-	} else if (values.memory === values.balloon) {
-	    delete res.balloon;
-	    res['delete'] = 'balloon,shares';
-	} else if (Ext.isDefined(values.shares) && (values.shares !== "")) {
-	    res.shares = values.shares;
-	} else {
-	    res['delete'] = "shares";
-	}
-
-	return res;
-    },
-
-    initComponent: function() {
-	var me = this;
-	var labelWidth = 160;
-
-	me.items= [
-	    {
-		xtype: 'pveMemoryField',
-		labelWidth: labelWidth,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		name: 'memory',
-		minValue: 1,
-		step: 32,
-		hotplug: me.hotplug,
-		listeners: {
-		    change: function(f, value, old) {
-			var bf = me.down('field[name=balloon]');
-			var balloon = bf.getValue();
-			bf.setMaxValue(value);
-			if (balloon === old) {
-			    bf.setValue(value);
-			}
-			bf.validate();
-		    }
-		}
-	    }
-	];
-
-	me.advancedItems= [
-	    {
-		xtype: 'pveMemoryField',
-		name: 'balloon',
-		minValue: 1,
-		maxValue: 512,
-		step: 32,
-		fieldLabel: gettext('Minimum memory') + ' (MiB)',
-		hotplug: me.hotplug,
-		labelWidth: labelWidth,
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			var memory = me.down('field[name=memory]').getValue();
-			var shares = me.down('field[name=shares]');
-			shares.setDisabled(value === memory);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'shares',
-		disabled: true,
-		minValue: 0,
-		maxValue: 50000,
-		value: '',
-		step: 10,
-		fieldLabel: gettext('Shares'),
-		labelWidth: labelWidth,
-		allowBlank: true,
-		emptyText: Proxmox.Utils.defaultText + ' (1000)',
-		submitEmptyText: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		labelWidth: labelWidth,
-		value: '1',
-		name: 'ballooning',
-		fieldLabel: gettext('Ballooning Device'),
-		listeners: {
-		    change: function(f, value) {
-			var bf = me.down('field[name=balloon]');
-			var shares = me.down('field[name=shares]');
-			var memory = me.down('field[name=memory]');
-			bf.setDisabled(!value);
-			shares.setDisabled(!value || (bf.getValue() === memory.getValue()));
-		    }
-		}
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = me.items;
-	    me.items = undefined;
-	    me.advancedColumn1 = me.advancedItems;
-	    me.advancedItems = undefined;
-	}
-	me.callParent();
-    }
-
-});
-
-Ext.define('PVE.qemu.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent: function() {
-	var me = this;
-
-	var memoryhotplug;
-	if(me.hotplug) {
-	    Ext.each(me.hotplug.split(','), function(el) {
-		if (el === 'memory') {
-		    memoryhotplug = 1;
-	        }
-	    });
-	}
-
-	var ipanel = Ext.create('PVE.qemu.MemoryInputPanel', {
-	    hotplug: memoryhotplug
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: [ ipanel ],
-	    // uncomment the following to use the async configiguration API
-	    // backgroundDelay: 5, 
-	    width: 400
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var data = response.result.data;
-
-		var values = {
-		    ballooning: data.balloon === 0 ? '0' : '1',
-		    shares: data.shares,
-		    memory: data.memory || '512',
-		    balloon: data.balloon > 0 ? data.balloon : (data.memory || '512')
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuNetworkInputPanel',
-    onlineHelp: 'qm_network_device',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	me.network.model = values.model;
-	if (values.nonetwork) {
-	    return {};
-	} else {
-	    me.network.bridge = values.bridge;
-	    me.network.tag = values.tag;
-	    me.network.firewall = values.firewall;
-	}
-	me.network.macaddr = values.macaddr;
-	me.network.disconnect = values.disconnect;
-	me.network.queues = values.queues;
-
-	if (values.rate) {
-	    me.network.rate = values.rate;
-	} else {
-	    delete me.network.rate;
-	}
-
-	var params = {};
-
-	params[me.confid] = PVE.Parser.printQemuNetwork(me.network);
-
-	return params;
-    },
-
-    setNetwork: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data) {
-	    data.networkmode = data.bridge ? 'bridge' : 'nat';
-	} else {
-	    data = {};
-	    data.networkmode = 'bridge';
-	}
-	me.network = data;
-	
-	me.setValues(me.network);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.bridgesel.setNodename(nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.network = {};
-	me.confid = 'net0';
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.bridgesel = Ext.create('PVE.form.BridgeSelector', {
-	    name: 'bridge',
-	    fieldLabel: gettext('Bridge'),
-	    nodename: me.nodename,
-	    autoSelect: true,
-	    allowBlank: false
-	});
-
-	me.column1 = [
-	    me.bridgesel,
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: ''
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		checked: (me.insideWizard || me.isCreate)
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Disconnect'),
-		name: 'disconnect'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1.unshift({
-		xtype: 'checkbox',
-		name: 'nonetwork',
-		inputValue: 'none',
-		boxLabel: gettext('No network device'),
-		listeners: {
-		    change: function(cb, value) {
-			var fields = [
-			    'disconnect',
-			    'bridge',
-			    'tag',
-			    'firewall',
-			    'model',
-			    'macaddr',
-			    'rate',
-			    'queues'
-			];
-			fields.forEach(function(fieldname) {
-			    me.down('field[name='+fieldname+']').setDisabled(value);
-			});
-			me.down('field[name=bridge]').validate();
-		    }
-		}
-	    });
-	    me.column2.unshift({
-		xtype: 'displayfield'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'pveNetworkCardSelector',
-		name: 'model',
-		fieldLabel: gettext('Model'),
-		value: PVE.qemu.OSDefaults.generic.networkCard,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'macaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		allowBlank: true,
-		emptyText: 'auto'
-	    });
-	me.advancedColumn2 = [
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: '',
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'queues',
-		fieldLabel: 'Multiqueue',
-		minValue: 1,
-		maxValue: 8,
-		value: '',
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";	    
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.NetworkInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    isCreate: me.isCreate
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Device'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		if (!me.isCreate) {
-		    var value = me.vmconfig[me.confid];
-		    var network = PVE.Parser.parseQemuNetwork(me.confid, value);
-		    if (!network) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse network options');
-			me.close();
-			return;
-		    }
-		    ipanel.setNetwork(me.confid, network);
-		} else {
-		    for (i = 0; i < 100; i++) {
-			confid = 'net' + i.toString();
-			if (!Ext.isDefined(me.vmconfig[confid])) {
-			    me.confid = confid;
-			    break;
-			}
-		    }
-		    ipanel.setNetwork(me.confid);		    
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.Smbios1InputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.PVE.qemu.Smbios1InputPanel',
-
-    insideWizard: false,
-
-    smbios1: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {
-	    smbios1: PVE.Parser.printQemuSmbios1(values)
-	};
-
-	return params;
-    },
-
-    setSmbios1: function(data) {
-	var me = this;
-
-	me.smbios1 = data;
-	
-	me.setValues(me.smbios1);
-    },
-
-    items: [
-	{
-	    xtype: 'textfield',
-	    fieldLabel: 'UUID',
-	    regex: /^[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$/,
-	    name: 'uuid'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Manufacturer'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'manufacturer'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Product'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'product'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Version'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'version'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Serial'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'serial'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: 'SKU',
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'sku'
-	},
-	{
-	    xtype: 'textareafield',
-	    fieldLabel: gettext('Family'),
-	    fieldStyle: {
-		height: '2em',
-		minHeight: '2em'
-	    },
-	    name: 'family'
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.Smbios1Edit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.Smbios1InputPanel', {});
-
-	Ext.applyIf(me, {
-	    subject: gettext('SMBIOS settings (type1)'),
-	    width: 450,
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		var i, confid;
-		me.vmconfig = response.result.data;
-		var value = me.vmconfig.smbios1;
-		if (value) {
-		    var data = PVE.Parser.parseQemuSmbios1(value);
-		    if (!data) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse smbios options');
-			me.close();
-			return;
-		    }
-		    ipanel.setSmbios1(data);
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.CDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuCDInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || (values.controller + values.deviceid);
-	
-	me.drive.media = 'cdrom';
-	if (values.mediaType === 'iso') {
-	    me.drive.file = values.cdimage;
-	} else if (values.mediaType === 'cdrom') {
-	    me.drive.file = 'cdrom';
-	} else {
-	    me.drive.file = 'none';
-	}
-
-	var params = {};
-		
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	
-	return params;	
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig, 'cdrom');
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	var values = {};
-	if (drive.file === 'cdrom') {
-	    values.mediaType = 'cdrom';
-	} else if (drive.file === 'none') {
-	    values.mediaType = 'none';
-	} else {
-	    values.mediaType = 'iso';
-	    var match = drive.file.match(/^([^:]+):/);
-	    if (match) {
-		values.cdstorage = match[1];
-		values.cdimage = drive.file;
-	    }
-	}
-
-	me.drive = drive;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	me.cdstoragesel.setNodename(nodename);
-	me.cdfilesel.setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	var items = [];
-
-	if (!me.confid) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		noVirtIO: true
-	    });
-	    items.push(me.bussel);
-	}
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'iso',
-	    boxLabel: gettext('Use CD/DVD disc image file (iso)'),
-	    checked: true,
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=cdstorage]').setDisabled(!value);
-		    var cdImageField = me.down('field[name=cdimage]');
-		    cdImageField.setDisabled(!value);
-		    if(value) {
-			cdImageField.validate();
-		    } else {
-			cdImageField.reset();
-		    }
-		}
-	    }
-	});
-
-	me.cdfilesel = Ext.create('PVE.form.FileSelector', {
-	    name: 'cdimage',
-	    nodename: me.nodename,
-	    storageContent: 'iso',
-	    fieldLabel: gettext('ISO image'),
-	    labelAlign: 'right',
-	    allowBlank: false
-	});
-	
-	me.cdstoragesel = Ext.create('PVE.form.StorageSelector', {
-	    name: 'cdstorage',
-	    nodename: me.nodename,
-	    fieldLabel: gettext('Storage'),
-	    labelAlign: 'right',
-	    storageContent: 'iso',
-	    allowBlank: false,
-	    autoSelect: me.insideWizard,
-	    listeners: {
-		change: function(f, value) {
-		    me.cdfilesel.setStorage(value);
-		}
-	    }
-	});
-
-	items.push(me.cdstoragesel);
-	items.push(me.cdfilesel);
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'cdrom',
-	    boxLabel: gettext('Use physical CD/DVD Drive')
-	});
-
-	items.push({
-	    xtype: 'radiofield',
-	    name: 'mediaType',
-	    inputValue: 'none',
-	    boxLabel: gettext('Do not use any media')
-	});
-
-	me.items = items;
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.CDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: 'CD/DVD Drive',
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-	
-	me.load({
-	    success:  function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert('Error', 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		}
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-/* 'change' property is assigned a string and then a function */
-Ext.define('PVE.qemu.HDInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveQemuHDInputPanel',
-    onlineHelp: 'qm_hard_disk',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    viewModel: {},
-
-    controller: {
-
-	xclass: 'Ext.app.ViewController',
-
-	onControllerChange: function(field) {
-	    var value = field.getValue();
-
-	    var allowIOthread = value.match(/^(virtio|scsi)/);
-	    this.lookup('iothread').setDisabled(!allowIOthread);
-	    if (!allowIOthread) {
-		this.lookup('iothread').setValue(false);
-	    }
-
-	    var virtio = value.match(/^virtio/);
-	    this.lookup('ssd').setDisabled(virtio);
-	    if (virtio) {
-		this.lookup('ssd').setValue(false);
-	    }
-
-	    this.lookup('scsiController').setVisible(value.match(/^scsi/));
-	},
-
-	control: {
-	    'field[name=controller]': {
-		change: 'onControllerChange',
-		afterrender: 'onControllerChange'
-	    },
-	    'field[name=iothread]' : {
-		change: function(f, value) {
-		    if (!this.getView().insideWizard) {
-			return;
-		    }
-		    var vmScsiType = value ? 'virtio-scsi-single': 'virtio-scsi-pci';
-		    this.lookupReference('scsiController').setValue(vmScsiType);
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var vm = this.getViewModel();
-	    if (view.isCreate) {
-		vm.set('isIncludedInBackup', true);
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var params = {};
-	var confid = me.confid || (values.controller + values.deviceid);
-
-	if (me.unused) {
-	    me.drive.file = me.vmconfig[values.unusedId];
-	    confid = values.controller + values.deviceid;
-	} else if (me.isCreate) {
-	    if (values.hdimage) {
-		me.drive.file = values.hdimage;
-	    } else {
-		me.drive.file = values.hdstorage + ":" + values.disksize;
-	    }
-	    me.drive.format = values.diskformat;
-	}
-
-	PVE.Utils.propertyStringSet(me.drive, !values.backup, 'backup', '0');
-	PVE.Utils.propertyStringSet(me.drive, values.noreplicate, 'replicate', 'no');
-	PVE.Utils.propertyStringSet(me.drive, values.discard, 'discard', 'on');
-	PVE.Utils.propertyStringSet(me.drive, values.ssd, 'ssd', 'on');
-	PVE.Utils.propertyStringSet(me.drive, values.iothread, 'iothread', 'on');
-	PVE.Utils.propertyStringSet(me.drive, values.cache, 'cache');
-
-        var names = ['mbps_rd', 'mbps_wr', 'iops_rd', 'iops_wr'];
-        Ext.Array.each(names, function(name) {
-            var burst_name = name + '_max';
-	    PVE.Utils.propertyStringSet(me.drive, values[name], name);
-	    PVE.Utils.propertyStringSet(me.drive, values[burst_name], burst_name);
-        });
-
-
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-
-	return params;
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-
-	me.vmconfig = vmconfig;
-
-	if (me.bussel) {
-	    me.bussel.setVMConfig(vmconfig);
-	    me.scsiController.setValue(vmconfig.scsihw);
-	}
-	if (me.unusedDisks) {
-	    var disklist = [];
-	    Ext.Object.each(vmconfig, function(key, value) {
-		if (key.match(/^unused\d+$/)) {
-		    disklist.push([key, value]);
-		}
-	    });
-	    me.unusedDisks.store.loadData(disklist);
-	    me.unusedDisks.setValue(me.confid);
-	}
-    },
-
-    setDrive: function(drive) {
-	var me = this;
-
-	me.drive = drive;
-
-	var values = {};
-	var match = drive.file.match(/^([^:]+):/);
-	if (match) {
-	    values.hdstorage = match[1];
-	}
-
-	values.hdimage = drive.file;
-	values.backup = PVE.Parser.parseBoolean(drive.backup, 1);
-	values.noreplicate = !PVE.Parser.parseBoolean(drive.replicate, 1);
-	values.diskformat = drive.format || 'raw';
-	values.cache = drive.cache || '__default__';
-	values.discard = (drive.discard === 'on');
-	values.ssd = PVE.Parser.parseBoolean(drive.ssd);
-	values.iothread = PVE.Parser.parseBoolean(drive.iothread);
-
-	values.mbps_rd = drive.mbps_rd;
-	values.mbps_wr = drive.mbps_wr;
-	values.iops_rd = drive.iops_rd;
-	values.iops_wr = drive.iops_wr;
-	values.mbps_rd_max = drive.mbps_rd_max;
-	values.mbps_wr_max = drive.mbps_wr_max;
-	values.iops_rd_max = drive.iops_rd_max;
-	values.iops_wr_max = drive.iops_wr_max;
-
-	me.setValues(values);
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var labelWidth = 140;
-
-	me.drive = {};
-
-	me.column1 = [];
-	me.column2 = [];
-
-	me.advancedColumn1 = [];
-	me.advancedColumn2 = [];
-
-	if (!me.confid || me.unused) {
-	    me.bussel = Ext.create('PVE.form.ControllerSelector', {
-		vmconfig: me.insideWizard ? {ide2: 'cdrom'} : {}
-	    });
-	    me.column1.push(me.bussel);
-
-	    me.scsiController = Ext.create('Ext.form.field.Display', {
-		fieldLabel: gettext('SCSI Controller'),
-		reference: 'scsiController',
-		bind: me.insideWizard ? {
-		    value: '{current.scsihw}'
-		} : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		submitValue: false,
-		hidden: true
-	    });
-	    me.column1.push(me.scsiController);
-	}
-
-	if (me.unused) {
-	    me.unusedDisks = Ext.create('Proxmox.form.KVComboBox', {
-		name: 'unusedId',
-		fieldLabel: gettext('Disk image'),
-		matchFieldWidth: false,
-		listConfig: {
-		    width: 350
-		},
-		data: [],
-		allowBlank: false
-	    });
-	    me.column1.push(me.unusedDisks);
-	} else if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveDiskStorageSelector',
-		storageContent: 'images',
-		name: 'disk',
-		nodename: me.nodename,
-		autoSelect: me.insideWizard
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'textfield',
-		disabled: true,
-		submitValue: false,
-		fieldLabel: gettext('Disk image'),
-                name: 'hdimage'
-	    });
-	}
-
-	me.column2.push(
-	    {
-		xtype: 'CacheTypeSelector',
-		name: 'cache',
-		value: '__default__',
-		fieldLabel: gettext('Cache')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Discard'),
-		reference: 'discard',
-		name: 'discard'
-	    }
-	);
-
-	me.advancedColumn1.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && me.confid.match(/^virtio/),
-		fieldLabel: gettext('SSD emulation'),
-		labelWidth: labelWidth,
-		name: 'ssd',
-		reference: 'ssd'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		disabled: me.confid && !me.confid.match(/^(virtio|scsi)/),
-		fieldLabel: 'IO thread',
-		labelWidth: labelWidth,
-		reference: 'iothread',
-		name: 'iothread'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write limit') + ' (MB/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write limit') + ' (ops/s)',
-		labelWidth: labelWidth,
-		emptyText: gettext('unlimited')
-	    }
-	);
-
-	me.advancedColumn2.push(
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Backup'),
-		autoEl: {
-		    tag: 'div',
-		    'data-qtip': gettext('Include volume in backup job'),
-		},
-		labelWidth: labelWidth,
-		name: 'backup',
-		bind: {
-		    value: '{isIncludedInBackup}',
-		},
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Skip replication'),
-		labelWidth: labelWidth,
-		name: 'noreplicate'
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_rd_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Read max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'mbps_wr_max',
-		minValue: 1,
-		step: 1,
-		fieldLabel: gettext('Write max burst') + ' (MB)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_rd_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Read max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'iops_wr_max',
-		minValue: 10,
-		step: 10,
-		fieldLabel: gettext('Write max burst') + ' (ops)',
-		labelWidth: labelWidth,
-		emptyText: gettext('default')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-/*jslint confusion: false */
-
-Ext.define('PVE.qemu.HDEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    backgroundDelay: 5,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.qemu.HDInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    me.subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-            me.subject = gettext('Hard Disk');
-	} else {
-           me.subject = gettext('Hard Disk') + ' (' + me.confid + ')';
-	}
-
-	me.items = [ ipanel ];
-
-	me.callParent();
-	/*jslint confusion: true*/
-	/* 'data' is assigned an empty array in same file, and here we
-	 * use it like an object
-	 */
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    var value = response.result.data[me.confid];
-		    var drive = PVE.Parser.parseQemuDrive(me.confid, value);
-		    if (!drive) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse drive options');
-			me.close();
-			return;
-		    }
-		    ipanel.setDrive(drive);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-	/*jslint confusion: false*/
-    }
-});
-Ext.define('PVE.window.HDResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/qemu/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 140,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 250,
-	    height: 150,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-Ext.define('PVE.window.HDMove', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-
-    move_disk: function(disk, storage, format, delete_disk) {
-	var me = this;
-	var qemu = (me.type === 'qemu');
-	var params = {};
-	params.storage = storage;
-	params[qemu ? 'disk':'volume'] = disk;
-
-	if (format && qemu) {
-	    params.format = format;
-	}
-
-	if (delete_disk) {
-	    params['delete'] = 1;
-	}
-
-	var url = '/nodes/' + me.nodename + '/' + me.type + '/' + me.vmid + '/';
-	url += qemu ? 'move_disk' : 'move_volume';
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: url,
-	    waitMsgTarget: me,
-	    method: 'POST',
-	    failure: function(response, opts) {
-		Ext.Msg.alert('Error', response.htmlStatus);
-	    },
-	    success: function(response, options) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', {
-		    upid: upid
-		});
-		win.show();
-		win.on('destroy', function() { me.close(); });
-	    }
-	});
-
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var diskarray = [];
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	if (!me.type) {
-	    me.type = 'qemu';
-	}
-
-	var qemu = (me.type === 'qemu');
-
-        var items = [
-            {
-                xtype: 'displayfield',
-                name: qemu ? 'disk' : 'volume',
-                value: me.disk,
-                fieldLabel: qemu ? gettext('Disk') : gettext('Mount Point'),
-                vtype: 'StorageId',
-                allowBlank: false
-            }
-        ];
-
-	items.push({
-	    xtype: 'pveDiskStorageSelector',
-	    storageLabel: gettext('Target Storage'),
-	    nodename: me.nodename,
-	    storageContent: qemu ? 'images' : 'rootdir',
-	    hideSize: true
-	});
-
-	items.push({
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Delete source'),
-	    name: 'deleteDisk',
-	    uncheckedValue: 0,
-	    checked: false
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = qemu ? gettext("Move disk") : gettext('Move Volume');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: me.title,
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.move_disk(me.disk, values.hdstorage, values.diskformat,
-				 values.deleteDisk);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    width: 350,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	me.mon(me.formPanel, 'validitychange', function(fp, isValid) {
-	    submitBtn.setDisabled(!isValid);
-	});
-
-	me.formPanel.isValid();
-    }
-});
-Ext.define('PVE.qemu.EFIDiskInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveEFIDiskInputPanel',
-
-    insideWizard: false,
-
-    unused: false, // ADD usused disk imaged
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = 'efidisk0';
-
-	if (values.hdimage) {
-	    me.drive.file = values.hdimage;
-	} else {
-	    // we use 1 here, because for efi the size gets overridden from the backend
-	    me.drive.file = values.hdstorage + ":1";
-	}
-
-	me.drive.format = values.diskformat;
-	var params = {};
-	params[confid] = PVE.Parser.printQemuDrive(me.drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items= [
-	    {
-		xtype: 'pveDiskStorageSelector',
-		name: 'efidisk0',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    },
-	    {
-		xtype: 'label',
-		text: gettext("Warning: The VM currently does not uses 'OVMF (UEFI)' as BIOS."),
-		userCls: 'pmx-hint',
-		hidden: me.usesEFI,
-	    },
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.EFIDiskEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-    subject: gettext('EFI Disk'),
-
-    width: 450,
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveEFIDiskInputPanel',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    confid: me.confid,
-	    nodename: nodename,
-	    usesEFI: me.usesEFI,
-	    isCreate: true,
-	}];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.qemu.DisplayInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveDisplayInputPanel',
-    onlineHelp: 'qm_display',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values, 'type');
-	if (ret === '') {
-	    return {
-		'delete': 'vga'
-	    };
-	}
-	return {
-	    vga: ret
-	};
-    },
-
-    items: [{
-	name: 'type',
-	xtype: 'proxmoxKVComboBox',
-	value: '__default__',
-	deleteEmpty: false,
-	fieldLabel: gettext('Graphic card'),
-	comboItems: PVE.Utils.kvm_vga_driver_array(),
-	validator: function() {
-	    var v = this.getValue();
-	    var cfg = this.up('proxmoxWindowEdit').vmconfig || {};
-
-	    if (v.match(/^serial\d+$/) && (!cfg[v] || cfg[v] !== 'socket')) {
-		var fmt = gettext("Serial interface '{0}' is not correctly configured.");
-		return Ext.String.format(fmt, v);
-	    }
-	    return true;
-	},
-	listeners: {
-	    change: function(cb, val) {
-		var me = this.up('panel');
-		if (!val) {
-		    return;
-		}
-		var disable = false;
-		var emptyText = Proxmox.Utils.defaultText;
-		switch (val) {
-		    case "cirrus":
-			emptyText = "4";
-			break;
-		    case "std":
-			emptyText = "16";
-			break;
-		    case "qxl":
-		    case "qxl2":
-		    case "qxl3":
-		    case "qxl4":
-			emptyText = "16";
-			break;
-		    case "vmware":
-			emptyText = "16";
-			break;
-		    case "none":
-		    case "serial0":
-		    case "serial1":
-		    case "serial2":
-		    case "serial3":
-			emptyText = 'N/A';
-			disable = true;
-			break;
-		    case "virtio":
-			emptyText = "256";
-			break;
-		    default:
-			break;
-		}
-		var memoryfield = me.down('field[name=memory]');
-		memoryfield.setEmptyText(emptyText);
-		memoryfield.setDisabled(disable);
-	    }
-	}
-    },{
-	xtype: 'proxmoxintegerfield',
-	emptyText: Proxmox.Utils.defaultText,
-	fieldLabel: gettext('Memory') + ' (MiB)',
-	minValue: 4,
-	maxValue: 512,
-	step: 4,
-	name: 'memory'
-    }]
-});
-
-Ext.define('PVE.qemu.DisplayEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Display'),
-    width: 350,
-
-    items: [{
-	xtype: 'pveDisplayInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-		var vga = me.vmconfig.vga || '__default__';
-		me.setValues(PVE.Parser.parsePropertyString(vga, 'type'));
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.KeyboardEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('Keyboard Layout'),
-	    items: {
-		xtype: 'VNCKeyboardSelector',
-		name: 'keyboard',
-		value: '__default__',
-		fieldLabel: gettext('Keyboard Layout')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.HardwareView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.HardwareView'],
-
-    onlineHelp: 'qm_virtual_machines_settings',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-	var iconCls = rowdef.iconCls;
-	var icon = '';
-	var txt = (rowdef.header || key);
-
-	metaData.tdAttr = "valign=middle";
-
-	if (rowdef.isOnStorageBus) {
-	    var value = me.getObjectValue(key, '', false);
-	    if (value === '') {
-		value = me.getObjectValue(key, '', true);
-	    }
-	    if (value.match(/vm-.*-cloudinit/)) {
-		iconCls = 'cloud';
-		txt = rowdef.cloudheader;
-	    } else if (value.match(/media=cdrom/)) {
-		metaData.tdCls = 'pve-itype-icon-cdrom';
-		return rowdef.cdheader;
-	    }
-	}
-
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	} else if (iconCls) {
-	    icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
-	    metaData.tdCls += " pve-itype-fa";
-	}
-
-	// only return icons in grid but not remove dialog
-	if (rowIndex !== undefined) {
-	    return icon + txt;
-	} else {
-	    return txt;
-	}
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	/*jslint confusion: true */
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
-		never_delete: true,
-		defaultValue: '512',
-		tdCls: 'pve-itype-icon-memory',
-		group: 2,
-		multiKey: ['memory', 'balloon', 'shares'],
-		renderer: function(value, metaData, record, ri, ci, store, pending) {
-		    var res = '';
-
-		    var max = me.getObjectValue('memory', 512, pending);
-		    var balloon =  me.getObjectValue('balloon', undefined, pending);
-		    var shares = me.getObjectValue('shares', undefined, pending);
-
-		    res  = Proxmox.Utils.format_size(max*1024*1024);
-
-		    if (balloon !== undefined && balloon > 0) {
-			res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
-
-			if (shares) {
-			    res += ' [shares=' + shares +']';
-			}
-		    } else if (balloon === 0) {
-			res += ' [balloon=0]';
-		    }
-		    return res;
-		}
-	    },
-	    sockets: {
-		header: gettext('Processors'),
-		never_delete: true,
-		editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ? 
-		    'PVE.qemu.ProcessorEdit' : undefined,
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		defaultValue: '1',
-		multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
-		renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
-
-		    var sockets = me.getObjectValue('sockets', 1, pending);
-		    var model = me.getObjectValue('cpu', undefined, pending);
-		    var cores = me.getObjectValue('cores', 1, pending);
-		    var numa = me.getObjectValue('numa', undefined, pending);
-		    var vcpus = me.getObjectValue('vcpus', undefined, pending);
-		    var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
-		    var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
-
-		    var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
-			sockets*cores, sockets, cores);
-
-		    if (model) {
-			res += ' [' + model + ']';
-		    }
-
-		    if (numa) {
-			res += ' [numa=' + numa +']';
-		    }
-
-		    if (vcpus) {
-			res += ' [vcpus=' + vcpus +']';
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit +']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits +']';
-		    }
-
-		    return res;
-		}
-	    },
-	    bios: {
-		header: 'BIOS',
-		group: 4,
-		never_delete: true,
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.BiosEdit' : undefined,
-		defaultValue: '',
-		iconCls: 'microchip',
-		renderer: PVE.Utils.render_qemu_bios
-	    },
-	    vga: {
-		header: gettext('Display'),
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
-		never_delete: true,
-		iconCls: 'desktop',
-		group:5,
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_vga_driver		
-	    },
-	    machine: {
-		header: gettext('Machine'),
-		editor: caps.vms['VM.Config.HWType'] ?  {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Machine'),
-		    width: 350,
-		    items: [{
-			xtype: 'proxmoxKVComboBox',
-			name: 'machine',
-			value: '__default__',
-			fieldLabel: gettext('Machine'),
-			comboItems: [
-			    ['__default__', PVE.Utils.render_qemu_machine('')],
-			    ['q35', 'q35']
-			]
-		    }]} : undefined,
-		iconCls: 'cogs',
-		never_delete: true,
-		group: 6,
-		defaultValue: '',
-		renderer: PVE.Utils.render_qemu_machine
-	    },
-	    scsihw: {
-		header: gettext('SCSI Controller'),
-		iconCls: 'database',
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.ScsiHwEdit' : undefined,
-		renderer: PVE.Utils.render_scsihw,
-		group: 7,
-		never_delete: true,
-		defaultValue: ''
-	    },
-	    vmstate: {
-		header: gettext('Hibernation VM State'),
-		iconCls: 'download',
-		del_extra_msg: gettext('The saved VM state will be permanently lost.'),
-		group: 100,
-	    },
-	    cores: {
-		visible: false
-	    },
-	    cpu: {
-		visible: false
-	    },
-	    numa: {
-		visible: false
-	    },
-	    balloon: {
-		visible: false
-	    },
-	    hotplug: {
-		visible: false
-	    },
-	    vcpus: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    shares: {
-		visible: false
-	    }
-	};
-	/*jslint confusion: false */
-
-	PVE.Utils.forEachBus(undefined, function(type, id) {
-	    var confid = type + id;
-	    rows[confid] = {
-		group: 10,
-		iconCls: 'hdd-o',
-		editor: 'PVE.qemu.HDEdit',
-		never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-		isOnStorageBus: true,
-		header: gettext('Hard Disk') + ' (' + confid +')',
-		cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
-		cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
-	    };
-	});
-	for (i = 0; i < PVE.Utils.hardware_counts.net; i++) {
-	    confid = "net" + i.toString();
-	    rows[confid] = {
-		group: 15,
-		order: i,
-		iconCls: 'exchange',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
-		never_delete: caps.vms['VM.Config.Network'] ? false : true,
-		header: gettext('Network Device') + ' (' + confid +')'
-	    };
-	}
-	rows.efidisk0 = {
-	    group: 20,
-	    iconCls: 'hdd-o',
-	    editor: null,
-	    never_delete: caps.vms['VM.Config.Disk'] ? false : true,
-	    header: gettext('EFI Disk')
-	};
-	for (i = 0; i < PVE.Utils.hardware_counts.usb; i++) {
-	    confid = "usb" + i.toString();
-	    rows[confid] = {
-		group: 25,
-		order: i,
-		iconCls: 'usb',
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('USB Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
-	    confid = "hostpci" + i.toString();
-	    rows[confid] = {
-		group: 30,
-		order: i,
-		tdCls: 'pve-itype-icon-pci',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
-		header: gettext('PCI Device') + ' (' + confid + ')'
-	    };
-	}
-	for (i = 0; i < PVE.Utils.hardware_counts.serial; i++) {
-	    confid = "serial" + i.toString();
-	    rows[confid] = {
-		group: 35,
-		order: i,
-		tdCls: 'pve-itype-icon-serial',
-		never_delete: caps.nodes['Sys.Console'] ? false : true,
-		header: gettext('Serial Port') + ' (' + confid + ')'
-	    };
-	}
-	rows.audio0 = {
-	    group: 40,
-	    iconCls: 'volume-up',
-	    editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.AudioEdit' : undefined,
-	    never_delete: caps.vms['VM.Config.HWType'] ? false : true,
-	    header: gettext('Audio Device')
-	};
-	for (i = 0; i < 256; i++) {
-	    rows["unused" + i.toString()] = {
-		group: 99,
-		order: i,
-		iconCls: 'hdd-o',
-		del_extra_msg: gettext('This will permanently erase all data.'),
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
-		header: gettext('Unused Disk') + ' ' + i.toString()
-	    };
-	}
-	rows.rng0 = {
-	    group: 45,
-	    tdCls: 'pve-itype-icon-die',
-	    editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.RNGEdit' : undefined,
-	    never_delete: caps.nodes['Sys.Console'] ? false : true,
-	    header: gettext("VirtIO RNG")
-	};
-
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-	    
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var editor = rowdef.editor;
-	    if (rowdef.isOnStorageBus) {
-		var value = me.getObjectValue(rec.data.key, '', true);
-		if (value.match(/vm-.*-cloudinit/)) {
-		    return;
-		} else if (value.match(/media=cdrom/)) {
-		    editor = 'PVE.qemu.CDEdit';
-		} else if (!diskCap) {
-		    return;
-		}
-	    }
-
-	    var win;
-
-	    if (Ext.isString(editor)) {
-		win = Ext.create(editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/' + baseurl
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-
-	    win.show();
-	    win.on('destroy', me.reload, me);
-	};
-
-	var run_resize = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var run_move = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_editor
-        });
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move disk'),
-	    selModel: sm,
-	    disabled: true,
-	    handler: run_move
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    defaultText: gettext('Remove'),
-	    altText: gettext('Detach'),
-	    selModel: sm,
-	    disabled: true,
-	    dangerous: true,
-	    RESTMethod: 'PUT',
-	    confirmMsg: function(rec) {
-		var warn = gettext('Are you sure you want to remove entry {0}');
-		if (this.text === this.altText) {
-		    warn = gettext('Are you sure you want to detach entry {0}');
-		}
-		var key = rec.data.key;
-		var entry = rows[key];
-
-		var rendered = me.renderKey(key, {}, rec);
-		var msg = Ext.String.format(warn, "'" + rendered + "'");
-
-		if (entry.del_extra_msg) {
-		    msg += '<br>' + entry.del_extra_msg;
-		}
-
-		return msg;
-	    },
-	    handler: function(b, e, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/api2/extjs/' + baseurl,
-		    waitMsgTarget: me,
-		    method: b.RESTMethod,
-		    params: {
-			'delete': rec.data.key
-		    },
-		    callback: () => me.reload(),
-		    failure: function (response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			if (b.RESTMethod === 'POST') {
-			    var upid = response.result.data;
-			    var win = Ext.create('Proxmox.window.TaskProgress', {
-				upid: upid,
-				listeners: {
-				    destroy: () => me.reload(),
-				}
-			    });
-			    win.show();
-			}
-		    }
-		});
-	    },
-	    listeners: {
-		render: function(btn) {
-		    // hack: calculate an optimal button width on first display
-		    // to prevent the whole toolbar to move when we switch
-		    // between the "Remove" and "Detach" labels
-		    var def = btn.getSize().width;
-
-		    btn.setText(btn.altText);
-		    var alt = btn.getSize().width;
-
-		    btn.setText(btn.defaultText);
-
-		    var optimal = alt > def ? alt : def;
-		    btn.setSize({ width: optimal });
-		}
-	    }
-	});
-
-	var revert_btn = new PVE.button.PendingRevert({
-	    apiurl: '/api2/extjs/' + baseurl,
-	});
-
-	var efidisk_menuitem = Ext.create('Ext.menu.Item',{
-	    text: gettext('EFI Disk'),
-	    iconCls: 'fa fa-fw fa-hdd-o black',
-	    disabled: !caps.vms['VM.Config.Disk'],
-	    handler: function() {
-		let bios = me.rstore.getData().map.bios;
-		let usesEFI = bios && (bios.data.value === 'ovmf' || bios.data.pending === 'ovmf');
-
-		var win = Ext.create('PVE.qemu.EFIDiskEdit', {
-		    url: '/api2/extjs/' + baseurl,
-		    pveSelNode: me.pveSelNode,
-		    usesEFI: usesEFI,
-		});
-		win.on('destroy', me.reload, me);
-		win.show();
-	    }
-	});
-
-	let counts = {};
-	let isAtLimit = (type) => (counts[type] >= PVE.Utils.hardware_counts[type]);
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    // en/disable hardwarebuttons
-	    counts = {};
-	    var hasCloudInit = false;
-	    me.rstore.getData().items.forEach(function(item){
-		if (!hasCloudInit && (
-		    /vm-.*-cloudinit/.test(item.data.value) ||
-		    /vm-.*-cloudinit/.test(item.data.pending)
-		)) {
-		    hasCloudInit = true;
-		    return;
-		}
-
-		let match = item.id.match(/^([^\d]+)\d+$/);
-		let type;
-		if (match && PVE.Utils.hardware_counts[match[1]] !== undefined) {
-		    type = match[1];
-		} else {
-		    return;
-		}
-
-		counts[type] = (counts[type] || 0) + 1;
-	    });
-
-	    // heuristic only for disabling some stuff, the backend has the final word.
-	    var noSysConsolePerm = !caps.nodes['Sys.Console'];
-	    var noVMConfigHWTypePerm = !caps.vms['VM.Config.HWType'];
-	    var noVMConfigNetPerm = !caps.vms['VM.Config.Network'];
-
-
-	    me.down('#addusb').setDisabled(noSysConsolePerm || isAtLimit('usb'));
-	    me.down('#addpci').setDisabled(noSysConsolePerm || isAtLimit('hostpci'));
-	    me.down('#addaudio').setDisabled(noVMConfigHWTypePerm || isAtLimit('audio'));
-	    me.down('#addserial').setDisabled(noVMConfigHWTypePerm || isAtLimit('serial'));
-	    me.down('#addnet').setDisabled(noVMConfigNetPerm || isAtLimit('net'));
-	    me.down('#addrng').setDisabled(noSysConsolePerm || isAtLimit('rng'));
-	    efidisk_menuitem.setDisabled(isAtLimit('efidisk'));
-	    me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
-
-	    if (!rec) {
-		remove_btn.disable();
-		edit_btn.disable();
-		resize_btn.disable();
-		move_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isCDRom = (value && !!value.toString().match(/media=cdrom/));
-	    var isUnusedDisk = key.match(/^unused\d+/);
-	    var isUsedDisk = !isUnusedDisk && rowdef.isOnStorageBus && !isCDRom;
-
-	    var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
-
-	    var isEfi = (key === 'efidisk0');
-
-	    remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true) || (isUnusedDisk && !diskCap));
-	    remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
-	    remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
-
-	    edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit || (!isCDRom && !diskCap));
-
-	    resize_btn.setDisabled(pending || !isUsedDisk || !diskCap);
-
-	    move_btn.setDisabled(pending || !(isUsedDisk || isEfi) || !diskCap);
-
-	    revert_btn.setDisabled(!pending);
-
-	};
-
-	Ext.apply(me, {
-	    url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
-	    interval: 5000,
-	    selModel: sm,
-	    run_editor: run_editor,
-	    tbar: [ 
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			cls: 'pve-add-hw-menu',
-			items: [
-			    {
-				text: gettext('Hard Disk'),
-				iconCls: 'fa fa-fw fa-hdd-o black',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.HDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CD/DVD Drive'),
-				iconCls: 'pve-itype-icon-cdrom',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CDEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Network Device'),
-				itemId: 'addnet',
-				iconCls: 'fa fa-fw fa-exchange black',
-				disabled: !caps.vms['VM.Config.Network'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.NetworkEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode,
-					isCreate: true
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    efidisk_menuitem,
-			    {
-				text: gettext('USB Device'),
-				itemId: 'addusb',
-				iconCls: 'fa fa-fw fa-usb black',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.USBEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('PCI Device'),
-				itemId: 'addpci',
-				iconCls: 'pve-itype-icon-pci',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.PCIEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Serial Port'),
-				itemId: 'addserial',
-				iconCls: 'pve-itype-icon-serial',
-				disabled: !caps.vms['VM.Config.Options'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.SerialEdit', {
-					url: '/api2/extjs/' + baseurl
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('CloudInit Drive'),
-				itemId: 'addci',
-				iconCls: 'fa fa-fw fa-cloud black',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.CIDriveEdit', {
-					url: '/api2/extjs/' + baseurl,
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('Audio Device'),
-				itemId: 'addaudio',
-				iconCls: 'fa fa-fw fa-volume-up black',
-				disabled: !caps.vms['VM.Config.HWType'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.AudioEdit', {
-					url: '/api2/extjs/' + baseurl,
-					isCreate: true,
-					isAdd: true
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext("VirtIO RNG"),
-				itemId: 'addrng',
-				iconCls: 'pve-itype-icon-die',
-				disabled: !caps.nodes['Sys.Console'],
-				handler: function() {
-				    var win = Ext.create('PVE.qemu.RNGEdit', {
-					url: '/api2/extjs/' + baseurl,
-					isCreate: true,
-					isAdd: true
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		remove_btn,
-		edit_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-
-	me.mon(me.getStore(), 'datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.qemu.ScsiHwEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.applyIf(me, {
-	    subject: gettext('SCSI Controller Type'),
-	    items: {
-		xtype: 'pveScsiHwSelector',
-		name: 'scsihw',
-		value: '__default__',
-		fieldLabel: gettext('Type')
-	    }
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-Ext.define('PVE.qemu.BiosEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: 'widget.pveQemuBiosEdit',
-
-    onlineHelp: 'qm_bios_and_uefi',
-    subject: 'BIOS',
-    autoLoad: true,
-
-    viewModel: {
-	data: {
-	    bios: '__default__',
-	    efidisk0: false,
-	},
-	formulas: {
-	    showEFIDiskHint: (get) => get('bios') === 'ovmf' && !get('efidisk0'),
-	},
-    },
-
-    items: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    onlineHelp: 'qm_bios_and_uefi',
-	    name: 'bios',
-	    value: '__default__',
-	    bind: '{bios}',
-	    fieldLabel: 'BIOS',
-	},
-	{
-	    xtype: 'displayfield',
-	    name: 'efidisk0',
-	    bind: '{efidisk0}',
-	    hidden: true,
-	},
-	{
-	    xtype: 'displayfield',
-	    userCls: 'pmx-hint',
-	    value: gettext('You need to add an EFI disk for storing the EFI settings. See the online help for details.'),
-	    bind: {
-		hidden: '{!showEFIDiskHint}',
-	    },
-	},
-    ],
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.PVE.qemu.Options'],
-
-    onlineHelp: 'qm_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    name: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Name'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Name'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    xtype: 'textfield',
-			    name: 'name',
-			    vtype: 'DnsName',
-			    value: '',
-			    fieldLabel: gettext('Name'),
-			    allowBlank: true
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.name === undefined ||
-				values.name === null ||
-				values.name === '') {
-				params = { 'delete':'name'};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ?
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'qm_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		editor: caps.vms['VM.Config.Options'] ? 'PVE.qemu.OSTypeEdit' : undefined,
-		renderer: PVE.Utils.render_kvm_ostype,
-		defaultValue: 'other'
-	    },
-	    bootdisk: {
-		visible: false
-	    },
-	    boot: {
-		header: gettext('Boot Order'),
-		defaultValue: 'cdn',
-		editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.BootOrderEdit' : undefined,
-		multiKey: ['boot', 'bootdisk'],
-		renderer: function(order, metaData, record, rowIndex, colIndex, store, pending) {
-		    var i;
-		    var text = '';
-		    var bootdisk = me.getObjectValue('bootdisk', undefined, pending);
-		    order = order || 'cdn';
-		    for (i = 0; i < order.length; i++) {
-			var sel = order.substring(i, i + 1);
-			if (text) {
-			    text += ', ';
-			}
-			if (sel === 'c') {
-			    if (bootdisk) {
-				text += "Disk '" + bootdisk + "'";
-			    } else {
-				text += "Disk";
-			    }
-			} else if (sel === 'n') {
-			    text += 'Network';
-			} else if (sel === 'a') {
-			    text += 'Floppy';
-			} else if (sel === 'd') {
-			    text += 'CD-ROM';
-			} else {
-			    text += sel;
-			}
-		    }
-		    return text;
-		}
-	    },
-	    tablet: {
-		header: gettext('Use tablet for pointer'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use tablet for pointer'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'tablet',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    hotplug: {
-		header: gettext('Hotplug'),
-		defaultValue: 'disk,network,usb',
-		renderer:  PVE.Utils.render_hotplug_features,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hotplug'),
-		    items: {
-			xtype: 'pveHotplugFeatureSelector',
-			name: 'hotplug',
-			value: '',
-			multiSelect: true,
-			fieldLabel: gettext('Hotplug'),
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    acpi: {
-		header: gettext('ACPI support'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('ACPI support'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'acpi',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    kvm: {
-		header: gettext('KVM hardware virtualization'),
-		defaultValue: true,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.HWType'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('KVM hardware virtualization'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'kvm',
-			checked: true,
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    freeze: {
-		header: gettext('Freeze CPU at startup'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.PowerMgmt'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Freeze CPU at startup'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'freeze',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Freeze CPU at startup')
-		    }
-		} : undefined
-	    },
-	    localtime: {
-		header: gettext('Use local time for RTC'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Use local time for RTC'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'localtime',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			labelWidth: 140,
-			fieldLabel: gettext('Use local time for RTC')
-		    }
-		} : undefined
-	    },
-	    startdate: {
-		header: gettext('RTC start date'),
-		defaultValue: 'now',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('RTC start date'),
-		    items: {
-			xtype: 'proxmoxtextfield',
-			name: 'startdate',
-			deleteEmpty: true,
-			value: 'now',
-			fieldLabel: gettext('RTC start date'),
-			vtype: 'QemuStartDate',
-			allowBlank: true
-		    }
-		} : undefined
-	    },
-	    smbios1: {
-		header: gettext('SMBIOS settings (type1)'),
-		defaultValue: '',
-		renderer: Ext.String.htmlEncode,
-		editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.Smbios1Edit' : undefined
-	    },
-	    agent: {
-		header: 'QEMU Guest Agent',
-		defaultValue: false,
-		renderer: PVE.Utils.render_qga_features,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Qemu Agent'),
-		    width: 350,
-		    items: {
-			xtype: 'pveAgentFeatureSelector',
-			name: 'agent'
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    spice_enhancements: {
-		header: gettext('Spice Enhancements'),
-		defaultValue: false,
-		renderer:  PVE.Utils.render_spice_enhancements,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Spice Enhancements'),
-		    onlineHelp: 'qm_spice_enhancements',
-		    items: {
-			xtype: 'pveSpiceEnhancementSelector',
-			name: 'spice_enhancements',
-		    }
-		} : undefined
-	    },
-	    vmstatestorage: {
-		header: gettext('VM State storage'),
-		defaultValue: '',
-		renderer: val => val || gettext('Automatic'),
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('VM State storage'),
-		    onlineHelp: 'chapter_virtual_machines', // FIXME: use 'qm_vmstatestorage' once available
-		    width: 350,
-		    items: {
-			xtype: 'pveStorageSelector',
-			storageContent: 'images',
-			allowBlank: true,
-			emptyText: gettext("Automatic (Storage used by the VM, or 'local')"),
-			autoSelect: false,
-			deleteEmpty: true,
-			skipEmptyText: true,
-			nodename: nodename,
-			name: 'vmstatestorage',
-		    }
-		} : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
-
-	var edit_btn = new Ext.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    handler: function() { me.run_editor(); }
-	});
-
-	var revert_btn = new PVE.button.PendingRevert();
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/qemu/" + vmid + "/pending",
-	    interval: 5000,
-	    cwidth1: 250,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.mon(me.getStore(), 'datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-
-Ext.define('PVE.qemu.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.qemu.Config',
-
-    onlineHelp: 'chapter_virtual_machines',
-
-    initComponent: function() {
-        var me = this;
-	var vm = me.pveSelNode.data;
-
-	var nodename = vm.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = vm.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!vm.template;
-
-	var running = !!vm.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + "/qemu/" + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + '/status/' + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var resumeBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resume'),
-	    disabled: !caps.vms['VM.PowerMgmt'],
-	    hidden: true,
-	    handler: function() {
-		vm_command('resume');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'qemu',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'qemu');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('qmtemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = vm.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    itemId: 'removeBtn',
-		    disabled: !caps.vms['VM.Allocate'],
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'VM', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('qmshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items: [{
-		    text: gettext('Reboot'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    tooltip: Ext.String.format(gettext('Shutdown, apply pending changes and reboot {0}'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreboot', vmid),
-		    handler: function() {
-			vm_command("reboot");
-		    },
-		    iconCls: 'fa fa-refresh'
-		},{
-		    text: gettext('Pause'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmpause', vmid),
-		    handler: function() {
-			vm_command("suspend");
-		    },
-		    iconCls: 'fa fa-pause'
-		},{
-		    text: gettext('Hibernate'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('qmsuspend', vmid),
-		    tooltip: gettext('Suspend to disk'),
-		    handler: function() {
-			vm_command("suspend", { todisk: 1 });
-		    },
-		    iconCls: 'fa fa-download'
-		},{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    dangerous: true,
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmstop', vmid),
-		    handler: function() {
-			vm_command("stop", { timeout: 30 });
-		    },
-		    iconCls: 'fa fa-stop'
-		},{
-		    text: gettext('Reset'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    tooltip: Ext.String.format(gettext('Reset {0} immediately'), 'VM'),
-		    confirmMsg: Proxmox.Utils.format_task_description('qmreset', vmid),
-		    handler: function() {
-			vm_command("reset");
-		    },
-		    iconCls: 'fa fa-bolt'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    hidden: template,
-	    consoleType: 'kvm',
-	    consoleName: vm.name,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Virtual Machine {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'kvmtab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', resumeBtn, startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveGuestSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push({
-		title: gettext('Console'),
-		itemId: 'console',
-		iconCls: 'fa fa-terminal',
-		xtype: 'pveNoVncConsole',
-		vmid: vmid,
-		consoleType: 'kvm',
-		nodename: nodename
-	    });
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Hardware'),
-		itemId: 'hardware',
-		iconCls: 'fa fa-desktop',
-		xtype: 'PVE.qemu.HardwareView'
-	    },
-	    {
-		title: 'Cloud-Init',
-		itemId: 'cloudinit',
-		iconCls: 'fa fa-cloud',
-		xtype: 'pveCiPanel'
-	    },
-	    {
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options',
-		xtype: 'PVE.qemu.Options'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		xtype: 'proxmoxNodeTasks',
-		iconCls: 'fa fa-list',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Monitor'] && !template) {
-	    me.items.push({
-		title: gettext('Monitor'),
-		iconCls: 'fa fa-eye',
-		itemId: 'monitor',
-		xtype: 'pveQemuMonitor'
-	    });
-	}
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback'] ||
-	    caps.vms['VM.Audit']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		type: 'qemu',
-		xtype: 'pveGuestSnapshotTree',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	var prevQMPStatus = 'unknown';
-        me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var qmpstatus;
-	    var spice = false;
-	    var xtermjs = false;
-	    var lock;
-
-	    if (!success) {
-		status = qmpstatus = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('qmpstatus');
-		qmpstatus = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-
-		spice = s.data.get('spice') ? true : false;
-		xtermjs = s.data.get('serial') ? true : false;
-
-	    }
-
-	    if (template) {
-		return;
-	    }
-
-	    var resume = (['prelaunch', 'paused', 'suspended'].indexOf(qmpstatus) !== -1);
-
-	    if (resume || lock === 'suspended') {
-		startBtn.setVisible(false);
-		resumeBtn.setVisible(true);
-	    } else {
-		startBtn.setVisible(true);
-		resumeBtn.setVisible(false);
-	    }
-
-	    consoleBtn.setEnableSpice(spice);
-	    consoleBtn.setEnableXtermJS(xtermjs);
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-
-	    let wasStopped = ['prelaunch', 'stopped', 'suspended'].indexOf(prevQMPStatus) !== -1;
-	    if (wasStopped && qmpstatus === 'running') {
-		let con = me.down('#console');
-		if (con) {
-		    con.reload();
-		}
-	    }
-
-	    prevQMPStatus = qmpstatus;
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-   }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    alias: 'widget.pveQemuCreateWizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    current: {
-		scsihw: ''
-	    }
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('Virtual Machine'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'qm_general_settings',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid',
-		    guestType: 'qemu',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'name',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Name'),
-		    allowBlank: true
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		}
-	    ],
-	    advancedColumn1: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'onboot',
-		    uncheckedValue: 0,
-		    defaultValue: 0,
-		    deleteDefaultValue: true,
-		    fieldLabel: gettext('Start at boot')
-		}
-	    ],
-	    advancedColumn2: [
-		{
-		    xtype: 'textfield',
-		    name: 'order',
-		    defaultValue: '',
-		    emptyText: 'any',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Start/Shutdown order')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'up',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Startup delay')
-		},
-		{
-		    xtype: 'textfield',
-		    name: 'down',
-		    defaultValue: '',
-		    emptyText: 'default',
-		    labelWidth: 120,
-		    fieldLabel: gettext('Shutdown timeout')
-		}
-	    ],
-	    onGetValues: function(values) {
-
-		['name', 'pool', 'onboot', 'agent'].forEach(function(field) {
-		    if (!values[field]) {
-			delete values[field];
-		    }
-		});
-
-		var res = PVE.Parser.printStartup({
-		    order: values.order,
-		    up: values.up,
-		    down: values.down
-		});
-
-		if (res) {
-		    values.startup = res;
-		}
-
-		delete values.order;
-		delete values.up;
-		delete values.down;
-
-		return values;
-	    }
-	},
-	{
-	    xtype: 'container',
-	    layout: 'hbox',
-	    defaults: {
-		flex: 1,
-		padding: '0 10'
-	    },
-	    title: gettext('OS'),
-	    items: [
-		{
-		    xtype: 'pveQemuCDInputPanel',
-		    bind: {
-			nodename: '{nodename}'
-		    },
-		    confid: 'ide2',
-		    insideWizard: true
-		},
-		{
-		    xtype: 'pveQemuOSTypePanel',
-		    insideWizard: true
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveQemuSystemPanel',
-	    title: gettext('System'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuHDInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Hard Disk'),
-	    isCreate: true,
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveQemuProcessorPanel',
-	    insideWizard: true,
-	    title: gettext('CPU')
-	},
-	{
-	    xtype: 'pveQemuMemoryPanel',
-	    insideWizard: true,
-	    title: gettext('Memory')
-	},
-	{
-	    xtype: 'pveQemuNetworkInputPanel',
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    title: gettext('Network'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-			    property : 'key',
-			    direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var kv = this.up('window').getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete') { // ignore
-			    return;
-			}
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/qemu',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response){
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-
-Ext.define('PVE.qemu.USBInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    mixins: ['Proxmox.Mixin.CBind' ],
-
-    autoComplete: false,
-    onlineHelp: 'qm_usb_passthrough',
-
-    viewModel: {
-	data: {}
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	if (!me.confid) {
-	    for (let i = 0; i < 6; i++) {
-		let id = 'usb' + i.toString();
-		if (!me.vmconfig[id]) {
-		    me.confid = id;
-		    break;
-		}
-	    }
-	}
-	var val = "";
-	var type = me.down('radiofield').getGroupValue();
-	switch (type) {
-	    case 'spice':
-		val = 'spice';
-		break;
-	    case 'hostdevice':
-	    case 'port':
-		val = 'host=' + values[type];
-		delete values[type];
-		break;
-	    default:
-		throw "invalid type selected";
-	}
-
-	if (values.usb3) {
-	    delete values.usb3;
-	    val += ',usb3=1';
-	}
-	values[me.confid] = val;
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'fieldcontainer',
-	    defaultType: 'radiofield',
-	    layout: 'fit',
-	    items: [
-		{
-		    name: 'usb',
-		    inputValue: 'spice',
-		    boxLabel: gettext('Spice Port'),
-		    submitValue: false,
-		    checked: true
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'hostdevice',
-		    boxLabel: gettext('Use USB Vendor/Device ID'),
-		    reference: 'hostdevice',
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    type: 'device',
-		    name: 'hostdevice',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    bind: { disabled: '{!hostdevice.checked}' },
-		    editable: true,
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Device'),
-		    labelAlign: 'right',
-		},
-		{
-		    name: 'usb',
-		    inputValue: 'port',
-		    boxLabel: gettext('Use USB Port'),
-		    reference: 'port',
-		    submitValue: false
-		},
-		{
-		    xtype: 'pveUSBSelector',
-		    disabled: true,
-		    name: 'port',
-		    cbind: { pveSelNode: '{pveSelNode}' },
-		    bind: { disabled: '{!port.checked}' },
-		    editable: true,
-		    type: 'port',
-		    allowBlank: false,
-		    fieldLabel: gettext('Choose Port'),
-		    labelAlign: 'right',
-		},
-		{
-		    xtype: 'checkbox',
-		    name: 'usb3',
-		    inputValue: true,
-		    checked: true,
-		    reference: 'usb3',
-		    fieldLabel: gettext('Use USB3')
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.USBEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-    width: 400,
-    subject: gettext('USB Device'),
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.USBInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.isCreate) {
-		    return;
-		}
-
-		var data = response.result.data[me.confid].split(',');
-		var port, hostdevice, usb3 = false;
-		var type = 'spice';
-
-		for (let i = 0; i < data.length; i++) {
-		    if (/^(host=)?(0x)?[a-zA-Z0-9]{4}\:(0x)?[a-zA-Z0-9]{4}$/.test(data[i])) {
-			hostdevice = data[i];
-			hostdevice = hostdevice.replace('host=', '').replace('0x','');
-			type = 'hostdevice';
-		    } else if (/^(host=)?(\d+)\-(\d+(\.\d+)*)$/.test(data[i])) {
-			port = data[i];
-			port = port.replace('host=', '');
-			type = 'port';
-		    }
-
-		    if (/^usb3=(1|on|true)$/.test(data[i])) {
-			usb3 = true;
-		    }
-		}
-		var values = {
-		    usb : type,
-		    hostdevice: hostdevice,
-		    port: port,
-		    usb3: usb3
-		};
-
-		ipanel.setValues(values);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.PCIInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    onlineHelp: 'qm_pci_passthrough',
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	me.vmconfig = vmconfig;
-
-	var hostpci = me.vmconfig[me.confid] || '';
-
-	var values = PVE.Parser.parsePropertyString(hostpci, 'host');
-	if (values.host) {
-	    if (!values.host.match(/^[0-9a-f]{4}:/i)) { // add optional domain
-		values.host = "0000:" + values.host;
-	    }
-	    if (values.host.length < 11) { // 0000:00:00 format not 0000:00:00.0
-		values.host += ".0";
-		values.multifunction = true;
-	    }
-	}
-
-	values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
-	values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
-	values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
-
-	me.setValues(values);
-	if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
-	    // machine is not set to some variant of q35, so we disable pcie
-	    var pcie = me.down('field[name=pcie]');
-	    pcie.setDisabled(true);
-	    pcie.setBoxLabel(gettext('Q35 only'));
-	}
-
-	if (values.romfile) {
-	    me.down('field[name=romfile]').setVisible(true);
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-	var ret = {};
-	if(!me.confid) {
-	    var i;
-	    for (i = 0; i < 5; i++) {
-		if (!me.vmconfig['hostpci' +  i.toString()]) {
-		    me.confid = 'hostpci' + i.toString();
-		    break;
-		}
-	    }
-	}
-	// remove optional '0000' domain
-	if (values.host.substring(0,5) === '0000:') {
-	    values.host = values.host.substring(5);
-	}
-	if (values.multifunction) {
-	    // modify host to skip the '.X'
-	    values.host = values.host.substring(0, values.host.indexOf('.'));
-	    delete values.multifunction;
-	}
-
-	if (values.rombar) {
-	    delete values.rombar;
-	} else {
-	    values.rombar = 0;
-	}
-
-	if (!values.romfile) {
-	    delete values.romfile;
-	}
-
-	ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
-	return ret;
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodename = me.pveSelNode.data.node;
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	me.column1 = [
-	    {
-		xtype: 'pvePCISelector',
-		fieldLabel: gettext('Device'),
-		name: 'host',
-		nodename: me.nodename,
-		allowBlank: false,
-		onLoadCallBack: function(store, records, success) {
-		    if (!success || !records.length) {
-			return;
-		    }
-
-		    var first = records[0];
-		    if (first.data.iommugroup === -1) {
-			// no iommu groups
-			var warning = Ext.create('Ext.form.field.Display', {
-			    columnWidth: 1,
-			    padding: '0 0 10 0',
-			    value: 'No IOMMU detected, please activate it.' +
-				   'See Documentation for further information.',
-			    userCls: 'pmx-hint'
-			});
-			me.items.insert(0, warning);
-			me.updateLayout(); // insert does not trigger that
-		    }
-		},
-		listeners: {
-		    change: function(pcisel, value) {
-			if (!value) {
-			    return;
-			}
-			var pcidev = pcisel.getStore().getById(value);
-			var mdevfield = me.down('field[name=mdev]');
-			mdevfield.setDisabled(!pcidev || !pcidev.data.mdev);
-			if (!pcidev) {
-			    return;
-			}
-			var id = pcidev.data.id.substring(0,5); // 00:00
-			var iommu = pcidev.data.iommugroup;
-			// try to find out if there are more devices
-			// in that iommu group
-			if (iommu !== -1) {
-			    var count = 0;
-			    pcisel.getStore().each(function(record) {
-				if (record.data.iommugroup === iommu &&
-				    record.data.id.substring(0,5) !== id)
-				{
-				    count++;
-				    return false;
-				}
-			    });
-			    var warning = me.down('#iommuwarning');
-			    if (count && !warning) {
-				warning = Ext.create('Ext.form.field.Display', {
-				    columnWidth: 1,
-				    padding: '0 0 10 0',
-				    itemId: 'iommuwarning',
-				    value: 'The selected Device is not in a seperate' +
-					   'IOMMU group, make sure this is intended.',
-				    userCls: 'pmx-hint'
-				});
-				me.items.insert(0, warning);
-				me.updateLayout(); // insert does not trigger that
-			    } else if (!count && warning) {
-				me.remove(warning);
-			    }
-			}
-			if (pcidev.data.mdev) {
-			    mdevfield.setPciID(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('All Functions'),
-		name: 'multifunction'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'pveMDevSelector',
-		name: 'mdev',
-		disabled: true,
-		fieldLabel: gettext('MDev Type'),
-		nodename: me.nodename,
-		listeners: {
-		    change: function(field, value) {
-			var mf = me.down('field[name=multifunction]');
-			if (!!value) {
-			    mf.setValue(false);
-			}
-			mf.setDisabled(!!value);
-		    }
-		}
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Primary GPU'),
-		name: 'x-vga'
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'ROM-Bar',
-		name: 'rombar'
-	    },
-	    {
-		xtype: 'displayfield',
-		submitValue: true,
-		hidden: true,
-		fieldLabel: 'ROM-File',
-		name: 'romfile'
-	    }
-	];
-
-	me.advancedColumn2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: 'PCI-Express',
-		name: 'pcie'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.PCIEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('PCI Device'),
-
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.confid;
-
-	var ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
-	    confid: me.confid,
-	    pveSelNode: me.pveSelNode
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.qemu.SerialnputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-
-    autoComplete: false,
-
-    setVMConfig: function(vmconfig) {
-	var me = this, i;
-	me.vmconfig = vmconfig;
-
-	for (i = 0; i < 4; i++) {
-	    var port = 'serial' +  i.toString();
-	    if (!me.vmconfig[port]) {
-		me.down('field[name=serialid]').setValue(i);
-		break;
-	    }
-	}
-
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id = 'serial' + values.serialid;
-	delete values.serialid;
-	values[id] = 'socket';
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'serialid',
-	    fieldLabel: gettext('Serial Port'),
-	    minValue: 0,
-	    maxValue: 3,
-	    allowBlank: false,
-	    validator: function(id) {
-		if (!this.rendered) {
-		    return true;
-		}
-		var me = this.up('panel');
-		if (me.vmconfig !== undefined && Ext.isDefined(me.vmconfig['serial' + id])) {
-			return "This device is already in use.";
-		}
-		return true;
-	    }
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.SerialEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    isAdd: true,
-
-    subject: gettext('Serial Port'),
-
-    initComponent : function() {
-	var me = this;
-
-	// for now create of (socket) serial port only
-	me.isCreate = true;
-
-	var ipanel = Ext.create('PVE.qemu.SerialnputPanel', {});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.window.IPInfo', {
-    extend: 'Ext.window.Window',
-    width: 600,
-    title: gettext('Guest Agent Network Information'),
-    height: 300,
-    layout: {
-	type: 'fit'
-    },
-    modal: true,
-    items: [
-	{
-	    xtype: 'grid',
-	    store: {},
-	    emptyText: gettext('No network information'),
-	    columns: [
-		{
-		    dataIndex: 'name',
-		    text: gettext('Name'),
-		    flex: 3
-		},
-		{
-		    dataIndex: 'hardware-address',
-		    text: gettext('MAC address'),
-		    width: 140
-		},
-		{
-		    dataIndex: 'ip-addresses',
-		    text: gettext('IP address'),
-		    align: 'right',
-		    flex: 4,
-		    renderer: function(val) {
-			if (!Ext.isArray(val)) {
-			    return '';
-			}
-			var ips = [];
-			val.forEach(function(ip) {
-			    var addr = ip['ip-address'];
-			    var pref = ip.prefix;
-			    if  (addr && pref) {
-				ips.push(addr + '/' + pref);
-			    }
-			});
-			return ips.join('<br>');
-		    }
-		}
-	    ]
-	}
-    ]
-});
-
-Ext.define('PVE.qemu.AgentIPView', {
-    extend: 'Ext.container.Container',
-    xtype: 'pveAgentIPView',
-
-    layout: {
-	type: 'hbox',
-	align: 'top'
-    },
-
-    nics: [],
-
-    items: [
-	{
-	    xtype: 'box',
-	    html: '<i class="fa fa-exchange"></i> IPs'
-	},
-	{
-	    xtype: 'container',
-	    flex: 1,
-	    layout: {
-		type: 'vbox',
-		align: 'right',
-		pack: 'end'
-	    },
-	    items: [
-		{
-		    xtype: 'label',
-		    flex: 1,
-		    itemId: 'ipBox',
-		    style: {
-			'text-align': 'right'
-		    }
-		},
-		{
-		    xtype: 'button',
-		    itemId: 'moreBtn',
-		    hidden: true,
-		    ui: 'default-toolbar',
-		    handler: function(btn) {
-			var me = this.up('pveAgentIPView');
-
-			var win = Ext.create('PVE.window.IPInfo');
-			win.down('grid').getStore().setData(me.nics);
-			win.show();
-		    },
-		    text: gettext('More')
-		}
-	    ]
-	}
-    ],
-
-    getDefaultIps: function(nics) {
-	var me = this;
-	var ips = [];
-	nics.forEach(function(nic) {
-	    if (nic['hardware-address'] &&
-		nic['hardware-address'] != '00:00:00:00:00:00') {
-
-		var nic_ips = nic['ip-addresses'] || [];
-		nic_ips.forEach(function(ip) {
-		    var p = ip['ip-address'];
-		    // show 2 ips at maximum
-		    if (ips.length < 2) {
-			ips.push(p);
-		    }
-		});
-	    }
-	});
-
-	return ips;
-    },
-
-    startIPStore: function(store, records, success) {
-	var me = this;
-	let agentRec = store.getById('agent');
-	let state = store.getById('status');
-
-	me.agent = (agentRec && agentRec.data.value === 1);
-	me.running = (state && state.data.value === 'running');
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!caps.vms['VM.Monitor']) {
-	    var errorText = gettext("Requires '{0}' Privileges");
-	    me.updateStatus(false, Ext.String.format(errorText, 'VM.Monitor'));
-	    return;
-	}
-
-	if (me.agent && me.running && me.ipStore.isStopped) {
-	    me.ipStore.startUpdate();
-	} else if (me.ipStore.isStopped) {
-	    me.updateStatus();
-	}
-    },
-
-    updateStatus: function(unsuccessful, defaulttext) {
-	var me = this;
-	var text = defaulttext || gettext('No network information');
-	var more = false;
-	if (unsuccessful) {
-	    text = gettext('Guest Agent not running');
-	} else if (me.agent && me.running) {
-	    if (Ext.isArray(me.nics) && me.nics.length) {
-		more = true;
-		var ips = me.getDefaultIps(me.nics);
-		if (ips.length !== 0) {
-		    text = ips.join('<br>');
-		}
-	    } else if (me.nics && me.nics.error) {
-		var msg = gettext('Cannot get info from Guest Agent<br>Error: {0}');
-		text = Ext.String.format(text, me.nics.error.desc);
-	    }
-	} else if (me.agent) {
-	    text = gettext('Guest Agent not running');
-	} else {
-	    text = gettext('No Guest Agent configured');
-	}
-
-	var ipBox = me.down('#ipBox');
-	ipBox.update(text);
-
-	var moreBtn = me.down('#moreBtn');
-	moreBtn.setVisible(more);
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw 'rstore not given';
-	}
-
-	if (!me.pveSelNode) {
-	    throw 'pveSelNode not given';
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	var vmid = me.pveSelNode.data.vmid;
-
-	me.ipStore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 10000,
-	    storeid: 'pve-qemu-agent-' + vmid,
-	    method: 'POST',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + nodename + '/qemu/' + vmid + '/agent/network-get-interfaces'
-	    }
-	});
-
-	me.callParent();
-
-	me.mon(me.ipStore, 'load', function(store, records, success) {
-	    if (records && records.length) {
-		me.nics = records[0].data.result;
-	    } else {
-		me.nics = undefined;
-	    }
-	    me.updateStatus(!success);
-	});
-
-	me.on('destroy', me.ipStore.stopUpdate);
-
-	// if we already have info about the vm, use it immediately
-	if (me.rstore.getCount()) {
-	    me.startIPStore(me.rstore, me.rstore.getData(), false);
-	}
-
-	// check if the guest agent is there on every statusstore load
-	me.mon(me.rstore, 'load', me.startIPStore, me);
-    }
-});
-Ext.define('PVE.qemu.CloudInit', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    xtype: 'pveCiPanel',
-
-    onlineHelp: 'qm_cloud_init',
-
-    tbar: [
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var me = this.up('grid');
-		var warn = gettext('Are you sure you want to remove entry {0}');
-
-		var entry = rec.data.key;
-		var msg = Ext.String.format(warn, "'"
-		    + me.renderKey(entry, {}, rec) + "'");
-
-		return msg;
-	    },
-	    enableFn: function(record) {
-		var me = this.up('grid');
-		var caps = Ext.state.Manager.get('GuiCap');
-		if (me.rows[record.data.key].never_delete ||
-		    !caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-
-		if (record.data.key === 'cipassword' && !record.data.value) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		var records = me.getSelection();
-		if (!records ||  !records.length) {
-		    return;
-		}
-
-		var id = records[0].data.key;
-		var match = id.match(/^net(\d+)$/);
-		if (match) {
-		    id = 'ipconfig' + match[1];
-		}
-
-		var params = {};
-		params['delete'] = id;
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: params,
-		    failure: function(response, opts) {
-			Ext.Msg.alert('Error', response.htmlStatus);
-		    },
-		    callback: function() {
-			me.reload();
-		    }
-		});
-	    },
-	    text: gettext('Remove')
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    disabled: true,
-	    enableFn: function(rec) {
-		let me = this.up('pveCiPanel');
-		return !!me.rows[rec.data.key].editor;
-	    },
-	    handler: function() {
-		var me = this.up('grid');
-		me.run_editor();
-	    },
-	    text: gettext('Edit')
-	},
-	'-',
-	{
-	    xtype: 'button',
-	    itemId: 'savebtn',
-	    text: gettext('Regenerate Image'),
-	    handler: function() {
-		var me = this.up('grid');
-		var eject_params = {};
-		var insert_params = {};
-		var disk = PVE.Parser.parseQemuDrive(me.ciDriveId, me.ciDrive);
-		var storage = '';
-		var stormatch = disk.file.match(/^([^\:]+)\:/);
-		if (stormatch) {
-		    storage = stormatch[1];
-		}
-		eject_params[me.ciDriveId] = 'none,media=cdrom';
-		insert_params[me.ciDriveId] = storage + ':cloudinit';
-
-		var failure = function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		};
-
-		Proxmox.Utils.API2Request({
-		    url: me.baseurl + '/config',
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: eject_params,
-		    failure: failure,
-		    callback: function() {
-			Proxmox.Utils.API2Request({
-			    url: me.baseurl + '/config',
-			    waitMsgTarget: me,
-			    method: 'PUT',
-			    params: insert_params,
-			    failure: failure,
-			    callback: function() {
-				me.reload();
-			    }
-			});
-		    }
-		});
-	    }
-	}
-    ],
-
-    border: false,
-
-    set_button_status: function(rstore, records, success) {
-	if (!success || records.length < 1) {
-	    return;
-	}
-	var me = this;
-	var found;
-	records.forEach(function(record) {
-	    if (found) {
-		return;
-	    }
-	    var id = record.data.key;
-	    var value = record.data.value;
-	    var ciregex = new RegExp("vm-" + me.pveSelNode.data.vmid + "-cloudinit");
-		if (id.match(/^(ide|scsi|sata)\d+$/) && ciregex.test(value)) {
-		    found = id;
-		    me.ciDriveId = found;
-		    me.ciDrive = value;
-		}
-	});
-
-	me.down('#savebtn').setDisabled(!found);
-	me.setDisabled(!found);
-	if (!found) {
-	    me.getView().mask(gettext('No CloudInit Drive found'), ['pve-static-mask']);
-	} else {
-	    me.getView().unmask();
-	}
-    },
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rows = me.rows;
-	var rowdef = rows[key] || {};
-
-	var icon = "";
-	if (rowdef.iconCls) {
-	    icon = '<i class="' + rowdef.iconCls + '"></i> ';
-	}
-	return icon + (rowdef.header || key);
-    },
-
-    listeners: {
-	activate: function () {
-	    var me = this;
-	    me.rstore.startUpdate();
-	},
-	itemdblclick: function() {
-	    var me = this;
-	    me.run_editor();
-	}
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-	var caps = Ext.state.Manager.get('GuiCap');
-	me.baseurl = '/api2/extjs/nodes/' + nodename + '/qemu/' + vmid;
-	me.url =  me.baseurl + '/pending';
-	me.editorConfig.url = me.baseurl + '/config';
-	me.editorConfig.pveSelNode = me.pveSelNode;
-
-	/*jslint confusion: true*/
-	/* editor is string and object */
-	me.rows = {
-	    ciuser: {
-		header: gettext('User'),
-		iconCls: 'fa fa-user',
-		never_delete: true,
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('User'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.defaultText,
-			    fieldLabel: gettext('User'),
-			    name: 'ciuser'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.defaultText;
-		}
-	    },
-	    cipassword: {
-		header: gettext('Password'),
-		iconCls: 'fa fa-unlock',
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Password'),
-		    items: [
-			{
-			    xtype: 'proxmoxtextfield',
-			    inputType: 'password',
-			    deleteEmpty: true,
-			    emptyText: Proxmox.Utils.noneText,
-			    fieldLabel: gettext('Password'),
-			    name: 'cipassword'
-			}
-		    ]
-		} : undefined,
-		renderer: function(value) {
-		    return value || Proxmox.Utils.noneText;
-		}
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    nameserver: {
-		header: gettext('DNS servers'),
-		iconCls: 'fa fa-globe',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		never_delete: true,
-		defaultValue: gettext('use host settings')
-	    },
-	    sshkeys: {
-		header: gettext('SSH public key'),
-		iconCls: 'fa fa-key',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.SSHKeyEdit' : undefined,
-		never_delete: true,
-		renderer: function(value) {
-		    value = decodeURIComponent(value);
-		    var keys = value.split('\n');
-		    var text = [];
-		    keys.forEach(function(key) {
-			if (key.length) {
-			    // First erase all quoted strings (eg. command="foo"
-			    var v = key.replace(/"(?:\\.|[^"\\])*"/g, '');
-			    // Now try to detect the comment:
-			    var res = v.match(/^\s*(\S+\s+)?(?:ssh-(?:dss|rsa|ed25519)|ecdsa-sha2-nistp\d+)\s+\S+\s+(.*?)\s*$/, '');
-			    if (res) {
-				key = Ext.String.htmlEncode(res[2]);
-				if (res[1]) {
-				    key += ' <span style="color:gray">(' + gettext('with options') + ')</span>';
-				}
-				text.push(key);
-				return;
-			    }
-			    // Most likely invalid at this point, so just stick to
-			    // the old value.
-			    text.push(Ext.String.htmlEncode(key));
-			}
-		    });
-		    if (text.length) {
-			return text.join('<br>');
-		    } else {
-			return Proxmox.Utils.noneText;
-		    }
-		},
-		defaultValue: ''
-	    }
-	};
-	var i;
-	var ipconfig_renderer = function(value, md, record, ri, ci, store, pending) {
-	    var id = record.data.key;
-	    var match = id.match(/^net(\d+)$/);
-	    var val = '';
-	    if (match) {
-		val = me.getObjectValue('ipconfig'+match[1], '', pending);
-	    }
-	    return val;
-	};
-	for (i = 0; i < 32; i++) {
-	    // we want to show an entry for every network device
-	    // even if it is empty
-	    me.rows['net' + i.toString()] = {
-		multiKey: ['ipconfig' + i.toString(), 'net' + i.toString()],
-		header: gettext('IP Config') + ' (net' + i.toString() +')',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.IPConfigEdit' : undefined,
-		iconCls: 'fa fa-exchange',
-		renderer: ipconfig_renderer
-	    };
-	    me.rows['ipconfig' + i.toString()] = {
-		visible: false
-	    };
-	}
-	/*jslint confusion: false*/
-
-	PVE.Utils.forEachBus(['ide', 'scsi', 'sata'], function(type, id) {
-	    me.rows[type+id] = {
-		visible: false
-	    };
-	});
-	me.callParent();
-	me.mon(me.rstore, 'load', me.set_button_status, me);
-    }
-});
-Ext.define('PVE.qemu.CIDriveInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveCIDriveInputPanel',
-
-    insideWizard: false,
-
-    vmconfig: {}, // used to select usused disks
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var drive = {};
-	var params = {};
-	drive.file = values.hdstorage + ":cloudinit";
-	drive.format = values.diskformat;
-	params[values.controller + values.deviceid] = PVE.Parser.printQemuDrive(drive);
-	return params;
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	me.down('#hdstorage').setNodename(nodename);
-	me.down('#hdimage').setStorage(undefined, nodename);
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.down('#drive').setVMConfig(config, 'cdrom');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.drive = {};
-
-	me.items = [
-	    {
-		xtype: 'pveControllerSelector',
-		noVirtIO: true,
-		itemId: 'drive',
-		fieldLabel: gettext('CloudInit Drive'),
-		name: 'drive'
-	    },
-	    {
-		xtype: 'pveDiskStorageSelector',
-		itemId: 'storselector',
-		storageContent: 'images',
-		nodename: me.nodename,
-		hideSize: true
-	    }
-	];
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.CIDriveEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveCIDriveEdit',
-
-    isCreate: true,
-    subject: gettext('CloudInit Drive'),
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.items = [{
-	    xtype: 'pveCIDriveInputPanel',
-	    itemId: 'cipanel',
-	    nodename: nodename
-	}];
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, opts) {
-		me.down('#cipanel').setVMConfig(response.result.data);
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.SSHKeyInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSSHKeyInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-	if (values.sshkeys) {
-	    values.sshkeys.trim();
-	}
-	if (!values.sshkeys.length) {
-	    values = {};
-	    values['delete'] = 'sshkeys';
-	    return values;
-	} else {
-	    values.sshkeys = encodeURIComponent(values.sshkeys);
-	}
-	return values;
-    },
-
-    items: [
-	{
-	    xtype: 'textarea',
-	    itemId: 'sshkeys',
-	    name: 'sshkeys',
-	    height: 250
-	},
-	{
-	    xtype: 'filebutton',
-	    itemId: 'filebutton',
-	    name: 'file',
-	    text: gettext('Load SSH Key File'),
-	    fieldLabel: 'test',
-	    listeners: {
-		change: function(btn, e, value) {
-		    var me = this.up('inputpanel');
-		    e = e.event;
-		    Ext.Array.each(e.target.files, function(file) {
-			PVE.Utils.loadSSHKeyFromFile(file, function(res) {
-			    var keysField = me.down('#sshkeys');
-			    var old = keysField.getValue();
-			    keysField.setValue(old + res);
-			});
-		    });
-		    btn.reset();
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.callParent();
-	if (!window.FileReader) {
-	    me.down('#filebutton').setVisible(false);
-	}
-
-    }
-});
-
-Ext.define('PVE.qemu.SSHKeyEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    width: 800,
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.qemu.SSHKeyInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('SSH Keys'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.create) {
-	    me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (data.sshkeys) {
-			data.sshkeys = decodeURIComponent(data.sshkeys);
-			ipanel.setValues(data);
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.qemu.IPConfigPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveIPConfigPanel',
-
-    insideWizard: false,
-
-    vmconfig: {},
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-
-	var params = {};
-
-	var cfg = PVE.Parser.printIPConfig(values);
-	if (cfg === '') {
-	    params['delete'] = [me.confid];
-	} else {
-	    params[me.confid] = cfg;
-	}
-	return params;
-    },
-
-    setVMConfig: function(config) {
-	var me = this;
-	me.vmconfig = config;
-    },
-
-    setIPConfig: function(confid, data) {
-	var me = this;
-
-	me.confid = confid;
-
-	if (data.ip === 'dhcp') {
-	    data.ipv4mode = data.ip;
-	    data.ip = '';
-	} else {
-	    data.ipv4mode = 'static';
-	}
-	if (data.ip6 === 'dhcp' || data.ip6 === 'auto') {
-	    data.ipv6mode = data.ip6;
-	    data.ip6 = '';
-	} else {
-	    data.ipv6mode = 'static';
-	}
-
-	me.ipconfig = data;
-	me.setValues(me.ipconfig);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.ipconfig = {};
-
-	me.column1 = [
-	    {
-		xtype: 'displayfield',
-		fieldLabel: gettext('Network Device'),
-		value: me.netid
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv4') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('IPv4/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: '',
-		vtype: 'IPAddress',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv4') +')'
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'displayfield'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: gettext('IPv6') + ':'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: false,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('DHCP'),
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: false,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: '',
-		vtype: 'IP6CIDRAddress',
-		disabled: true,
-		fieldLabel: gettext('IPv6/CIDR')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: '',
-		disabled: true,
-		fieldLabel: gettext('Gateway') + ' (' + gettext('IPv6') +')'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.qemu.IPConfigEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-
-	var me = this;
-
-	// convert confid from netX to ipconfigX
-	var match = me.confid.match(/^net(\d+)$/);
-	if (match) {
-	    me.netid = me.confid;
-	    me.confid = 'ipconfig' + match[1];
-	}
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	me.isCreate = me.confid ? false : true;
-
-	var ipanel = Ext.create('PVE.qemu.IPConfigPanel', {
-	    confid: me.confid,
-	    netid: me.netid,
-	    nodename: nodename
-	});
-
-	Ext.applyIf(me, {
-	    subject: gettext('Network Config'),
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		me.vmconfig = response.result.data;
-		var ipconfig = {};
-		var value = me.vmconfig[me.confid];
-		if (value) {
-		    ipconfig = PVE.Parser.parseIPConfig(me.confid, value);
-		    if (!ipconfig) {
-			Ext.Msg.alert(gettext('Error'), gettext('Unable to parse network configuration'));
-			me.close();
-			return;
-		    }
-		}
-		ipanel.setIPConfig(me.confid, ipconfig);
-		ipanel.setVMConfig(me.vmconfig);
-	    }
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.qemu.SystemInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveQemuSystemPanel',
-
-    onlineHelp: 'qm_system_settings',
-
-    viewModel: {
-	data: {
-	    efi: false,
-	    addefi: true
-	},
-
-	formulas: {
-	    efidisk: function(get) {
-		return get('efi') && get('addefi');
-	    }
-	}
-    },
-
-    onGetValues: function(values) {
-	if (values.vga && values.vga.substr(0,6) === 'serial') {
-	    values['serial' + values.vga.substr(6,1)] = 'socket';
-	}
-
-	var efidrive = {};
-	if (values.hdimage) {
-	    efidrive.file = values.hdimage;
-	} else if (values.hdstorage) {
-	    efidrive.file = values.hdstorage + ":1";
-	}
-
-	if (values.diskformat) {
-	    efidrive.format = values.diskformat;
-	}
-
-	delete values.hdimage;
-	delete values.hdstorage;
-	delete values.diskformat;
-
-	if (efidrive.file) {
-	    values.efidisk0 = PVE.Parser.printQemuDrive(efidrive);
-	}
-
-	return values;
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	scsihwChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('current.scsihw', value);
-	    }
-	},
-
-	biosChange: function(field, value) {
-	    var me = this;
-	    if (me.getView().insideWizard) {
-		me.getViewModel().set('efi', value === 'ovmf');
-	    }
-	},
-
-	control: {
-	    'pveScsiHwSelector': {
-		change: 'scsihwChange'
-	    },
-	    'pveQemuBiosSelector': {
-		change: 'biosChange'
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    value: '__default__',
-	    deleteEmpty: false,
-	    fieldLabel: gettext('Graphic card'),
-	    name: 'vga',
-	    comboItems: PVE.Utils.kvm_vga_driver_array()
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'agent',
-	    uncheckedValue: 0,
-	    defaultValue: 0,
-	    deleteDefaultValue: true,
-	    fieldLabel: gettext('Qemu Agent')
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'pveScsiHwSelector',
-	    name: 'scsihw',
-	    value: '__default__',
-	    bind: {
-		value: '{current.scsihw}'
-	    },
-	    fieldLabel: gettext('SCSI Controller')
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'pveQemuBiosSelector',
-	    name: 'bios',
-	    value: '__default__',
-	    fieldLabel: 'BIOS'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    bind: {
-		value: '{addefi}',
-		hidden: '{!efi}',
-		disabled: '{!efi}'
-	    },
-	    hidden: true,
-	    submitValue: false,
-	    disabled: true,
-	    fieldLabel: gettext('Add EFI Disk')
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    name: 'efidisk0',
-	    storageContent: 'images',
-	    bind: {
-		nodename: '{nodename}',
-		hidden: '{!efi}',
-		disabled: '{!efidisk}'
-	    },
-	    autoSelect: false,
-	    disabled: true,
-	    hidden: true,
-	    hideSize: true
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'machine',
-	    value: '__default__',
-	    fieldLabel: gettext('Machine'),
-	    comboItems: [
-		['__default__', PVE.Utils.render_qemu_machine('')],
-		['q35', 'q35']
-	    ]
-	}
-    ]
-
-});
-Ext.define('PVE.qemu.AudioInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveAudioInputPanel',
-
-    // FIXME: enable once we bumped doc-gen so this ref is included
-    //onlineHelp: 'qm_audio_device',
-
-    onGetValues: function(values) {
-	var ret = PVE.Parser.printPropertyString(values);
-	if (ret === '') {
-	    return {
-		'delete': 'audio0'
-	    };
-	}
-	return {
-	    audio0: ret
-	};
-    },
-
-    items: [{
-	name: 'device',
-	xtype: 'proxmoxKVComboBox',
-	value: 'ich9-intel-hda',
-	fieldLabel: gettext('Audio Device'),
-	comboItems: [
-	    ['ich9-intel-hda', 'ich9-intel-hda'],
-	    ['intel-hda', 'intel-hda'],
-	    ['AC97', 'AC97']
-	]
-    }, {
-	name: 'driver',
-	xtype: 'displayfield',
-	value: 'spice',
-	submitValue: true,
-	fieldLabel: gettext('Backend Driver'),
-    }]
-});
-
-Ext.define('PVE.qemu.AudioEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmconfig: undefined,
-
-    subject: gettext('Audio Device'),
-
-    items: [{
-	xtype: 'pveAudioInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	me.load({
-	    success: function(response) {
-		me.vmconfig = response.result.data;
-
-		var audio0 = me.vmconfig.audio0;
-		if (audio0) {
-		    me.setValues(PVE.Parser.parsePropertyString(audio0));
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.qemu.RNGInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveRNGInputPanel',
-
-    // FIXME: enable once we bumped doc-gen so this ref is included
-    //onlineHelp: 'qm_virtio_rng',
-
-    onGetValues: function(values) {
-	if (values.max_bytes === "") {
-	    values.max_bytes = "0";
-	} else if (values.max_bytes === "1024" && values.period === "") {
-	    delete values.max_bytes;
-	}
-
-	var ret = PVE.Parser.printPropertyString(values);
-
-	return {
-	    rng0: ret
-	};
-    },
-
-    setValues: function(values) {
-	if (values.max_bytes == 0) {
-	    values.max_bytes = null;
-	}
-
-	this.callParent(arguments);
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#max_bytes': {
-		change: function(el, newVal) {
-		    let limitWarning = this.lookupReference('limitWarning');
-		    limitWarning.setHidden(!!newVal);
-		}
-	    },
-	    '#source': {
-		change: function(el, newVal) {
-		    let limitWarning = this.lookupReference('sourceWarning');
-		    limitWarning.setHidden(newVal !== '/dev/random');
-		}
-	    }
-	}
-    },
-
-    items: [{
-	itemId: 'source',
-	name: 'source',
-	xtype: 'proxmoxKVComboBox',
-	value: '/dev/urandom',
-	fieldLabel: gettext('Entropy source'),
-	labelWidth: 130,
-	comboItems: [
-	    ['/dev/urandom', '/dev/urandom'],
-	    ['/dev/random', '/dev/random'],
-	    ['/dev/hwrng', '/dev/hwrng']
-	]
-    },
-    {
-	xtype: 'numberfield',
-	itemId: 'max_bytes',
-	name: 'max_bytes',
-	minValue: 0,
-	step: 1,
-	value: 1024,
-	fieldLabel: gettext('Limit (Bytes/Period)'),
-	labelWidth: 130,
-	emptyText: gettext('unlimited')
-    },
-    {
-	xtype: 'numberfield',
-	name: 'period',
-	minValue: 1,
-	step: 1,
-	fieldLabel: gettext('Period') + ' (ms)',
-	labelWidth: 130,
-	emptyText: gettext('1000')
-    },
-    {
-	xtype: 'displayfield',
-	reference: 'sourceWarning',
-	value: gettext('Using /dev/random as entropy source is discouraged, as it can lead to host entropy starvation. /dev/urandom is preferred, and does not lead to a decrease in security in practice.'),
-	userCls: 'pmx-hint',
-	hidden: true
-    },
-    {
-	xtype: 'displayfield',
-	reference: 'limitWarning',
-	value: gettext('Disabling the limiter can potentially allow a guest to overload the host. Proceed with caution.'),
-	userCls: 'pmx-hint',
-	hidden: true
-    }]
-});
-
-Ext.define('PVE.qemu.RNGEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    subject: gettext('VirtIO RNG'),
-
-    items: [{
-	xtype: 'pveRNGInputPanel'
-    }],
-
-    initComponent : function() {
-	var me = this;
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    me.vmconfig = response.result.data;
-
-		    var rng0 = me.vmconfig.rng0;
-		    if (rng0) {
-			me.setValues(PVE.Parser.parsePropertyString(rng0));
-		    }
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.lxc.NetworkInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcNetworkInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_network',
-
-    setNodename: function(nodename) {
-	var me = this;
-
-	if (!nodename || (me.nodename === nodename)) {
-	    return;
-	}
-
-	me.nodename = nodename;
-
-	var bridgesel = me.query("[isFormField][name=bridge]")[0];
-	bridgesel.setNodename(nodename);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var id;
-	if (me.isCreate) {
-	    id = values.id;
-	    delete values.id;
-	} else {
-	    id = me.ifname;
-	}
-
-	if (!id) {
-	    return {};
-	}
-
-	var newdata = {};
-
-	if (values.ipv6mode !== 'static') {
-	    values.ip6 = values.ipv6mode;
-	}
-	if (values.ipv4mode !== 'static') {
-	    values.ip = values.ipv4mode;
-	}
-	newdata[id] = PVE.Parser.printLxcNetwork(values);
-	return newdata;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var cdata = {};
-
-	if (me.insideWizard) {
-	    me.ifname = 'net0';
-	    cdata.name = 'eth0';
-	    me.dataCache = {};
-	}
-	cdata.firewall =  (me.insideWizard || me.isCreate);
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.isCreate) {
-	    if (!me.ifname) {
-		throw "no interface name specified";
-	    }
-	    if (!me.dataCache[me.ifname]) {
-		throw "no such interface '" + me.ifname + "'";
-	    }
-
-	    cdata = PVE.Parser.parseLxcNetwork(me.dataCache[me.ifname]);
-	}
-
-	var i;
-	for (i = 0; i < 10; i++) {
-	    if (me.isCreate && !me.dataCache['net'+i.toString()]) {
-		me.ifname = 'net' + i.toString();
-		break;
-	    }
-	}
-
-	var idselector = {
-	    xtype: 'hidden',
-	    name: 'id',
-	    value: me.ifname
-	};
-
-	me.column1 = [
-	    idselector,
-	    {
-		xtype: 'textfield',
-		name: 'name',
-		fieldLabel: gettext('Name'),
-		emptyText: '(e.g., eth0)',
-		allowBlank: false,
-		value: cdata.name,
-		validator: function(value) {
-		    var result = '';
-		    Ext.Object.each(me.dataCache, function(key, netstr) {
-			if (!key.match(/^net\d+/) || key === me.ifname) {
-			    return; // continue
-			}
-			var net = PVE.Parser.parseLxcNetwork(netstr);
-			if (net.name === value) {
-			    result = "interface name already in use";
-			    return false;
-			}
-		    });
-		    if (result !== '') {
-			return result;
-		    }
-		    // validator can return bool/string
-		    /*jslint confusion:true*/
-		    return true;
-		}
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'hwaddr',
-		fieldLabel: gettext('MAC address'),
-		vtype: 'MacAddress',
-		value: cdata.hwaddr,
-		allowBlank: true,
-		emptyText: 'auto'
-	    },
-	    {
-		xtype: 'PVE.form.BridgeSelector',
-		name: 'bridge',
-		nodename: me.nodename,
-		fieldLabel: gettext('Bridge'),
-		value: cdata.bridge,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveVlanField',
-		name: 'tag',
-		value: cdata.tag
-	    },
-	    {
-		xtype: 'numberfield',
-		name: 'rate',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		minValue: 0,
-		maxValue: 10*1024,
-		value: cdata.rate,
-		emptyText: 'unlimited',
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Firewall'),
-		name: 'firewall',
-		value: cdata.firewall
-	    }
-	];
-
-	var dhcp4 = (cdata.ip === 'dhcp');
-	if (dhcp4) {
-	    cdata.ip = '';
-	    cdata.gw = '';
-	}
-
-	var auto6 = (cdata.ip6 === 'auto');
-	var dhcp6 = (cdata.ip6 === 'dhcp');
-	if (auto6 || dhcp6) {
-	    cdata.ip6 = '';
-	    cdata.gw6 = '';
-	}
-	
-	me.column2 = [
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv4:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv4mode',
-			inputValue: 'static',
-			checked: !dhcp4,
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip]').setEmptyText(
-				    !!value ? Proxmox.Utils.NoneText : ""
-				);
-				me.down('field[name=ip]').setDisabled(!value);
-				me.down('field[name=gw]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv4mode',
-			inputValue: 'dhcp',
-			checked: dhcp4,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip',
-		vtype: 'IPCIDRAddress',
-		value: cdata.ip,
-		emptyText: dhcp4 ? '' : Proxmox.Utils.NoneText,
-		disabled: dhcp4,
-		fieldLabel: 'IPv4/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw',
-		value: cdata.gw,
-		vtype: 'IPAddress',
-		disabled: dhcp4,
-		fieldLabel: gettext('Gateway') + ' (IPv4)',
-		margin: '0 0 3 0' // override bottom margin to account for the menuseparator
-	    },
-	    {
-		xtype: 'menuseparator',
-		height: '3',
-		margin: '0'
-	    },
-	    {
-		layout: {
-		    type: 'hbox',
-		    align: 'middle'
-		},
-		border: false,
-		margin: '0 0 5 0',
-		items: [
-		    {
-			xtype: 'label',
-			text: 'IPv6:' // do not localize
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: gettext('Static'),
-			name: 'ipv6mode',
-			inputValue: 'static',
-			checked: !(auto6 || dhcp6),
-			margin: '0 0 0 10',
-			listeners: {
-			    change: function(cb, value) {
-				me.down('field[name=ip6]').setEmptyText(
-				    !!value ? Proxmox.Utils.NoneText : ""
-				);
-				me.down('field[name=ip6]').setDisabled(!value);
-				me.down('field[name=gw6]').setDisabled(!value);
-			    }
-			}
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'DHCP', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'dhcp',
-			checked: dhcp6,
-			margin: '0 0 0 10'
-		    },
-		    {
-			xtype: 'radiofield',
-			boxLabel: 'SLAAC', // do not localize
-			name: 'ipv6mode',
-			inputValue: 'auto',
-			checked: auto6,
-			margin: '0 0 0 10'
-		    }
-		]
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'ip6',
-		value: cdata.ip6,
-		emptyText: dhcp6 || auto6 ? '' : Proxmox.Utils.NoneText,
-		vtype: 'IP6CIDRAddress',
-		disabled: (dhcp6 || auto6),
-		fieldLabel: 'IPv6/CIDR' // do not localize
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'gw6',
-		vtype: 'IP6Address',
-		value: cdata.gw6,
-		disabled: (dhcp6 || auto6),
-		fieldLabel: gettext('Gateway') + ' (IPv6)'
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    isAdd: true,
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.dataCache) {
-	    throw "no dataCache specified";
-	}
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var ipanel = Ext.create('PVE.lxc.NetworkInputPanel', {
-	    ifname: me.ifname,
-	    nodename: me.nodename,
-	    dataCache: me.dataCache,
-	    isCreate: me.isCreate
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Network Device') + ' (veth)',
-	    digest: me.dataCache.digest,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.NetworkView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveLxcNetworkView',
-
-    onlineHelp: 'pct_container_network',
-
-    dataCache: {}, // used to store result of last load
-
-    stateful: true,
-    stateId: 'grid-lxc-network',
-
-    load: function() {
-	var me = this;
-
-	Proxmox.Utils.setErrorMask(me, true);
-
-	Proxmox.Utils.API2Request({
-	    url: me.url,
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, gettext('Error') + ': ' + response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		me.dataCache = data;
-		var records = [];
-		Ext.Object.each(data, function(key, value) {
-		    if (!key.match(/^net\d+/)) {
-			return; // continue
-		    }
-		    var net = PVE.Parser.parseLxcNetwork(value);
-		    net.id = key;
-		    records.push(net);
-		});
-		me.store.loadData(records);
-		me.down('button[name=addButton]').setDisabled((records.length >= 10));
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.url = '/nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var store = new Ext.data.Store({
-	    model: 'pve-lxc-network',
-	    sorters: [
-		{
-		    property : 'id',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !!caps.vms['VM.Config.Network'];
-	    },
-	    confirmMsg: function (rec) {
-		return Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					 "'" + rec.data.id + "'");
-	    },
-	    handler: function(btn, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: me.url,
-		    waitMsgTarget: me,
-		    method: 'PUT',
-		    params: { 'delete': rec.data.id,  digest: me.dataCache.digest },
-		    callback: function() {
-			me.load();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!caps.vms['VM.Config.Network']) {
-		return false;
-	    }
-
-	    var win = Ext.create('PVE.lxc.NetworkEdit', {
-		url: me.url,
-		nodename: nodename,
-		dataCache: me.dataCache,
-		ifname: rec.data.id
-	    });
-	    win.on('destroy', me.load, me);
-	    win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: sm,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!caps.vms['VM.Config.Network']) {
-		    return false;
-		}
-		return true;
-	    },
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    name: 'addButton',
-		    disabled: !caps.vms['VM.Config.Network'],
-		    handler: function() {
-			var win = Ext.create('PVE.lxc.NetworkEdit', {
-			    url: me.url,
-			    nodename: nodename,
-			    isCreate: true,
-			    dataCache: me.dataCache
-			});
-			win.on('destroy', me.load, me);
-			win.show();
-		    }
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 50,
-		    dataIndex: 'id'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 80,
-		    dataIndex: 'name'
-		},
-		{
-		    header: gettext('Bridge'),
-		    width: 80,
-		    dataIndex: 'bridge'
-		},
-		{
-		    header: gettext('Firewall'),
-		    width: 80,
-		    dataIndex: 'firewall',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('VLAN Tag'),
-		    width: 80,
-		    dataIndex: 'tag'
-		},
-		{
-		    header: gettext('MAC address'),
-		    width: 110,
-		    dataIndex: 'hwaddr'
-		},
-		{
-		    header: gettext('IP address'),
-		    width: 150,
-		    dataIndex: 'ip',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.ip && rec.data.ip6) {
-			    return rec.data.ip + "<br>" + rec.data.ip6;
-			} else if (rec.data.ip6) {
-			    return rec.data.ip6;
-			} else {
-			    return rec.data.ip;
-			}
-		    }
-		},
-		{
-		    header: gettext('Gateway'),
-		    width: 150,
-		    dataIndex: 'gw',
-		    renderer: function(value, metaData, rec) {
-			if (rec.data.gw && rec.data.gw6) {
-			    return rec.data.gw + "<br>" + rec.data.gw6;
-			} else if (rec.data.gw6) {
-			    return rec.data.gw6;
-			} else {
-			    return rec.data.gw;
-			}
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: me.load,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-   }
-}, function() {
-
-    Ext.define('pve-lxc-network', {
-	extend: "Ext.data.Model",
-	proxy: { type: 'memory' },
-	fields: [ 'id', 'name', 'hwaddr', 'bridge',
-		  'ip', 'gw', 'ip6', 'gw6', 'tag', 'firewall' ]
-    });
-
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.RessourceView', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.pveLxcRessourceView'],
-
-    onlineHelp: 'pct_configuration',
-
-    renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
-	var me = this;
-	var rowdef = me.rows[key] || {};
-
-	metaData.tdAttr = "valign=middle";
-	if (rowdef.tdCls) {
-	    metaData.tdCls = rowdef.tdCls;
-	}
-	return rowdef.header || key;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var i, confid;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) { 
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-	var diskCap = caps.vms['VM.Config.Disk'];
-
-	var mpeditor = caps.vms['VM.Config.Disk'] ? 'PVE.lxc.MountPointEdit' : undefined;
-
-	var rows = {
-	    memory: {
-		header: gettext('Memory'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-memory',
-		group: 1,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    swap: {
-		header: gettext('Swap'),
-		editor: caps.vms['VM.Config.Memory'] ? 'PVE.lxc.MemoryEdit' : undefined,
-		defaultValue: 512,
-		tdCls: 'pve-itype-icon-swap',
-		group: 2,
-		renderer: function(value) {
-		    return Proxmox.Utils.format_size(value*1024*1024);
-		}
-	    },
-	    cores: {
-		header: gettext('Cores'),
-		editor: caps.vms['VM.Config.CPU'] ? 'PVE.lxc.CPUEdit' : undefined,
-		defaultValue: '',
-		tdCls: 'pve-itype-icon-processor',
-		group: 3,
-		renderer: function(value) {
-		    var cpulimit = me.getObjectValue('cpulimit');
-		    var cpuunits = me.getObjectValue('cpuunits');
-		    var res;
-		    if (value) {
-			res = value;
-		    } else {
-			res = gettext('unlimited');
-		    }
-
-		    if (cpulimit) {
-			res += ' [cpulimit=' + cpulimit + ']';
-		    }
-
-		    if (cpuunits) {
-			res += ' [cpuunits=' + cpuunits + ']';
-		    }
-		    return res;
-		}
-	    },
-	    rootfs: {
-		header: gettext('Root Disk'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: mpeditor,
-		tdCls: 'pve-itype-icon-storage',
-		group: 4
-	    },
-	    cpulimit: {
-		visible: false
-	    },
-	    cpuunits: {
-		visible: false
-	    },
-	    unprivileged: {
-		visible: false
-	    }
-	};
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    confid = bus + i;
-	    var group = 5;
-	    var header;
-	    if (bus === 'mp') {
-		header = gettext('Mount Point') + ' (' + confid + ')';
-	    } else {
-		header = gettext('Unused Disk') + ' ' + i;
-		group += 1;
-	    }
-	    rows[confid] = {
-		group: group,
-		order: i,
-		tdCls: 'pve-itype-icon-storage',
-		editor: mpeditor,
-		header: header
-	    };
-	}, true);
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	var run_resize = function() {
-	    var rec = me.selModel.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.MPResize', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid
-	    });
-
-	    win.show();
-	};
-
-	var run_remove = function(b, e, rec) {
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/' + baseurl,
-		waitMsgTarget: me,
-		method: 'PUT',
-		params: {
-		    'delete': rec.data.key
-		},
-		failure: function (response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var run_move = function(b, e, rec) {
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.window.HDMove', {
-		disk: rec.data.key,
-		nodename: nodename,
-		vmid: vmid,
-		type: 'lxc'
-	    });
-
-	    win.show();
-
-	    win.on('destroy', me.reload, me);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    enableFn: function(rec) {
-		if (!rec) {
-		    return false;
-		}
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var resize_btn = new Proxmox.button.Button({
-	    text: gettext('Resize disk'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    handler: run_resize
-	});
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    confirmMsg: function(rec) {
-		var msg = Ext.String.format(gettext('Are you sure you want to remove entry {0}'),
-					    "'" + me.renderKey(rec.data.key, {}, rec) + "'");
-		if (rec.data.key.match(/^unused\d+$/)) {
-		    msg += " " + gettext('This will permanently erase all data.');
-		}
-
-		return msg;
-	    },
-	    handler: run_remove
-	});
-
-	var move_btn = new Proxmox.button.Button({
-	    text: gettext('Move Volume'),
-	    selModel: me.selModel,
-	    disabled: true,
-	    dangerous: true,
-	    handler: run_move
-	});
-
-	var revert_btn = new PVE.button.PendingRevert();
-
-	var set_button_status = function() {
-	    var rec = me.selModel.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		remove_btn.disable();
-		resize_btn.disable();
-		revert_btn.disable();
-		return;
-	    }
-	    var key = rec.data.key;
-	    var value = rec.data.value;
-	    var rowdef = rows[key];
-
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var isDisk = (rowdef.tdCls == 'pve-itype-icon-storage');
-	    var isUnusedDisk = key.match(/^unused\d+/);
-
-	    var noedit = rec.data['delete'] || !rowdef.editor;
-	    if (!noedit && Proxmox.UserName !== 'root@pam' && key.match(/^mp\d+$/)) {
-		var mp = PVE.Parser.parseLxcMountPoint(value);
-		if (mp.type !== 'volume') {
-		    noedit = true;
-		}
-	    }
-	    edit_btn.setDisabled(noedit);
-
-	    remove_btn.setDisabled(!isDisk || rec.data.key === 'rootfs' || !diskCap || pending);
-	    resize_btn.setDisabled(!isDisk || !diskCap || isUnusedDisk);
-	    move_btn.setDisabled(!isDisk || !diskCap);
-	    revert_btn.setDisabled(!pending);
-
-	};
-	
-	var sorterFn = function(rec1, rec2) {
-	    var v1 = rec1.data.key;
-	    var v2 = rec2.data.key;
-	    var g1 = rows[v1].group || 0;
-	    var g2 = rows[v2].group || 0;
-	    var order1 = rows[v1].order || 0;
-	    var order2 = rows[v2].order || 0;
-
-	    if ((g1 - g2) !== 0) {
-		return g1 - g2;
-	    }
-
-	    if ((order1 - order2) !== 0) {
-		return order1 - order2;
-	    }
-
-	    if (v1 > v2) {
-		return 1;
-	    } else if (v1 < v2) {
-	        return -1;
-	    } else {
-		return 0;
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/pending",
-	    selModel: me.selModel,
-	    interval: 2000,
-	    cwidth1: 170,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: [
-			    {
-				text: gettext('Mount Point'),
-				iconCls: 'pve-itype-icon-storage',
-				disabled: !caps.vms['VM.Config.Disk'],
-				handler: function() {
-				    var win = Ext.create('PVE.lxc.MountPointEdit', {
-					url: '/api2/extjs/' + baseurl,
-					unprivileged: me.getObjectValue('unprivileged'),
-					pveSelNode: me.pveSelNode
-				    });
-				    win.on('destroy', me.reload, me);
-				    win.show();
-				}
-			    }
-			]
-		    })
-		},
-		edit_btn,
-		remove_btn,
-		resize_btn,
-		move_btn,
-		revert_btn
-	    ],
-	    rows: rows,
-	    sorterFn: sorterFn,
-	    editorConfig: {
-		pveSelNode: me.pveSelNode,
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.mon(me.getStore(), 'datachanged', function() {
-	    set_button_status();
-	});
-
-	Ext.apply(me.editorConfig, { unprivileged: me.getObjectValue('unprivileged') });
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.FeaturesInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcFeaturesInputPanel',
-
-    // used to save the mounts fstypes until sending
-    mounts: [],
-
-    fstypes: ['nfs', 'cifs'],
-
-    viewModel: {
-	parent: null,
-	data: {
-	    unprivileged: false
-	},
-	formulas: {
-	    privilegedOnly: function(get) {
-		return (get('unprivileged') ? gettext('privileged only') : '');
-	    },
-	    unprivilegedOnly: function(get) {
-		return (!get('unprivileged') ? gettext('unprivileged only') : '');
-	    }
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('keyctl'),
-	    name: 'keyctl',
-	    bind: {
-		disabled: '{!unprivileged}',
-		boxLabel: '{unprivilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    fieldLabel: gettext('Nesting'),
-	    name: 'nesting'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'nfs',
-	    fieldLabel: 'NFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'cifs',
-	    fieldLabel: 'CIFS',
-	    bind: {
-		disabled: '{unprivileged}',
-		boxLabel: '{privilegedOnly}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'fuse',
-	    fieldLabel: 'FUSE'
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'mknod',
-	    fieldLabel: gettext('Create Device Nodes'),
-	    boxLabel: gettext('Experimental'),
-	},
-    ],
-
-    onGetValues: function(values) {
-	var me = this;
-	var mounts = me.mounts;
-	me.fstypes.forEach(function(fs) {
-	    if (values[fs]) {
-		mounts.push(fs);
-	    }
-	    delete values[fs];
-	});
-
-	if (mounts.length) {
-	    values.mount = mounts.join(';');
-	}
-
-	var featuresstring = PVE.Parser.printPropertyString(values, undefined);
-	if (featuresstring == '') {
-	    return { 'delete': 'features' };
-	}
-	return { features: featuresstring };
-    },
-
-    setValues: function(values) {
-	var me = this;
-
-	me.viewModel.set('unprivileged', values.unprivileged);
-
-	if (values.features) {
-	    var res = PVE.Parser.parsePropertyString(values.features);
-	    me.mounts = [];
-	    if (res.mount) {
-		res.mount.split(/[; ]/).forEach(function(item) {
-		    if (me.fstypes.indexOf(item) === -1) {
-			me.mounts.push(item);
-		    } else {
-			res[item] = 1;
-		    }
-		});
-	    }
-	    this.callParent([res]);
-	}
-    }
-});
-
-Ext.define('PVE.lxc.FeaturesEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveLxcFeaturesEdit',
-
-    subject: gettext('Features'),
-    autoLoad: true,
-    width: 350,
-
-    items: [{
-	xtype: 'pveLxcFeaturesInputPanel'
-    }],
-});
-/*jslint confusion: true */
-Ext.define('PVE.lxc.Options', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.pveLxcOptions'],
-
-    onlineHelp: 'pct_options',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    onboot: {
-		header: gettext('Start at boot'),
-		defaultValue: '',
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Start at boot'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'onboot',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			fieldLabel: gettext('Start at boot')
-		    }
-		} : undefined
-	    },
-	    startup: {
-		header: gettext('Start/Shutdown order'),
-		defaultValue: '',
-		renderer: PVE.Utils.render_kvm_startup,
-		editor: caps.vms['VM.Config.Options'] && caps.nodes['Sys.Modify'] ? 
-		    {
-			xtype: 'pveWindowStartupEdit',
-			onlineHelp: 'pct_startup_and_shutdown'
-		    } : undefined
-	    },
-	    ostype: {
-		header: gettext('OS Type'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    arch: {
-		header: gettext('Architecture'),
-		defaultValue: Proxmox.Utils.unknownText
-	    },
-	    console: {
-		header: '/dev/console',
-		defaultValue: 1,
-		renderer: Proxmox.Utils.format_enabled_toggle,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: '/dev/console',
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'console',
-			uncheckedValue: 0,
-			defaultValue: 1,
-			deleteDefaultValue: true,
-			checked: true,
-			fieldLabel: '/dev/console'
-		    }
-		} : undefined
-	    },
-	    tty: {
-		header: gettext('TTY count'),
-		defaultValue: 2,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('TTY count'),
-		    items: {
-			xtype: 'proxmoxintegerfield',
-			name: 'tty',
-			minValue: 0,
-			maxValue: 6,
-			value: 2,
-			fieldLabel: gettext('TTY count'),
-			emptyText: gettext('Default'),
-			deleteEmpty: true
-		    }
-		} : undefined
-	    },
-	    cmode: {
-		header: gettext('Console mode'),
-		defaultValue: 'tty',
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Console mode'),
-		    items: {
-			xtype: 'proxmoxKVComboBox',
-			name: 'cmode',
-			deleteEmpty: true,
-			value: '__default__',
-			comboItems: [
-			    ['__default__', Proxmox.Utils.defaultText + " (tty)"],
-			    ['tty', "/dev/tty[X]"],
-			    ['console', "/dev/console"],
-			    ['shell', "shell"]
-			],
-			fieldLabel: gettext('Console mode')
-		    }
-		} : undefined
-	    },
-	    protection: {
-		header: gettext('Protection'),
-		defaultValue: false,
-		renderer: Proxmox.Utils.format_boolean,
-		editor: caps.vms['VM.Config.Options'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Protection'),
-		    items: {
-			xtype: 'proxmoxcheckbox',
-			name: 'protection',
-			uncheckedValue: 0,
-			defaultValue: 0,
-			deleteDefaultValue: true,
-			fieldLabel: gettext('Enabled')
-		    }
-		} : undefined
-	    },
-	    unprivileged: {
-		header: gettext('Unprivileged container'),
-		renderer: Proxmox.Utils.format_boolean,
-		defaultValue: 0
-	    },
-	    features: {
-		header: gettext('Features'),
-		defaultValue: Proxmox.Utils.noneText,
-		editor: Proxmox.UserName === 'root@pam' ?
-		    'PVE.lxc.FeaturesEdit' : undefined
-	    },
-	    hookscript: {
-		header: gettext('Hookscript')
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: function() { me.run_editor(); }
-	});
-
-	var revert_btn = new PVE.button.PendingRevert();
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-
-	    var key = rec.data.key;
-	    var pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    var rowdef = rows[key];
-
-	    edit_btn.setDisabled(!rowdef.editor);
-	    revert_btn.setDisabled(!pending);
-	};
-
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/pending",
-	    selModel: sm,
-	    interval: 5000,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: '/api2/extjs/' + baseurl
-	    },
-	    listeners: {
-		itemdblclick: me.run_editor,
-		selectionchange: set_button_status
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.mon(me.getStore(), 'datachanged', function() {
-	    set_button_status();
-	});
-
-    }
-});
-
-Ext.define('PVE.lxc.DNSInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcDNSInputPanel',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var deletes = [];
-	if (!values.searchdomain && !me.insideWizard) {
-	    deletes.push('searchdomain');
-	}
-
-	if (values.nameserver) {
-	    var list = values.nameserver.split(/[\ \,\;]+/);
-	    values.nameserver = list.join(' ');
-	} else if(!me.insideWizard) {
-	    deletes.push('nameserver');
-	}
-
-	if (deletes.length) {
-	    values['delete'] = deletes.join(',');
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxtextfield',
-		name: 'searchdomain',
-		skipEmptyText: true,
-		fieldLabel: gettext('DNS domain'),
-		emptyText: gettext('use host settings'),
-		allowBlank: true
-	    },
-	    {
-		xtype: 'proxmoxtextfield',
-		fieldLabel: gettext('DNS servers'),
-		vtype: 'IP64AddressList',
-		allowBlank: true,
-		emptyText: gettext('use host settings'),
-		name: 'nameserver',
-		itemId: 'nameserver'
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.DNSEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	var ipanel = Ext.create('PVE.lxc.DNSInputPanel');
-
-	Ext.apply(me, {
-	    subject: gettext('Resources'),
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response, options) {
-		    var values = response.result.data;
-
-		    if (values.nameserver) {
-			values.nameserver.replace(/[,;]/, ' ');
-			values.nameserver.replace(/^\s+/, '');
-		    }
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-Ext.define('PVE.lxc.DNS', {
-    extend: 'Proxmox.grid.PendingObjectGrid',
-    alias: ['widget.pveLxcDNS'],
-
-    onlineHelp: 'pct_container_network',
-
-    initComponent : function() {
-	var me = this;
-	var i;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = me.pveSelNode.data.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var rows = {
-	    hostname: {
-		required: true,
-		defaultValue: me.pveSelNode.data.name,
-		header: gettext('Hostname'),
-		editor: caps.vms['VM.Config.Network'] ? {
-		    xtype: 'proxmoxWindowEdit',
-		    subject: gettext('Hostname'),
-		    items: {
-			xtype: 'inputpanel',
-			items:{
-			    fieldLabel: gettext('Hostname'),
-			    xtype: 'textfield',
-			    name: 'hostname',
-			    vtype: 'DnsName',
-			    allowBlank: true,
-			    emptyText: 'CT' + vmid.toString()
-			},
-			onGetValues: function(values) {
-			    var params = values;
-			    if (values.hostname === undefined ||
-				values.hostname === null ||
-				values.hostname === '') {
-				params = { hostname: 'CT'+vmid.toString()};
-			    }
-			    return params;
-			}
-		    }
-		} : undefined
-	    },
-	    searchdomain: {
-		header: gettext('DNS domain'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    },
-	    nameserver: {
-		header: gettext('DNS server'),
-		defaultValue: '',
-		editor: caps.vms['VM.Config.Network'] ? 'PVE.lxc.DNSEdit' : undefined,
-		renderer: function(value) {
-		    return value || gettext('use host settings');
-		}
-	    }
-	};
-
-	var baseurl = 'nodes/' + nodename + '/lxc/' + vmid + '/config';
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var rowdef = rows[rec.data.key];
-	    if (!rowdef.editor) {
-		return;
-	    }
-
-	    var win;
-	    if (Ext.isString(rowdef.editor)) {
-		win = Ext.create(rowdef.editor, {
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/nodes/' + nodename + '/lxc/' + vmid + '/config'
-		});
-	    } else {
-		var config = Ext.apply({
-		    pveSelNode: me.pveSelNode,
-		    confid: rec.data.key,
-		    url: '/api2/extjs/nodes/' + nodename + '/lxc/' + vmid + '/config'
-		}, rowdef.editor);
-		win = Ext.createWidget(rowdef.editor.xtype, config);
-		win.load();
-	    }
-	    //win.load();
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    enableFn: function(rec) {
-		var rowdef = rows[rec.data.key];
-		return !!rowdef.editor;
-	    },
-	    handler: run_editor
-	});
-
-	var revert_btn = new PVE.button.PendingRevert();
-
-	var set_button_status = function() {
-	    var sm = me.getSelectionModel();
-	    var rec = sm.getSelection()[0];
-
-	    if (!rec) {
-		edit_btn.disable();
-		return;
-	    }
-	    let key = rec.data.key;
-
-	    let rowdef = rows[key];
-	    edit_btn.setDisabled(!rowdef.editor);
-
-	    let pending = rec.data['delete'] || me.hasPendingChanges(key);
-	    revert_btn.setDisabled(!pending);
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/nodes/" + nodename + "/lxc/" + vmid + "/pending",
-	    selModel: sm,
-	    cwidth1: 150,
-	    interval: 5000,
-	    run_editor: run_editor,
-	    tbar: [ edit_btn, revert_btn ],
-	    rows: rows,
-	    editorConfig: {
-		url: "/api2/extjs/" + baseurl
-	    },
-	    listeners: {
-		itemdblclick: run_editor,
-		selectionchange: set_button_status,
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-
-	me.mon(me.getStore(), 'datachanged', function() {
-	    set_button_status();
-	});
-    }
-});
-Ext.define('PVE.lxc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.lxc.Config',
-
-    onlineHelp: 'chapter_pct',
-
-    initComponent: function() {
-        var me = this;
-	var vm = me.pveSelNode.data;
-
-	var nodename = vm.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var vmid = vm.vmid;
-	if (!vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var template = !!vm.template;
-
-	var running = !!vm.uptime;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var base_url = '/nodes/' + nodename + '/lxc/' + vmid;
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json' + base_url + '/status/current',
-	    interval: 1000
-	});
-
-	var vm_command = function(cmd, params) {
-	    Proxmox.Utils.API2Request({
-		params: params,
-		url: base_url + "/status/" + cmd,
-		waitMsgTarget: me,
-		method: 'POST',
-		failure: function(response, opts) {
-		    Ext.Msg.alert('Error', response.htmlStatus);
-		}
-	    });
-	};
-
-	var startBtn = Ext.create('Ext.Button', {
-	    text: gettext('Start'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || running,
-	    hidden: template,
-	    handler: function() {
-		vm_command('start');
-	    },
-	    iconCls: 'fa fa-play'
-	});
-
-	var shutdownBtn = Ext.create('PVE.button.Split', {
-	    text: gettext('Shutdown'),
-	    disabled: !caps.vms['VM.PowerMgmt'] || !running,
-	    hidden: template,
-	    confirmMsg: Proxmox.Utils.format_task_description('vzshutdown', vmid),
-	    handler: function() {
-		vm_command('shutdown');
-	    },
-	    menu: {
-		items:[{
-		    text: gettext('Reboot'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('vzreboot', vmid),
-		    tooltip: Ext.String.format(gettext('Reboot {0}'), 'CT'),
-		    handler: function() {
-			vm_command("reboot");
-		    },
-		    iconCls: 'fa fa-refresh'
-		},
-		{
-		    text: gettext('Stop'),
-		    disabled: !caps.vms['VM.PowerMgmt'],
-		    confirmMsg: Proxmox.Utils.format_task_description('vzstop', vmid),
-		    tooltip: Ext.String.format(gettext('Stop {0} immediately'), 'CT'),
-		    dangerous: true,
-		    handler: function() {
-			vm_command("stop");
-		    },
-		    iconCls: 'fa fa-stop'
-		}]
-	    },
-	    iconCls: 'fa fa-power-off'
-	});
-
-	var migrateBtn = Ext.create('Ext.Button', {
-	    text: gettext('Migrate'),
-	    disabled: !caps.vms['VM.Migrate'],
-	    hidden: PVE.data.ResourceStore.getNodes().length < 2,
-	    handler: function() {
-		var win = Ext.create('PVE.window.Migrate', {
-		    vmtype: 'lxc',
-		    nodename: nodename,
-		    vmid: vmid
-		});
-		win.show();
-	    },
-	    iconCls: 'fa fa-send-o'
-	});
-
-	var moreBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('More'),
-	    menu: { items: [
-		{
-		    text: gettext('Clone'),
-		    iconCls: 'fa fa-fw fa-clone',
-		    hidden: caps.vms['VM.Clone'] ? false : true,
-		    handler: function() {
-			PVE.window.Clone.wrap(nodename, vmid, template, 'lxc');
-		    }
-		},
-		{
-		    text: gettext('Convert to template'),
-		    disabled: template,
-		    xtype: 'pveMenuItem',
-		    iconCls: 'fa fa-fw fa-file-o',
-		    hidden: caps.vms['VM.Allocate'] ? false : true,
-		    confirmMsg: Proxmox.Utils.format_task_description('vztemplate', vmid),
-		    handler: function() {
-			Proxmox.Utils.API2Request({
-			    url: base_url + '/template',
-			    waitMsgTarget: me,
-			    method: 'POST',
-			    failure: function(response, opts) {
-				Ext.Msg.alert('Error', response.htmlStatus);
-			    }
-			});
-		    }
-		},
-		{
-		    iconCls: 'fa fa-heartbeat ',
-		    hidden: !caps.nodes['Sys.Console'],
-		    text: gettext('Manage HA'),
-		    handler: function() {
-			var ha = vm.hastate;
-			Ext.create('PVE.ha.VMResourceEdit', {
-			    vmid: vmid,
-			    guestType: 'ct',
-			    isCreate: (!ha || ha === 'unmanaged')
-			}).show();
-		    }
-		},
-		{
-		    text: gettext('Remove'),
-		    disabled: !caps.vms['VM.Allocate'],
-		    itemId: 'removeBtn',
-		    handler: function() {
-			Ext.create('PVE.window.SafeDestroy', {
-			    url: base_url,
-			    item: { type: 'CT', id: vmid }
-			}).show();
-		    },
-		    iconCls: 'fa fa-trash-o'
-		}
-	    ]}
-	});
-
-	var consoleBtn = Ext.create('PVE.button.ConsoleButton', {
-	    disabled: !caps.vms['VM.Console'],
-	    consoleType: 'lxc',
-	    consoleName: vm.name,
-	    hidden: template,
-	    nodename: nodename,
-	    vmid: vmid
-	});
-
-	var statusTxt = Ext.create('Ext.toolbar.TextItem', {
-	    data: {
-		lock: undefined
-	    },
-	    tpl: [
-		'<tpl if="lock">',
-		'<i class="fa fa-lg fa-lock"></i> ({lock})',
-		'</tpl>'
-	    ]
-	});
-
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Container {0} on node '{1}'"), vm.text, nodename),
-	    hstateid: 'lxctab',
-	    tbarSpacing: false,
-	    tbar: [ statusTxt, '->', startBtn, shutdownBtn, migrateBtn, consoleBtn, moreBtn ],
-	    defaults: { statusStore: me.statusStore },
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    xtype: 'pveGuestSummary',
-		    iconCls: 'fa fa-book',
-		    itemId: 'summary'
-		}
-	    ]
-	});
-
-	if (caps.vms['VM.Console'] && !template) {
-	    me.items.push(
-		{
-		    title: gettext('Console'),
-		    itemId: 'consolejs',
-		    iconCls: 'fa fa-terminal',
-		    xtype: 'pveNoVncConsole',
-		    vmid: vmid,
-		    consoleType: 'lxc',
-		    xtermjs: true,
-		    nodename: nodename
-		}
-	    );
-	}
-
-	me.items.push(
-	    {
-		title: gettext('Resources'),
-		itemId: 'resources',
-		expandedOnInit: true,
-		iconCls: 'fa fa-cube',
-		xtype: 'pveLxcRessourceView'
-	    },
-	    {
-		title: gettext('Network'),
-		iconCls: 'fa fa-exchange',
-		itemId: 'network',
-		xtype: 'pveLxcNetworkView'
-	    },
-	    {
-		title: gettext('DNS'),
-		iconCls: 'fa fa-globe',
-		itemId: 'dns',
-		xtype: 'pveLxcDNS'
-	    },
-	    {
-		title: gettext('Options'),
-		itemId: 'options',
-		iconCls: 'fa fa-gear',
-		xtype: 'pveLxcOptions'
-	    },
-	    {
-		title: gettext('Task History'),
-		itemId: 'tasks',
-		iconCls: 'fa fa-list',
-		xtype: 'proxmoxNodeTasks',
-		nodename: nodename,
-		vmidFilter: vmid
-	    }
-	);
-
-	if (caps.vms['VM.Backup']) {
-	    me.items.push({
-		title: gettext('Backup'),
-		iconCls: 'fa fa-floppy-o',
-		xtype: 'pveBackupView',
-		itemId: 'backup'
-	    },
-	    {
-		title: gettext('Replication'),
-		iconCls: 'fa fa-retweet',
-		xtype: 'pveReplicaView',
-		itemId: 'replication'
-	    });
-	}
-
-	if ((caps.vms['VM.Snapshot'] || caps.vms['VM.Snapshot.Rollback'] ||
-	    caps.vms['VM.Audit']) && !template) {
-	    me.items.push({
-		title: gettext('Snapshots'),
-		iconCls: 'fa fa-history',
-		xtype: 'pveGuestSnapshotTree',
-		type: 'lxc',
-		itemId: 'snapshot'
-	    });
-	}
-
-	if (caps.vms['VM.Console']) {
-	    me.items.push(
-		{
-		    xtype: 'pveFirewallRules',
-		    title: gettext('Firewall'),
-		    iconCls: 'fa fa-shield',
-		    allow_iface: true,
-		    base_url: base_url + '/firewall/rules',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall'
-		},
-		{
-		    xtype: 'pveFirewallOptions',
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-gear',
-		    onlineHelp: 'pve_firewall_vm_container_configuration',
-		    title: gettext('Options'),
-		    base_url: base_url + '/firewall/options',
-		    fwtype: 'vm',
-		    itemId: 'firewall-options'
-		},
-		{
-		    xtype: 'pveFirewallAliases',
-		    title: gettext('Alias'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-external-link',
-		    base_url: base_url + '/firewall/aliases',
-		    itemId: 'firewall-aliases'
-		},
-		{
-		    xtype: 'pveIPSet',
-		    title: gettext('IPSet'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list-ol',
-		    base_url: base_url + '/firewall/ipset',
-		    list_refs_url: base_url + '/firewall/refs',
-		    itemId: 'firewall-ipset'
-		},
-		{
-		    title: gettext('Log'),
-		    groups: ['firewall'],
-		    iconCls: 'fa fa-list',
-		    onlineHelp: 'chapter_pve_firewall',
-		    itemId: 'firewall-fwlog',
-		    xtype: 'proxmoxLogView',
-		    url: '/api2/extjs' + base_url + '/firewall/log'
-		}
-	    );
-	}
-
-	if (caps.vms['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		itemId: 'permissions',
-		iconCls: 'fa fa-unlock',
-		path: '/vms/' + vmid
-	    });
-	}
-
-	me.callParent();
-
-	var prevStatus = 'unknown';
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var status;
-	    var lock;
-	    if (!success) {
-		status = 'unknown';
-	    } else {
-		var rec = s.data.get('status');
-		status = rec ? rec.data.value : 'unknown';
-		rec = s.data.get('template');
-		template = rec.data.value || false;
-		rec = s.data.get('lock');
-		lock = rec ? rec.data.value : undefined;
-	    }
-
-	    statusTxt.update({ lock: lock });
-
-	    startBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status === 'running' || template);
-	    shutdownBtn.setDisabled(!caps.vms['VM.PowerMgmt'] || status !== 'running');
-	    me.down('#removeBtn').setDisabled(!caps.vms['VM.Allocate'] || status !== 'stopped');
-	    consoleBtn.setDisabled(template);
-
-	    if (prevStatus === 'stopped' && status === 'running') {
-		let con = me.down('#consolejs');
-		if (con) {
-		    con.reload();
-		}
-	    }
-
-	    prevStatus = status;
-	});
-
-	me.on('afterrender', function() {
-	    me.statusStore.startUpdate();
-	});
-
-	me.on('destroy', function() {
-	    me.statusStore.stopUpdate();
-	});
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.lxc.CreateWizard', {
-    extend: 'PVE.window.Wizard',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    viewModel: {
-	data: {
-	    nodename: '',
-	    storage: '',
-	    unprivileged: true
-	}
-    },
-
-    cbindData: {
-	nodename: undefined
-    },
-
-    subject: gettext('LXC Container'),
-
-    items: [
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('General'),
-	    onlineHelp: 'pct_general',
-	    column1: [
-		{
-		    xtype: 'pveNodeSelector',
-		    name: 'nodename',
-		    cbind: {
-			selectCurNode: '{!nodename}',
-			preferredValue: '{nodename}'
-		    },
-		    bind: {
-			value: '{nodename}'
-		    },
-		    fieldLabel: gettext('Node'),
-		    allowBlank: false,
-		    onlineValidator: true
-		},
-		{
-		    xtype: 'pveGuestIDSelector',
-		    name: 'vmid', // backend only knows vmid
-		    guestType: 'lxc',
-		    value: '',
-		    loadNextFreeID: true,
-		    validateExists: false
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'hostname',
-		    vtype: 'DnsName',
-		    value: '',
-		    fieldLabel: gettext('Hostname'),
-		    skipEmptyText: true,
-		    allowBlank: true
-		},
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'unprivileged',
-		    value: true,
-		    bind: {
-			value: '{unprivileged}'
-		    },
-		    fieldLabel: gettext('Unprivileged container')
-		}
-	    ],
-	    column2: [
-		{
-		    xtype: 'pvePoolSelector',
-		    fieldLabel: gettext('Resource Pool'),
-		    name: 'pool',
-		    value: '',
-		    allowBlank: true
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'password',
-		    value: '',
-		    fieldLabel: gettext('Password'),
-		    allowBlank: false,
-		    minLength: 5,
-		    change: function(f, value) {
-			if (f.rendered) {
-			    f.up().down('field[name=confirmpw]').validate();
-			}
-		    }
-		},
-		{
-		    xtype: 'textfield',
-		    inputType: 'password',
-		    name: 'confirmpw',
-		    value: '',
-		    fieldLabel: gettext('Confirm password'),
-		    allowBlank: true,
-		    submitValue: false,
-		    validator: function(value) {
-			var pw = this.up().down('field[name=password]').getValue();
-			if (pw !== value) {
-			    return "Passwords do not match!";
-			}
-			return true;
-		    }
-		},
-		{
-		    xtype: 'proxmoxtextfield',
-		    name: 'ssh-public-keys',
-		    value: '',
-		    fieldLabel: gettext('SSH public key'),
-		    allowBlank: true,
-		    validator: function(value) {
-			var pwfield = this.up().down('field[name=password]');
-			if (value.length) {
-			    var key = PVE.Parser.parseSSHKey(value);
-			    if (!key) {
-				return "Failed to recognize ssh key";
-			    }
-			    pwfield.allowBlank = true;
-			} else {
-			    pwfield.allowBlank = false;
-			}
-			pwfield.validate();
-			return true;
-		    },
-		    afterRender: function() {
-			if (!window.FileReader) {
-			    // No FileReader support in this browser
-			    return;
-			}
-			var cancel = function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			};
-			var field = this;
-			field.inputEl.on('dragover', cancel);
-			field.inputEl.on('dragenter', cancel);
-			field.inputEl.on('drop', function(ev) {
-			    ev = ev.event;
-			    if (ev.preventDefault) {
-				ev.preventDefault();
-			    }
-			    var files = ev.dataTransfer.files;
-			    PVE.Utils.loadSSHKeyFromFile(files[0], function(v) {
-				field.setValue(v);
-			    });
-			});
-		    }
-		},
-		{
-		    xtype: 'filebutton',
-		    name: 'file',
-		    hidden: !window.FileReader,
-		    text: gettext('Load SSH Key File'),
-		    listeners: {
-			change: function(btn, e, value) {
-			    e = e.event;
-			    var field = this.up().down('proxmoxtextfield[name=ssh-public-keys]');
-			    PVE.Utils.loadSSHKeyFromFile(e.target.files[0], function(v) {
-				field.setValue(v);
-			    });
-			    btn.reset();
-			}
-		    }
-		}
-	    ]
-	},
-	{
-	    xtype: 'inputpanel',
-	    title: gettext('Template'),
-	    onlineHelp: 'pct_container_images',
-	    column1: [
-		{
-		    xtype: 'pveStorageSelector',
-		    name: 'tmplstorage',
-		    fieldLabel: gettext('Storage'),
-		    storageContent: 'vztmpl',
-		    autoSelect: true,
-		    allowBlank: false,
-		    bind: {
-			value: '{storage}',
-			nodename: '{nodename}'
-		    }
-		},
-		{
-		    xtype: 'pveFileSelector',
-		    name: 'ostemplate',
-		    storageContent: 'vztmpl',
-		    fieldLabel: gettext('Template'),
-		    bind: {
-			storage: '{storage}',
-			nodename: '{nodename}'
-		    },
-		    allowBlank: false
-		}
-	    ]
-	},
-	{
-	    xtype: 'pveLxcMountPointInputPanel',
-	    title: gettext('Root Disk'),
-	    insideWizard: true,
-	    isCreate: true,
-	    unused: false,
-	    bind: {
-		nodename: '{nodename}',
-		unprivileged: '{unprivileged}'
-	    },
-	    confid: 'rootfs'
-	},
-	{
-	    xtype: 'pveLxcCPUInputPanel',
-	    title: gettext('CPU'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcMemoryInputPanel',
-	    title: gettext('Memory'),
-	    insideWizard: true
-	},
-	{
-	    xtype: 'pveLxcNetworkInputPanel',
-	    title: gettext('Network'),
-	    insideWizard: true,
-	    bind: {
-		nodename: '{nodename}'
-	    },
-	    isCreate: true
-	},
-	{
-	    xtype: 'pveLxcDNSInputPanel',
-	    title: gettext('DNS'),
-	    insideWizard: true
-	},
-	{
-	    title: gettext('Confirm'),
-	    layout: 'fit',
-	    items: [
-		{
-		    xtype: 'grid',
-		    store: {
-			model: 'KeyValue',
-			sorters: [{
-				property : 'key',
-				direction: 'ASC'
-			}]
-		    },
-		    columns: [
-			{header: 'Key', width: 150, dataIndex: 'key'},
-			{header: 'Value', flex: 1, dataIndex: 'value'}
-		    ]
-		}
-	    ],
-	    dockedItems: [
-		{
-		    xtype: 'proxmoxcheckbox',
-		    name: 'start',
-		    dock: 'bottom',
-		    margin: '5 0 0 0',
-		    boxLabel: gettext('Start after created')
-		}
-	    ],
-	    listeners: {
-		show: function(panel) {
-		    var wizard = this.up('window');
-		    var kv = wizard.getValues();
-		    var data = [];
-		    Ext.Object.each(kv, function(key, value) {
-			if (key === 'delete' || key === 'tmplstorage') { // ignore
-			    return;
-			}
-			if (key === 'password') { // don't show pw
-			    return;
-			}
-			var html = Ext.htmlEncode(Ext.JSON.encode(value));
-			data.push({ key: key, value: value });
-		    });
-
-		    var summarystore = panel.down('grid').getStore();
-		    summarystore.suspendEvents();
-		    summarystore.removeAll();
-		    summarystore.add(data);
-		    summarystore.sort();
-		    summarystore.resumeEvents();
-		    summarystore.fireEvent('refresh');
-		}
-	    },
-	    onSubmit: function() {
-		var wizard = this.up('window');
-		var kv = wizard.getValues();
-		delete kv['delete'];
-
-		var nodename = kv.nodename;
-		delete kv.nodename;
-		delete kv.tmplstorage;
-
-		if (!kv.pool.length) {
-		    delete kv.pool;
-		}
-
-		if (!kv.password.length && kv['ssh-public-keys']) {
-		    delete kv.password;
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + nodename + '/lxc',
-		    waitMsgTarget: wizard,
-		    method: 'POST',
-		    params: kv,
-		    success: function(response, opts){
-			var upid = response.result.data;
-
-			var win = Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid
-			});
-			win.show();
-			wizard.close();
-		    },
-		    failure: function(response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	}
-    ]
-});
-
-
-
-/*jslint confusion: true */
-var labelWidth = 120;
-
-Ext.define('PVE.lxc.MemoryEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('Memory'),
-	    items: Ext.create('PVE.lxc.MemoryInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-
-Ext.define('PVE.lxc.CPUEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.apply(me, {
-	    subject: gettext('CPU'),
-	    items: Ext.create('PVE.lxc.CPUInputPanel')
-	});
-
-	me.callParent();
-
-	me.load();
-    }
-});
-
-Ext.define('PVE.lxc.CPUInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcCPUInputPanel',
-
-    onlineHelp: 'pct_cpu',
-
-    insideWizard: false,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	PVE.Utils.delete_if_default(values, 'cores', '', me.insideWizard);
-	// cpu{limit,unit} aren't in the wizard so create is always false
-	PVE.Utils.delete_if_default(values, 'cpulimit', '0', 0);
-	PVE.Utils.delete_if_default(values, 'cpuunits', '1024', 0);
-
-	return values;
-    },
-
-    advancedColumn1: [
-	{
-	    xtype: 'numberfield',
-	    name: 'cpulimit',
-	    minValue: 0,
-	    value: '',
-	    step: 1,
-	    fieldLabel: gettext('CPU limit'),
-	    allowBlank: true,
-	    emptyText: gettext('unlimited')
-	}
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'cpuunits',
-	    fieldLabel: gettext('CPU units'),
-	    value: 1024,
-	    minValue: 8,
-	    maxValue: 500000,
-	    labelWidth: labelWidth,
-	    allowBlank: false
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'cores',
-		minValue: 1,
-		maxValue: 128,
-		value: me.insideWizard ? 1 : '',
-		fieldLabel: gettext('Cores'),
-		allowBlank: true,
-		deleteEmpty: true,
-		emptyText: gettext('unlimited')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.lxc.MemoryInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    alias: 'widget.pveLxcMemoryInputPanel',
-
-    onlineHelp: 'pct_memory',
-
-    insideWizard: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var items = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'memory',
-		minValue: 16,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Memory') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'swap',
-		minValue: 0,
-		value: '512',
-		step: 32,
-		fieldLabel: gettext('Swap') + ' (MiB)',
-		labelWidth: labelWidth,
-		allowBlank: false
-	    }
-	];
-
-	if (me.insideWizard) {
-	    me.column1 = items;
-	} else {
-	    me.items = items;
-	}
- 
-	me.callParent();
-    }
-});
-Ext.define('PVE.window.MPResize', {
-    extend: 'Ext.window.Window',
-
-    resizable: false,
-
-    resize_disk: function(disk, size) {
-	var me = this;
-        var params =  { disk: disk, size: '+' + size + 'G' };
-
-	Proxmox.Utils.API2Request({
-	    params: params,
-	    url: '/nodes/' + me.nodename + '/lxc/' + me.vmid + '/resize',
-	    waitMsgTarget: me,
-	    method: 'PUT',
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response, opts) {
-		var upid = response.result.data;
-		var win = Ext.create('Proxmox.window.TaskViewer', { upid: upid });
-		win.show();
-		me.close();
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.vmid) {
-	    throw "no VM ID specified";
-	}
-
-	var items = [
-	    {
-		xtype: 'displayfield',
-		name: 'disk',
-		value: me.disk,
-		fieldLabel: gettext('Disk'),
-		vtype: 'StorageId',
-		allowBlank: false
-	    }
-	];
-
-	me.hdsizesel = Ext.createWidget('numberfield', {
-	    name: 'size',
-	    minValue: 0,
-	    maxValue: 128*1024,
-	    decimalPrecision: 3,
-	    value: '0',
-	    fieldLabel: gettext('Size Increment') + ' (GiB)',
-	    allowBlank: false
-	});
-
-	items.push(me.hdsizesel);
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    bodyPadding: 10,
-	    border: false,
-	    fieldDefaults: {
-		labelWidth: 120,
-		anchor: '100%'
-	    },
-	    items: items
-	});
-
-	var form = me.formPanel.getForm();
-
-	var submitBtn;
-
-	me.title = gettext('Resize disk');
-	submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Resize disk'),
-	    handler: function() {
-		if (form.isValid()) {
-		    var values = form.getValues();
-		    me.resize_disk(me.disk, values.size);
-		}
-	    }
-	});
-
-	Ext.apply(me, {
-	    modal: true,
-	    border: false,
-	    layout: 'fit',
-	    buttons: [ submitBtn ],
-	    items: [ me.formPanel ]
-	});
-
-
-	me.callParent();
-
-	if (!me.disk) {
-	    return;
-	}
-
-    }
-});
-/*jslint confusion: true*/
-/* hidden: boolean and string
- * bind: function and object
- * disabled: boolean and string
- */
-Ext.define('PVE.lxc.MountPointInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    xtype: 'pveLxcMountPointInputPanel',
-
-    insideWizard: false,
-
-    onlineHelp: 'pct_container_storage',
-
-    unused: false, // add unused disk imaged
-
-    unprivileged: false,
-
-    vmconfig: {}, // used to select unused disks
-
-    setUnprivileged: function(unprivileged) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.unprivileged = unprivileged;
-	vm.set('unpriv', unprivileged);
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var confid = me.confid || "mp"+values.mpid;
-	me.mp.file = me.down('field[name=file]').getValue();
-
-	if (me.unused) {
-	    confid = "mp"+values.mpid;
-	} else if (me.isCreate) {
-	    me.mp.file = values.hdstorage + ':' + values.disksize;
-	}
-
-	// delete unnecessary fields
-	delete values.mpid;
-	delete values.hdstorage;
-	delete values.disksize;
-	delete values.diskformat;
-
-	let mountopts = (values.mountoptions || []).join(';');
-	PVE.Utils.propertyStringSet(me.mp, values.mp, 'mp');
-	PVE.Utils.propertyStringSet(me.mp, values.mountoptions, 'mountoptions', mountopts);
-	PVE.Utils.propertyStringSet(me.mp, values.backup, 'backup');
-	PVE.Utils.propertyStringSet(me.mp, values.quota, 'quota');
-	PVE.Utils.propertyStringSet(me.mp, values.ro, 'ro');
-	PVE.Utils.propertyStringSet(me.mp, values.acl, 'acl');
-	PVE.Utils.propertyStringSet(me.mp, values.replicate, 'replicate');
-
-	var res = {};
-	res[confid] = PVE.Parser.printLxcMountPoint(me.mp);
-	return res;
-    },
-
-
-    setMountPoint: function(mp) {
-	var me = this;
-	var vm = this.getViewModel();
-	vm.set('mptype', mp.type);
-	if (mp.mountoptions) {
-	    mp.mountoptions = mp.mountoptions.split(';');
-	}
-	me.mp = mp;
-
-	if (this.confid === 'rootfs') {
-	    var field = me.down('field[name=mountoptions]');
-	    var forbidden = ['nodev', 'noexec'];
-	    var filtered = field.comboItems.filter(e => !forbidden.includes(e[0]));
-	    field.setComboItems(filtered);
-	}
-
-	me.setValues(mp);
-    },
-
-    setVMConfig: function(vmconfig) {
-	var me = this;
-	var vm = me.getViewModel();
-	me.vmconfig = vmconfig;
-	vm.set('unpriv', vmconfig.unprivileged);
-
-	PVE.Utils.forEachMP(function(bus, i) {
-	    var name = "mp" + i.toString();
-	    if (!Ext.isDefined(vmconfig[name])) {
-		me.down('field[name=mpid]').setValue(i);
-		return false;
-	    }
-	});
-    },
-
-    setNodename: function(nodename) {
-	var me = this;
-	var vm = me.getViewModel();
-	vm.set('node', nodename);
-	me.down('#diskstorage').setNodename(nodename);
-    },
-
-    controller:  {
-	xclass: 'Ext.app.ViewController',
-
-	control: {
-	    'field[name=mpid]': {
-		change: function(field, value) {
-		    field.validate();
-		}
-	    },
-	    '#hdstorage': {
-		change: function(field, newValue) {
-		    var me = this;
-		    if (!newValue) {
-			return;
-		    }
-
-		    var rec = field.store.getById(newValue);
-		    if (!rec) {
-			return;
-		    }
-
-		    var vm = me.getViewModel();
-		    vm.set('type', rec.data.type);
-		}
-	    }
-	},
-
-	init: function(view) {
-	    var me = this;
-	    var vm = this.getViewModel();
-	    view.mp = {};
-	    vm.set('confid', view.confid);
-	    vm.set('unused', view.unused);
-	    vm.set('node', view.nodename);
-	    vm.set('unpriv', view.unprivileged);
-	    vm.set('hideStorSelector', view.unused || !view.isCreate);
-
-	    // can be array if created from unused disk
-	    if (view.isCreate) {
-		vm.set('isIncludedInBackup', true);
-	    }
-	}
-    },
-
-    viewModel: {
-	data: {
-	    unpriv: false,
-	    unused: false,
-	    showStorageSelector: false,
-	    mptype: '',
-	    type: '',
-	    confid: '',
-	    node: ''
-	},
-
-	formulas: {
-	    quota: function(get) {
-		return !(get('type') === 'zfs' ||
-			 get('type') === 'zfspool' ||
-			 get('unpriv') ||
-			 get('isBind'));
-	    },
-	    hasMP: function(get) {
-		return !!get('confid') && !get('unused');
-	    },
-	    isRoot: function(get) {
-		return get('confid') === 'rootfs';
-	    },
-	    isBind: function(get) {
-		return get('mptype') === 'bind';
-	    },
-	    isBindOrRoot: function(get) {
-		return get('isBind') || get('isRoot');
-	    }
-	}
-    },
-
-    column1: [
-	{
-	    xtype: 'proxmoxintegerfield',
-	    name: 'mpid',
-	    fieldLabel: gettext('Mount Point ID'),
-	    minValue: 0,
-	    maxValue: PVE.Utils.mp_counts.mps - 1,
-	    hidden: true,
-	    allowBlank: false,
-	    disabled: true,
-	    bind: {
-		hidden: '{hasMP}',
-		disabled: '{hasMP}'
-	    },
-	    validator: function(value) {
-		var me = this.up('inputpanel');
-		if (!me.rendered) {
-		    return;
-		}
-		if (Ext.isDefined(me.vmconfig["mp"+value])) {
-		    return "Mount point is already in use.";
-		}
-		/*jslint confusion: true*/
-		/* returns a string above */
-		return true;
-	    }
-	},
-	{
-	    xtype: 'pveDiskStorageSelector',
-	    itemId: 'diskstorage',
-	    storageContent: 'rootdir',
-	    hidden: true,
-	    autoSelect: true,
-	    selectformat: false,
-	    defaultSize: 8,
-	    bind: {
-		hidden: '{hideStorSelector}',
-		disabled: '{hideStorSelector}',
-		nodename: '{node}'
-	    }
-	},
-	{
-	    xtype: 'textfield',
-	    disabled: true,
-	    submitValue: false,
-	    fieldLabel: gettext('Disk image'),
-	    name: 'file',
-	    bind: {
-		hidden: '{!hideStorSelector}'
-	    }
-	}
-    ],
-
-    column2: [
-	{
-	    xtype: 'textfield',
-	    name: 'mp',
-	    value: '',
-	    emptyText:  gettext('/some/path'),
-	    allowBlank: false,
-	    disabled: true,
-	    fieldLabel: gettext('Path'),
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'backup',
-	    fieldLabel: gettext('Backup'),
-	    autoEl: {
-		tag: 'div',
-		'data-qtip': gettext('Include volume in backup job'),
-	    },
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isBindOrRoot}',
-		value: '{isIncludedInBackup}'
-	    }
-	}
-    ],
-
-    advancedColumn1: [
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'quota',
-	    defaultValue: 0,
-	    bind: {
-		disabled: '{!quota}'
-	    },
-	    fieldLabel: gettext('Enable quota'),
-	    listeners: {
-		disable: function() {
-		    this.reset();
-		}
-	    }
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'ro',
-	    defaultValue: 0,
-	    bind: {
-		hidden: '{isRoot}',
-		disabled: '{isRoot}'
-	    },
-	    fieldLabel: gettext('Read-only')
-	},
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'mountoptions',
-	    fieldLabel: gettext('Mount options'),
-	    deleteEmpty: false,
-	    comboItems: [
-		['noatime', 'noatime'],
-		['nodev', 'nodev'],
-		['noexec', 'noexec'],
-		['nosuid', 'nosuid']
-	    ],
-	    multiSelect: true,
-	    value: [],
-	    allowBlank: true
-	},
-    ],
-
-    advancedColumn2: [
-	{
-	    xtype: 'proxmoxKVComboBox',
-	    name: 'acl',
-	    fieldLabel: 'ACLs',
-	    deleteEmpty: false,
-	    comboItems: [
-		['__default__', Proxmox.Utils.defaultText],
-		['1', Proxmox.Utils.enabledText],
-		['0', Proxmox.Utils.disabledText]
-	    ],
-	    value: '__default__',
-	    bind: {
-		disabled: '{isBind}'
-	    },
-	    allowBlank: true
-	},
-	{
-	    xtype: 'proxmoxcheckbox',
-	    inputValue: '0', // reverses the logic
-	    name: 'replicate',
-	    fieldLabel: gettext('Skip replication')
-	}
-    ]
-});
-
-Ext.define('PVE.lxc.MountPointEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    unprivileged: false,
-
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var unused = me.confid && me.confid.match(/^unused\d+$/);
-
-	me.isCreate = me.confid ? unused : true;
-
-	var ipanel = Ext.create('PVE.lxc.MountPointInputPanel', {
-	    confid: me.confid,
-	    nodename: nodename,
-	    unused: unused,
-	    unprivileged: me.unprivileged,
-	    isCreate: me.isCreate
-	});
-
-	var subject;
-	if (unused) {
-	    subject = gettext('Unused Disk');
-	} else if (me.isCreate) {
-	    subject = gettext('Mount Point');
-	} else {
-	    subject = gettext('Mount Point') + ' (' + me.confid + ')';
-	}
-
-	Ext.apply(me, {
-	    subject: subject,
-	    defaultFocus: me.confid !== 'rootfs' ? 'textfield[name=mp]' : 'tool',
-	    items: ipanel
-	});
-
-	me.callParent();
-
-	me.load({
-	    success: function(response, options) {
-		ipanel.setVMConfig(response.result.data);
-		if (me.confid) {
-		    /*jslint confusion: true*/
-		    /*data is defined as array above*/
-		    var value = response.result.data[me.confid];
-		    /*jslint confusion: false*/
-		    var mp = PVE.Parser.parseLxcMountPoint(value);
-
-		    if (!mp) {
-			Ext.Msg.alert(gettext('Error'), 'Unable to parse mount point options');
-			me.close();
-			return;
-		    }
-
-		    ipanel.setMountPoint(mp);
-		    me.isValid(); // trigger validation
-		}
-	    }
-	});
-    }
-});
-Ext.define('PVE.pool.StatusView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pvePoolStatusView'],
-    disabled: true,
-
-    title: gettext('Status'),
-    cwidth1: 150,
-    interval: 30000,
-    //height: 195,
-    initComponent : function() {
-	var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var rows = {
-	    comment: {
-		header: gettext('Comment'), 
-		renderer: Ext.String.htmlEncode,
-		required: true
-	    }
-	};
-
-	Ext.apply(me, {
-	    url: "/api2/json/pools/" + pool,
-	    rows: rows
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pvePoolSummary',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	var statusview = Ext.create('PVE.pool.StatusView', {
-	    pveSelNode: me.pveSelNode,
-	    style: 'padding-top:0px'
-	});
-
-	var rstore = statusview.rstore;
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    defaults: {
-		style: 'padding-top:10px',
-		width: 800
-	    },
-	    items: [ statusview ]
-	});
-
-	me.on('activate', rstore.startUpdate);
-	me.on('destroy', rstore.stopUpdate);	
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.pool.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.pvePoolConfig',
-
-    onlineHelp: 'pveum_pools',
-
-    initComponent: function() {
-        var me = this;
-
-	var pool = me.pveSelNode.data.pool;
-	if (!pool) {
-	    throw "no pool specified";
-	}
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Resource Pool") + ': ' + pool),
-	    hstateid: 'pooltab',
-	    items: [
-		{
-		    title: gettext('Summary'),
-		    iconCls: 'fa fa-book',
-		    xtype: 'pvePoolSummary',
-		    itemId: 'summary'
-		},
-		{
-		    title: gettext('Members'),
-		    xtype: 'pvePoolMembers',
-		    iconCls: 'fa fa-th',
-		    pool: pool,
-		    itemId: 'members'
-		},
-		{
-		    xtype: 'pveACLView',
-		    title: gettext('Permissions'),
-		    iconCls: 'fa fa-unlock',
-		    itemId: 'permissions',
-		    path: '/pool/' + pool
-		}
-	    ]
-	});
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.panel.StorageBase', {
-    extend: 'Proxmox.panel.InputPanel',
-    controller: 'storageEdit',
-
-    type: '',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = me.type;
-	} else {
-	    delete values.storage;
-	}
-
-	values.disable = values.enable ? 0 : 1;
-	delete values.enable;
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1.unshift({
-	    xtype: me.isCreate ? 'textfield' : 'displayfield',
-	    name: 'storage',
-	    value: me.storageId || '',
-	    fieldLabel: 'ID',
-	    vtype: 'StorageId',
-	    allowBlank: false
-	});
-
-	me.column2.unshift(
-	    {
-		xtype: 'pveNodeSelector',
-		name: 'nodes',
-		disabled: me.storageId === 'local',
-		fieldLabel: gettext('Nodes'),
-		emptyText: gettext('All') + ' (' + gettext('No restrictions') +')',
-		multiSelect: true,
-		autoSelect: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enable',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Enable')
-	    }
-	);
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.storageId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/storage';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/storage/' + me.storageId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create(me.paneltype, {
-	    type: me.type,
-	    isCreate: me.isCreate,
-	    storageId: me.storageId
-	});
-
-	Ext.apply(me, {
-            subject: PVE.Utils.format_storage_type(me.type),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-		    var ctypes = values.content || '';
-
-		    values.content = ctypes.split(',');
-
-		    if (values.nodes) {
-			values.nodes = values.nodes.split(',');
-		    }
-		    values.enable = values.disable ? 0 : 1;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.grid.TemplateSelector', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveTemplateSelector',
-
-    stateful: true,
-    stateId: 'grid-template-selector',
-    viewConfig: {
-	trackOver: false
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/aplinfo";
-	var store = new Ext.data.Store({
-	    model: 'pve-aplinfo',
-	    groupField: 'section',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
-            groupHeaderTpl: '{[ "Section: " + values.name ]} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		'->',
-		gettext('Search'),
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    var value = field.getValue().toLowerCase();
-			    store.clearFilter(true);
-			    store.filterBy(function(rec) {
-				return (rec.data['package'].toLowerCase().indexOf(value) !== -1)
-				|| (rec.data.headline.toLowerCase().indexOf(value) !== -1);
-			    });
-			}
-		    }
-		}
-	    ],
-	    features: [ groupingFeature ],
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Package'),
-		    flex: 1,
-		    dataIndex: 'package'
-		},
-		{
-		    header: gettext('Version'),
-		    width: 80,
-		    dataIndex: 'version'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1.5,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'headline'
-		}
-	    ],
-	    listeners: {
-		afterRender: reload
-	    }
-	});
-
-	me.callParent();
-    }
-
-}, function() {
-
-    Ext.define('pve-aplinfo', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'template', 'type', 'package', 'version', 'headline', 'infopage',
-	    'description', 'os', 'section'
-	],
-	idProperty: 'template'
-    });
-
-});
-
-Ext.define('PVE.storage.TemplateDownload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveTemplateDownload',
-
-    modal: true,
-    title: gettext('Templates'),
-    layout: 'fit',
-    width: 900,
-    height: 600,
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var grid = Ext.create('PVE.grid.TemplateSelector', {
-	    border: false,
-	    scrollable: true,
-	    nodename: me.nodename
-	});
-
-	var sm = grid.getSelectionModel();
-
-	var submitBtn = Ext.create('Proxmox.button.Button', {
-	    text: gettext('Download'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(button, event, rec) {
-		Proxmox.Utils.API2Request({
-		    url: '/nodes/' + me.nodename + '/aplinfo',
-		    params: {
-			storage: me.storage,
-			template: rec.data.template
-		    },
-		    method: 'POST',
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    },
-		    success: function(response, options) {
-			var upid = response.result.data;
-
-			Ext.create('Proxmox.window.TaskViewer', {
-			    upid: upid,
-			    listeners: {
-				destroy: me.reloadGrid
-			    }
-			}).show();
-
-			me.close();
-		    }
-		});
-	    }
-	});
-
-        Ext.apply(me, {
-	    items: grid,
-	    buttons: [ submitBtn ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.Upload', {
-    extend: 'Ext.window.Window',
-    alias: 'widget.pveStorageUpload',
-
-    resizable: false,
-
-    modal: true,
-
-    initComponent : function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	var xhr;
-
-	if (!me.nodename) {
-	    throw "no node name specified";
-	}
-
-	if (!me.storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + me.nodename + "/storage/" + me.storage + "/upload";
-
-	var pbar = Ext.create('Ext.ProgressBar', {
-            text: 'Ready',
-	    hidden: true
-	});
-
-	me.formPanel = Ext.create('Ext.form.Panel', {
-	    method: 'POST',
-	    waitMsgTarget: true,
-	    bodyPadding: 10,
-	    border: false,
-	    width: 300,
-	    fieldDefaults: {
-		labelWidth: 100,
-		anchor: '100%'
-            },
-	    items: [
-		{
-		    xtype: 'pveContentTypeSelector',
-		    cts: me.contents,
-		    fieldLabel: gettext('Content'),
-		    name: 'content',
-		    value: me.contents[0] || '',
-		    allowBlank: false
-		},
-		{
-		    xtype: 'filefield',
-		    name: 'filename',
-		    buttonText: gettext('Select File...'),
-		    allowBlank: false,
-		    listeners: {
-			afterrender: function(cmp) {
-			    cmp.fileInputEl.set({
-				accept: '.img, .iso'
-			    });
-			}
-		    }
-		},
-		pbar
-	    ]
-	});
-
-	var form = me.formPanel.getForm();
-
-	var doStandardSubmit = function() {
-	    form.submit({
-		url: "/api2/htmljs" + baseurl,
-		waitMsg: gettext('Uploading file...'),
-		success: function(f, action) {
-		    me.close();
-		},
-		failure: function(f, action) {
-		    var msg = PVE.Utils.extractFormActionError(action);
-                    Ext.Msg.alert(gettext('Error'), msg);
-		}
-	    });
-	};
-
-	var updateProgress = function(per, bytes) {
-	    var text = (per * 100).toFixed(2) + '%';
-	    if (bytes) {
-		text += " (" + Proxmox.Utils.format_size(bytes) + ')';
-	    }
-	    pbar.updateProgress(per, text);
-	};
-
-	var abortBtn = Ext.create('Ext.Button', {
-	    text: gettext('Abort'),
-	    disabled: true,
-	    handler: function() {
-		me.close();
-	    }
-	});
-
-	var submitBtn = Ext.create('Ext.Button', {
-	    text: gettext('Upload'),
-	    disabled: true,
-	    handler: function(button) {
-		var fd;
-		try {
-		    fd = new FormData();
-		} catch (err) {
-		    doStandardSubmit();
-		    return;
-		}
-
-		button.setDisabled(true);
-		abortBtn.setDisabled(false);
-
-		var field = form.findField('content');
-		fd.append("content", field.getValue());
-		field.setDisabled(true);
-
-		field = form.findField('filename');
-		var file = field.fileInputEl.dom;
-		fd.append("filename", file.files[0]);
-		field.setDisabled(true);
-
-		pbar.setVisible(true);
-		updateProgress(0);
-
-		xhr = new XMLHttpRequest();
-
-		xhr.addEventListener("load", function(e) {
-		    if (xhr.status == 200) {
-			me.close();
-		    } else {
-			var msg = gettext('Error') + " " + xhr.status.toString() + ": " + Ext.htmlEncode(xhr.statusText);
-			if (xhr.responseText !== "") {
-			    var result = Ext.decode(xhr.responseText);
-			    result.message = msg;
-			    msg = Proxmox.Utils.extractRequestError(result, true);
-			}
-			Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			    me.close();
-			});
-		    }
-		}, false);
-
-		xhr.addEventListener("error", function(e) {
-		    var msg = "Error " + e.target.status.toString() + " occurred while receiving the document.";
-		    Ext.Msg.alert(gettext('Error'), msg, function(btn) {
-			me.close();
-		    });
-		});
-
-		xhr.upload.addEventListener("progress", function(evt) {
-		    if (evt.lengthComputable) {
-			var percentComplete = evt.loaded / evt.total;
-			updateProgress(percentComplete, evt.loaded);
-		    }
-		}, false);
-
-		xhr.open("POST", "/api2/json" + baseurl, true);
-		xhr.send(fd);
-	    }
-	});
-
-	form.on('validitychange', function(f, valid) {
-	    submitBtn.setDisabled(!valid);
-	});
-
-        Ext.apply(me, {
-            title: gettext('Upload'),
-	    items: me.formPanel,
-	    buttons: [ abortBtn, submitBtn ],
-	    listeners: {
-		close: function() {
-		    if (xhr) {
-			xhr.abort();
-		    }
-		}
-	    }
-	});
-
-        me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ContentView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: 'widget.pveStorageContentView',
-
-    stateful: true,
-    stateId: 'grid-storage-content',
-    viewConfig: {
-	trackOver: false,
-	loadMask: false
-    },
-    features: [
-	{
-	    ftype: 'grouping',
-	    groupHeaderTpl: '{name} ({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'
-	}
-    ],
-    initComponent : function() {
-	var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var baseurl = "/nodes/" + nodename + "/storage/" + storage + "/content";
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-storage-content',
-	    groupField: 'content',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json' + baseurl
-	    },
-	    sorters: {
-		property: 'volid',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	    me.statusStore.load();
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var templateButton = Ext.create('Proxmox.button.Button',{
-	    itemId: 'tmpl-btn',
-	    text: gettext('Templates'),
-	    handler: function() {
-		var win = Ext.create('PVE.storage.TemplateDownload', {
-		    nodename: nodename,
-		    storage: storage,
-		    reloadGrid: reload
-		});
-		win.show();
-	    }
-	});
-
-	var uploadButton = Ext.create('Proxmox.button.Button', {
-	    contents : ['iso','vztmpl'],
-	    text: gettext('Upload'),
-	    handler: function() {
-		var me = this;
-		var win = Ext.create('PVE.storage.Upload', {
-		    nodename: nodename,
-		    storage: storage,
-		    contents: me.contents
-		});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	var imageRemoveButton;
-	var removeButton = Ext.create('Proxmox.button.StdRemoveButton',{
-	    selModel: sm,
-	    delay: 5,
-	    enableFn: function(rec) {
-		if (rec && rec.data.content !== 'images') {
-		    imageRemoveButton.setVisible(false);
-		    removeButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: baseurl + '/'
-	});
-
-	imageRemoveButton = Ext.create('Proxmox.button.Button',{
-	    selModel: sm,
-	    hidden: true,
-	    text: gettext('Remove'),
-	    enableFn: function(rec) {
-		if (rec && rec.data.content === 'images') {
-		    removeButton.setVisible(false);
-		    imageRemoveButton.setVisible(true);
-		    return true;
-		}
-		return false;
-	    },
-	    handler: function(btn, event, rec) {
-		me = this;
-
-		var url = baseurl + '/' + rec.data.volid;
-		var vmid = rec.data.vmid;
-
-		var store = PVE.data.ResourceStore;
-
-		if (vmid && store.findVMID(vmid)) {
-		    var guest_node = store.guestNode(vmid);
-		    var storage_path = 'storage/' + nodename + '/' + storage;
-
-		    // allow to delete local backed images if a VMID exists on another node.
-		    if (store.storageIsShared(storage_path) || guest_node == nodename) {
-			var msg = Ext.String.format(
-			    gettext("Cannot remove image, a guest with VMID '{0}' exists!"), vmid);
-			msg += '<br />' + gettext("You can delete the image from the guest's hardware pane");
-
-			Ext.Msg.show({
-			    title: gettext('Cannot remove disk image.'),
-			    icon: Ext.Msg.ERROR,
-			    msg: msg
-			});
-			return;
-		    }
-		}
-		var win = Ext.create('PVE.window.SafeDestroy', {
-		    title: Ext.String.format(gettext("Destroy '{0}'"), rec.data.volid),
-		    showProgress: true,
-		    url: url,
-		    item: { type: 'Image', id: vmid }
-		}).show();
-		win.on('destroy', function() {
-		    me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-			url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-		    });
-		    reload();
-
-		});
-	    }
-	});
-
-	me.statusStore = Ext.create('Proxmox.data.ObjectStore', {
-	    url: '/api2/json/nodes/' + nodename + '/storage/' + storage + '/status'
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Restore'),
-		    selModel: sm,
-		    disabled: true,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b, e, rec) {
-			var vmtype;
-			if (PVE.Utils.volume_is_qemu_backup(rec.data.volid, rec.data.format)) {
-			    vmtype = 'qemu';
-			} else if (PVE.Utils.volume_is_lxc_backup(rec.data.volid, rec.data.format)) {
-			    vmtype = 'lxc';
-			} else {
-			    return;
-			}
-
-			var win = Ext.create('PVE.window.Restore', {
-			    nodename: nodename,
-			    volid: rec.data.volid,
-			    volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
-			    vmtype: vmtype
-			});
-			win.show();
-			win.on('destroy', reload);
-		    }
-		},
-		removeButton,
-		imageRemoveButton,
-		templateButton,
-		uploadButton,
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Show Configuration'),
-		    disabled: true,
-		    selModel: sm,
-		    enableFn: function(rec) {
-			return rec && rec.data.content === 'backup';
-		    },
-		    handler: function(b,e,rec) {
-			var win = Ext.create('PVE.window.BackupConfig', {
-			    volume: rec.data.volid,
-			    pveSelNode: me.pveSelNode
-			});
-
-			win.show();
-		    }
-		},
-		'->',
-		gettext('Search') + ':', ' ',
-		{
-		    xtype: 'textfield',
-		    width: 200,
-		    enableKeyEvents: true,
-		    listeners: {
-			buffer: 500,
-			keyup: function(field) {
-			    store.clearFilter(true);
-			    store.filter([
-				{
-				    property: 'text',
-				    value: field.getValue(),
-				    anyMatch: true,
-				    caseSensitive: false
-				}
-			    ]);
-			}
-		    }
-		}
-	    ],
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    flex: 1,
-		    sortable: true,
-		    renderer: PVE.Utils.render_storage_content,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Date'),
-		    width: 150,
-		    dataIndex: 'vdate'
-		},
-		{
-		    header: gettext('Format'),
-		    width: 100,
-		    dataIndex: 'format'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Size'),
-		    width: 100,
-		    renderer: Proxmox.Utils.format_size,
-		    dataIndex: 'size'
-		}
-	    ],
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-
-	// disable the buttons/restrict the upload window
-	// if templates or uploads are not allowed
-	me.mon(me.statusStore, 'load', function(s, records, success) {
-	    var availcontent = [];
-	    Ext.Array.each(records, function(item){
-		if (item.id === 'content') {
-		    availcontent = item.data.value.split(',');
-		}
-	    });
-	    var templ = false;
-	    var upload = false;
-	    var cts = [];
-
-	    Ext.Array.each(availcontent, function(content) {
-		if (content === 'vztmpl') {
-		    templ = true;
-		    cts.push('vztmpl');
-		} else if (content === 'iso') {
-		    upload = true;
-		    cts.push('iso');
-		}
-	    });
-
-	    if (templ !== upload) {
-		uploadButton.contents = cts;
-	    }
-
-	    templateButton.setDisabled(!templ);
-	    uploadButton.setDisabled(!upload && !templ);
-	});
-    }
-}, function() {
-
-    Ext.define('pve-storage-content', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'volid', 'content', 'format', 'size', 'used', 'vmid',
-	    'channel', 'id', 'lun',
-	    {
-		name: 'text',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    return PVE.Utils.render_storage_content(value, {}, record);
-		}
-	    },
-	    {
-		name: 'vdate',
-		convert: function(value, record) {
-		    // check for volid, because if you click on a grouping header,
-		    // it calls convert (but with an empty volid)
-		    if (value || record.data.volid === null) {
-			return value;
-		    }
-		    let t = record.data.content;
-		    if (t === "backup") {
-			let v = record.data.volid;
-			let match = v.match(/(\d{4}_\d{2}_\d{2})-(\d{2}_\d{2}_\d{2})/);
-			if (match) {
-			    let date = match[1].replace(/_/g, '-');
-			    let time = match[2].replace(/_/g, ':');
-			    return date + " " + time;
-			}
-		    }
-		    if (record.data.ctime) {
-			let ctime = new Date(record.data.ctime * 1000);
-			return Ext.Date.format(ctime,'Y-m-d H:i:s');
-		    }
-		    return '';
-		}
-	    },
-	],
-	idProperty: 'volid'
-    });
-
-});
-Ext.define('PVE.storage.StatusView', {
-    extend: 'PVE.panel.StatusView',
-    alias: 'widget.pveStorageStatusView',
-
-    height: 230,
-    title: gettext('Status'),
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	xtype: 'pveInfoWidget',
-	padding: '0 30 5 30'
-    },
-    items: [
-	{
-	    xtype: 'box',
-	    height: 30
-	},
-	{
-	    itemId: 'enabled',
-	    title: gettext('Enabled'),
-	    printBar: false,
-	    textField: 'disabled',
-	    renderer: Proxmox.Utils.format_neg_boolean
-	},
-	{
-	    itemId: 'active',
-	    title: gettext('Active'),
-	    printBar: false,
-	    textField: 'active',
-	    renderer: Proxmox.Utils.format_boolean
-	},
-	{
-	    itemId: 'content',
-	    title: gettext('Content'),
-	    printBar: false,
-	    textField: 'content',
-	    renderer: PVE.Utils.format_content_types
-	},
-	{
-	    itemId: 'type',
-	    title: gettext('Type'),
-	    printBar: false,
-	    textField: 'type',
-	    renderer: PVE.Utils.format_storage_type
-	},
-	{
-	    xtype: 'box',
-	    height: 10
-	},
-	{
-	    itemId: 'usage',
-	    title: gettext('Usage'),
-	    valueField: 'used',
-	    maxField: 'total'
-	}
-    ],
-
-    updateTitle: function() {
-	return;
-    }
-});
-Ext.define('PVE.storage.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveStorageSummary',
-    scrollable: true,
-    bodyPadding: 5,
-    tbar: [
-	'->',
-	{
-	    xtype: 'proxmoxRRDTypeSelector'
-	}
-    ],
-    layout: {
-	type: 'column'
-    },
-    defaults: {
-	padding: 5,
-	columnWidth: 1
-    },
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storage = me.pveSelNode.data.storage;
-	if (!storage) {
-	    throw "no storage ID specified";
-	}
-
-	var rstore  = Ext.create('Proxmox.data.ObjectStore', {
-	    url: "/api2/json/nodes/" + nodename + "/storage/" + storage + "/status",
-	    interval: 1000
-	});
-
-	var rrdstore = Ext.create('Proxmox.data.RRDStore', {
-	    rrdurl:  "/api2/json/nodes/" + nodename + "/storage/" + storage + "/rrddata",
-	    model: 'pve-rrd-storage'
-	});
-
-	Ext.apply(me, {
-	    items: [
-		{
-		    xtype: 'pveStorageStatusView',
-		    pveSelNode: me.pveSelNode,
-		    rstore: rstore
-		},
-		{
-		    xtype: 'proxmoxRRDChart',
-		    title: gettext('Usage'),
-		    fields: ['total','used'],
-		    fieldTitles: ['Total Size', 'Used Size'],
-		    store: rrdstore
-		}
-	    ],
-	    listeners: {
-		activate: function() { rstore.startUpdate(); rrdstore.startUpdate(); },
-		destroy: function() { rstore.stopUpdate(); rrdstore.stopUpdate(); }
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.Browser', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.storage.Browser',
-
-    onlineHelp: 'chapter_storage',
-
-    initComponent: function() {
-        var me = this;
-
-	var nodename = me.pveSelNode.data.node;
-	if (!nodename) {
-	    throw "no node name specified";
-	}
-
-	var storeid = me.pveSelNode.data.storage;
-	if (!storeid) {
-	    throw "no storage ID specified";
-	}
-
-
-	me.items = [
-	    {
-		title: gettext('Summary'),
-		xtype: 'pveStorageSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    }
-	];
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	Ext.apply(me, {
-	    title: Ext.String.format(gettext("Storage {0} on node {1}"),
-				     "'" + storeid + "'", "'" + nodename + "'"),
-	    hstateid: 'storagetab'
-	});
-
-	if (caps.storage['Datastore.Allocate'] ||
-	    caps.storage['Datastore.AllocateSpace'] ||
-	    caps.storage['Datastore.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageContentView',
-		title: gettext('Content'),
-		iconCls: 'fa fa-th',
-		itemId: 'content'
-	    });
-	}
-
-	if (caps.storage['Permissions.Modify']) {
-	    me.items.push({
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		path: '/storage/' + storeid
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.storage.DirInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_directory',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'path',
-		value: '',
-		fieldLabel: gettext('Directory'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.NFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveNFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'path',
-    displayField: 'path',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.nfsServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.nfsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.nfsServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'path', 'options' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/nfs'
-	    }
-	});
-
-	store.sort('path', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.NFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_nfs',
-
-    options : [],
-
-    onGetValues: function(values) {
-	var me = this;
-
-	var i;
-	var res = [];
-	for (i = 0; i < me.options.length; i++) {
-	    var item = me.options[i];
-	    if (!item.match(/^vers=(.*)$/)) {
-		res.push(item);
-	    }
-	}
-	if (values.nfsversion && values.nfsversion !== '__default__') {
-	    res.push('vers=' + values.nfsversion);
-	}
-	delete values.nfsversion;
-	values.options = res.join(',');
-	if (values.options === '') {
-	    delete values.options;
-	    if (!me.isCreate) {
-		values["delete"] = "options";
-	    }
-	}
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	var me = this;
-	if (values.options) {
-	    var res = values.options;
-	    me.options = values.options.split(',');
-	    me.options.forEach(function(item) {
-		var match = item.match(/^vers=(.*)$/);
-		if (match) {
-		    values.nfsversion = match[1];
-		}
-	    });
-	}
-	return me.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=export]');
-			    exportField.setServer(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'pveNFSScan' : 'displayfield',
-		name: 'export',
-		value: '',
-		fieldLabel: 'Export',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.advancedColumn1 = [
-	    {
-		xtype: 'proxmoxKVComboBox',
-		fieldLabel: gettext('NFS Version'),
-		name: 'nfsversion',
-		value: '__default__',
-		deleteEmpty: false,
-		comboItems: [
-			['__default__', Proxmox.Utils.defaultText],
-			['3', '3'],
-			['4', '4'],
-			['4.1', '4.1'],
-			['4.2', '4.2']
-		]
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.CIFSScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveCIFSScan',
-
-    queryParam: 'server',
-
-    valueField: 'share',
-    displayField: 'share',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.cifsServer) {
-	    me.store.removeAll();
-	}
-
-	var params = {};
-	if (me.cifsUsername && me.cifsPassword) {
-	    params.username =  me.cifsUsername;
-	    params.password = me.cifsPassword;
-	}
-
-	if (me.cifsDomain) {
-	    params.domain = me.cifsDomain;
-	}
-
-	me.store.getProxy().setExtraParams(params);
-	me.allQuery = me.cifsServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	this.cifsServer = server;
-    },
-
-    setUsername: function(username) {
-	this.cifsUsername = username;
-    },
-
-    setPassword: function(password) {
-	this.cifsPassword = password;
-    },
-
-    setDomain: function(domain) {
-	this.cifsDomain = domain;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: ['description', 'share'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/cifs'
-	    }
-	});
-	store.sort('share', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.CIFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_cifs',
-
-    initComponent : function() {
-	var me = this;
-
-	var passwordfield = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    inputType: 'password',
-	    name: 'password',
-	    value: me.isCreate ? '' : '********',
-	    fieldLabel: gettext('Password'),
-	    allowBlank: false,
-	    disabled: me.isCreate,
-	    minLength: 1,
-	    listeners: {
-		change: function(f, value) {
-
-		    if (me.isCreate) {
-			var exportField = me.down('field[name=share]');
-			exportField.setPassword(value);
-		    }
-		}
-	    }
-	});
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=share]');
-			    exportField.setServer(value);
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: '',
-		fieldLabel: gettext('Username'),
-		emptyText: gettext('Guest user'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (!me.isCreate) {
-			    return;
-			}
-			var exportField = me.down('field[name=share]');
-			exportField.setUsername(value);
-
-			if (value == "") {
-			    passwordfield.disable();
-			} else {
-			    passwordfield.enable();
-			}
-			passwordfield.validate();
-		    }
-		}
-	    },
-	    passwordfield,
-	    {
-		xtype: me.isCreate ? 'pveCIFSScan' : 'displayfield',
-		name: 'share',
-		value: '',
-		fieldLabel: 'Share',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'domain',
-		value: me.isCreate ? '' : undefined,
-		fieldLabel: gettext('Domain'),
-		allowBlank: true,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-
-			    var exportField = me.down('field[name=share]');
-			    exportField.setDomain(value);
-			}
-		    }
-		}
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.GlusterFsScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveGlusterFsScan',
-
-    queryParam: 'server',
-
-    valueField: 'volname',
-    displayField: 'volname',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: 'Scanning...',
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.glusterServer) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.glusterServer;
-
-	me.callParent();
-    },
-
-    setServer: function(server) {
-	var me = this;
-
-	me.glusterServer = server;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'volname' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/glusterfs'
-	    }
-	});
-
-	store.sort('volname', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.GlusterFsInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_glusterfs',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'server',
-		value: '',
-		fieldLabel: gettext('Server'),
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var volumeField = me.down('field[name=volume]');
-			    volumeField.setServer(value);
-			    volumeField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		name: 'server2',
-		value: '',
-		fieldLabel: gettext('Second Server'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'pveGlusterFsScan' : 'displayfield',
-		name: 'volume',
-		value: '',
-		fieldLabel: 'Volume name',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'iso', 'backup', 'vztmpl', 'snippets'],
-		name: 'content',
-		value: 'images',
-		multiSelect: true,
-		fieldLabel: gettext('Content'),
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		disabled: true,
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.IScsiScan', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveIScsiScan',
-
-    queryParam: 'portal',
-    valueField: 'target',
-    displayField: 'target',
-    matchFieldWidth: false,
-    listConfig: {
-	loadingText: gettext('Scanning...'),
-	width: 350
-    },
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.portal) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.portal;
-
-	me.callParent();
-    },
-
-    setPortal: function(portal) {
-	var me = this;
-
-	me.portal = portal;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'target', 'portal' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/iscsi'
-	    }
-	});
-
-	store.sort('target', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.IScsiInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_open_iscsi',
-
-    onGetValues: function(values) {
-	var me = this;
-
-	values.content = values.luns ? 'images' : 'none';
-	delete values.luns;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function(values) {
-	values.luns = (values.content.indexOf('images') !== -1) ? true : false;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: 'Portal',
-		allowBlank: false,
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    var exportField = me.down('field[name=target]');
-			    exportField.setPortal(value);
-			    exportField.setValue('');
-			}
-		    }
-		}
-	    },
-	    {
-		readOnly: !me.isCreate,
-		xtype: me.isCreate ? 'pveIScsiScan' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: 'Target',
-		allowBlank: false
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'checkbox',
-		name: 'luns',
-		checked: true,
-		fieldLabel: gettext('Use LUNs directly')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.VgSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveVgSelector',
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'vg', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	store.sort('vg', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseStorageSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseStorageSelector',
-
-    existingGroupsText: gettext("Existing volume groups"),
-    queryMode: 'local',
-    editable: false,
-    value: '',
-    valueField: 'storage',
-    displayField: 'text',
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {
-		addRecords: true,
-		params: {
-		    type: 'iscsi'
-		}
-	    },
-	    fields: [ 'storage', 'type', 'content',
-		      {
-			  name: 'text',
-			  convert: function(value, record) {
-			      if (record.data.storage) {
-				  return record.data.storage + " (iSCSI)";
-			      } else {
-				  return me.existingGroupsText;
-			      }
-			  }
-		      }],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/storage/'
-	    }
-	});
-
-	store.loadData([{ storage: '' }], true);
-
-	store.sort('storage', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LVMInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvm',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.VgSelector', {
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		allowBlank: false
-	    });
-
-	    var baseField = Ext.createWidget('pveFileSelector', {
-		name: 'base',
-		hidden: true,
-		disabled: true,
-		nodename: 'localhost',
-		storageContent: 'images',
-		fieldLabel: gettext('Base volume'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseStorageSelector',
-		name: 'basesel',
-		fieldLabel: gettext('Base storage'),
-		submitValue: false,
-		listeners: {
-		    change: function(f, value) {
-			if (value) {
-			    vgnameField.setVisible(true);
-			    vgnameField.setDisabled(false);
-			    vgField.setVisible(false);
-			    vgField.setDisabled(true);
-			    baseField.setVisible(true);
-			    baseField.setDisabled(false);
-			} else {
-			    vgnameField.setVisible(false);
-			    vgnameField.setDisabled(true);
-			    vgField.setVisible(true);
-			    vgField.setDisabled(false);
-			    baseField.setVisible(false);
-			    baseField.setDisabled(true);
-			}
-			baseField.setStorage(value);
-		    }
-		}
-	    });
-
-	    me.column1.push(baseField);
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	// here value is an array, 
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'shared',
-		uncheckedValue: 0,
-		fieldLabel: gettext('Shared')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.TPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveTPSelector',
-
-    queryParam: 'vg',
-    valueField: 'lv',
-    displayField: 'lv',
-    editable: false,
-
-    doRawQuery: function() {
-    },
-
-    onTriggerClick: function() {
-	var me = this;
-
-	if (!me.queryCaching || me.lastQuery !== me.vg) {
-	    me.store.removeAll();
-	}
-
-	me.allQuery = me.vg;
-
-	me.callParent();
-    },
-
-    setVG: function(myvg) {
-	var me = this;
-
-	me.vg = myvg;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'lv' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvmthin'
-	    }
-	});
-
-	store.sort('lv', 'ASC');
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.BaseVGSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveBaseVGSelector',
-
-    valueField: 'vg',
-    displayField: 'vg',
-    queryMode: 'local',
-    editable: false,
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {},
-	    fields: [ 'vg', 'size', 'free'],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/lvm'
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    listConfig: {
-		loadingText: gettext('Scanning...')
-	    }
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.LvmThinInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_lvmthin',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	var vgnameField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'vgname',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Volume group'),
-	    allowBlank: false
-	});
-
-	var thinpoolField = Ext.createWidget(me.isCreate ? 'textfield' : 'displayfield', {
-	    name: 'thinpool',
-	    hidden: !!me.isCreate,
-	    disabled: !!me.isCreate,
-	    value: '',
-	    fieldLabel: gettext('Thin Pool'),
-	    allowBlank: false
-	});
-
-	if (me.isCreate) {
-	    var vgField = Ext.create('PVE.storage.TPoolSelector', {
-		name: 'thinpool',
-		fieldLabel: gettext('Thin Pool'),
-		allowBlank: false
-	    });
-
-	    me.column1.push({
-		xtype: 'pveBaseVGSelector',
-		name: 'vgname',
-		fieldLabel: gettext('Volume group'),
-		listeners: {
-		    change: function(f, value) {
-			if (me.isCreate) {
-			    vgField.setVG(value);
-			    vgField.setValue('');
-			}
-		    }
-		}
-	    });
-
-	    me.column1.push(vgField);
-	}
-
-	me.column1.push(vgnameField);
-
-	me.column1.push(thinpoolField);
-
-	// here value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push({
-	    xtype: 'pveContentTypeSelector',
-	    cts: ['images', 'rootdir'],
-	    fieldLabel: gettext('Content'),
-	    name: 'content',
-	    value: ['images', 'rootdir'],
-	    multiSelect: true,
-	    allowBlank: false
-	});
-	/*jslint confusion: false*/
-
-	me.column2 = [];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.CephFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'storage_cephfs',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'cephfs';
-
-	me.column1 = [];
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		value: '',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		value: 'admin',
-		bind:  {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['backup', 'iso', 'vztmpl', 'snippets'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: 'backup',
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		fieldLabel: gettext('Max Backups'),
-		name: 'maxfiles',
-		reference: 'maxfiles',
-		minValue: 0,
-		maxValue: 365,
-		value: me.isCreate ? '1' : undefined,
-		allowBlank: false
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged cephFS')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.Ceph.Model', {
-    extend: 'Ext.app.ViewModel',
-    alias: 'viewmodel.cephstorage',
-
-    data: {
-	pveceph: true,
-	pvecephPossible: true
-    }
-});
-
-Ext.define('PVE.storage.Ceph.Controller', {
-    extend: 'PVE.controller.StorageEdit',
-    alias: 'controller.cephstorage',
-
-    control: {
-	'#': {
-	    afterrender: 'queryMonitors'
-	},
-	'textfield[name=username]': {
-	    disable: 'resetField'
-	},
-	'displayfield[name=monhost]': {
-	    enable: 'queryMonitors'
-	},
-	'textfield[name=monhost]': {
-	    disable: 'resetField',
-	    enable: 'resetField'
-	}
-    },
-    resetField: function(field) {
-	field.reset();
-    },
-    queryMonitors: function(field, newVal, oldVal) {
-	// we get called with two signatures, the above one for a field
-	// change event and the afterrender from the view, this check only
-	// can be true for the field change one and omit the API request if
-	// pveceph got unchecked - as it's not needed there.
-	if (field && !newVal && oldVal) {
-	    return;
-	}
-	var view = this.getView();
-	var vm = this.getViewModel();
-	if (!(view.isCreate || vm.get('pveceph'))) {
-	    return; // only query on create or if editing a pveceph store
-	}
-
-	var monhostField = this.lookupReference('monhost');
-
-	Proxmox.Utils.API2Request({
-	    url: '/api2/json/nodes/localhost/ceph/mon',
-	    method: 'GET',
-	    scope: this,
-	    callback: function(options, success, response) {
-		var data = response.result.data;
-		if (response.status === 200) {
-		    if (data.length > 0) {
-			var monhost = Ext.Array.pluck(data, 'name').sort().join(',');
-			monhostField.setValue(monhost);
-			monhostField.resetOriginalValue();
-			if (view.isCreate) {
-			    vm.set('pvecephPossible', true);
-			}
-		    } else {
-			vm.set('pveceph', false);
-		    }
-		} else {
-		    vm.set('pveceph', false);
-		    vm.set('pvecephPossible', false);
-		}
-	    }
-	});
-    }
-});
-
-Ext.define('PVE.storage.RBDInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-    controller: 'cephstorage',
-
-    onlineHelp: 'ceph_rados_block_devices',
-
-    viewModel: {
-	type: 'cephstorage'
-    },
-
-    setValues: function(values) {
-	if (values.monhost) {
-	    this.viewModel.set('pveceph', false);
-	    this.lookupReference('pvecephRef').setValue(false);
-	    this.lookupReference('pvecephRef').resetOriginalValue();
-	}
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-	me.type = 'rbd';
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push({
-		xtype: 'pveCephPoolSelector',
-		nodename: me.nodename,
-		name: 'pool',
-		bind: {
-		    disabled: '{!pveceph}',
-		    submitValue: '{pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },{
-		xtype: 'textfield',
-		name: 'pool',
-		value: 'rbd',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	} else {
-	    me.column1.push({
-		xtype: 'displayfield',
-		nodename: me.nodename,
-		name: 'pool',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    });
-	}
-
-	me.column1.push(
-	    {
-		xtype: 'textfield',
-		name: 'monhost',
-		vtype: 'HostList',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}',
-		    hidden: '{pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)',
-		allowBlank: false
-	    },
-	    {
-		xtype: 'displayfield',
-		reference: 'monhost',
-		bind: {
-		    disabled: '{!pveceph}',
-		    hidden: '{!pveceph}'
-		},
-		value: '',
-		fieldLabel: 'Monitor(s)'
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'username',
-		bind: {
-		    disabled: '{pveceph}',
-		    submitValue: '{!pveceph}'
-		},
-		value: 'admin',
-		fieldLabel: gettext('User name'),
-		allowBlank: true
-	    }
-	);
-
-	me.column2 = [
-	    {
-		xtype: 'pveContentTypeSelector',
-		cts: ['images', 'rootdir'],
-		fieldLabel: gettext('Content'),
-		name: 'content',
-		value: ['images'],
-		multiSelect: true,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'krbd',
-		uncheckedValue: 0,
-		fieldLabel: 'KRBD'
-	    }
-	];
-
-	me.columnB = [{
-	    xtype: 'proxmoxcheckbox',
-	    name: 'pveceph',
-	    reference: 'pvecephRef',
-	    bind : {
-		disabled: '{!pvecephPossible}',
-		value: '{pveceph}'
-	    },
-	    checked: true,
-	    uncheckedValue: 0,
-	    submitValue: false,
-	    hidden: !me.isCreate,
-	    boxLabel: gettext('Use Proxmox VE managed hyper-converged ceph pool')
-	}];
-
-	me.callParent();
-    }
-});
-/*jslint confusion: true*/
-Ext.define('PVE.storage.ZFSInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    isLIO: false,
-	    isComstar: true,
-	    hasWriteCacheOption: true
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[name=iscsiprovider]': {
-		change: 'changeISCSIProvider'
-	    }
-	},
-	changeISCSIProvider: function(f, newVal, oldVal) {
-	    var vm = this.getViewModel();
-	    vm.set('isLIO', newVal === 'LIO');
-	    vm.set('isComstar', newVal === 'comstar');
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
-	}
-    },
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.content = 'images';
-	}
-
-	values.nowritecache = values.writecache ? 0 : 1;
-	delete values.writecache;
-
-	return me.callParent([values]);
-    },
-
-    setValues: function diff(values) {
-	values.writecache = values.nowritecache ? 0 : 1;
-	this.callParent([values]);
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'portal',
-		value: '',
-		fieldLabel: gettext('Portal'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('Pool'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'blocksize',
-		value: '4k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'target',
-		value: '',
-		fieldLabel: gettext('Target'),
-		allowBlank: false
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_tg',
-		value: '',
-		fieldLabel: gettext('Target group'),
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		allowBlank: true
-	    }
-	];
-
-	me.column2 = [
-	    {
-		xtype: me.isCreate ? 'pveiScsiProviderSelector' : 'displayfield',
-		name: 'iscsiprovider',
-		value: 'comstar',
-		fieldLabel: gettext('iSCSI Provider'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'writecache',
-		checked: true,
-		bind: me.isCreate ? { disabled: '{!hasWriteCacheOption}' } : { hidden: '{!hasWriteCacheOption}' },
-		uncheckedValue: 0,
-		fieldLabel: gettext('Write cache')
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'comstar_hg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
-		fieldLabel: gettext('Host group'),
-		allowBlank: true
-	    },
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'lio_tpg',
-		value: '',
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
-		allowBlank: false,
-		fieldLabel: gettext('Target portal group')
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.storage.ZFSPoolSelector', {
-    extend: 'Ext.form.field.ComboBox',
-    alias: 'widget.pveZFSPoolSelector',
-    valueField: 'pool',
-    displayField: 'pool',
-    queryMode: 'local',
-    editable: false,
-    listConfig: {
-	loadingText: gettext('Scanning...')
-    },
-    initComponent : function() {
-	var me = this;
-
-	if (!me.nodename) {
-	    me.nodename = 'localhost';
-	}
-
-	var store = Ext.create('Ext.data.Store', {
-	    autoLoad: {}, // true,
-	    fields: [ 'pool', 'size', 'free' ],
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodename + '/scan/zfs'
-	    }
-	});
-
-	store.sort('pool', 'ASC');
-
-	Ext.apply(me, {
-	    store: store
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.storage.ZFSPoolInputPanel', {
-    extend: 'PVE.panel.StorageBase',
-
-    onlineHelp: 'storage_zfspool',
-
-    initComponent : function() {
-	var me = this;
-
-	me.column1 = [];
-
-	if (me.isCreate) {
-	    me.column1.push(Ext.create('PVE.storage.ZFSPoolSelector', {
-		name: 'pool',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	} else {
-	    me.column1.push(Ext.createWidget('displayfield', {
-		name: 'pool',
-		value: '',
-		fieldLabel: gettext('ZFS Pool'),
-		allowBlank: false
-	    }));
-	}
-
-	// value is an array,
-	// while before it was a string
-	/*jslint confusion: true*/
-	me.column1.push(
-	    {xtype: 'pveContentTypeSelector',
-	     cts: ['images', 'rootdir'],
-	     fieldLabel: gettext('Content'),
-	     name: 'content',
-	     value: ['images', 'rootdir'],
-	     multiSelect: true,
-	     allowBlank: false
-	});
-	/*jslint confusion: false*/
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'sparse',
-		checked: false,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Thin provision')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'blocksize',
-		emptyText: '8k',
-		fieldLabel: gettext('Block Size'),
-		allowBlank: true
-	    }
-	];
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.StatusView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAStatusView'],
-
-    onlineHelp: 'chapter_ha_manager',
-
-    sortPriority: {
-	quorum: 1,
-	master: 2,
-	lrm: 3,
-	service: 4
-    },
-    
-    initComponent : function() {
-	var me = this;
-
-	if (!me.rstore) {
-	    throw "no rstore given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sortAfterUpdate: true,
-	    sorters: [{
-		sorterFn: function(rec1, rec2) {
-		    var p1 = me.sortPriority[rec1.data.type];
-		    var p2 = me.sortPriority[rec2.data.type];
-		    return (p1 !== p2) ? ((p1 > p2) ? 1 : -1) : 0;
-		}
-	    }],
-	    filters: {
-		property: 'type',
-		value: 'service',
-		operator: '!='
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Type'),
-		    width: 80,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('Status'),
-		    width: 80,
-		    flex: 1,
-		    dataIndex: 'status'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);	
-
-    }
-}, function() {
-
-    Ext.define('pve-ha-status', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'id', 'type', 'node', 'status', 'sid',
-	    'state', 'group', 'comment',
-	    'max_restart', 'max_relocate', 'type',
-	    'crm_state', 'request_state',
-	    {
-		name: 'vname',
-		convert: function(value, record) {
-		    let sid = record.data.sid;
-		    if (!sid) return '';
-
-		    let res = sid.match(/^(\S+):(\S+)$/);
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			return '-';
-		    }
-		    let vmid = res[2];
-		    return PVE.data.ResourceStore.guestName(vmid);
-		},
-	    },
-	],
-	idProperty: 'id'
-    });
-
-});
-Ext.define('PVE.ha.Status', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveHAStatus',
-
-    onlineHelp: 'chapter_ha_manager',
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	me.rstore = Ext.create('Proxmox.data.ObjectStore', {
-	    interval: me.interval,
-	    model: 'pve-ha-status',
-	    storeid: 'pve-store-' + (++Ext.idSeed),
-	    groupField: 'type',
-	    proxy: {
-                type: 'proxmox',
-		url: '/api2/json/cluster/ha/status/current'
-	    }
-	});
-
-	me.items = [{
-	    xtype: 'pveHAStatusView',
-	    title: gettext('Status'),
-	    rstore: me.rstore,
-	    border: 0,
-	    collapsible: true,
-	    padding: '0 0 20 0'
-	},{
-	    xtype: 'pveHAResourcesView',
-	    flex: 1,
-	    collapsible: true,
-	    title: gettext('Resources'),
-	    border: 0,
-	    rstore: me.rstore
-	}];
-
-	me.callParent();
-	me.on('activate', me.rstore.startUpdate);
-    }
-});
-Ext.define('PVE.ha.GroupSelector', {
-    extend: 'Proxmox.form.ComboGrid',
-    alias: ['widget.pveHAGroupSelector'],
-
-    value: [],
-    autoSelect: false,
-    valueField: 'group',
-    displayField: 'group',
-    listConfig: {
-	columns: [
-	    {
-		header: gettext('Group'),
-		width: 100,
-		sortable: true,
-		dataIndex: 'group'
-	    },
-	    {
-		header: gettext('Nodes'),
-		width: 100,
-		sortable: false,
-		dataIndex: 'nodes'
-	    },
-	    {
-		header: gettext('Comment'),
-		flex: 1,
-		dataIndex: 'comment',
-		renderer: Ext.String.htmlEncode
-	    }
-	]
-    },
-    store: {
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-    },
-
-    initComponent: function() {
-	var me = this;
-	me.callParent();
-	me.getStore().load();
-    }
-
-}, function() {
-
-    Ext.define('pve-ha-groups', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'group', 'type', 'digest', 'nodes', 'comment',
-	    {
-		name : 'restricted',
-		type: 'boolean'
-	    },
-	    {
-		name : 'nofailback',
-		type: 'boolean'
-	    }
-	],
-	proxy: {
-            type: 'proxmox',
-	    url: "/api2/json/cluster/ha/groups"
-	},
-	idProperty: 'group'
-    });
-});
-Ext.define('PVE.ha.VMResourceInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_resource_config',
-    vmid: undefined,
-    
-    onGetValues: function(values) {
-	var me = this;
-
-	if (values.vmid) {
-	    values.sid = values.vmid;
-	}
-	delete values.vmid;
-
-	PVE.Utils.delete_if_default(values, 'group', '', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_restart', '1', me.isCreate);
-	PVE.Utils.delete_if_default(values, 'max_relocate', '1', me.isCreate);
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-	var MIN_QUORUM_VOTES = 3;
-
-	var disabledHint = Ext.createWidget({
-	    xtype: 'displayfield', // won't get submitted by default
-	    userCls: 'pmx-hint',
-	    value: 'Disabling the resource will stop the guest system. ' +
-	    'See the online help for details.',
-	    hidden: true
-	});
-
-	var fewVotesHint = Ext.createWidget({
-	    itemId: 'fewVotesHint',
-	    xtype: 'displayfield',
-	    userCls: 'pmx-hint',
-	    value: 'At least three quorum votes are recommended for reliable HA.',
-	    hidden: true
-	});
-
-	Proxmox.Utils.API2Request({
-	    url: '/cluster/config/nodes',
-	    method: 'GET',
-	    failure: function(response) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    },
-	    success: function(response) {
-		var nodes = response.result.data;
-		var votes = 0;
-		Ext.Array.forEach(nodes, function(node) {
-		    var vote = parseInt(node.quorum_votes, 10); // parse as base 10
-		    votes += vote || 0; // parseInt might return NaN, which is false
-		});
-
-		if (votes < MIN_QUORUM_VOTES) {
-		    fewVotesHint.setVisible(true);
-		}
-	    }
-	});
-
-	/*jslint confusion: true */
-	var vmidStore = (me.vmid) ? {} : {
-	    model: 'PVEResources',
-	    autoLoad: true,
-	    sorters: 'vmid',
-	    filters: [
-		{
-		    property: 'type',
-		    value: /lxc|qemu/
-		},
-		{
-		    property: 'hastate',
-		    value: /unmanaged/
-		}
-	    ]
-	};
-
-	// value is a string above, but a number below
-	me.column1 = [
-	    {
-		xtype: me.vmid ? 'displayfield' : 'vmComboSelector',
-		submitValue: me.isCreate,
-		name: 'vmid',
-		fieldLabel: (me.vmid && me.guestType === 'ct') ? 'CT' : 'VM',
-		value: me.vmid,
-		store: vmidStore,
-		validateExists: true
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_restart',
-		fieldLabel: gettext('Max. Restart'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    },
-	    {
-		xtype: 'proxmoxintegerfield',
-		name: 'max_relocate',
-		fieldLabel: gettext('Max. Relocate'),
-		value: 1,
-		minValue: 0,
-		maxValue: 10,
-		allowBlank: false
-	    }
-	];
-	/*jslint confusion: false */
-
-	me.column2 = [
-	    {
-		xtype: 'pveHAGroupSelector',
-		name: 'group',
-		fieldLabel: gettext('Group')
-	    },
-	    {
-		xtype: 'proxmoxKVComboBox',
-		name: 'state',
-		value: 'started',
-		fieldLabel: gettext('Request State'),
-		comboItems: [
-		    ['started', 'started'],
-		    ['stopped', 'stopped'],
-		    ['ignored', 'ignored'],
-		    ['disabled', 'disabled']
-		],
-		listeners: {
-		    'change': function(field, newValue) {
-			if (newValue === 'disabled') {
-			    disabledHint.setVisible(true);
-			}
-			else {
-			    if (disabledHint.isVisible()) {
-				disabledHint.setVisible(false);
-			    }
-			}
-		    }
-		}
-	    },
-	    disabledHint
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    fewVotesHint
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.VMResourceEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    vmid: undefined,
-    guestType: undefined,
-    isCreate: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	if (me.isCreate === undefined) {
-	    me.isCreate = !me.vmid;
-	}
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/resources';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/resources/' + me.vmid;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.VMResourceInputPanel', {
-	    isCreate: me.isCreate,
-	    vmid: me.vmid,
-	    guestType: me.guestType
-	});
-
-	Ext.apply(me, {
-	    subject: gettext('Resource') + ': ' + gettext('Container') +
-	    '/' + gettext('Virtual Machine'),
-	    isAdd: true,
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    var regex =  /^(\S+):(\S+)$/;
-		    var res = regex.exec(values.sid);
-
-		    if (res[1] !== 'vm' && res[1] !== 'ct') {
-			throw "got unexpected resource type";
-		    }
-
-		    values.vmid = res[2];
-		    
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.ResourcesView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAResourcesView'],
-
-    onlineHelp: 'ha_manager_resources',
-
-    stateful: true,
-    stateId: 'grid-ha-resources',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	if (!me.rstore) {
-	    throw "no store given";
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	var store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    filters: {
-		property: 'type',
-		value: 'service'
-	    }
-	});
-
-	var reload = function() {
-	    me.rstore.load();
-	};
-
-	var render_error = function(dataIndex, value, metaData, record) {
-	    var errors = record.data.errors;
-	    if (errors) {
-		var msg = errors[dataIndex];
-		if (msg) {
-		    metaData.tdCls = 'proxmox-invalid-row';
-		    var html = '<p>' +  Ext.htmlEncode(msg) + '</p>';
-		    metaData.tdAttr = 'data-qwidth=600 data-qtitle="ERROR" data-qtip="' + 
-			html.replace(/\"/g,'&quot;') + '"';
-		}
-	    }
-	    return value;
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    var sid = rec.data.sid;
-	    
-	    var regex =  /^(\S+):(\S+)$/;
-	    var res = regex.exec(sid);
-
-	    if (res[1] !== 'vm' && res[1] !== 'ct') {
-		return;
-	    }
-	    var guestType = res[1];
-	    var vmid = res[2];
-	    
-            var win = Ext.create('PVE.ha.VMResourceEdit',{
-                guestType: guestType,
-                vmid: vmid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/resources/',
-	    getUrl: function(rec) {
-		var me = this;
-		return me.baseurl + '/' + rec.get('sid');
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.VMResourceEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-
-	    columns: [
-		{
-		    header: 'ID',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'sid'
-		},
-		{
-		    header: gettext('State'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'state'
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Request State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    renderer: function(v) {
-			return v || 'started';
-		    },
-		    dataIndex: 'request_state'
-		},
-		{
-		    header: gettext('CRM State'),
-		    width: 100,
-		    hidden: true,
-		    sortable: true,
-		    dataIndex: 'crm_state'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'vname',
-		},
-		{
-		    header: gettext('Max. Restart'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_restart'
-		},
-		{
-		    header: gettext('Max. Relocate'),
-		    width: 100,
-		    sortable: true,
-		    renderer: (v) => v === undefined ? '1' : v,
-		    dataIndex: 'max_relocate'
-		},
-		{
-		    header: gettext('Group'),
-		    width: 200,
-		    sortable: true,
-		    renderer: function(value, metaData, record) {
-			return render_error('group', value, metaData, record);
-		    },
-		    dataIndex: 'group'
-		},
-		{
-		    header: gettext('Description'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.GroupInputPanel', {
-    extend: 'Proxmox.panel.InputPanel',
-    onlineHelp: 'ha_manager_groups',
-
-    groupId: undefined,
-
-    onGetValues: function(values) {
-	var me = this;
-
-	if (me.isCreate) {
-	    values.type = 'group';
-	}
-
-	return values;
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var update_nodefield, update_node_selection;
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    update_nodefield(selected);
-		}
-	    }
-	});
-
-	// use already cached data to avoid an API call
-	var data = PVE.data.ResourceStore.getNodes();
-
-	var store = Ext.create('Ext.data.Store', {
-	    fields: [ 'node', 'mem', 'cpu', 'priority' ],
-	    data: data,
-	    proxy: {
-		type: 'memory',
-		reader: {type: 'json'}
-	    },
-	    sorters: [
-		{
-		    property : 'node',
-		    direction: 'ASC'
-		}
-	    ]
-	});
-
-	var nodegrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    columns: [
-		{
-		    header: gettext('Node'),
-		    flex: 1,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Memory usage') + " %",
-		    renderer: PVE.Utils.render_mem_usage_percent,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'mem'
-		},
-		{
-		    header: gettext('CPU usage'),
-		    renderer: PVE.Utils.render_cpu,
-		    sortable: true,
-		    width: 150,
-		    dataIndex: 'cpu'
-		},
-		{
-		    header: 'Priority',
-		    xtype: 'widgetcolumn',
-		    dataIndex: 'priority',
-		    sortable: true,
-		    stopSelection: true,
-		    widget: {
-			xtype: 'proxmoxintegerfield',
-			minValue: 0,
-			maxValue: 1000,
-			isFormField: false,
-			listeners: {
-			    change: function(numberfield, value, old_value) {
-				var record = numberfield.getWidgetRecord();
-				record.set('priority', value);
-				update_nodefield(sm.getSelection());
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	var nodefield = Ext.create('Ext.form.field.Hidden', {
-	    name: 'nodes',
-	    value: '',
-	    listeners: {
-		change: function (nodefield, value) {
-		    update_node_selection(value);
-		}
-	    },
-	    isValid: function () {
-		var value = nodefield.getValue();
-		return (value && 0 !== value.length);
-	    }
-	});
-
-	update_node_selection = function(string) {
-	    sm.deselectAll(true);
-
-	    string.split(',').forEach(function (e, idx, array) {
-		var res = e.split(':');
-
-		store.each(function(record) {
-		    var node = record.get('node');
-
-		    if (node == res[0]) {
-			sm.select(record, true);
-			record.set('priority', res[1]);
-			record.commit();
-		    }
-		});
-	    });
-	    nodegrid.reconfigure(store);
-
-	};
-
-	update_nodefield = function(selected) {
-	    var nodes = '';
-	    var first_iteration = true;
-	    Ext.Array.each(selected, function(record) {
-		if (!first_iteration) {
-		    nodes += ',';
-		}
-		first_iteration = false;
-
-		nodes += record.data.node;
-		if (record.data.priority) {
-		    nodes += ':' + record.data.priority;
-		}
-	    });
-
-	    // nodefield change listener calls us again, which results in a
-	    // endless recursion, suspend the event temporary to avoid this
-	    nodefield.suspendEvent('change');
-	    nodefield.setValue(nodes);
-	    nodefield.resumeEvent('change');
-	};
-
-	me.column1 = [
-	    {
-		xtype: me.isCreate ? 'textfield' : 'displayfield',
-		name: 'group',
-		value: me.groupId || '',
-		fieldLabel: 'ID',
-		vtype: 'StorageId',
-		allowBlank: false
-	    },
-	    nodefield
-	];
-
-	me.column2 = [
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'restricted',
-		uncheckedValue: 0,
-		fieldLabel: 'restricted'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'nofailback',
-		uncheckedValue: 0,
-		fieldLabel: 'nofailback'
-	    }
-	];
-
-	me.columnB = [
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-	    },
-	    nodegrid
-	];
-	
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.ha.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    groupId: undefined,
-
-    initComponent : function() {
-	var me = this;
- 
-	me.isCreate = !me.groupId;
-
-	if (me.isCreate) {
-            me.url = '/api2/extjs/cluster/ha/groups';
-            me.method = 'POST';
-        } else {
-            me.url = '/api2/extjs/cluster/ha/groups/' + me.groupId;
-            me.method = 'PUT';
-        }
-
-	var ipanel = Ext.create('PVE.ha.GroupInputPanel', {
-	    isCreate: me.isCreate,
-	    groupId: me.groupId
-	});
-
-	Ext.apply(me, {
-            subject: gettext('HA Group'),
-	    items: [ ipanel ]
-	});
-	
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success:  function(response, options) {
-		    var values = response.result.data;
-
-		    ipanel.setValues(values);
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.ha.GroupsView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveHAGroupsView'],
-
-    onlineHelp: 'ha_manager_groups',
-
-    stateful: true,
-    stateId: 'grid-ha-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-groups',
-	    sorters: { 
-		property: 'group', 
-		order: 'DESC' 
-	    }
-	});
-	
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-
-            var win = Ext.create('PVE.ha.GroupEdit',{
-                groupId: rec.data.group
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/ha/groups/',
-	    callback: function() {
-		reload();
-	    }
-	});
-	
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    disabled: !caps.nodes['Sys.Console'],
-		    handler: function() {
-			var win = Ext.create('PVE.ha.GroupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		edit_btn, remove_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Group'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'group'
-		},
-		{
-		    header: 'restricted',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'restricted'
-		},
-		{
-		    header: 'nofailback',
-		    width: 100,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'nofailback'
-		},
-		{
-		    header: gettext('Nodes'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'nodes'
-		},
-		{
-		    header: gettext('Comment'),
-		    flex: 1,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		beforeselect: function(grid, record, index, eOpts) {
-		    if (!caps.nodes['Sys.Console']) {
-			return false;
-		    }
-		},
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.ha.FencingView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: ['widget.pveFencingView'],
-
-    onlineHelp: 'ha_manager_fencing',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-ha-fencing',
-	    data: []
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    stateful: false,
-	    viewConfig: {
-		trackOver: false,
-		deferEmptyText: false,
-		emptyText: 'Use watchdog based fencing.'
-	    },
-	    columns: [
-		{
-		    header: 'Node',
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Command'),
-		    flex: 1,
-		    dataIndex: 'command'
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-ha-fencing', {
-	extend: 'Ext.data.Model',
-	fields: [ 
-	    'node', 'command', 'digest'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Summary', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSummary',
-
-    scrollable: true,
-
-    bodyPadding: 5,
-
-    layout: 'column',
-
-    defaults: {
-	padding: 5,
-	columnWidth: 1,
-    },
-
-    items: [
-	{
-	    itemId: 'dcHealth',
-	    xtype: 'pveDcHealth'
-	},
-	{
-	    itemId: 'dcGuests',
-	    xtype: 'pveDcGuests'
-	},
-	{
-	    title: gettext('Resources'),
-	    xtype: 'panel',
-	    minHeight: 250,
-	    bodyPadding: 5,
-	    layout: 'hbox',
-	    defaults: {
-		xtype: 'proxmoxGauge',
-		flex: 1
-	    },
-	    items:[
-		{
-		    title: gettext('CPU'),
-		    itemId: 'cpu'
-		},
-		{
-		    title: gettext('Memory'),
-		    itemId: 'memory'
-		},
-		{
-		    title: gettext('Storage'),
-		    itemId: 'storage'
-		}
-	    ]
-	},
-	{
-	    itemId: 'nodeview',
-	    xtype: 'pveDcNodeView',
-	    height: 250
-	},
-	{
-	    title: gettext('Subscriptions'),
-	    height: 220,
-	    items: [
-		{
-		    itemId: 'subscriptions',
-		    xtype: 'pveHealthWidget',
-		    userCls: 'pointer',
-		    listeners: {
-			element: 'el',
-			click: function() {
-			    if (this.component.userCls === 'pointer') {
-				window.open('https://www.proxmox.com/en/proxmox-ve/pricing', '_blank');
-			    }
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-
-    listeners: {
-	resize: function(panel) {
-	    PVE.Utils.updateColumns(panel);
-	},
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-status',
-	    model: 'pve-dc-nodes',
-	    proxy: {
-                type: 'proxmox',
-                url: "/api2/json/cluster/status"
-	    }
-	});
-
-	var gridstore = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: rstore,
-	    filters: {
-		property: 'type',
-		value: 'node'
-	    },
-	    sorters: {
-		property: 'id',
-		direction: 'ASC'
-	    }
-	});
-
-	me.callParent();
-
-	me.getComponent('nodeview').setStore(gridstore);
-
-	var gueststatus = me.getComponent('dcGuests');
-
-	var cpustat = me.down('#cpu');
-	var memorystat = me.down('#memory');
-	var storagestat = me.down('#storage');
-	var sp = Ext.state.Manager.getProvider();
-
-	me.mon(PVE.data.ResourceStore, 'load', function(curstore, results) {
-	    me.suspendLayout = true;
-
-	    var cpu = 0;
-	    var maxcpu = 0;
-
-	    var nodes = 0;
-
-	    var memory = 0;
-	    var maxmem = 0;
-
-	    var countedStorages = {};
-	    var used = 0;
-	    var total = 0;
-	    var usableStorages = {};
-	    var storages = sp.get('dash-storages') || '';
-	    storages.split(',').forEach(function(storage){
-		if (storage !== '') {
-		    usableStorages[storage] = true;
-		}
-	    });
-
-	    var qemu = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var lxc = {
-		running: 0,
-		paused: 0,
-		stopped: 0,
-		template: 0
-	    };
-	    var error = 0;
-
-	    var i;
-
-	    for (i = 0; i < results.length; i++) {
-		var item = results[i];
-		switch(item.data.type) {
-		    case 'node':
-			cpu += (item.data.cpu * item.data.maxcpu);
-			maxcpu += item.data.maxcpu || 0;
-			memory += item.data.mem || 0;
-			maxmem += item.data.maxmem || 0;
-			nodes++;
-
-			// update grid also
-			var griditem = gridstore.getById(item.data.id);
-			if (griditem) {
-			    griditem.set('cpuusage', item.data.cpu);
-			    var max = item.data.maxmem || 1;
-			    var val = item.data.mem || 0;
-			    griditem.set('memoryusage', val/max);
-			    griditem.set('uptime', item.data.uptime);
-			    griditem.commit(); //else it marks the fields as dirty
-			}
-			break;
-		    case 'storage':
-			if (!Ext.Object.isEmpty(usableStorages)) {
-			    if (usableStorages[item.data.id] === true) {
-				used += item.data.disk;
-				total += item.data.maxdisk;
-			    }
-			    break;
-			}
-			if (!countedStorages[item.data.storage] ||
-			    (!item.data.shared && !countedStorages[item.data.id])) {
-			    used += item.data.disk;
-			    total += item.data.maxdisk;
-
-			    countedStorages[item.data.storage === 'local'?item.data.id:item.data.storage] = true;
-			}
-			break;
-		    case 'qemu':
-			qemu[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    case 'lxc':
-			lxc[item.data.template ? 'template' : item.data.status]++;
-			if (item.data.hastate === 'error') {
-			    error++;
-			}
-			break;
-		    default: break;
-		}
-	    }
-
-	    var text = Ext.String.format(gettext('of {0} CPU(s)'), maxcpu);
-	    cpustat.updateValue((cpu/maxcpu), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(memory), PVE.Utils.render_size(maxmem));
-	    memorystat.updateValue((memory/maxmem), text);
-
-	    text = Ext.String.format(gettext('{0} of {1}'), PVE.Utils.render_size(used), PVE.Utils.render_size(total));
-	    storagestat.updateValue((used/total), text);
-
-	    gueststatus.updateValues(qemu,lxc,error);
-
-	    me.suspendLayout = false;
-	    me.updateLayout(true);
-	});
-
-	var dcHealth = me.getComponent('dcHealth');
-	me.mon(rstore, 'load', dcHealth.updateStatus, dcHealth);
-
-	var subs = me.down('#subscriptions');
-	me.mon(rstore, 'load', function(store, records, success) {
-	    var i;
-	    var level;
-	    var mixed = false;
-	    for (i = 0; i < records.length; i++) {
-		if (records[i].get('type') !== 'node') {
-		    continue;
-		}
-		var node = records[i];
-		if (node.get('status') === 'offline') {
-		    continue;
-		}
-
-		var curlevel = node.get('level');
-
-		if (curlevel === '') { // no subscription trumps all, set and break
-		    level = '';
-		    break;
-		}
-
-		if (level === undefined) { // save level
-		    level = curlevel;
-		} else if (level !== curlevel) { // detect different levels
-		    mixed = true;
-		}
-	    }
-
-	    var data = {
-		title: Proxmox.Utils.unknownText,
-		text: Proxmox.Utils.unknownText,
-		iconCls: PVE.Utils.get_health_icon(undefined, true)
-	    };
-	    if (level === '') {
-		data = {
-		    title: gettext('No Subscription'),
-		    iconCls: PVE.Utils.get_health_icon('critical', true),
-		    text: gettext('You have at least one node without subscription.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (mixed) {
-		data = {
-		    title: gettext('Mixed Subscriptions'),
-		    iconCls: PVE.Utils.get_health_icon('warning', true),
-		    text: gettext('Warning: Your subscription levels are not the same.')
-		};
-		subs.setUserCls('pointer');
-	    } else if (level) {
-		data = {
-		    title: PVE.Utils.render_support_level(level),
-		    iconCls: PVE.Utils.get_health_icon('good', true),
-		    text: gettext('Your subscription status is valid.')
-		};
-		subs.setUserCls('');
-	    }
-
-	    subs.setData(data);
-	});
-
-	me.on('destroy', function(){
-	    rstore.stopUpdate();
-	});
-
-	me.mon(sp, 'statechange', function(provider, key, value) {
-	    if (key !== 'summarycolumns') {
-		return;
-	    }
-	    PVE.Utils.updateColumns(me);
-	});
-
-	rstore.startUpdate();
-    }
-
-});
-Ext.define('PVE.window.ReplicaEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveReplicaEdit',
-
-    subject: gettext('Replication Job'),
-
-
-    url: '/cluster/replication',
-    method: 'POST',
-
-    initComponent: function() {
-	var me = this;
-
-	var vmid = me.pveSelNode.data.vmid;
-	var nodename = me.pveSelNode.data.node;
-
-	var items = [];
-
-	items.push({
-	    xtype: (me.isCreate && !vmid)?'pveGuestIDSelector':'displayfield',
-	    name: 'guest',
-	    fieldLabel: 'CT/VM ID',
-	    value: vmid || ''
-	});
-
-	items.push(
-	    {
-		xtype: me.isCreate ? 'pveNodeSelector':'displayfield',
-		name: 'target',
-		disallowedNodes: [nodename],
-		allowBlank: false,
-		onlineValidator: true,
-		fieldLabel: gettext("Target")
-	    },
-	    {
-		xtype: 'pveCalendarEvent',
-		fieldLabel: gettext('Schedule'),
-		emptyText: '*/15 - ' + Ext.String.format(gettext('Every {0} minutes'), 15),
-		name: 'schedule'
-	    },
-	    {
-		xtype: 'numberfield',
-		fieldLabel: gettext('Rate limit') + ' (MB/s)',
-		step: 1,
-		minValue: 1,
-		emptyText: gettext('unlimited'),
-		name: 'rate'
-	    },
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Comment'),
-		name: 'comment'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		name: 'enabled',
-		defaultValue: 'on',
-		checked: true,
-		fieldLabel: gettext('Enabled')
-	    }
-	);
-
-	me.items = [
-	    {
-		xtype: 'inputpanel',
-		itemId: 'ipanel',
-		onlineHelp: 'pvesr_schedule_time_format',
-
-		onGetValues: function(values) {
-		    var me = this.up('window');
-
-		    values.disable = values.enabled ? 0 : 1;
-		    delete values.enabled;
-
-		    PVE.Utils.delete_if_default(values, 'rate', '', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'disable', 0, me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'schedule', '*/15', me.isCreate);
-		    PVE.Utils.delete_if_default(values, 'comment', '', me.isCreate);
-
-		    if (me.isCreate) {
-			values.type = 'local';
-			var vm = vmid || values.guest;
-			var id = -1;
-			if (me.highestids[vm] !== undefined) {
-			    id = me.highestids[vm];
-			}
-			id++;
-			values.id = vm + '-' + id.toString();
-			delete values.guest;
-		    }
-		    return values;
-		},
-		items: items
-	    }
-	];
-
-	me.callParent();
-
-	if (me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var jobs = response.result.data;
-		    var highestids = {};
-		    Ext.Array.forEach(jobs, function(job) {
-			var match = /^([0-9]+)\-([0-9]+)$/.exec(job.id);
-			if (match) {
-			    var vmid = parseInt(match[1],10);
-			    var id = parseInt(match[2],10);
-			    if (highestids[vmid] < id ||
-				highestids[vmid] === undefined) {
-				highestids[vmid] = id;
-			    }
-			}
-		    });
-
-		    me.highestids = highestids;
-		}
-	    });
-
-	} else {
-	    me.load({
-		success: function(response, options) {
-		    response.result.data.enabled = !response.result.data.disable;
-		    me.setValues(response.result.data);
-		    me.digest = response.result.data.digest;
-		}
-	    });
-	}
-    }
-});
-
-/*jslint confusion: true */
-/* callback is a function and string */
-Ext.define('PVE.grid.ReplicaView', {
-    extend: 'Ext.grid.Panel',
-    xtype: 'pveReplicaView',
-
-    onlineHelp: 'chapter_pvesr',
-
-    stateful: true,
-    stateId: 'grid-pve-replication-status',
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-
-	addJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		isCreate: true,
-		method: 'POST',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	editJob: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var data = rec.data;
-	    var win = Ext.create('PVE.window.ReplicaEdit', {
-		url: '/cluster/replication/' + data.id,
-		method: 'PUT',
-		pveSelNode: me.pveSelNode
-	    });
-	    win.on('destroy', function() { controller.reload(); });
-	    win.show();
-	},
-
-	scheduleJobNow: function(button,event,rec) {
-	    var me = this.getView();
-	    var controller = this;
-
-	    Proxmox.Utils.API2Request({
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/schedule_now",
-		method: 'POST',
-		waitMsgTarget: me,
-		callback: function() { controller.reload(); },
-		failure: function (response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	showLog: function(button, event, rec) {
-	    var me = this.getView();
-	    var controller = this;
-	    var logView = Ext.create('Proxmox.panel.LogView', {
-		border: false,
-		url: "/api2/extjs/nodes/" + me.nodename + "/replication/" + rec.data.id + "/log"
-	    });
-	    var win = Ext.create('Ext.window.Window', {
-		items: [ logView ],
-		layout: 'fit',
-		width: 800,
-		height: 400,
-		modal: true,
-		title: gettext("Replication Log")
-	    });
-	    var task = {
-		run: function() {
-		    logView.requestUpdate();
-		},
-		interval: 1000
-	    };
-	    Ext.TaskManager.start(task);
-	    win.on('destroy', function() {
-		Ext.TaskManager.stop(task);
-		controller.reload();
-	    });
-	    win.show();
-	},
-
-	reload: function() {
-	    var me = this.getView();
-	    me.rstore.load();
-	},
-
-	dblClick: function(grid, record, item) {
-	    var me = this;
-	    me.editJob(undefined, undefined, record);
-	},
-
-	// check for cluster
-	// currently replication is for cluster only, so we disable the whole
-	// component
-	checkPrerequisites: function() {
-	    var me = this.getView();
-	    if (PVE.data.ResourceStore.getNodes().length < 2) {
-		me.mask(gettext("Replication needs at least two nodes"), ['pve-static-mask']);
-	    }
-	},
-
-	control: {
-	    '#': {
-		itemdblclick: 'dblClick',
-		afterlayout: 'checkPrerequisites'
-	    }
-	}
-    },
-
-    tbar: [
-	{
-	    text: gettext('Add'),
-	    itemId: 'addButton',
-	    handler: 'addJob'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Edit'),
-	    itemId: 'editButton',
-	    handler: 'editJob',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxStdRemoveButton',
-	    itemId: 'removeButton',
-	    baseurl: '/api2/extjs/cluster/replication/',
-	    dangerous: true,
-	    callback: 'reload'
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Log'),
-	    itemId: 'logButton',
-	    handler: 'showLog',
-	    disabled: true
-	},
-	{
-	    xtype: 'proxmoxButton',
-	    text: gettext('Schedule now'),
-	    itemId: 'scheduleNowButton',
-	    handler: 'scheduleJobNow',
-	    disabled: true
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-	var mode = '';
-	var url = '/cluster/replication';
-
-	me.nodename = me.pveSelNode.data.node;
-	me.vmid = me.pveSelNode.data.vmid;
-
-	me.columns = [
-	    {
-		text: gettext('Enabled'),
-		dataIndex: 'enabled',
-		xtype: 'checkcolumn',
-		sortable: true,
-		disabled: true
-	    },
-	    {
-		text: 'ID',
-		dataIndex: 'id',
-		width: 60,
-		hidden: true
-	    },
-	    {
-		text: gettext('Guest'),
-		dataIndex: 'guest',
-		width: 75
-	    },
-	    {
-		text: gettext('Job'),
-		dataIndex: 'jobnum',
-		width: 60
-	    },
-	    {
-		text: gettext('Target'),
-		dataIndex: 'target'
-	    }
-	];
-
-	if (!me.nodename) {
-	    mode = 'dc';
-	    me.stateId = 'grid-pve-replication-dc';
-	} else if (!me.vmid) {
-	    mode = 'node';
-	    url = '/nodes/' + me.nodename + '/replication';
-	} else {
-	    mode = 'vm';
-	    url = '/nodes/' + me.nodename + '/replication' + '?guest=' + me.vmid;
-	}
-
-	if (mode !== 'dc') {
-	    me.columns.push(
-		{
-		    text: gettext('Status'),
-		    dataIndex: 'state',
-		    minWidth: 160,
-		    flex: 1,
-		    renderer: function(value, metadata, record) {
-
-			if (record.data.pid) {
-			    metadata.tdCls = 'x-grid-row-loading';
-			    return '';
-			}
-
-			var icons = [];
-			var states = [];
-
-			if (record.data.remove_job) {
-			    icons.push('<i class="fa fa-ban warning" title="'
-					+ gettext("Removal Scheduled") + '"></i>');
-			    states.push(gettext("Removal Scheduled"));
-			}
-
-			if (record.data.error) {
-			    icons.push('<i class="fa fa-times critical" title="'
-					+ gettext("Error") + '"></i>');
-			    states.push(record.data.error);
-			}
-
-			if (icons.length == 0) {
-			    icons.push('<i class="fa fa-check good"></i>');
-			    states.push(gettext('OK'));
-			}
-
-			return icons.join(',') + ' ' + states.join(',');
-		    }
-		},
-		{
-		    text: gettext('Last Sync'),
-		    dataIndex: 'last_sync',
-		    width: 150,
-		    renderer: function(value, metadata, record) {
-			if (!value) {
-			    return '-';
-			}
-
-			if (record.data.pid) {
-			    return gettext('syncing');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		},
-		{
-		    text: gettext('Duration'),
-		    dataIndex: 'duration',
-		    width: 60,
-		    renderer: PVE.Utils.render_duration
-		},
-		{
-		    text: gettext('Next Sync'),
-		    dataIndex: 'next_sync',
-		    width: 150,
-		    renderer: function(value) {
-			if (!value) {
-			    return '-';
-			}
-
-			var now = new Date();
-			var next = new Date(value*1000);
-
-			if (next < now) {
-			    return gettext('pending');
-			}
-
-			return Proxmox.Utils.render_timestamp(value);
-		    }
-		}
-	    );
-	}
-
-	me.columns.push(
-	    {
-		text: gettext('Schedule'),
-		width: 75,
-		dataIndex: 'schedule'
-	    },
-	    {
-		text: gettext('Rate limit'),
-		dataIndex: 'rate',
-		renderer: function(value) {
-		    if (!value) {
-			return gettext('unlimited');
-		    }
-
-		    return value.toString() + ' MB/s';
-		},
-		hidden: true
-	    },
-	    {
-		text: gettext('Comment'),
-		dataIndex: 'comment',
-		renderer: Ext.htmlEncode
-	    }
-	);
-
-	me.rstore = Ext.create('Proxmox.data.UpdateStore', {
-	    storeid: 'pve-replica-' + me.nodename + me.vmid,
-	    model: (mode === 'dc')? 'pve-replication' : 'pve-replication-state',
-	    interval: 3000,
-	    proxy: {
-		type: 'proxmox',
-		url: "/api2/json" + url
-	    }
-	});
-
-	me.store = Ext.create('Proxmox.data.DiffStore', {
-	    rstore: me.rstore,
-	    sorters: [
-		{
-		    property: 'guest'
-		},
-		{
-		    property: 'jobnum'
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	// we cannot access the log and scheduleNow button
-	// in the datacenter, because
-	// we do not know where/if the jobs runs
-	if (mode === 'dc') {
-	    me.down('#logButton').setHidden(true);
-	    me.down('#scheduleNowButton').setHidden(true);
-	}
-
-	// if we set the warning mask, we do not want to load
-	// or set the mask on store errors
-	if (PVE.data.ResourceStore.getNodes().length < 2) {
-	    return;
-	}
-
-	Proxmox.Utils.monStoreErrors(me, me.rstore);
-
-	me.on('destroy', me.rstore.stopUpdate);
-	me.rstore.startUpdate();
-    }
-}, function() {
-
-    Ext.define('pve-replication', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'target', 'comment', 'rate', 'type',
-	    { name: 'guest', type: 'integer' },
-	    { name: 'jobnum', type: 'integer' },
-	    { name: 'schedule', defaultValue: '*/15' },
-	    { name: 'disable', defaultValue: '' },
-	    { name: 'enabled', calculate: function(data) { return !data.disable; } }
-	]
-    });
-
-    Ext.define('pve-replication-state', {
-	extend: 'pve-replication',
-	fields: [
-	    'last_sync', 'next_sync', 'error', 'duration', 'state',
-	    'fail_count', 'remove_job', 'pid'
-	]
-    });
-
-});
-Ext.define('PVE.dc.Health', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcHealth',
-
-    title: gettext('Health'),
-
-    bodyPadding: 10,
-    height: 220,
-    layout: {
-	type: 'hbox',
-	align: 'stretch'
-    },
-
-    defaults: {
-	flex: 1,
-	xtype: 'box',
-	style: {
-	    'text-align':'center'
-	}
-    },
-
-    nodeList: [],
-    nodeIndex: 0,
-
-    updateStatus: function(store, records, success) {
-	var me = this;
-	if (!success) {
-	    return;
-	}
-
-	var cluster = {
-	    iconCls: PVE.Utils.get_health_icon('good', true),
-	    text: gettext("Standalone node - no cluster defined")
-	};
-
-	var nodes = {
-	    online: 0,
-	    offline: 0
-	};
-
-	// by default we have one node
-	var numNodes = 1;
-	var i;
-
-	for (i = 0; i < records.length; i++) {
-	    var item = records[i];
-	    if (item.data.type === 'node') {
-		nodes[item.data.online === 1 ? 'online':'offline']++;
-	    } else if(item.data.type === 'cluster') {
-		cluster.text = gettext("Cluster") + ": ";
-		cluster.text += item.data.name + ", ";
-		cluster.text += gettext("Quorate") + ": ";
-		cluster.text += Proxmox.Utils.format_boolean(item.data.quorate);
-		if (item.data.quorate != 1) {
-		    cluster.iconCls = PVE.Utils.get_health_icon('critical', true);
-		}
-
-		numNodes = item.data.nodes;
-	    }
-	}
-
-	if (numNodes !== (nodes.online + nodes.offline)) {
-	    nodes.offline = numNodes - nodes.online;
-	}
-
-	me.getComponent('clusterstatus').updateHealth(cluster);
-	me.getComponent('nodestatus').update(nodes);
-    },
-
-    updateCeph: function(store, records, success) {
-	var me = this;
-	var cephstatus = me.getComponent('ceph');
-	if (!success || records.length < 1) {
-
-	    // if ceph status is already visible
-	    // don't stop to update
-	    if (cephstatus.isVisible()) {
-		return;
-	    }
-
-	    // try all nodes until we either get a successful api call,
-	    // or we tried all nodes
-	    if (++me.nodeIndex >= me.nodeList.length) {
-		me.cephstore.stopUpdate();
-	    } else {
-		store.getProxy().setUrl('/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status');
-	    }
-
-	    return;
-	}
-
-	var state = PVE.Utils.render_ceph_health(records[0].data.health || {});
-	cephstatus.updateHealth(state);
-	cephstatus.setVisible(true);
-    },
-
-    listeners: {
-	destroy: function() {
-	    var me = this;
-	    me.cephstore.stopUpdate();
-	}
-    },
-
-    items: [
-	{
-	    itemId: 'clusterstatus',
-	    xtype: 'pveHealthWidget',
-	    title: gettext('Status')
-	},
-	{
-	    itemId: 'nodestatus',
-	    data: {
-		online: 0,
-		offline: 0
-	    },
-	    tpl: [
-		'<h3>' + gettext('Nodes') + '</h3><br />',
-		'<div style="width: 150px;margin: auto;font-size: 12pt">',
-		'<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-check">&nbsp;</i>',
-		gettext('Online'),
-		'</div>',
-		'<div class="right-aligned">{online}</div>',
-		'<br /><br />',
-		'<div class="left-aligned">',
-		'<i class="critical fa fa-fw fa-times">&nbsp;</i>',
-		gettext('Offline'),
-		'</div>',
-		'<div class="right-aligned">{offline}</div>',
-		'</div>'
-	    ]
-	},
-	{
-	    itemId: 'ceph',
-	    width: 250,
-	    columnWidth: undefined,
-	    userCls: 'pointer',
-	    title: 'Ceph',
-	    xtype: 'pveHealthWidget',
-	    hidden: true,
-	    listeners: {
-		element: 'el',
-		click: function() {
-		    var sp = Ext.state.Manager.getProvider();
-		    sp.set('dctab', {value:'ceph'}, true);
-		}
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	me.nodeList = PVE.data.ResourceStore.getNodes();
-	me.nodeIndex = 0;
-	me.cephstore = Ext.create('Proxmox.data.UpdateStore', {
-	    interval: 3000,
-	    storeid: 'pve-cluster-ceph',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json/nodes/' + me.nodeList[me.nodeIndex].node + '/ceph/status'
-	    }
-	});
-	me.callParent();
-	me.mon(me.cephstore, 'load', me.updateCeph, me);
-	me.cephstore.startUpdate();
-    }
-});
-Ext.define('PVE.dc.Guests', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcGuests',
-
-
-    title: gettext('Guests'),
-    height: 220,
-    layout: {
-	type: 'table',
-	columns: 2,
-	tableAttrs: {
-	    style: {
-		width: '100%'
-	    }
-	}
-    },
-    bodyPadding: '0 20 20 20',
-
-    defaults: {
-	xtype: 'box',
-	padding: '0 50 0 50',
-	style: {
-	    'text-align':'center',
-	    'line-height':'1.2'
-	}
-    },
-    items: [{
-	itemId: 'qemu',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("Virtual Machines") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'lxc',
-	data: {
-	    running: 0,
-	    paused: 0,
-	    stopped: 0,
-	    template: 0
-	},
-	tpl: [
-	    '<h3>' + gettext("LXC Container") + '</h3>',
-	    '<div class="left-aligned">',
-		'<i class="good fa fa-fw fa-play-circle">&nbsp;</i>',
-		gettext('Running'),
-	    '</div>',
-	    '<div class="right-aligned">{running}</div>' + '<br />',
-	    '<tpl if="paused &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="warning fa fa-fw fa-pause-circle">&nbsp;</i>',
-		    gettext('Paused'),
-		'</div>',
-		'<div class="right-aligned">{paused}</div>' + '<br />',
-	    '</tpl>',
-	    '<div class="left-aligned">',
-		'<i class="faded fa fa-fw fa-stop-circle">&nbsp;</i>',
-		gettext('Stopped'),
-	    '</div>',
-	    '<div class="right-aligned">{stopped}</div>' + '<br />',
-	    '<tpl if="template &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="fa fa-fw fa-circle-o">&nbsp;</i>',
-		    gettext('Templates'),
-		'</div>',
-		'<div class="right-aligned">{template}</div>',
-	    '</tpl>'
-	]
-    },{
-	itemId: 'error',
-	colspan: 2,
-	data: {
-	    num: 0
-	},
-	columnWidth: 1,
-	padding: '10 250 0 250',
-	tpl: [
-	    '<tpl if="num &gt; 0">',
-		'<div class="left-aligned">',
-		    '<i class="critical fa fa-fw fa-times-circle">&nbsp;</i>',
-		    gettext('Error'),
-		'</div>',
-		'<div class="right-aligned">{num}</div>',
-	    '</tpl>'
-	]
-    }],
-
-    updateValues: function(qemu, lxc, error) {
-	var me = this;
-	me.getComponent('qemu').update(qemu);
-	me.getComponent('lxc').update(lxc);
-	me.getComponent('error').update({num: error});
-    }
-});
- /*jslint confusion: true*/
-Ext.define('PVE.dc.OptionView', {
-    extend: 'Proxmox.grid.ObjectGrid',
-    alias: ['widget.pveDcOptionView'],
-
-    onlineHelp: 'datacenter_configuration_file',
-
-    monStoreErrors: true,
-
-    add_inputpanel_row: function(name, text, opts) {
-	var me = this;
-
-	opts = opts || {};
-	me.rows = me.rows || {};
-
-	var canEdit = (opts.caps === undefined || opts.caps);
-	me.rows[name] = {
-	    required: true,
-	    defaultValue: opts.defaultValue,
-	    header: text,
-	    renderer: opts.renderer,
-	    editor: canEdit ? {
-		xtype: 'proxmoxWindowEdit',
-		width: opts.width || 350,
-		subject: text,
-		onlineHelp: opts.onlineHelp,
-		fieldDefaults: {
-		    labelWidth: opts.labelWidth || 100
-		},
-		setValues: function(values) {
-		    var edit_value = values[name];
-
-		    if (opts.parseBeforeSet) {
-			edit_value = PVE.Parser.parsePropertyString(edit_value);
-		    }
-
-		    Ext.Array.each(this.query('inputpanel'), function(panel) {
-			panel.setValues(edit_value);
-		    });
-		},
-		url: opts.url,
-		items: [{
-		    xtype: 'inputpanel',
-		    onGetValues: function(values) {
-			if (values === undefined || Object.keys(values).length === 0) {
-			    return { 'delete': name };
-			}
-			var ret_val = {};
-			ret_val[name] = PVE.Parser.printPropertyString(values);
-			return ret_val;
-		    },
-		    items: opts.items
-		}]
-	    } : undefined
-	};
-    },
-
-    render_bwlimits: function(value) {
-	if (!value) {
-	    return gettext("None");
-	}
-
-	let parsed = PVE.Parser.parsePropertyString(value);
-	return Object.entries(parsed)
-	    .map(([k, v]) => k + ": " + Proxmox.Utils.format_size(v * 1024) + "/s")
-	    .join(',');
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.add_combobox_row('keyboard', gettext('Keyboard Layout'), {
-	    renderer: PVE.Utils.render_kvm_language,
-	    comboItems: PVE.Utils.kvm_keymap_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('http_proxy', gettext('HTTP proxy'), {
-	    defaultValue: Proxmox.Utils.noneText,
-	    vtype: 'HttpProxy',
-	    deleteEmpty: true
-	});
-	me.add_combobox_row('console', gettext('Console Viewer'), {
-	    renderer: PVE.Utils.render_console_viewer,
-	    comboItems: PVE.Utils.console_viewer_array(),
-	    defaultValue: '__default__',
-	    deleteEmpty: true
-	});
-	me.add_text_row('email_from', gettext('Email from address'), {
-	    deleteEmpty: true,
-	    vtype: 'proxmoxMail',
-	    defaultValue: 'root@$hostname'
-	});
-	me.add_text_row('mac_prefix', gettext('MAC address prefix'), {
-	    deleteEmpty: true,
-	    vtype: 'MacPrefix',
-	    defaultValue: Proxmox.Utils.noneText
-	});
-	me.add_inputpanel_row('migration', gettext('Migration Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.vms['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    defaultKey: 'type',
-	    items: [{
-		xtype: 'displayfield',
-		name: 'type',
-		fieldLabel: gettext('Type'),
-		value: 'secure',
-		submitValue: true,
-	    }, {
-		xtype: 'proxmoxNetworkSelector',
-		name: 'network',
-		fieldLabel: gettext('Network'),
-		value: null,
-		emptyText: Proxmox.Utils.defaultText,
-		autoSelect: false,
-		skipEmptyText: true
-	    }]
-	});
-	me.add_inputpanel_row('ha', gettext('HA Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.dc['Sys.Modify'],
-	    labelWidth: 120,
-	    url: "/api2/extjs/cluster/options",
-	    onlineHelp: 'ha_manager_shutdown_policy',
-	    items: [{
-		xtype: 'proxmoxKVComboBox',
-		name: 'shutdown_policy',
-		fieldLabel: gettext('Shutdown Policy'),
-		deleteEmpty: false,
-		value: '__default__',
-		comboItems: [
-		    ['__default__', Proxmox.Utils.defaultText + ' (conditional)' ],
-		    ['freeze', 'freeze'],
-		    ['failover', 'failover'],
-		    ['migrate', 'migrate'],
-		    ['conditional', 'conditional']
-		],
-		defaultValue: '__default__'
-	    }]
-	});
-	me.add_inputpanel_row('u2f', gettext('U2F Settings'), {
-	    renderer: PVE.Utils.render_dc_ha_opts,
-	    caps: caps.dc['Sys.Modify'],
-	    width: 450,
-	    url: "/api2/extjs/cluster/options",
-	    onlineHelp: 'pveum_configure_u2f',
-	    items: [{
-		xtype: 'textfield',
-		name: 'appid',
-		fieldLabel: gettext('U2F AppID URL'),
-		emptyText: gettext('Defaults to origin'),
-		value: '',
-		skipEmptyText: true,
-		deleteEmpty: true,
-		submitEmptyText: false,
-		skipEmptyText: true,
-	    }, {
-		xtype: 'textfield',
-		name: 'origin',
-		fieldLabel: gettext('U2F Origin'),
-		emptyText: gettext('Defaults to requesting host URI'),
-		value: '',
-		deleteEmpty: true,
-		skipEmptyText: true,
-		submitEmptyText: false,
-	    },
-	    {
-		xtype: 'displayfield',
-		userCls: 'pmx-hint',
-		value: gettext('NOTE: Changing an AppID breaks existing U2F registrations!'),
-	    }]
-	});
-	me.add_inputpanel_row('bwlimit', gettext('Bandwidth Limits'), {
-	    renderer: me.render_bwlimits,
-	    caps: caps.dc['Sys.Modify'],
-	    width: 450,
-	    url: "/api2/extjs/cluster/options",
-	    parseBeforeSet: true,
-	    labelWidth: 120,
-	    items: [{
-		xtype: 'pveBandwidthField',
-		name: 'default',
-		fieldLabel: gettext('Default'),
-		emptyText: gettext('none'),
-		backendUnit: "KiB",
-	    },
-	    {
-		xtype: 'pveBandwidthField',
-		name: 'restore',
-		fieldLabel: gettext('Backup Restore'),
-		emptyText: gettext('default'),
-		backendUnit: "KiB",
-	    },
-	    {
-		xtype: 'pveBandwidthField',
-		name: 'migration',
-		fieldLabel: gettext('Migration'),
-		emptyText: gettext('default'),
-		backendUnit: "KiB",
-	    },
-	    {
-		xtype: 'pveBandwidthField',
-		name: 'clone',
-		fieldLabel: gettext('Clone'),
-		emptyText: gettext('default'),
-		backendUnit: "KiB",
-	    },
-	    {
-		xtype: 'pveBandwidthField',
-		name: 'move',
-		fieldLabel: gettext('Disk Move'),
-		emptyText: gettext('default'),
-		backendUnit: "KiB",
-	    }]
-	});
-	me.add_integer_row('max_workers', gettext('Maximal Workers/bulk-action'), {
-	    deleteEmpty: true,
-	    defaultValue: 4,
-	    minValue: 1,
-	    maxValue: 64, // arbitrary but generous limit as limits are good
-	});
-
-	me.selModel = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    tbar: [{
-		text: gettext('Edit'),
-		xtype: 'proxmoxButton',
-		disabled: true,
-		handler: function() { me.run_editor(); },
-		selModel: me.selModel
-	    }],
-	    url: "/api2/json/cluster/options",
-	    editorConfig: {
-		url: "/api2/extjs/cluster/options"
-	    },
-	    interval: 5000,
-	    cwidth1: 200,
-	    listeners: {
-		itemdblclick: me.run_editor
-	    }
-	});
-
-	me.callParent();
-
-	// set the new value for the default console
-	me.mon(me.rstore, 'load', function(store, records, success) {
-	    if (!success) {
-		return;
-	    }
-
-	    var rec = store.getById('console');
-	    PVE.VersionInfo.console = rec.data.value;
-	    if (rec.data.value === '__default__') {
-		delete PVE.VersionInfo.console;
-	    }
-	});
-
-	me.on('activate', me.rstore.startUpdate);
-	me.on('destroy', me.rstore.stopUpdate);
-	me.on('deactivate', me.rstore.stopUpdate);
-    }
-});
-Ext.define('PVE.dc.StorageView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveStorageView'],
-
-    onlineHelp: 'chapter_storage',
-
-    stateful: true,
-    stateId: 'grid-dc-storage',
-
-    createStorageEditWindow: function(type, sid) {
-	var schema = PVE.Utils.storageSchema[type];
-	if (!schema || !schema.ipanel) {
-	    throw "no editor registered for storage type: " + type;
-	}
-
-	Ext.create('PVE.storage.BaseEdit', {
-	    paneltype: 'PVE.storage.' + schema.ipanel,
-	    type: type,
-	    storageId: sid,
-	    autoShow: true,
-	    listeners: {
-		destroy: this.reloadStore
-	    }
-	});
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-storage',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/storage"
-	    },
-	    sorters: {
-		property: 'storage',
-		order: 'DESC'
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var type = rec.data.type,
-	        sid = rec.data.storage;
-
-	    me.createStorageEditWindow(type, sid);
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/storage/',
-	    callback: reload
-	});
-
-	// else we cannot dynamically generate the add menu handlers
-	var addHandleGenerator = function(type) {
-	    return function() { me.createStorageEditWindow(type); };
-	};
-	var addMenuItems = [], type;
-	/*jslint forin: true */
-	for (type in PVE.Utils.storageSchema) {
-	    var storage = PVE.Utils.storageSchema[type];
-	    if (storage.hideAdd) {
-		continue;
-	    }
-	    addMenuItems.push({
-		text:  PVE.Utils.format_storage_type(type),
-		iconCls: 'fa fa-fw fa-' + storage.faIcon,
-		handler: addHandleGenerator(type)
-	    });
-	}
-
-	Ext.apply(me, {
-	    store: store,
-	    reloadStore: reload,
-	    selModel: sm,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: new Ext.menu.Menu({
-			items: addMenuItems
-		    })
-		},
-		remove_btn,
-		edit_btn
-	    ],
-	    columns: [
-		{
-		    header: 'ID',
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Type'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'type',
-		    renderer: PVE.Utils.format_storage_type
-		},
-		{
-		    header: gettext('Content'),
-		    flex: 3,
-		    sortable: true,
-		    dataIndex: 'content',
-		    renderer: PVE.Utils.format_content_types
-		},
-		{
-		    header: gettext('Path') + '/' + gettext('Target'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'path',
-		    renderer: function(value, metaData, record) {
-			if (record.data.target) {
-			    return record.data.target;
-			}
-			return value;
-		    }
-		},
-		{
-		    header: gettext('Shared'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'shared',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Enabled'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'disable',
-		    renderer: Proxmox.Utils.format_neg_boolean
-		},
-		{
-		    header: gettext('Bandwidth Limit'),
-		    flex: 2,
-		    sortable: true,
-		    dataIndex: 'bwlimit'
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-storage', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'content', 'server', 'portal', 'target', 'export', 'storage',
-	    { name: 'shared', type: 'boolean'},
-	    { name: 'disable', type: 'boolean'}
-	],
-	idProperty: 'storage'
-    });
-
-});
-/*global u2f,QRCode,Uint8Array*/
-/*jslint confusion: true*/
-Ext.define('PVE.window.TFAEdit', {
-    extend: 'Ext.window.Window',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    onlineHelp: 'pveum_tfa_auth', // fake to ensure this gets a link target
-
-    modal: true,
-    resizable: false,
-    title: gettext('Two Factor Authentication'),
-    subject: 'TFA',
-    url: '/api2/extjs/access/tfa',
-    width: 512,
-
-    layout: {
-	type: 'vbox',
-	align: 'stretch'
-    },
-
-    updateQrCode: function() {
-	var me = this;
-	var values = me.lookup('totp_form').getValues();
-	var algorithm = values.algorithm;
-	if (!algorithm) {
-	    algorithm = 'SHA1';
-	}
-
-	me.qrcode.makeCode(
-	    'otpauth://totp/' + encodeURIComponent(me.userid) +
-	    '?secret=' + values.secret +
-	    '&period=' + values.step +
-	    '&digits=' + values.digits +
-	    '&algorithm=' + algorithm +
-	    '&issuer=' + encodeURIComponent(values.issuer)
-	);
-
-	me.lookup('challenge').setVisible(true);
-	me.down('#qrbox').setVisible(true);
-    },
-
-    showError: function(error) {
-	Ext.Msg.alert(
-	    gettext('Error'),
-	    PVE.Utils.render_u2f_error(error)
-	);
-    },
-
-    doU2FChallenge: function(response) {
-	var me = this;
-
-	var data = response.result.data;
-	me.lookup('password').setDisabled(true);
-	var msg = Ext.Msg.show({
-	    title: 'U2F: '+gettext('Setup'),
-	    message: gettext('Please press the button on your U2F Device'),
-	    buttons: []
-	});
-	Ext.Function.defer(function() {
-	    u2f.register(data.appId, [data], [], function(data) {
-		msg.close();
-		if (data.errorCode) {
-		    me.showError(data.errorCode);
-		} else {
-		    me.respondToU2FChallenge(data);
-		}
-	    });
-	}, 500, me);
-    },
-
-    respondToU2FChallenge: function(data) {
-	var me = this;
-	var params = {
-	    userid: me.userid,
-	    action: 'confirm',
-	    response: JSON.stringify(data)
-	};
-	if (Proxmox.UserName !== 'root@pam') {
-	    params.password = me.lookup('password').value;
-	}
-	Proxmox.Utils.API2Request({
-	    url: '/api2/extjs/access/tfa',
-	    params: params,
-	    method: 'PUT',
-	    success: function() {
-		me.close();
-		Ext.Msg.show({
-		    title: gettext('Success'),
-		    message: gettext('U2F Device successfully connected.'),
-		    buttons: Ext.Msg.OK
-		});
-	    },
-	    failure: function(response, opts) {
-		Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-	    }
-	});
-    },
-
-    viewModel: {
-	data: {
-	    in_totp_tab: true,
-	    tfa_required: false,
-	    tfa_type: null, // dependencies of formulas should not be undefined
-	    valid: false,
-	    u2f_available: true,
-	    secret: "",
-	},
-	formulas: {
-	    showTOTPVerifiction: function(get) {
-		return get('secret').length > 0 && get('canSetupTOTP');
-	    },
-	    canDeleteTFA: function(get) {
-		return (get('tfa_type') !== null && !get('tfa_required'));
-	    },
-	    canSetupTOTP: function(get) {
-		var tfa = get('tfa_type');
-		return (tfa === null || tfa === 'totp' || tfa === 1);
-	    },
-	    canSetupU2F: function(get) {
-		var tfa = get('tfa_type');
-		return (get('u2f_available') && (tfa === null || tfa === 'u2f' || tfa === 1));
-	    },
-	    secretEmpty: function(get) {
-		return get('secret').length === 0;
-	    },
-	    selectedTab: function(get) {
-		return (get('tfa_type') || 'totp') + '-panel';
-	    },
-	}
-    },
-
-    afterLoading: function(realm_tfa_type, user_tfa_type) {
-	var me = this;
-	var viewmodel = me.getViewModel();
-	if (user_tfa_type === 'oath') {
-	    user_tfa_type = 'totp';
-	    viewmodel.set('secret', '');
-	}
-
-	// if the user has no tfa, generate a secret for him
-	if (!user_tfa_type) {
-	    me.getController().randomizeSecret();
-	}
-
-	viewmodel.set('tfa_type', user_tfa_type || null);
-	if (!realm_tfa_type) {
-	    // There's no TFA enforced by the realm, everything works.
-	    viewmodel.set('u2f_available', true);
-	    viewmodel.set('tfa_required', false);
-	} else if (realm_tfa_type === 'oath') {
-	    // The realm explicitly requires TOTP
-	    if (user_tfa_type !== 'totp' && user_tfa_type !== null) {
-		// user had a different tfa method, so
-		// we have to change back to the totp tab and
-		// generate a secret
-		viewmodel.set('tfa_type', 'totp');
-		me.getController().randomizeSecret();
-	    }
-	    viewmodel.set('tfa_required', true);
-	    viewmodel.set('u2f_available', false);
-	} else {
-	    // The realm enforces some other TFA type (yubico)
-	    me.close();
-	    Ext.Msg.alert(
-		gettext('Error'),
-		Ext.String.format(
-		    gettext("Custom 2nd factor configuration is not supported on realms with '{0}' TFA."),
-		    realm_tfa_type
-		)
-	    );
-	}
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    'field[qrupdate=true]': {
-		change: function() {
-		    var me = this.getView();
-		    me.updateQrCode();
-		}
-	    },
-	    'field': {
-		validitychange: function(field, valid) {
-		    var me = this;
-		    var viewModel = me.getViewModel();
-		    var form = me.lookup('totp_form');
-		    var challenge = me.lookup('challenge');
-		    var password = me.lookup('password');
-		    viewModel.set('valid', form.isValid() && challenge.isValid() && password.isValid());
-		}
-	    },
-	    '#': {
-		show: function() {
-		    var me = this.getView();
-		    var viewmodel = this.getViewModel();
-
-		    var loadMaskContainer = me.down('#tfatabs');
-		    Proxmox.Utils.API2Request({
-			url: '/access/users/' + encodeURIComponent(me.userid) + '/tfa',
-			waitMsgTarget: loadMaskContainer,
-			method: 'GET',
-			success: function(response, opts) {
-			    var data = response.result.data;
-			    me.afterLoading(data.realm, data.user);
-			},
-			failure: function(response, opts) {
-			    me.close();
-			    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-			}
-		    });
-
-		    me.qrdiv = document.createElement('center');
-		    me.qrcode = new QRCode(me.qrdiv, {
-			width: 256,
-			height: 256,
-			correctLevel: QRCode.CorrectLevel.M
-		    });
-		    me.down('#qrbox').getEl().appendChild(me.qrdiv);
-
-		    if (Proxmox.UserName === 'root@pam') {
-			me.lookup('password').setVisible(false);
-			me.lookup('password').setDisabled(true);
-		    }
-		}
-	    },
-	    '#tfatabs': {
-		tabchange: function(panel, newcard) {
-		    var viewmodel = this.getViewModel();
-		    viewmodel.set('in_totp_tab', newcard.itemId === 'totp-panel');
-		}
-	    }
-	},
-
-	applySettings: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new',
-		key: 'v2-' + values.secret,
-		config: PVE.Parser.printPropertyString({
-		    type: 'oath',
-		    digits: values.digits,
-		    step: values.step
-		}),
-		// this is used to verify that the client generates the correct codes:
-		response: me.lookup('challenge').value
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	deleteTFA: function() {
-	    var me = this;
-	    var values = me.lookup('totp_form').getValues();
-	    var params = {
-		userid: me.getView().userid,
-		action: 'delete'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response, opts) {
-		    me.getView().close();
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	},
-
-	randomizeSecret: function() {
-	    var me = this;
-	    var rnd = new Uint8Array(32);
-	    window.crypto.getRandomValues(rnd);
-	    var data = '';
-	    rnd.forEach(function(b) {
-		// secret must be base32, so just use the first 5 bits
-		b = b & 0x1f;
-		if (b < 26) {
-		    // A..Z
-		    data += String.fromCharCode(b + 0x41);
-		} else {
-		    // 2..7
-		    data += String.fromCharCode(b-26 + 0x32);
-		}
-	    });
-	    me.getViewModel().set('secret', data);
-	},
-
-	startU2FRegistration: function() {
-	    var me = this;
-
-	    var params = {
-		userid: me.getView().userid,
-		action: 'new'
-	    };
-
-	    if (Proxmox.UserName !== 'root@pam') {
-		params.password = me.lookup('password').value;
-	    }
-
-	    Proxmox.Utils.API2Request({
-		url: '/api2/extjs/access/tfa',
-		params: params,
-		method: 'PUT',
-		waitMsgTarget: me.getView(),
-		success: function(response) {
-		    me.getView().doU2FChallenge(response);
-		},
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		}
-	    });
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'tabpanel',
-	    itemId: 'tfatabs',
-	    reference: 'tfatabs',
-	    border: false,
-	    bind: {
-		activeTab: '{selectedTab}',
-	    },
-	    items: [
-		{
-		    xtype: 'panel',
-		    title: 'TOTP',
-		    itemId: 'totp-panel',
-		    reference: 'totp_panel',
-		    tfa_type: 'totp',
-		    border: false,
-		    bind: {
-			disabled: '{!canSetupTOTP}'
-		    },
-		    layout: {
-			type: 'vbox',
-			align: 'stretch'
-		    },
-		    items: [
-			{
-			    xtype: 'form',
-			    layout: 'anchor',
-			    border: false,
-			    reference: 'totp_form',
-			    fieldDefaults: {
-				anchor: '100%',
-				padding: '0 5'
-			    },
-			    items: [
-				{
-				    xtype: 'displayfield',
-				    fieldLabel: gettext('User name'),
-				    cbind: {
-					value: '{userid}'
-				    }
-				},
-				{
-				    layout: 'hbox',
-				    border: false,
-				    padding: '0 0 5 0',
-				    items: [{
-					xtype: 'textfield',
-					fieldLabel: gettext('Secret'),
-					emptyText: gettext('Unchanged'),
-					name: 'secret',
-					reference: 'tfa_secret',
-					regex: /^[A-Z2-7=]+$/,
-					regexText: 'Must be base32 [A-Z2-7=]',
-					maskRe: /[A-Z2-7=]/,
-					qrupdate: true,
-					bind: {
-					    value: "{secret}",
-					},
-					flex: 4
-				    },
-				    {
-					xtype: 'button',
-					text: gettext('Randomize'),
-					reference: 'randomize_button',
-					handler: 'randomizeSecret',
-					flex: 1
-				    }]
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Time period'),
-				    name: 'step',
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    value: 30,
-				    minValue: 10,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'numberfield',
-				    fieldLabel: gettext('Digits'),
-				    name: 'digits',
-				    value: 6,
-				    // Google Authenticator ignores this and generates bogus data
-				    hidden: true,
-				    minValue: 6,
-				    maxValue: 8,
-				    qrupdate: true
-				},
-				{
-				    xtype: 'textfield',
-				    fieldLabel: gettext('Issuer Name'),
-				    name: 'issuer',
-				    value: 'Proxmox Web UI',
-				    qrupdate: true
-				}
-			    ]
-			},
-			{
-			    xtype: 'box',
-			    itemId: 'qrbox',
-			    visible: false, // will be enabled when generating a qr code
-			    bind: {
-				visible: '{!secretEmpty}',
-			    },
-			    style: {
-				'background-color': 'white',
-				padding: '5px',
-				width: '266px',
-				height: '266px'
-			    }
-			},
-			{
-			    xtype: 'textfield',
-			    fieldLabel: gettext('Verification Code'),
-			    allowBlank: false,
-			    reference: 'challenge',
-			    bind: {
-				disabled: '{!showTOTPVerifiction}',
-				visible: '{showTOTPVerifiction}',
-			    },
-			    padding: '0 5',
-			    emptyText: gettext('Scan QR code and enter TOTP auth. code to verify')
-			}
-		    ]
-		},
-		{
-		    title: 'U2F',
-		    itemId: 'u2f-panel',
-		    reference: 'u2f_panel',
-		    tfa_type: 'u2f',
-		    border: false,
-		    padding: '5 5',
-		    layout: {
-			type: 'vbox',
-			align: 'middle'
-		    },
-		    bind: {
-			disabled: '{!canSetupU2F}'
-		    },
-		    items: [
-			{
-			    xtype: 'label',
-			    width: 500,
-			    text: gettext('To register a U2F device, connect the device, then click the button and follow the instructions.')
-			}
-		    ]
-		}
-	    ]
-	},
-	{
-	    xtype: 'textfield',
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'),
-	    minLength: 5,
-	    reference: 'password',
-	    allowBlank: false,
-	    validateBlank: true,
-	    padding: '0 0 5 5',
-	    emptyText: gettext('verify current password')
-	}
-    ],
-
-    buttons: [
-	{
-	    xtype: 'proxmoxHelpButton'
-	},
-	'->',
-	{
-	    text: gettext('Apply'),
-	    handler: 'applySettings',
-	    bind: {
-		hidden: '{!in_totp_tab}',
-		disabled: '{!valid}'
-	    }
-	},
-	{
-	    xtype: 'button',
-	    text: gettext('Register U2F Device'),
-	    handler: 'startU2FRegistration',
-	    bind: {
-		hidden: '{in_totp_tab}',
-		disabled: '{tfa_type}'
-	    }
-	},
-	{
-	    text: gettext('Delete'),
-	    reference: 'delete_button',
-	    disabled: true,
-	    handler: 'deleteTFA',
-	    bind: {
-		disabled: '{!canDeleteTFA}'
-	    }
-	}
-    ],
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid given";
-	}
-
-	me.callParent();
-
-	Ext.GlobalEvents.fireEvent('proxmoxShowHelp', 'pveum_tfa_auth');
-    }
-});
-Ext.define('PVE.dc.UserEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcUserEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.userid;
-
-        var url;
-        var method;
-        var realm;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/users';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/users/' + encodeURIComponent(me.userid);
-            method = 'PUT';
-	}
-
-	var verifypw;
-	var pwfield;
-
-	var validate_pw = function() {
-	    if (verifypw.getValue() !== pwfield.getValue()) {
-		return gettext("Passwords do not match");
-	    }
-	    return true;
-	};
-
-	verifypw = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Confirm password'), 
-	    name: 'verifypassword',
-	    submitValue: false,
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	pwfield = Ext.createWidget('textfield', { 
-	    inputType: 'password',
-	    fieldLabel: gettext('Password'), 
-	    minLength: 5,
-	    name: 'password',
-	    disabled: true,
-	    hidden: true,
-	    validator: validate_pw
-	});
-
-	var update_passwd_field = function(realm) {
-	    if (realm === 'pve') {
-		pwfield.setVisible(true);
-		pwfield.setDisabled(false);
-		verifypw.setVisible(true);
-		verifypw.setDisabled(false);
-	    } else {
-		pwfield.setVisible(false);
-		pwfield.setDisabled(true);
-		verifypw.setVisible(false);
-		verifypw.setDisabled(true);
-	    }
-
-	};
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'userid',
-                fieldLabel: gettext('User name'),
-                value: me.userid,
-                allowBlank: false,
-                submitValue: me.isCreate ? true : false
-            },
-	    pwfield, verifypw,
-	    {
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		multiSelect: true,
-		allowBlank: true,
-		fieldLabel: gettext('Group')
-	    },
-            {
-                xtype: 'datefield',
-                name: 'expire',
-		emptyText: 'never',
-		format: 'Y-m-d',
-		submitFormat: 'U',
-                fieldLabel: gettext('Expire')
-            },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enabled'),
-		name: 'enable',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    }
-        ];
-
-        var column2 = [
-	    {
-		xtype: 'textfield',
-		name: 'firstname',
-		fieldLabel: gettext('First Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'lastname',
-		fieldLabel: gettext('Last Name')
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'email',
-		fieldLabel: gettext('E-Mail'),
-		vtype: 'proxmoxMail'
-	    }
-	];
-
-        if (me.isCreate) {
-            column1.splice(1,0,{
-                xtype: 'pveRealmComboBox',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                allowBlank: false,
-		matchFieldWidth: false,
-		listConfig: { width: 300 },
-                listeners: {
-                    change: function(combo, newValue){
-                        realm = newValue;
-			update_passwd_field(realm);
-                    }
-                },
-                submitValue: false
-            });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [
-		{
-		    xtype: 'textfield',
-		    name: 'comment',
-		    fieldLabel: gettext('Comment')
-		}
-	    ],
-	    advancedItems: [
-		{
-		    xtype: 'textfield',
-		    name: 'keys',
-		    fieldLabel: gettext('Key IDs')
-		}
-	    ],
-	    onGetValues: function(values) {
-		// hack: ExtJS datefield does not submit 0, so we need to set that
-		if (!values.expire) {
-		    values.expire = 0;
-		}
-
-		if (realm) {
-		    values.userid = values.userid + '@' + realm;
-		}
-
-		if (!values.password) {
-		    delete values.password;
-		}
-
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            subject: gettext('User'),
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 110 // for spanish translation 
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-		    if (Ext.isDefined(data.expire)) {
-			if (data.expire) {
-			    data.expire = new Date(data.expire * 1000);
-			} else {
-			    // display 'never' instead of '1970-01-01'
-			    data.expire = null;
-			}
-		    }
-		    me.setValues(data);
-		    if (data.keys) {
-			if ( data.keys === 'x!oath' || data.keys === 'x!u2f' ) {
-			    me.down('[name="keys"]').setDisabled(1);
-			}
-		    }
-                }
-            });
-        }
-    }
-});
-/*jslint confusion: true */
-Ext.define('PVE.dc.UserView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveUserView'],
-
-    onlineHelp: 'pveum_users',
-
-    stateful: true,
-    stateId: 'grid-users',
-
-    initComponent : function() {
-	var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	var store = new Ext.data.Store({
-            id: "users",
-	    model: 'pve-users',
-	    sorters: { 
-		property: 'userid', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/access/users/',
-	    enableFn: function(rec) {
-		if (!caps.access['User.Modify']) {
-		    return false;
-		}
-		return rec.data.userid !== 'root@pam';
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
- 
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec || !caps.access['User.Modify']) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.UserEdit',{
-                userid: rec.data.userid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    enableFn: function(rec) {
-		return !!caps.access['User.Modify'];
-	    },
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var pwchange_btn = new Proxmox.button.Button({
-	    text: gettext('Password'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('Proxmox.window.PasswordEdit', {
-                    userid: rec.data.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var tfachange_btn = new Proxmox.button.Button({
-	    text: 'TFA',
-	    disabled: true,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var d = rec.data;
-		var tfa_type = PVE.Parser.parseTfaType(d.keys);
-		var win = Ext.create('PVE.window.TFAEdit',{
-		    tfa_type: tfa_type,
-		    userid: d.userid
-		});
-		win.on('destroy', reload);
-		win.show();
-	    }
-	});
-
-	var perm_btn = new Proxmox.button.Button({
-	    text: gettext('Permissions'),
-	    disabled: false,
-	    selModel: sm,
-	    handler: function(btn, event, rec) {
-		var win = Ext.create('PVE.dc.PermissionView', {
-                    userid: rec.data.userid
-		});
-		win.show();
-	    }
-	});
-
-        var tbar = [
-            {
-		text: gettext('Add'),
-		disabled: !caps.access['User.Modify'],
-		handler: function() {
-                    var win = Ext.create('PVE.dc.UserEdit',{
-                    });
-                    win.on('destroy', reload);
-                    win.show();
-		}
-            },
-	    edit_btn, remove_btn, pwchange_btn, tfachange_btn, perm_btn
-        ];
-
-	var render_username = function(userid) {
-	    return userid.match(/^(.+)(@[^@]+)$/)[1];
-	};
-
-	var render_realm = function(userid) {
-	    return userid.match(/@([^@]+)$/)[1];
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('User name'),
-		    width: 200,
-		    sortable: true,
-		    renderer: render_username,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    renderer: render_realm,
-		    dataIndex: 'userid'
-		},
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_boolean,
-		    dataIndex: 'enable'
-		},
-		{
-		    header: gettext('Expire'),
-		    width: 80,
-		    sortable: true,
-		    renderer: Proxmox.Utils.format_expire, 
-		    dataIndex: 'expire'
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    renderer: PVE.Utils.render_full_name,
-		    dataIndex: 'firstname'
-		},
-		{
-		    header: 'TFA',
-		    width: 50,
-		    sortable: true,
-		    renderer: function(v) {
-			var tfa_type = PVE.Parser.parseTfaType(v);
-			if (tfa_type === undefined) {
-			    return Proxmox.Utils.noText;
-			} else if (tfa_type === 1) {
-			    return Proxmox.Utils.yesText;
-			} else {
-			    return tfa_type;
-			}
-		    },
-		    dataIndex: 'keys'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-
-	Proxmox.Utils.monStoreErrors(me, store);
-    }
-});
-Ext.define('PVE.dc.PoolView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pvePoolView'],
-
-    onlineHelp: 'pveum_pools',
-
-    stateful: true,
-    stateId: 'grid-pools',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-pools',
-	    sorters: { 
-		property: 'poolid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/pools/',
-	    callback: function () {
-		reload();
-	    }
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.PoolEdit',{
-                poolid: rec.data.poolid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.PoolEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'poolid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.PoolEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcPoolEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.poolid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/pools';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/pools/' + me.poolid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Pool'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'poolid',
-		    value: me.poolid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.GroupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveGroupView'],
-
-    onlineHelp: 'pveum_groups',
-
-    stateful: true,
-    stateId: 'grid-groups',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-groups',
-	    sorters: { 
-		property: 'groupid', 
-		order: 'DESC' 
-	    }
-	});
-
-        var reload = function() {
-            store.load();
-        };
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    callback: function() {
-		reload();
-	    },
-	    baseurl: '/access/groups/'
-	});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.GroupEdit',{
-                groupid: rec.data.groupid
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var tbar = [
-            {
-		text: gettext('Create'),
-		handler: function() {
-		    var win = Ext.create('PVE.dc.GroupEdit', {});
-		    win.on('destroy', reload);
-		    win.show();
-		}
-            },
-	    edit_btn, remove_btn
-        ];
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Name'),
-		    width: 200,
-		    sortable: true,
-		    dataIndex: 'groupid'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    renderer: Ext.String.htmlEncode,
-		    dataIndex: 'comment',
-		    flex: 1
-		},
-		{
-		    header: gettext('Users'),
-		    sortable: false,
-		    dataIndex: 'users',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.GroupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcGroupEdit'],
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.groupid;
-
-        var url;
-        var method;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/groups';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/groups/' + me.groupid;
-            method = 'PUT';
-        }
-
-        Ext.applyIf(me, {
-            subject: gettext('Group'),
-            url: url,
-            method: method,
-            items: [
-                {
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    fieldLabel: gettext('Name'),
-		    name: 'groupid',
-		    value: me.groupid,
-		    allowBlank: false
-		},
-                {
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Comment'),
-		    name: 'comment',
-		    allowBlank: true
-		}
-            ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load();
-        }
-    }
-});
-Ext.define('PVE.dc.RoleView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveRoleView'],
-
-    onlineHelp: 'pveum_roles',
-
-    stateful: true,
-    stateId: 'grid-roles',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-roles',
-	    sorters: {
-		property: 'roleid',
-		order: 'DESC'
-	    }
-	});
-
-	var render_privs = function(value, metaData) {
-
-	    if (!value) {
-		return '-';
-	    }
-
-	    // allow word wrap
-	    metaData.style = 'white-space:normal;';
-
-	    return value.replace(/\,/g, ' ');
-	};
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-		store.load();
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    if (!!rec.data.special) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.RoleEdit',{
-		roleid: rec.data.roleid,
-		privs: rec.data.privs
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Built-In'),
-		    width: 65,
-		    sortable: true,
-		    dataIndex: 'special',
-		    renderer: Proxmox.Utils.format_boolean
-		},
-		{
-		    header: gettext('Name'),
-		    width: 150,
-		    sortable: true,
-		    dataIndex: 'roleid'
-		},
-		{
-		    itemid: 'privs',
-		    header: gettext('Privileges'),
-		    sortable: false,
-		    renderer: render_privs,
-		    dataIndex: 'privs',
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: function() {
-		    store.load();
-		},
-		itemdblclick: run_editor
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.RoleEdit', {});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		{
-		    xtype: 'proxmoxButton',
-		    text: gettext('Edit'),
-		    disabled: true,
-		    selModel: sm,
-		    handler: run_editor,
-		    enableFn: (rec) => !rec.data.special,
-		},
-		{
-		    xtype: 'proxmoxStdRemoveButton',
-		    selModel: sm,
-		    callback: function() {
-			reload();
-		    },
-		    baseurl: '/access/roles/',
-		    enableFn: (rec) => !rec.data.special,
-		}
-	    ]
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.RoleEdit', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveDcRoleEdit',
-
-    width: 400,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = !me.roleid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-	    url = '/api2/extjs/access/roles';
-	    method = 'POST';
-	} else {
-	    url = '/api2/extjs/access/roles/' + me.roleid;
-	    method = 'PUT';
-	}
-
-	Ext.applyIf(me, {
-	    subject: gettext('Role'),
-	    url: url,
-	    method: method,
-	    items: [
-		{
-		    xtype: me.isCreate ? 'proxmoxtextfield' : 'displayfield',
-		    name: 'roleid',
-		    value: me.roleid,
-		    allowBlank: false,
-		    fieldLabel: gettext('Name')
-		},
-		{
-		    xtype: 'pvePrivilegesSelector',
-		    name: 'privs',
-		    value: me.privs,
-		    allowBlank: false,
-		    fieldLabel: gettext('Privileges')
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	if (!me.isCreate) {
-	    me.load({
-		success: function(response) {
-		    var data = response.result.data;
-		    var keys = Ext.Object.getKeys(data);
-
-		    me.setValues({
-			privs: keys,
-			roleid: me.roleid
-		    });
-		}
-	    });
-	}
-    }
-});
-Ext.define('PVE.dc.ACLAdd', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveACLAdd'],
-    url: '/access/acl',
-    method: 'PUT',
-    isAdd: true,
-    initComponent : function() {
-
-        var me = this;
-
-	me.isCreate = true;
-
-	var items = [
-	    {
-		xtype: me.path ? 'hiddenfield' : 'pvePermPathSelector',
-		name: 'path',
-		value: me.path,
-		allowBlank: false,
-		fieldLabel: gettext('Path')
-	    }
-	];
-
-	if (me.aclType === 'group') {
-	    me.subject = gettext("Group Permission");
-	    items.push({
-		xtype: 'pveGroupSelector',
-		name: 'groups',
-		fieldLabel: gettext('Group')
-	    });
-	} else if (me.aclType === 'user') {
-	    me.subject = gettext("User Permission");
-	    items.push({
-		xtype: 'pveUserSelector',
-		name: 'users',
-		fieldLabel: gettext('User')
-	    });
-	} else {
-	    throw "unknown ACL type";
-	}
-
-	items.push({
-	    xtype: 'pveRoleSelector',
-	    name: 'roles',
-	    value: 'NoAccess',
-	    fieldLabel: gettext('Role')
-	});
-
-	if (!me.path) {
-	    items.push({
-		xtype: 'proxmoxcheckbox',
-		name: 'propagate',
-		checked: true,
-		uncheckedValue: 0,
-		fieldLabel: gettext('Propagate')
-	    });
-	}
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    items: items,
-	    onlineHelp: 'pveum_permission_management'
-	});
-
-	Ext.apply(me, {
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.dc.ACLView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveACLView'],
-
-    onlineHelp: 'chapter_user_management',
-
-    stateful: true,
-    stateId: 'grid-acls',
-
-    // use fixed path
-    path: undefined,
-
-    initComponent : function() {
-	var me = this;
-
-	var store = Ext.create('Ext.data.Store',{
-	    model: 'pve-acl',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/access/acl"
-	    },
-	    sorters: {
-		property: 'path',
-		order: 'DESC'
-	    }
-	});
-
-	if (me.path) {
-	    store.addFilter(Ext.create('Ext.util.Filter',{
-		filterFn: function(item) {
-		    if (item.data.path === me.path) {
-			return true;
-		    }
-		}
-	    }));
-	}
-
-	var render_ugid = function(ugid, metaData, record) {
-	    if (record.data.type == 'group') {
-		return '@' + ugid;
-	    }
-
-	    return ugid;
-	};
-
-	var columns = [
-	    {
-		header: gettext('User') + '/' + gettext('Group'),
-		flex: 1,
-		sortable: true,
-		renderer: render_ugid,
-		dataIndex: 'ugid'
-	    },
-	    {
-		header: gettext('Role'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'roleid'
-	    }
-	];
-
-	if (!me.path) {
-	    columns.unshift({
-		header: gettext('Path'),
-		flex: 1,
-		sortable: true,
-		dataIndex: 'path'
-	    });
-	    columns.push({
-		header: gettext('Propagate'),
-		width: 80,
-		sortable: true,
-		dataIndex: 'propagate'
-	    });
-	}
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var remove_btn = new Proxmox.button.Button({
-	    text: gettext('Remove'),
-	    disabled: true,
-	    selModel: sm,
-	    confirmMsg: gettext('Are you sure you want to remove this entry'),
-	    handler: function(btn, event, rec) {
-		var params = {
-		    'delete': 1,
-		    path: rec.data.path,
-		    roles: rec.data.roleid
-		};
-		if (rec.data.type === 'group') {
-		    params.groups = rec.data.ugid;
-		} else if (rec.data.type === 'user') {
-		    params.users = rec.data.ugid;
-		} else {
-		    throw 'unknown data type';
-		}
-
-		Proxmox.Utils.API2Request({
-		    url: '/access/acl',
-		    params: params,
-		    method: 'PUT',
-		    waitMsgTarget: me,
-		    callback: function() {
-			reload();
-		    },
-		    failure: function (response, opts) {
-			Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    }
-		});
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    menu: {
-			xtype: 'menu',
-			items: [
-			    {
-				text: gettext('Group Permission'),
-				iconCls: 'fa fa-fw fa-group',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'group',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    },
-			    {
-				text: gettext('User Permission'),
-				iconCls: 'fa fa-fw fa-user',
-				handler: function() {
-				    var win = Ext.create('PVE.dc.ACLAdd',{
-					aclType: 'user',
-					path: me.path
-				    });
-				    win.on('destroy', reload);
-				    win.show();
-				}
-			    }
-			]
-		    }
-		},
-		remove_btn
-	    ],
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: columns,
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-acl', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'path', 'type', 'ugid', 'roleid',
-	    {
-		name: 'propagate',
-		type: 'boolean'
-	    }
-	]
-    });
-
-});
-Ext.define('PVE.dc.AuthView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveAuthView'],
-
-    onlineHelp: 'pveum_authentication_realms',
-
-    stateful: true,
-    stateId: 'grid-authrealms',
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-domains',
-	    sorters: { 
-		property: 'realm', 
-		order: 'DESC' 
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-            var win = Ext.create('PVE.dc.AuthEdit',{
-                realm: rec.data.realm,
-		authType: rec.data.type
-            });
-            win.on('destroy', reload);
-            win.show();
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    baseurl: '/access/domains/',
-	    selModel: sm,
-	    enableFn: function(rec) {
-		return !(rec.data.type === 'pve' || rec.data.type === 'pam');
-	    },
-	    callback: function() {
-		reload();
-	    }
-        });
-
-        var tbar = [
-	    {
-		text: gettext('Add'),
-		menu: new Ext.menu.Menu({
-		    items: [
-			{
-			    text: gettext('Active Directory Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit', {
-				    authType: 'ad'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			},
-			{
-			    text: gettext('LDAP Server'),
-			    handler: function() {
-				var win = Ext.create('PVE.dc.AuthEdit',{
-				    authType: 'ldap'
-				});
-				win.on('destroy', reload);
-				win.show();
-			    }
-			}
-		    ]
-		})
-	    },
-	    edit_btn, remove_btn
-        ];
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-            tbar: tbar,
-	    viewConfig: {
-		trackOver: false
-	    },
-	    columns: [
-		{
-		    header: gettext('Realm'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'realm'
-		},
-		{
-		    header: gettext('Type'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'type'
-		},
-		{
-		    header: gettext('TFA'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'tfa'
-		},
-		{
-		    header: gettext('Comment'),
-		    sortable: false,
-		    dataIndex: 'comment',
-		    renderer: Ext.String.htmlEncode,
-		    flex: 1
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('PVE.dc.AuthEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcAuthEdit'],
-
-    isAdd: true,
-
-    initComponent : function() {
-        var me = this;
-
-        me.isCreate = !me.realm;
-
-        var url;
-        var method;
-        var serverlist;
-
-        if (me.isCreate) {
-            url = '/api2/extjs/access/domains';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/access/domains/' + me.realm;
-            method = 'PUT';
-        }
-
-        var column1 = [
-            {
-                xtype: me.isCreate ? 'textfield' : 'displayfield',
-                name: 'realm',
-                fieldLabel: gettext('Realm'),
-                value: me.realm,
-                allowBlank: false
-            }
-	];
-
-	if (me.authType === 'ad') {
-
-	    me.subject = gettext('Active Directory Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'domain',
-                fieldLabel: gettext('Domain'),
-                emptyText: 'company.net',
-                allowBlank: false
-            });
-
-	} else if (me.authType === 'ldap') {
-
-	    me.subject = gettext('LDAP Server');
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'base_dn',
-                fieldLabel: gettext('Base Domain Name'),
-		emptyText: 'CN=Users,DC=Company,DC=net',
-                allowBlank: false
-            });
-
-            column1.push({
-                xtype: 'textfield',
-                name: 'user_attr',
-                emptyText: 'uid / sAMAccountName',
-                fieldLabel: gettext('User Attribute Name'),
-                allowBlank: false
-            });
-	} else if (me.authType === 'pve') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'Proxmox VE authentication server';
-
-	} else if (me.authType === 'pam') {
-
-	    if (me.isCreate) {
-		throw 'unknown auth type';
-	    }
-
-	    me.subject = 'linux PAM';
-
-	} else {
-	    throw 'unknown auth type ';
-	}
-
-        column1.push({
-            xtype: 'proxmoxcheckbox',
-            fieldLabel: gettext('Default'),
-            name: 'default',
-            uncheckedValue: 0
-        });
-
-        var column2 = [];
-
-	if (me.authType === 'ldap' || me.authType === 'ad') {
-	    column2.push(
-		{
-                    xtype: 'textfield',
-                    fieldLabel: gettext('Server'),
-                    name: 'server1',
-                    allowBlank: false
-		},
-		{
-                    xtype: 'proxmoxtextfield',
-                    fieldLabel: gettext('Fallback Server'),
-		    deleteEmpty: !me.isCreate,
-		    name: 'server2'
-		},
-		{
-                    xtype: 'proxmoxintegerfield',
-                    name: 'port',
-                    fieldLabel: gettext('Port'),
-                    minValue: 1,
-                    maxValue: 65535,
-		    emptyText: gettext('Default'),
-		    submitEmptyText: false
-		},
-		{
-                    xtype: 'proxmoxcheckbox',
-                    fieldLabel: 'SSL',
-                    name: 'secure',
-                    uncheckedValue: 0
-		}
-            );
-	}
-
-	// Two Factor Auth settings
-
-        column2.push({
-            xtype: 'proxmoxKVComboBox',
-            name: 'tfa',
-	    deleteEmpty: !me.isCreate,
-	    value: '',
-            fieldLabel: gettext('TFA'),
-	    comboItems: [ ['__default__', Proxmox.Utils.noneText], ['oath', 'OATH'], ['yubico', 'Yubico']],
-	    listeners: {
-		change: function(f, value) {
-		    if (!me.rendered) {
-			return;
-		    }
-		    me.down('field[name=oath_step]').setVisible(value === 'oath');
-		    me.down('field[name=oath_digits]').setVisible(value === 'oath');
-		    me.down('field[name=yubico_api_id]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_api_key]').setVisible(value === 'yubico');
-		    me.down('field[name=yubico_url]').setVisible(value === 'yubico');
-		}
-	    }
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_step',
-	    value: '',
-	    minValue: 10,
-	    emptyText: Proxmox.Utils.defaultText + ' (30)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH time step'
-        });
-
-	column2.push({
-            xtype: 'proxmoxintegerfield',
-            name: 'oath_digits',
-	    value: '',
-	    minValue: 6,
-	    maxValue: 8,
-	    emptyText: Proxmox.Utils.defaultText + ' (6)',
-	    submitEmptyText: false,
-	    hidden: true,
-            fieldLabel: 'OATH password length'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_id',
-	    hidden: true,
-            fieldLabel: 'Yubico API Id'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_api_key',
-	    hidden: true,
-            fieldLabel: 'Yubico API Key'
-        });
-
-	column2.push({
-            xtype: 'textfield',
-            name: 'yubico_url',
-	    hidden: true,
-            fieldLabel: 'Yubico URL'
-        });
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    column1: column1,
-	    column2: column2,
-	    columnB: [{
-		xtype: 'textfield',
-		name: 'comment',
-		fieldLabel: gettext('Comment')
-            }],
-	    onGetValues: function(values) {
-		if (!values.port) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'port' });
-		    }
-		    delete values.port;
-		}
-
-		if (me.isCreate) {
-		    values.type = me.authType;
-		}
-
-		if (values.tfa === 'oath') {
-		    values.tfa = "type=oath";
-		    if (values.oath_step) {
-			values.tfa += ",step=" + values.oath_step;
-		    }
-		    if (values.oath_digits) {
-			values.tfa += ",digits=" + values.oath_digits;
-		    }
-		} else if (values.tfa === 'yubico') {
-		    values.tfa = "type=yubico";
-		    values.tfa += ",id=" + values.yubico_api_id;
-		    values.tfa += ",key=" + values.yubico_api_key;
-		    if (values.yubico_url) {
-			values.tfa += ",url=" + values.yubico_url;
-		    }
-		} else {
-		    delete values.tfa;
-		}
-
-		delete values.oath_step;
-		delete values.oath_digits;
-		delete values.yubico_api_id;
-		delete values.yubico_api_key;
-		delete values.yubico_url;
-		
-		return values;
-	    }
-	});
-
-	Ext.applyIf(me, {
-            url: url,
-            method: method,
-	    fieldDefaults: {
-		labelWidth: 120
-	    },
-	    items: [ ipanel ]
-        });
-
-        me.callParent();
-
-        if (!me.isCreate) {
-            me.load({
-                success: function(response, options) {
-		    var data = response.result.data || {};
-		    // just to be sure (should not happen)
-		    if (data.type !== me.authType) {
-			me.close();
-			throw "got wrong auth type";
-		    }
-
-		    if (data.tfa) {
-			var tfacfg = PVE.Parser.parseTfaConfig(data.tfa);
-			data.tfa = tfacfg.type;
-			if (tfacfg.type === 'yubico') {
-			    data.yubico_api_key = tfacfg.key;
-			    data.yubico_api_id = tfacfg.id;
-			    data.yubico_url = tfacfg.url;
-			} else if (tfacfg.type === 'oath') {
-			    // step is a number before
-			    /*jslint confusion: true*/
-			    data.oath_step = tfacfg.step;
-			    data.oath_digits = tfacfg.digits;
-			    /*jslint confusion: false*/
-			}
-		    }
-
-                    me.setValues(data);
-                }
-            });
-        }
-    }
-});
-Ext.define('PVE.dc.BackupEdit', {
-    extend: 'Proxmox.window.Edit',
-    alias: ['widget.pveDcBackupEdit'],
-
-    defaultFocus: undefined,
-
-    initComponent : function() {
-         var me = this;
-
-        me.isCreate = !me.jobid;
-
-	var url;
-	var method;
-
-	if (me.isCreate) {
-            url = '/api2/extjs/cluster/backup';
-            method = 'POST';
-        } else {
-            url = '/api2/extjs/cluster/backup/' + me.jobid;
-            method = 'PUT';
-        }
-
-	var vmidField = Ext.create('Ext.form.field.Hidden', {
-	    name: 'vmid'
-	});
-
-	/*jslint confusion: true*/
-	// 'value' can be assigned a string or an array
-	var selModeField =  Ext.create('Proxmox.form.KVComboBox', {
-	    xtype: 'proxmoxKVComboBox',
-	    comboItems: [
-		['include', gettext('Include selected VMs')],
-		['all', gettext('All')],
-		['exclude', gettext('Exclude selected VMs')],
-		['pool', gettext('Pool based')]
-	    ],
-	    fieldLabel: gettext('Selection mode'),
-	    name: 'selMode',
-	    value: ''
-	});
-
-	var sm = Ext.create('Ext.selection.CheckboxModel', {
-	    mode: 'SIMPLE',
-	    listeners: {
-		selectionchange: function(model, selected) {
-		    var sel = [];
-		    Ext.Array.each(selected, function(record) {
-			sel.push(record.data.vmid);
-		    });
-
-		    // to avoid endless recursion suspend the vmidField change
-		    // event temporary as it calls us again
-		    vmidField.suspendEvent('change');
-		    vmidField.setValue(sel);
-		    vmidField.resumeEvent('change');
-		}
-	    }
-	});
-
-	var storagesel = Ext.create('PVE.form.StorageSelector', {
-	    fieldLabel: gettext('Storage'),
-	    nodename: 'localhost',
-	    storageContent: 'backup',
-	    allowBlank: false,
-	    name: 'storage'
-	});
-
-	var store = new Ext.data.Store({
-	    model: 'PVEResources',
-	    sorters: {
-		property: 'vmid',
-		order: 'ASC'
-	    }
-	});
-
-	var vmgrid = Ext.createWidget('grid', {
-	    store: store,
-	    border: true,
-	    height: 300,
-	    selModel: sm,
-	    disabled: true,
-	    columns: [
-		{
-		    header: 'ID',
-		    dataIndex: 'vmid',
-		    width: 60
-		},
-		{
-		    header: gettext('Node'),
-		    dataIndex: 'node'
-		},
-		{
-		    header: gettext('Status'),
-		    dataIndex: 'uptime',
-		    renderer: function(value) {
-			if (value) {
-			    return Proxmox.Utils.runningText;
-			} else {
-			    return Proxmox.Utils.stoppedText;
-			}
-		    }
-		},
-		{
-		    header: gettext('Name'),
-		    dataIndex: 'name',
-		    flex: 1
-		},
-		{
-		    header: gettext('Type'),
-		    dataIndex: 'type'
-		}
-	    ]
-	});
-
-	var selectPoolMembers = function(poolid) {
-	    if (!poolid) {
-		return;
-	    }
-	    sm.deselectAll(true);
-	    store.filter([
-		{
-		    id: 'poolFilter',
-		    property: 'pool',
-		    value: poolid
-		}
-	    ]);
-	    sm.selectAll(true);
-	};
-
-	var selPool = Ext.create('PVE.form.PoolSelector', {
-	    fieldLabel: gettext('Pool to backup'),
-	    hidden: true,
-	    allowBlank: true,
-	    name: 'pool',
-	    listeners: {
-		change: function( selpool, newValue, oldValue) {
-		    selectPoolMembers(newValue);
-		}
-	    }
-	});
-
-	var nodesel = Ext.create('PVE.form.NodeSelector', {
-	    name: 'node',
-	    fieldLabel: gettext('Node'),
-	    allowBlank: true,
-	    editable: true,
-	    autoSelect: false,
-	    emptyText: '-- ' + gettext('All') + ' --',
-	    listeners: {
-		change: function(f, value) {
-		    storagesel.setNodename(value || 'localhost');
-		    var mode = selModeField.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!value || rec.get('node') === value);
-		    });
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    }
-
-		    if (mode === 'pool') {
-			selectPoolMembers(selPool.value);
-		    }
-		}
-	    }
-	});
-
-	var column1 = [
-	    nodesel,
-	    storagesel,
-	    {
-		xtype: 'pveDayOfWeekSelector',
-		name: 'dow',
-		fieldLabel: gettext('Day of week'),
-		multiSelect: true,
-		value: ['sat'],
-		allowBlank: false
-	    },
-	    {
-		xtype: 'timefield',
-		fieldLabel: gettext('Start Time'),
-		name: 'starttime',
-		format: 'H:i',
-		formatText: 'HH:MM',
-		value: '00:00',
-		allowBlank: false
-	    },
-	    selModeField,
-	    selPool
-	];
-
-	var column2 = [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Send email to'),
-		name: 'mailto'
-	    },
-	    {
-		xtype: 'pveEmailNotificationSelector',
-		fieldLabel: gettext('Email notification'),
-		name: 'mailnotification',
-		deleteEmpty: me.isCreate ? false : true,
-		value: me.isCreate ? 'always' : ''
-	    },
-	    {
-		xtype: 'pveCompressionSelector',
-		fieldLabel: gettext('Compression'),
-		name: 'compress',
-		deleteEmpty: me.isCreate ? false : true,
-		value: 'lzo'
-	    },
-	    {
-		xtype: 'pveBackupModeSelector',
-		fieldLabel: gettext('Mode'),
-		value: 'snapshot',
-		name: 'mode'
-	    },
-	    {
-		xtype: 'proxmoxcheckbox',
-		fieldLabel: gettext('Enable'),
-		name: 'enabled',
-		uncheckedValue: 0,
-		defaultValue: 1,
-		checked: true
-	    },
-	    vmidField
-	];
-	/*jslint confusion: false*/
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	    onlineHelp: 'chapter_vzdump',
-	    column1: column1,
-	    column2:  column2,
-	    onGetValues: function(values) {
-		if (!values.node) {
-		    if (!me.isCreate) {
-			Proxmox.Utils.assemble_field_data(values, { 'delete': 'node' });
-		    }
-		    delete values.node;
-		}
-
-		var selMode = values.selMode;
-		delete values.selMode;
-
-		if (selMode === 'all') {
-		    values.all = 1;
-		    values.exclude = '';
-		    delete values.vmid;
-		} else if (selMode === 'exclude') {
-		    values.all = 1;
-		    values.exclude = values.vmid;
-		    delete values.vmid;
-		} else if (selMode === 'pool') {
-		    delete values.vmid;
-		}
-
-		if (selMode !== 'pool') {
-		    delete values.pool;
-		}
-		return values;
-	    }
-	});
-
-	var update_vmid_selection = function(list, mode) {
-	    if (mode !== 'all' && mode !== 'pool') {
-		sm.deselectAll(true);
-		if (list) {
-		    Ext.Array.each(list.split(','), function(vmid) {
-			var rec = store.findRecord('vmid', vmid);
-			if (rec) {
-			    sm.select(rec, true);
-			}
-		    });
-		}
-	    }
-	};
-
-	vmidField.on('change', function(f, value) {
-	    var mode = selModeField.getValue();
-	    update_vmid_selection(value, mode);
-	});
-
-	selModeField.on('change', function(f, value, oldValue) {
-	    if (oldValue === 'pool') {
-		store.removeFilter('poolFilter');
-	    }
-
-	    if (oldValue === 'all') {
-		sm.deselectAll(true);
-		vmidField.setValue('');
-	    }
-
-	    if (value === 'all') {
-		sm.selectAll(true);
-		vmgrid.setDisabled(true);
-	    } else {
-		vmgrid.setDisabled(false);
-	    }
-
-	    if (value === 'pool') {
-		vmgrid.setDisabled(true);
-		vmidField.setValue('');
-		selPool.setVisible(true);
-		selPool.allowBlank = false;
-		selectPoolMembers(selPool.value);
-
-	    } else {
-		selPool.setVisible(false);
-		selPool.allowBlank = true;
-	    }
-	    var list = vmidField.getValue();
-	    update_vmid_selection(list, value);
-	});
-
-	var reload = function() {
-	    store.load({
-		params: { type: 'vm' },
-		callback: function() {
-		    var node = nodesel.getValue();
-		    store.clearFilter();
-		    store.filterBy(function(rec) {
-			return (!node || node.length === 0 || rec.get('node') === node);
-		    });
-		    var list = vmidField.getValue();
-		    var mode = selModeField.getValue();
-		    if (mode === 'all') {
-			sm.selectAll(true);
-		    } else if (mode === 'pool'){
-			selectPoolMembers(selPool.value);
-		    } else {
-			update_vmid_selection(list, mode);
-		    }
-		}
-	    });
-	};
-
-        Ext.applyIf(me, {
-            subject: gettext("Backup Job"),
-            url: url,
-            method: method,
-	    items: [ ipanel, vmgrid ]
-        });
-
-        me.callParent();
-
-        if (me.isCreate) {
-	    selModeField.setValue('include');
-	} else {
-            me.load({
-		success: function(response, options) {
-		    var data = response.result.data;
-
-		    data.dow = data.dow.split(',');
-
-		    if (data.all || data.exclude) {
-			if (data.exclude) {
-			    data.vmid = data.exclude;
-			    data.selMode = 'exclude';
-			} else {
-			    data.vmid = '';
-			    data.selMode = 'all';
-			}
-		    } else if (data.pool) {
-			data.selMode = 'pool';
-			data.selPool = data.pool;
-		    } else {
-			data.selMode = 'include';
-		    }
-
-		    me.setValues(data);
-               }
-            });
-        }
-
-	reload();
-    }
-});
-
-
-Ext.define('PVE.dc.BackupView', {
-    extend: 'Ext.grid.GridPanel',
-
-    alias: ['widget.pveDcBackupView'],
-
-    onlineHelp: 'chapter_vzdump',
-
-    allText: '-- ' + gettext('All') + ' --',
-    allExceptText: gettext('All except {0}'),
-
-    initComponent : function() {
-	var me = this;
-
-	var store = new Ext.data.Store({
-	    model: 'pve-cluster-backup',
-	    proxy: {
-                type: 'proxmox',
-		url: "/api2/json/cluster/backup"
-	    }
-	});
-
-	var reload = function() {
-	    store.load();
-	};
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-
-	    var win = Ext.create('PVE.dc.BackupEdit', {
-		jobid: rec.data.id
-	    });
-	    win.on('destroy', reload);
-	    win.show();
-	};
-
-	var run_backup_now = function(job) {
-	    job = Ext.clone(job);
-
-	    let jobNode = job.node;
-	    // Remove properties related to scheduling
-	    delete job.enabled;
-	    delete job.starttime;
-	    delete job.dow;
-	    delete job.id;
-	    delete job.node;
-	    job.all = job.all === true ? 1 : 0;
-
-	    let allNodes = PVE.data.ResourceStore.getNodes();
-	    let nodes = allNodes.filter(node => node.status === 'online').map(node => node.node);
-	    let errors = [];
-
-	    if (jobNode !== undefined) {
-		if (!nodes.includes(jobNode)) {
-		    Ext.Msg.alert('Error', "Node '"+ jobNode +"' from backup job isn't online!");
-		    return;
-		}
-		nodes = [ jobNode ];
-	    } else {
-		let unkownNodes = allNodes.filter(node => node.status !== 'online');
-		if (unkownNodes.length > 0)
-		    errors.push(unkownNodes.map(node => node.node + ": " + gettext("Node is offline")));
-	    }
-	    let jobTotalCount = nodes.length, jobsStarted = 0;
-
-	    Ext.Msg.show({
-		title: gettext('Please wait...'),
-		closable: false,
-		progress: true,
-		progressText: '0/' + jobTotalCount,
-	    });
-
-	    let postRequest = function () {
-		jobsStarted++;
-		Ext.Msg.updateProgress(jobsStarted / jobTotalCount, jobsStarted + '/' + jobTotalCount);
-
-		if (jobsStarted == jobTotalCount) {
-		    Ext.Msg.hide();
-		    if (errors.length > 0) {
-			Ext.Msg.alert('Error', 'Some errors have been encountered:<br />' + errors.join('<br />'));
-		    }
-		}
-	    };
-
-	    nodes.forEach(node => Proxmox.Utils.API2Request({
-		url: '/nodes/' + node + '/vzdump',
-		method: 'POST',
-		params: job,
-		failure: function (response, opts) {
-		    errors.push(node + ': ' + response.htmlStatus);
-		    postRequest();
-		},
-		success: postRequest
-	    }));
-	};
-
-	var edit_btn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	var run_btn = new Proxmox.button.Button({
-	    text: gettext('Run now'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: function() {
-		var rec = sm.getSelection()[0];
-		if (!rec) {
-		    return;
-		}
-
-		Ext.Msg.show({
-		    title: gettext('Confirm'),
-		    icon: Ext.Msg.QUESTION,
-		    msg: gettext('Start the selected backup job now?'),
-		    buttons: Ext.Msg.YESNO,
-		    callback: function(btn) {
-			if (btn !== 'yes') {
-			    return;
-			}
-			run_backup_now(rec.data);
-		    }
-		});
-	    }
-	});
-
-	var remove_btn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: '/cluster/backup',
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Proxmox.Utils.monStoreErrors(me, store);
-
-	Ext.apply(me, {
-	    store: store,
-	    selModel: sm,
-	    stateful: true,
-	    stateId: 'grid-dc-backup',
-	    viewConfig: {
-		trackOver: false
-	    },
-	    tbar: [
-		{
-		    text: gettext('Add'),
-		    handler: function() {
-			var win = Ext.create('PVE.dc.BackupEdit',{});
-			win.on('destroy', reload);
-			win.show();
-		    }
-		},
-		'-',
-		remove_btn,
-		edit_btn,
-		'-',
-		run_btn
-	    ],
-	    columns: [
-		{
-		    header: gettext('Enabled'),
-		    width: 80,
-		    dataIndex: 'enabled',
-		    xtype: 'checkcolumn',
-		    sortable: true,
-		    disabled: true,
-		    disabledCls: 'x-item-enabled',
-		    stopSelection: false
-		},
-		{
-		    header: gettext('Node'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'node',
-		    renderer: function(value) {
-			if (value) {
-			    return value;
-			}
-			return me.allText;
-		    }
-		},
-		{
-		    header: gettext('Day of week'),
-		    width: 200,
-		    sortable: false,
-		    dataIndex: 'dow',
-		    renderer: function(val) {
-			var dows = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
-			var selected = [];
-			var cur = -1;
-			val.split(',').forEach(function(day){
-			    cur++;
-			    var dow = (dows.indexOf(day)+6)%7;
-			    if (cur === dow) {
-				if (selected.length === 0 || selected[selected.length-1] === 0) {
-				    selected.push(1);
-				} else {
-				    selected[selected.length-1]++;
-				}
-			    } else {
-				while (cur < dow) {
-				    cur++;
-				    selected.push(0);
-				}
-				selected.push(1);
-			    }
-			});
-
-			cur = -1;
-			var days = [];
-			selected.forEach(function(item) {
-			    cur++;
-			    if (item > 2) {
-				days.push(Ext.Date.dayNames[(cur+1)] + '-' + Ext.Date.dayNames[(cur+item)%7]);
-				cur += item-1;
-			    } else if (item == 2) {
-				days.push(Ext.Date.dayNames[cur+1]);
-				days.push(Ext.Date.dayNames[(cur+2)%7]);
-				cur++;
-			    } else if (item == 1) {
-				days.push(Ext.Date.dayNames[(cur+1)%7]);
-			    }
-			});
-			return days.join(', ');
-		    }
-		},
-		{
-		    header: gettext('Start Time'),
-		    width: 60,
-		    sortable: true,
-		    dataIndex: 'starttime'
-		},
-		{
-		    header: gettext('Storage'),
-		    width: 100,
-		    sortable: true,
-		    dataIndex: 'storage'
-		},
-		{
-		    header: gettext('Selection'),
-		    flex: 1,
-		    sortable: false,
-		    dataIndex: 'vmid',
-		    renderer: function(value, metaData, record) {
-			/*jslint confusion: true */
-			if (record.data.all) {
-			    if (record.data.exclude) {
-				return Ext.String.format(me.allExceptText, record.data.exclude);
-			    }
-			    return me.allText;
-			}
-			if (record.data.vmid) {
-			    return record.data.vmid;
-			}
-
-			if (record.data.pool) {
-			    return "Pool '"+ record.data.pool + "'";
-			}
-
-			return "-";
-		    }
-		}
-	    ],
-	    listeners: {
-		activate: reload,
-		itemdblclick: run_editor
-	    }
-	});
-
-	me.callParent();
-    }
-}, function() {
-
-    Ext.define('pve-cluster-backup', {
-	extend: 'Ext.data.Model',
-	fields: [
-	    'id', 'starttime', 'dow',
-	    'storage', 'node', 'vmid', 'exclude',
-	    'mailto', 'pool', 'compress', 'mode',
-	    { name: 'enabled', type: 'boolean' },
-	    { name: 'all', type: 'boolean' }
-	]
-    });
-});
-Ext.define('PVE.dc.Support', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveDcSupport',
-    pveGuidePath: '/pve-docs/index.html',
-    onlineHelp: 'getting_help',
-
-    invalidHtml: '<h1>No valid subscription</h1>' + PVE.Utils.noSubKeyHtml,
-
-    communityHtml: 'Please use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> for any questions.',
-
-    activeHtml: 'Please use our <a target="_blank" href="https://my.proxmox.com">support portal</a> for any questions. You can also use the public community <a target="_blank" href="https://forum.proxmox.com">forum</a> to get additional information.',
-
-    bugzillaHtml: '<h1>Bug Tracking</h1>Our bug tracking system is available <a target="_blank" href="https://bugzilla.proxmox.com">here</a>.',
-
-    docuHtml: function() {
-	var me = this;
-	var guideUrl = window.location.origin + me.pveGuidePath;
-	var text = Ext.String.format('<h1>Documentation</h1>'
-	+ 'The official Proxmox VE Administration Guide'
-	+ ' is included with this installation and can be browsed at '
-	+ '<a target="_blank" href="{0}">{0}</a>', guideUrl);
-	return text;
-    },
-
-    updateActive: function(data) {
-	var me = this;
-	
-	var html = '<h1>' + data.productname + '</h1>' + me.activeHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-
-    updateCommunity: function(data) {
-	var me = this;
-
-	var html = '<h1>' + data.productname + '</h1>' + me.communityHtml; 
-	html += '<br><br>' + me.docuHtml();
-	html += '<br><br>' + me.bugzillaHtml;
-
-	me.update(html);
-    },
-	 
-    updateInactive: function(data) {
-	var me = this;
-	me.update(me.invalidHtml);
-    },
-
-    initComponent: function() {
-        var me = this;
-
-	var reload = function() {
-	    Proxmox.Utils.API2Request({
-		url: '/nodes/localhost/subscription',
-		method: 'GET',
-		waitMsgTarget: me,
-		failure: function(response, opts) {
-		    Ext.Msg.alert(gettext('Error'), response.htmlStatus);
-		    me.update('Unable to load subscription status' + ": " + response.htmlStatus);
-		},
-		success: function(response, opts) {
-		    var data = response.result.data;
-
-		    if (data.status === 'Active') {
-			if (data.level === 'c') {
-			    me.updateCommunity(data);
-			} else {
-			    me.updateActive(data);
-			}
-		    } else {
-			me.updateInactive(data);
-		    }
-		}
-	    });
-	};
-
-	Ext.apply(me, {
-	    autoScroll: true,
-	    bodyStyle: 'padding:10px',
-	    listeners: {
-		activate: reload
-	    }
-	});
-
-	me.callParent();
-    }
-});
-Ext.define('pve-security-groups', {
-    extend: 'Ext.data.Model',
-
-    fields: [ 'group', 'comment', 'digest' ],
-    idProperty: 'group'
-});
-
-Ext.define('PVE.SecurityGroupEdit', {
-    extend: 'Proxmox.window.Edit',
-
-    base_url: "/cluster/firewall/groups",
-
-    allow_iface: false,
-
-    initComponent : function() {
-	var me = this;
-
-	me.isCreate = (me.group_name === undefined);
-
-	var subject;
-
-        me.url = '/api2/extjs' + me.base_url;
-        me.method = 'POST';
-	
-	var items = [	    
-	    {
-		xtype: 'textfield',
-		name: 'group',
-		value: me.group_name || '',
-		fieldLabel: gettext('Name'),
-		allowBlank: false
-	    },
-	    {
-		xtype: 'textfield',
-		name: 'comment',
-		value: me.group_comment || '',
-		fieldLabel: gettext('Comment')
-	    }
-	];
-
-	if (me.isCreate) {
-	    subject = gettext('Security Group');
-        } else {
-	    subject = gettext('Security Group') + " '" + me.group_name + "'";
-	    items.push({
-		xtype: 'hiddenfield',
-		name: 'rename',
-		value: me.group_name
-	    });
-        }
-
-	var ipanel = Ext.create('Proxmox.panel.InputPanel', {
-	// InputPanel does not have a 'create' property, does it need a 'isCreate'
-	    isCreate: me.isCreate,
-	    items: items 
-	});
-
-
-	Ext.apply(me, {
-            subject: subject,
-	    items: [ ipanel ]
-	});
-
-	me.callParent();
-    }
-});
-
-Ext.define('PVE.SecurityGroupList', {
-    extend: 'Ext.grid.Panel',
-    alias: 'widget.pveSecurityGroupList',
-
-    stateful: true,
-    stateId: 'grid-securitygroups',
-
-    rule_panel: undefined,
-
-    addBtn: undefined,
-    removeBtn: undefined,
-    editBtn: undefined,
-
-    base_url: "/cluster/firewall/groups",
-
-    initComponent: function() {
-	/*jslint confusion: true */
-        var me = this;
-
-	if (me.rule_panel == undefined) {
-	    throw "no rule panel specified";
-	}
-
-	if (me.base_url == undefined) {
-	    throw "no base_url specified";
-	}
-
-	var store = new Ext.data.Store({
-	    model: 'pve-security-groups',
-	    proxy: {
-		type: 'proxmox',
-		url: '/api2/json' + me.base_url
-	    },
-	    sorters: {
-		property: 'group',
-		order: 'DESC'
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	var reload = function() {
-	    var oldrec = sm.getSelection()[0];
-	    store.load(function(records, operation, success) {
-		if (oldrec) {
-		    var rec = store.findRecord('group', oldrec.data.group);
-		    if (rec) {
-			sm.select(rec);
-		    }
-		}
-	    });
-	};
-
-	var run_editor = function() {
-	    var rec = sm.getSelection()[0];
-	    if (!rec) {
-		return;
-	    }
-	    var win = Ext.create('PVE.SecurityGroupEdit', {
-		digest: rec.data.digest,
-		group_name: rec.data.group,
-		group_comment: rec.data.comment
-	    });
-	    win.show();
-	    win.on('destroy', reload);
-	};
-
-	me.editBtn = new Proxmox.button.Button({
-	    text: gettext('Edit'),
-	    disabled: true,
-	    selModel: sm,
-	    handler: run_editor
-	});
-
-	me.addBtn = new Proxmox.button.Button({
-	    text: gettext('Create'),
-	    handler: function() {
-		sm.deselectAll();
-		var win = Ext.create('PVE.SecurityGroupEdit', {});
-		win.show();
-		win.on('destroy', reload);
-	    }
-	});
-
-	me.removeBtn = Ext.create('Proxmox.button.StdRemoveButton', {
-	    selModel: sm,
-	    baseurl: me.base_url + '/',
-	    enableFn: function(rec) {
-		return (rec && me.base_url);
-	    },
-	    callback: function() {
-		reload();
-	    }
-	});
-
-	Ext.apply(me, {
-	    store: store,
-	    tbar: [ '<b>' + gettext('Group') + ':</b>', me.addBtn, me.removeBtn, me.editBtn ],
-	    selModel: sm,
-	    columns: [
-		{ header: gettext('Group'), dataIndex: 'group', width: '100' },
-		{ header: gettext('Comment'), dataIndex: 'comment', renderer: Ext.String.htmlEncode, flex: 1 }
-	    ],
-	    listeners: {
-		itemdblclick: run_editor,
-		select: function(sm, rec) {
-		    var url = '/cluster/firewall/groups/' + rec.data.group;
-		    me.rule_panel.setBaseUrl(url);
-		},
-		deselect: function() {
-		    me.rule_panel.setBaseUrl(undefined);
-		},
-		show: reload
-	    }
-	});
-
-	me.callParent();
-
-	store.load();
-    }
-});
-
-Ext.define('PVE.SecurityGroups', {
-    extend: 'Ext.panel.Panel',
-    alias: 'widget.pveSecurityGroups',
-
-    title: 'Security Groups',
-
-    initComponent: function() {
-	var me = this;
-
-	var rule_panel = Ext.createWidget('pveFirewallRules', {
-	    region: 'center',
-	    allow_groups: false,
-	    list_refs_url: '/cluster/firewall/refs',
-	    tbar_prefix: '<b>' + gettext('Rules') + ':</b>',
-	    border: false
-	});
-
-	var sglist = Ext.createWidget('pveSecurityGroupList', {
-	    region: 'west',
-	    rule_panel: rule_panel,
-	    width: '25%',
-	    border: false,
-	    split: true
-	});
-
-
-	Ext.apply(me, {
-            layout: 'border',
-            items: [ sglist, rule_panel ],
-	    listeners: {
-		show: function() {
-		    sglist.fireEvent('show', sglist);
-		}
-	    }
-	});
-
-	me.callParent();
-    }
-});
-/*
- * Datacenter config panel, located in the center of the ViewPort after the Datacenter view is selected
- */
-
-Ext.define('PVE.dc.Config', {
-    extend: 'PVE.panel.Config',
-    alias: 'widget.PVE.dc.Config',
-
-    onlineHelp: 'pve_admin_guide',
-
-    initComponent: function() {
-        var me = this;
-
-	var caps = Ext.state.Manager.get('GuiCap');
-
-	me.items = [];
-
-	Ext.apply(me, {
-	    title: gettext("Datacenter"),
-	    hstateid: 'dctab'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		title: gettext('Summary'),
-		xtype: 'pveDcSummary',
-		iconCls: 'fa fa-book',
-		itemId: 'summary'
-	    },
-	    {
-		title: gettext('Cluster'),
-		xtype: 'pveClusterAdministration',
-		iconCls: 'fa fa-server',
-		itemId: 'cluster'
-	    },
-	    {
-		title: 'Ceph',
-		itemId: 'ceph',
-		iconCls: 'fa fa-ceph',
-		xtype: 'pveNodeCephStatus'
-	    },
-	    {
-		xtype: 'pveDcOptionView',
-		title: gettext('Options'),
-		iconCls: 'fa fa-gear',
-		itemId: 'options'
-	    });
-	}
-
-	if (caps.storage['Datastore.Allocate'] || caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveStorageView',
-		title: gettext('Storage'),
-		iconCls: 'fa fa-database',
-		itemId: 'storage'
-	    });
-	}
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveDcBackupView',
-		iconCls: 'fa fa-floppy-o',
-		title: gettext('Backup'),
-		itemId: 'backup'
-	    },
-	    {
-		xtype: 'pveReplicaView',
-		iconCls: 'fa fa-retweet',
-		title: gettext('Replication'),
-		itemId: 'replication'
-	    },
-	    {
-		xtype: 'pveACLView',
-		title: gettext('Permissions'),
-		iconCls: 'fa fa-unlock',
-		itemId: 'permissions',
-		expandedOnInit: true
-	    });
-	}
-
-	me.items.push({
-	    xtype: 'pveUserView',
-	    groups: ['permissions'],
-	    iconCls: 'fa fa-user',
-	    title: gettext('Users'),
-	    itemId: 'users'
-	});
-
-	if (caps.dc['Sys.Audit']) {
-	    me.items.push({
-		xtype: 'pveGroupView',
-		title: gettext('Groups'),
-		iconCls: 'fa fa-users',
-		groups: ['permissions'],
-		itemId: 'groups'
-	    },
-	    {
-		xtype: 'pvePoolView',
-		title: gettext('Pools'),
-		iconCls: 'fa fa-tags',
-		groups: ['permissions'],
-		itemId: 'pools'
-	    },
-	    {
-		xtype: 'pveRoleView',
-		title: gettext('Roles'),
-		iconCls: 'fa fa-male',
-		groups: ['permissions'],
-		itemId: 'roles'
-	    },
-	    {
-		xtype: 'pveAuthView',
-		title: gettext('Authentication'),
-		groups: ['permissions'],
-		iconCls: 'fa fa-key',
-		itemId: 'domains'
-	    },
-	    {
-		xtype: 'pveHAStatus',
-		title: 'HA',
-		iconCls: 'fa fa-heartbeat',
-		itemId: 'ha'
-	    },
-	    {
-		title: gettext('Groups'),
-		groups: ['ha'],
-		xtype: 'pveHAGroupsView',
-		iconCls: 'fa fa-object-group',
-		itemId: 'ha-groups'
-	    },
-	    {
-		title: gettext('Fencing'),
-		groups: ['ha'],
-		iconCls: 'fa fa-bolt',
-		xtype: 'pveFencingView',
-		itemId: 'ha-fencing'
-	    },
-	    {
-		xtype: 'pveFirewallRules',
-		title: gettext('Firewall'),
-		allow_iface: true,
-		base_url: '/cluster/firewall/rules',
-		list_refs_url: '/cluster/firewall/refs',
-		iconCls: 'fa fa-shield',
-		itemId: 'firewall'
-	    },
-	    {
-		xtype: 'pveFirewallOptions',
-		title: gettext('Options'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-gear',
-		base_url: '/cluster/firewall/options',
-		onlineHelp: 'pve_firewall_cluster_wide_setup',
-		fwtype: 'dc',
-		itemId: 'firewall-options'
-	    },
-	    {
-		xtype: 'pveSecurityGroups',
-		title: gettext('Security Group'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-group',
-		itemId: 'firewall-sg'
-	    },
-	    {
-		xtype: 'pveFirewallAliases',
-		title: gettext('Alias'),
-		groups: ['firewall'],
-		iconCls: 'fa fa-external-link',
-		base_url: '/cluster/firewall/aliases',
-		itemId: 'firewall-aliases'
-	    },
-	    {
-		xtype: 'pveIPSet',
-		title: 'IPSet',
-		groups: ['firewall'],
-		iconCls: 'fa fa-list-ol',
-		base_url: '/cluster/firewall/ipset',
-		list_refs_url: '/cluster/firewall/refs',
-		itemId: 'firewall-ipset'
-	    },
-	    {
-		xtype: 'pveDcSupport',
-		title: gettext('Support'),
-		itemId: 'support',
-		iconCls: 'fa fa-comments-o'
-	    });
-	}
-
-	me.callParent();
-   }
-});
-Ext.define('PVE.dc.NodeView', {
-    extend: 'Ext.grid.GridPanel',
-    alias: 'widget.pveDcNodeView',
-
-    title: gettext('Nodes'),
-    disableSelection: true,
-    scrollable: true,
-
-    columns: [
-	{
-	    header: gettext('Name'),
-	    flex: 1,
-	    sortable: true,
-	    dataIndex: 'name'
-	},
-	{
-	    header: 'ID',
-	    width: 40,
-	    sortable: true,
-	    dataIndex: 'nodeid'
-	},
-	{
-	    header: gettext('Online'),
-	    width: 60,
-	    sortable: true,
-	    dataIndex: 'online',
-	    renderer: function(value) {
-		var cls = (value)?'good':'critical';
-		return  '<i class="fa ' + PVE.Utils.get_health_icon(cls) + '"><i/>';
-	    }
-	},
-	{
-	    header: gettext('Support'),
-	    width: 100,
-	    sortable: true,
-	    dataIndex: 'level',
-	    renderer: PVE.Utils.render_support_level
-	},
-	{
-	    header: gettext('Server Address'),
-	    width: 115,
-	    sortable: true,
-	    dataIndex: 'ip'
-	},
-	{
-	    header: gettext('CPU usage'),
-	    sortable: true,
-	    width: 110,
-	    dataIndex: 'cpuusage',
-	    tdCls: 'x-progressbar-default-cell',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Memory usage'),
-	    width: 110,
-	    sortable: true,
-	    tdCls: 'x-progressbar-default-cell',
-	    dataIndex: 'memoryusage',
-	    xtype: 'widgetcolumn',
-	    widget: {
-		xtype: 'pveProgressBar'
-	    }
-	},
-	{
-	    header: gettext('Uptime'),
-	    sortable: true,
-	    dataIndex: 'uptime',
-	    align: 'right',
-	    renderer: Proxmox.Utils.render_uptime
-	}
-    ],
-
-    stateful: true,
-    stateId: 'grid-cluster-nodes',
-    tools: [
-	{
-	    type: 'up',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = Math.max(me.getHeight()-50, 250);
-		me.setHeight(height);
-	    }
-	},
-	{
-	    type: 'down',
-	    handler: function(){
-		var me = this.up('grid');
-		var height = me.getHeight()+50;
-		me.setHeight(height);
-	    }
-	}
-    ]
-}, function() {
-
-    Ext.define('pve-dc-nodes', {
-	extend: 'Ext.data.Model',
-	fields: [ 'id', 'type', 'name', 'nodeid', 'ip', 'level', 'local', 'online'],
-	idProperty: 'id'
-    });
-
-});
-
-Ext.define('PVE.widget.ProgressBar',{
-    extend: 'Ext.Progress',
-    alias: 'widget.pveProgressBar',
-
-    animate: true,
-    textTpl: [
-	'{percent}%'
-    ],
-
-    setValue: function(value){
-	var me = this;
-	me.callParent([value]);
-
-	me.removeCls(['warning', 'critical']);
-
-	if (value > 0.89) {
-	    me.addCls('critical');
-	} else if (value > 0.59) {
-	    me.addCls('warning');
-	}
-    }
-});
-/*jslint confusion: true*/
-Ext.define('pve-cluster-nodes', {
-    extend: 'Ext.data.Model',
-    fields: [
-	'node', { type: 'integer', name: 'nodeid' }, 'ring0_addr', 'ring1_addr',
-	{ type: 'integer', name: 'quorum_votes' }
-    ],
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/nodes"
-    },
-    idProperty: 'nodeid'
-});
-
-Ext.define('pve-cluster-info', {
-    extend: 'Ext.data.Model',
-    proxy: {
-        type: 'proxmox',
-	url: "/api2/json/cluster/config/join"
-    }
-});
-
-Ext.define('PVE.ClusterAdministration', {
-    extend: 'Ext.panel.Panel',
-    xtype: 'pveClusterAdministration',
-
-    title: gettext('Cluster Administration'),
-    onlineHelp: 'chapter_pvecm',
-
-    border: false,
-    defaults: { border: false },
-
-    viewModel: {
-	parent: null,
-	data: {
-	    totem: {},
-	    nodelist: [],
-	    preferred_node: {
-		name: '',
-		fp: '',
-		addr: ''
-	    },
-	    isInCluster: false,
-	    nodecount: 0
-	}
-    },
-
-    items: [
-	{
-	    xtype: 'panel',
-	    title: gettext('Cluster Information'),
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.store = Ext.create('Proxmox.data.UpdateStore', {
-			autoStart: true,
-			interval: 15 * 1000,
-			storeid: 'pve-cluster-info',
-			model: 'pve-cluster-info'
-		    });
-		    view.store.on('load', this.onLoad, this);
-		    view.on('destroy', view.store.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var vm = this.getViewModel();
-		    if (!success || !records || !records[0].data) {
-			vm.set('totem', {});
-			vm.set('isInCluster', false);
-			vm.set('nodelist', []);
-			vm.set('preferred_node', {
-			    name: '',
-			    addr: '',
-			    fp: ''
-			});
-			return;
-		    }
-		    var data = records[0].data;
-		    vm.set('totem', data.totem);
-		    vm.set('isInCluster', !!data.totem.cluster_name);
-		    vm.set('nodelist', data.nodelist);
-
-		    var nodeinfo = Ext.Array.findBy(data.nodelist, function (el) {
-			return el.name === data.preferred_node;
-		    });
-
-		    var links = [];
-		    PVE.Utils.forEachCorosyncLink(nodeinfo,
-			(num, link) => links.push(link));
-
-		    vm.set('preferred_node', {
-			name: data.preferred_node,
-			addr: nodeinfo.pve_addr,
-			ring_addr: links,
-			fp: nodeinfo.pve_fp
-		    });
-		},
-
-		onCreate: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterCreateWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		},
-
-		onClusterInfo: function() {
-		    var vm = this.getViewModel();
-		    var win = Ext.create('PVE.ClusterInfoWindow', {
-			joinInfo: {
-			    ipAddress: vm.get('preferred_node.addr'),
-			    fingerprint: vm.get('preferred_node.fp'),
-			    ring_addr: vm.get('preferred_node.ring_addr'),
-			    totem: vm.get('totem')
-			}
-		    });
-		    win.show();
-		},
-
-		onJoin: function() {
-		    var view = this.getView();
-		    view.store.stopUpdate();
-		    var win = Ext.create('PVE.ClusterJoinNodeWindow', {
-			autoShow: true,
-			listeners: {
-			    destroy: function() {
-				view.store.startUpdate();
-			    }
-			}
-		    });
-		}
-	    },
-	    tbar: [
-		{
-		    text: gettext('Create Cluster'),
-		    reference: 'createButton',
-		    handler: 'onCreate',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Information'),
-		    reference: 'addButton',
-		    handler: 'onClusterInfo',
-		    bind: {
-			disabled: '{!isInCluster}'
-		    }
-		},
-		{
-		    text: gettext('Join Cluster'),
-		    reference: 'joinButton',
-		    handler: 'onJoin',
-		    bind: {
-			disabled: '{isInCluster}'
-		    }
-		}
-	    ],
-	    layout: 'hbox',
-	    bodyPadding: 5,
-	    items: [
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Cluster Name'),
-		    bind: {
-			value: '{totem.cluster_name}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Config Version'),
-		    bind: {
-			value: '{totem.config_version}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    fieldLabel: gettext('Number of Nodes'),
-		    labelWidth: 120,
-		    bind: {
-			value: '{nodecount}',
-			hidden: '{!isInCluster}'
-		    },
-		    flex: 1
-		},
-		{
-		    xtype: 'displayfield',
-		    value: gettext('Standalone node - no cluster defined'),
-		    bind: {
-			hidden: '{isInCluster}'
-		    },
-		    flex: 1
-		}
-	    ]
-	},
-	{
-	    xtype: 'grid',
-	    title: gettext('Cluster Nodes'),
-	    autoScroll: true,
-	    enableColumnHide: false,
-	    controller: {
-		xclass: 'Ext.app.ViewController',
-
-		init: function(view) {
-		    view.rstore = Ext.create('Proxmox.data.UpdateStore', {
-			autoLoad: true,
-			xtype: 'update',
-			interval: 5 * 1000,
-			autoStart: true,
-			storeid: 'pve-cluster-nodes',
-			model: 'pve-cluster-nodes'
-		    });
-		    view.setStore(Ext.create('Proxmox.data.DiffStore', {
-			rstore: view.rstore,
-			sorters: {
-			    property: 'nodeid',
-			    order: 'DESC'
-			}
-		    }));
-		    Proxmox.Utils.monStoreErrors(view, view.rstore);
-		    view.rstore.on('load', this.onLoad, this);
-		    view.on('destroy', view.rstore.stopUpdate);
-		},
-
-		onLoad: function(store, records, success) {
-		    var view = this.getView();
-		    var vm = this.getViewModel();
-
-		    if (!success || !records || !records.length) {
-			vm.set('nodecount', 0);
-			return;
-		    }
-		    vm.set('nodecount', records.length);
-
-		    // show/hide columns according to used links
-		    var linkIndex = view.columns.length;
-		    var columns = Ext.each(view.columns, (col, i) => {
-			if (col.linkNumber !== undefined) {
-			    col.setHidden(true);
-
-			    // save offset at which link columns start, so we
-			    // can address them directly below
-			    if (i < linkIndex) {
-				linkIndex = i;
-			    }
-			}
-		    });
-
-		    PVE.Utils.forEachCorosyncLink(records[0].data,
-			(linknum, val) => {
-			    if (linknum > 7) {
-				return;
-			    }
-			    view.columns[linkIndex+linknum].setHidden(false);
-			}
-		    );
-		}
-	    },
-	    columns: {
-		items: [
-		    {
-			header: gettext('Nodename'),
-			hidden: false,
-			dataIndex: 'name'
-		    },
-		    {
-			header: gettext('ID'),
-			minWidth: 100,
-			width: 100,
-			flex: 0,
-			hidden: false,
-			dataIndex: 'nodeid'
-		    },
-		    {
-			header: gettext('Votes'),
-			minWidth: 100,
-			width: 100,
-			flex: 0,
-			hidden: false,
-			dataIndex: 'quorum_votes'
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 0),
-			dataIndex: 'ring0_addr',
-			linkNumber: 0
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 1),
-			dataIndex: 'ring1_addr',
-			linkNumber: 1
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 2),
-			dataIndex: 'ring2_addr',
-			linkNumber: 2
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 3),
-			dataIndex: 'ring3_addr',
-			linkNumber: 3
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 4),
-			dataIndex: 'ring4_addr',
-			linkNumber: 4
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 5),
-			dataIndex: 'ring5_addr',
-			linkNumber: 5
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 6),
-			dataIndex: 'ring6_addr',
-			linkNumber: 6
-		    },
-		    {
-			header: Ext.String.format(gettext('Link {0}'), 7),
-			dataIndex: 'ring7_addr',
-			linkNumber: 7
-		    }
-		],
-		defaults: {
-		    flex: 1,
-		    hidden: true,
-		    minWidth: 150
-		}
-	    }
-	}
-    ]
-});
-/*jslint confusion: true*/
-Ext.define('PVE.ClusterCreateWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterCreateWindow',
-
-    title: gettext('Create Cluster'),
-    width: 600,
-
-    method: 'POST',
-    url: '/cluster/config',
-
-    isCreate: true,
-    subject: gettext('Cluster'),
-    showTaskViewer: true,
-
-    onlineHelp: 'pvecm_create_cluster',
-
-    items: {
-	xtype: 'inputpanel',
-	items: [{
-	    xtype: 'textfield',
-	    fieldLabel: gettext('Cluster Name'),
-	    allowBlank: false,
-	    maxLength: 15,
-	    name: 'clustername'
-	},
-	{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-	    emptyText: gettext("Optional, defaults to IP resolved by node's hostname"),
-	    name: 'link0',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}],
-	advancedItems: [{
-	    xtype: 'proxmoxNetworkSelector',
-	    fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-	    emptyText: gettext("Optional second link for redundancy"),
-	    name: 'link1',
-	    autoSelect: false,
-	    valueField: 'address',
-	    displayField: 'address',
-	    skipEmptyText: true
-	}]
-    }
-});
-
-Ext.define('PVE.ClusterInfoWindow', {
-    extend: 'Ext.window.Window',
-    xtype: 'pveClusterInfoWindow',
-    mixins: ['Proxmox.Mixin.CBind'],
-
-    width: 800,
-    modal: true,
-    resizable: false,
-    title: gettext('Cluster Join Information'),
-
-    joinInfo: {
-	ipAddress: undefined,
-	fingerprint: undefined,
-	totem: {}
-    },
-
-    items: [
-	{
-	    xtype: 'component',
-	    border: false,
-	    padding: '10 10 10 10',
-	    html: gettext("Copy the Join Information here and use it on the node you want to add.")
-	},
-	{
-	    xtype: 'container',
-	    layout: 'form',
-	    border: false,
-	    padding: '0 10 10 10',
-	    items: [
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('IP Address'),
-		    cbind: { value: '{joinInfo.ipAddress}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textfield',
-		    fieldLabel: gettext('Fingerprint'),
-		    cbind: { value: '{joinInfo.fingerprint}' },
-		    editable: false
-		},
-		{
-		    xtype: 'textarea',
-		    inputId: 'pveSerializedClusterInfo',
-		    fieldLabel: gettext('Join Information'),
-		    grow: true,
-		    cbind: { joinInfo: '{joinInfo}' },
-		    editable: false,
-		    listeners: {
-			afterrender: function(field) {
-			    if (!field.joinInfo) {
-				return;
-			    }
-			    var jsons = Ext.JSON.encode(field.joinInfo);
-			    var base64s = Ext.util.Base64.encode(jsons);
-			    field.setValue(base64s);
-			}
-		    }
-		}
-	    ]
-	}
-    ],
-    dockedItems: [{
-	dock: 'bottom',
-	xtype: 'toolbar',
-	items: [{
-	    xtype: 'button',
-	    handler: function(b) {
-		var el = document.getElementById('pveSerializedClusterInfo');
-		el.select();
-		document.execCommand("copy");
-	    },
-	    text: gettext('Copy Information')
-	}]
-    }]
-});
-
-Ext.define('PVE.ClusterJoinNodeWindow', {
-    extend: 'Proxmox.window.Edit',
-    xtype: 'pveClusterJoinNodeWindow',
-
-    title: gettext('Cluster Join'),
-    width: 800,
-
-    method: 'POST',
-    url: '/cluster/config/join',
-
-    defaultFocus: 'textarea[name=serializedinfo]',
-    isCreate: true,
-    bind: {
-	submitText: '{submittxt}',
-    },
-    showTaskViewer: true,
-
-    onlineHelp: 'pvecm_join_node_to_cluster',
-
-    viewModel: {
-	parent: null,
-	data: {
-	    info: {
-		fp: '',
-		ip: '',
-		clusterName: '',
-		ring0Needed: false,
-		ring1Possible: false,
-		ring1Needed: false
-	    }
-	},
-	formulas: {
-	    ring0EmptyText: function(get) {
-		if (get('info.ring0Needed')) {
-		    return gettext("Cannot use default address safely");
-		} else {
-		    return gettext("Default: IP resolved by node's hostname");
-		}
-	    },
-	    submittxt: function(get) {
-		let cn = get('info.clusterName');
-		if (cn) {
-		    return `${gettext('Join')} '${cn}'`;
-		}
-		return gettext('Join');
-	    },
-	},
-    },
-
-    controller: {
-	xclass: 'Ext.app.ViewController',
-	control: {
-	    '#': {
-		close: function() {
-		    delete PVE.Utils.silenceAuthFailures;
-		}
-	    },
-	    'proxmoxcheckbox[name=assistedEntry]': {
-		change: 'onInputTypeChange'
-	    },
-	    'textarea[name=serializedinfo]': {
-		change: 'recomputeSerializedInfo',
-		enable: 'resetField'
-	    },
-	    'proxmoxtextfield[name=ring1_addr]': {
-		enable: 'ring1Needed'
-	    },
-	    'textfield': {
-		disable: 'resetField'
-	    }
-	},
-	resetField: function(field) {
-	    field.reset();
-	},
-	ring1Needed: function(f) {
-	    var vm = this.getViewModel();
-	    f.allowBlank = !vm.get('info.ring1Needed');
-	},
-	onInputTypeChange: function(field, assistedInput) {
-	    var vm = this.getViewModel();
-	    if (!assistedInput) {
-		vm.set('info.ring1Possible', true);
-	    }
-	},
-	recomputeSerializedInfo: function(field, value) {
-	    var vm = this.getViewModel();
-	    var jsons = Ext.util.Base64.decode(value);
-	    var joinInfo = Ext.JSON.decode(jsons, true);
-
-	    var info = {
-		fp: '',
-		ring1Needed: false,
-		ring1Possible: false,
-		ip: '',
-		clusterName: ''
-	    };
-
-	    var totem = {};
-	    if (!(joinInfo && joinInfo.totem)) {
-		field.valid = false;
-	    } else {
-		var ring0Needed = false;
-		if (joinInfo.ring_addr !== undefined) {
-		    ring0Needed = joinInfo.ring_addr[0] !== joinInfo.ipAddress;
-		}
-
-		info = {
-		    ip: joinInfo.ipAddress,
-		    fp: joinInfo.fingerprint,
-		    ring0Needed: ring0Needed,
-		    ring1Possible: !!joinInfo.totem['interface']['1'],
-		    ring1Needed: !!joinInfo.totem['interface']['1'],
-		    clusterName: joinInfo.totem['cluster_name']
-		};
-		totem = joinInfo.totem;
-		field.valid = true;
-	    }
-
-	    vm.set('info', info);
-	}
-    },
-
-    submit: function() {
-	// joining may produce temporarily auth failures, ignore as long the task runs
-	PVE.Utils.silenceAuthFailures = true;
-	this.callParent();
-    },
-
-    taskDone: function(success) {
-	delete PVE.Utils.silenceAuthFailures;
-	if (success) {
-	    var txt = gettext('Cluster join task finished, node certificate may have changed, reload GUI!');
-	    // ensure user cannot do harm
-	    Ext.getBody().mask(txt, ['pve-static-mask']);
-	    // TaskView may hide above mask, so tell him directly
-	    Ext.Msg.show({
-		title: gettext('Join Task Finished'),
-		icon: Ext.Msg.INFO,
-		msg: txt
-	    });
-	    // reload always (if user wasn't faster), but wait a bit for pveproxy
-	    Ext.defer(function() {
-		window.location.reload(true);
-	    }, 5000);
-	}
-    },
-
-    items: [{
-	xtype: 'proxmoxcheckbox',
-	reference: 'assistedEntry',
-	name: 'assistedEntry',
-	submitValue: false,
-	value: true,
-	autoEl: {
-	    tag: 'div',
-	    'data-qtip': gettext('Select if join information should be extracted from pasted cluster information, deselect for manual entering')
-	},
-	boxLabel: gettext('Assisted join: Paste encoded cluster join information and enter password.')
-    },
-    {
-	xtype: 'textarea',
-	name: 'serializedinfo',
-	submitValue: false,
-	allowBlank: false,
-	fieldLabel: gettext('Information'),
-	emptyText: gettext('Paste encoded Cluster Information here'),
-	validator: function(val) {
-	    return val === '' || this.valid ||
-	       gettext('Does not seem like a valid encoded Cluster Information!');
-	},
-	bind: {
-	    disabled: '{!assistedEntry.checked}',
-	    hidden: '{!assistedEntry.checked}'
-	},
-	value: ''
-    },
-    {
-	xtype: 'inputpanel',
-	column1: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Peer Address'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.ip}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'hostname'
-	    },
-	    {
-		xtype: 'textfield',
-		inputType: 'password',
-		emptyText: gettext("Peer's root password"),
-		fieldLabel: gettext('Password'),
-		allowBlank: false,
-		name: 'password'
-	    }
-	],
-	column2: [
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 0),
-		bind: {
-		    emptyText: '{ring0EmptyText}',
-		    allowBlank: '{!info.ring0Needed}'
-		},
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		name: 'link0'
-	    },
-	    {
-		xtype: 'proxmoxNetworkSelector',
-		fieldLabel: Ext.String.format(gettext('Link {0}'), 1),
-		skipEmptyText: true,
-		autoSelect: false,
-		valueField: 'address',
-		displayField: 'address',
-		bind: {
-		    disabled: '{!info.ring1Possible}',
-		    allowBlank: '{!info.ring1Needed}',
-		},
-		name: 'link1'
-	    }
-	],
-	columnB: [
-	    {
-		xtype: 'textfield',
-		fieldLabel: gettext('Fingerprint'),
-		allowBlank: false,
-		bind: {
-		    value: '{info.fp}',
-		    readOnly: '{assistedEntry.checked}'
-		},
-		name: 'fingerprint'
-	    }
-	]
-    }]
-});
-/*jslint confusion: true */
-
-Ext.define('pve-permissions', {
-    extend: 'Ext.data.TreeModel',
-    fields: [
-	'text', 'type',
-	{ type: 'boolean', name: 'propagate' }
-    ]
-});
-
-Ext.define('PVE.dc.PermissionGridPanel', {
-    extend: 'Ext.tree.Panel',
-    onlineHelp: 'chapter_user_management',
-
-    scrollable: true,
-
-    sorterFn: function(rec1, rec2) {
-	var v1, v2;
-
-	if (rec1.data.type != rec2.data.type) {
-	    v2 = rec1.data.type;
-	    v1 = rec2.data.type;
-	} else {
-	    v1 = rec1.data.text;
-	    v2 = rec2.data.text;
-	}
-
-	return (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
-    },
-
-    initComponent: function() {
-	var me = this;
-
-	Proxmox.Utils.API2Request({
-	    url: '/access/permissions?userid=' + me.userid,
-	    method: 'GET',
-	    failure: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, response.htmlStatus);
-		me.load_task.delay(me.load_delay);
-	    },
-	    success: function(response, opts) {
-		Proxmox.Utils.setErrorMask(me, false);
-		var result = Ext.decode(response.responseText);
-		var data = result.data || {};
-		var records = [];
-
-		var root = { name: '__root', expanded: true, children: [] };
-		var idhash = {};
-		Ext.Object.each(data, function(path, perms) {
-		    var path_item = {};
-		    path_item.text = path;
-		    path_item.type = 'path';
-		    path_item.children = [];
-		    Ext.Object.each(perms, function(perm, propagate) {
-			var perm_item = {};
-			perm_item.text = perm;
-			perm_item.type = 'perm';
-			perm_item.propagate = propagate == 1 ? true : false;
-			perm_item.iconCls = 'fa fa-fw fa-unlock';
-			perm_item.leaf = true;
-			path_item.children.push(perm_item);
-			path_item.expandable = true;
-		    });
-		    idhash[path] = path_item;
-		});
-
-		if (!idhash['/']) {
-		    idhash['/'] = {
-			children: [],
-			text: '/',
-			type: 'path',
-		    };
-		}
-
-		Ext.Object.each(idhash, function(path, item) {
-		    var parent_item;
-		    if (path == '/') {
-			parent_item = root;
-			item.expand = true;
-		    } else {
-			let split_path = path.split('/');
-			while (split_path.pop()) {
-			    let parent_path = split_path.join('/');
-			    if (parent_item = idhash[parent_path]) {
-				break;
-			    }
-			}
-		    }
-		    if (!parent_item) {
-			parent_item = idhash['/'];
-		    }
-		    parent_item.children.push(item);
-		});
-
-		me.setRootNode(root);
-	    }
-	});
-
-	var sm = Ext.create('Ext.selection.RowModel', {});
-
-	Ext.apply(me, {
-	    layout: 'fit',
-	    rootVisible: false,
-	    animate: false,
-	    sortableColumns: false,
-	    selModel: sm,
-	    columns: [
-		{
-		    xtype: 'treecolumn',
-		    header: gettext('Path') + '/' + gettext('Permission'),
-		    flex: 1,
-		    sortable: true,
-		    dataIndex: 'text'
-		},
-		{
-		    header: gettext('Propagate'),
-		    width: 80,
-		    sortable: true,
-		    renderer: function(value) {
-			if (Ext.isDefined(value)) {
-			    return Proxmox.Utils.format_boolean(value);
-			} else {
-			    return '';
-			}
-		    },
-		    dataIndex: 'propagate'
-		},
-	    ],
-	    listeners: {
-	    }
-	});
-
-	me.callParent();
-
-	me.store.sorters.add(new Ext.util.Sorter({
-	    sorterFn: me.sorterFn
-	}));
-    }
-});
-
-Ext.define('PVE.dc.PermissionView', {
-    extend: 'Ext.window.Window',
-    scrollable: true,
-    width: 800,
-    height: 600,
-    layout: 'fit',
-
-    initComponent: function() {
-	var me = this;
-
-	if (!me.userid) {
-	    throw "no userid specified";
-	}
-
-	var grid = Ext.create('PVE.dc.PermissionGridPanel', {
-	    userid: me.userid
-	});
-
-	Ext.apply(me, {
-	    title: me.userid + ' - ' + gettext('Permissions'),
-	    items: [ grid ]
-	});
-
-	me.callParent();
-    }
-});
-
-/*
- * Workspace base class
- *
- * popup login window when auth fails (call onLogin handler)
- * update (re-login) ticket every 15 minutes
- *
- */
-
-Ext.define('PVE.Workspace', {
-    extend: 'Ext.container.Viewport',
-
-    title: 'Proxmox Virtual Environment',
-
-    loginData: null, // Data from last login call
-
-    onLogin: function(loginData) {},
-
-    // private
-    updateLoginData: function(loginData) {
-	var me = this;
-	me.loginData = loginData;
-	Proxmox.Utils.setAuthData(loginData);
-
-	var rt = me.down('pveResourceTree');
-	rt.setDatacenterText(loginData.clustername);
-
-	if (loginData.cap) {
-	    Ext.state.Manager.set('GuiCap', loginData.cap);
-	}
-	me.response401count = 0;
-
-	me.onLogin(loginData);
-    },
-
-    // private
-    showLogin: function() {
-	var me = this;
-
-	Proxmox.Utils.authClear();
-	Proxmox.UserName = null;
-	me.loginData = null;
-
-	if (!me.login) {
-	    me.login = Ext.create('PVE.window.LoginWindow', {
-		handler: function(data) {
-		    me.login = null;
-		    me.updateLoginData(data);
-		    Proxmox.Utils.checked_command(function() {}); // display subscription status
-		}
-	    });
-	}
-	me.onLogin(null);
-        me.login.show();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.tip.QuickTipManager.init();
-
-	// fixme: what about other errors
-	Ext.Ajax.on('requestexception', function(conn, response, options) {
-	    if (response.status == 401 && !PVE.Utils.silenceAuthFailures) { // auth failure
-		// don't immediately show as logged out to cope better with some big
-		// upgrades, which may temporarily produce a false positive 401 err
-		me.response401count++;
-		if (me.response401count > 5) {
-		    me.showLogin();
-		}
-	    }
-	});
-
-	me.callParent();
-
-        if (!Proxmox.Utils.authOK()) {
-	    me.showLogin();
-	} else { 
-	    if (me.loginData) {
-		me.onLogin(me.loginData);
-	    }
-	}
-
-	Ext.TaskManager.start({
-	    run: function() {
-		var ticket = Proxmox.Utils.authOK();
-		if (!ticket || !Proxmox.UserName) {
-		    return;
-		}
-
-		Ext.Ajax.request({
-		    params: { 
-			username: Proxmox.UserName,
-			password: ticket
-		    },
-		    url: '/api2/json/access/ticket',
-		    method: 'POST',
-		    success: function(response, opts) {
-			var obj = Ext.decode(response.responseText);
-			me.updateLoginData(obj.data);
-		    }
-		});
-	    },
-	    interval: 15*60*1000
-	});
-
-    }
-});
-
-Ext.define('PVE.StdWorkspace', {
-    extend: 'PVE.Workspace',
-
-    alias: ['widget.pveStdWorkspace'],
-
-    // private
-    setContent: function(comp) {
-	var me = this;
-	
-	var cont = me.child('#content');
-
-	var lay = cont.getLayout();
-
-	var cur = lay.getActiveItem();
-
-	if (comp) {
-	    Proxmox.Utils.setErrorMask(cont, false);
-	    comp.border = false;
-	    cont.add(comp);
-	    if (cur !== null && lay.getNext()) {
-		lay.next();
-		var task = Ext.create('Ext.util.DelayedTask', function(){
-		    cont.remove(cur);
-		});
-		task.delay(10);
-	    }
-	}
-	else {
-	    // helper for cleaning the content when logging out
-	    cont.removeAll();
-	}
-    },
-
-    selectById: function(nodeid) {
-	var me = this;
-	var tree = me.down('pveResourceTree');
-	tree.selectById(nodeid);
-    },
-
-    onLogin: function(loginData) {
-	var me = this;
-
-	me.updateUserInfo();
-
-	if (loginData) {
-	    PVE.data.ResourceStore.startUpdate();
-
-	    Proxmox.Utils.API2Request({
-		url: '/version',
-		method: 'GET',
-		success: function(response) {
-		    PVE.VersionInfo = response.result.data;
-		    me.updateVersionInfo();
-		}
-	    });
-	}
-    },
-
-    updateUserInfo: function() {
-	var me = this;
-	var ui = me.query('#userinfo')[0];
-	ui.setText(Proxmox.UserName || '');
-	ui.updateLayout();
-    },
-
-    updateVersionInfo: function() {
-	var me = this;
-
-	var ui = me.query('#versioninfo')[0];
-
-	if (PVE.VersionInfo) {
-	    var version = PVE.VersionInfo.version;
-	    ui.update('Virtual Environment ' + version);
-	} else {
-	    ui.update('Virtual Environment');
-	}
-	ui.updateLayout();
-    },
-
-    initComponent : function() {
-	var me = this;
-
-	Ext.History.init();
-
-	var sprovider = Ext.create('PVE.StateProvider');
-	Ext.state.Manager.setProvider(sprovider);
-
-	var selview = Ext.create('PVE.form.ViewSelector');
-
-	var rtree = Ext.createWidget('pveResourceTree', {
-	    viewFilter: selview.getViewFilter(),
-	    flex: 1,
-	    selModel: {
-		selType: 'treemodel',
-		listeners: {
-		    selectionchange: function(sm, selected) {
-			if (selected.length > 0) {
-			    var n = selected[0];
-			    var tlckup = {
-				root: 'PVE.dc.Config',
-				node: 'PVE.node.Config',
-				qemu: 'PVE.qemu.Config',
-				lxc: 'PVE.lxc.Config',
-				storage: 'PVE.storage.Browser',
-				pool: 'pvePoolConfig'
-			    };
-			    var comp = {
-				xtype: tlckup[n.data.type || 'root'] || 
-				    'pvePanelConfig',
-				showSearch: (n.data.id === 'root') ||
-				    Ext.isDefined(n.data.groupbyid),
-				pveSelNode: n,
-				workspace: me,
-				viewFilter: selview.getViewFilter()
-			    };
-			    PVE.curSelectedNode = n;
-			    me.setContent(comp);
-			}
-		    }
-		}
-	    }
-	});
-
-	selview.on('select', function(combo, records) { 
-	    if (records) {
-		var view = combo.getViewFilter();
-		rtree.setViewFilter(view);
-	    }
-	});
-
-	var caps = sprovider.get('GuiCap');
-
-	var createVM = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-desktop',
-	    text: gettext("Create VM"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.qemu.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	var createCT = Ext.createWidget('button', {
-	    pack: 'end',
-	    margin: '3 5 0 0',
-	    baseCls: 'x-btn',
-	    iconCls: 'fa fa-cube',
-	    text: gettext("Create CT"),
-	    disabled: !caps.vms['VM.Allocate'],
-	    handler: function() {
-		var wiz = Ext.create('PVE.lxc.CreateWizard', {});
-		wiz.show();
-	    } 
-	});
-
-	sprovider.on('statechange', function(sp, key, value) {
-	    if (key === 'GuiCap' && value) {
-		caps = value;
-		createVM.setDisabled(!caps.vms['VM.Allocate']);
-		createCT.setDisabled(!caps.vms['VM.Allocate']);
-	    }
-	});
-
-	Ext.apply(me, {
-	    layout: { type: 'border' },
-	    border: false,
-	    items: [
-		{
-		    region: 'north',
-		    layout: { 
-			type: 'hbox',
-			align: 'middle'
-		    },
-		    baseCls: 'x-plain',		
-		    defaults: {
-			baseCls: 'x-plain'			
-		    },
-		    border: false,
-		    margin: '2 0 2 5',
-		    items: [
-			{
-			    html: '<a class="x-unselectable" target=_blank href="https://www.proxmox.com">' +
-				'<img style="padding-top:4px;padding-right:5px" src="/pve2/images/proxmox_logo.png"/></a>'
-			},
-			{
-			    minWidth: 150,
-			    id: 'versioninfo',
-			    html: 'Virtual Environment'
-			},
-			{
-			    xtype: 'pveGlobalSearchField',
-			    tree: rtree
-			},
-			{
-			    flex: 1
-			},
-			{
-			    xtype: 'proxmoxHelpButton',
-			    hidden: false,
-			    baseCls: 'x-btn',
-			    iconCls: 'fa fa-book x-btn-icon-el-default-toolbar-small ',
-			    listenToGlobalEvent: false,
-			    onlineHelp: 'pve_documentation_index',
-			    text: gettext('Documentation'),
-			    margin: '0 5 0 0'
-			},
-			createVM, 
-			createCT,
-			{
-			    pack: 'end',
-			    margin: '0 5 0 0',
-			    id: 'userinfo',
-			    xtype: 'button',
-			    baseCls: 'x-btn',
-			    style: {
-				// proxmox dark grey p light grey as border
-				backgroundColor: '#464d4d',
-				borderColor: '#ABBABA'
-			    },
-			    iconCls: 'fa fa-user',
-			    menu: [
-				{
-				    iconCls: 'fa fa-gear',
-				    text: gettext('My Settings'),
-				    handler: function() {
-					var win = Ext.create('PVE.window.Settings');
-					win.show();
-				    }
-				},
-				{
-				    text: gettext('Password'),
-				    iconCls: 'fa fa-fw fa-key',
-				    handler: function() {
-					var win = Ext.create('Proxmox.window.PasswordEdit', {
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				{
-				    text: 'TFA',
-				    iconCls: 'fa fa-fw fa-lock',
-				    handler: function(btn, event, rec) {
-					var win = Ext.create('PVE.window.TFAEdit',{
-					    userid: Proxmox.UserName
-					});
-					win.show();
-				    }
-				},
-				'-',
-				{
-				    iconCls: 'fa fa-fw fa-sign-out',
-				    text: gettext("Logout"),
-				    handler: function() {
-					PVE.data.ResourceStore.loadData([], false);
-					me.showLogin();
-					me.setContent(null);
-					var rt = me.down('pveResourceTree');
-					rt.setDatacenterText(undefined);
-					rt.clearTree();
-
-					// empty the stores of the StatusPanel child items
-					var statusPanels = Ext.ComponentQuery.query('pveStatusPanel grid');
-					Ext.Array.forEach(statusPanels, function(comp) {
-					    if (comp.getStore()) {
-						comp.getStore().loadData([], false);
-					    }
-					});
-				    }
-				}
-			    ]
-			}
-		    ]
-		},
-		{
-		    region: 'center',
-		    stateful: true,
-		    stateId: 'pvecenter',
-		    minWidth: 100,
-		    minHeight: 100,
-		    id: 'content',
-		    xtype: 'container',
-		    layout: { type: 'card' },
-		    border: false,
-		    margin: '0 5 0 0',
-		    items: []
-		},
-		{
-		    region: 'west',
-		    stateful: true,
-		    stateId: 'pvewest',
-		    itemId: 'west',
-		    xtype: 'container',
-		    border: false,
-		    layout: { type: 'vbox', align: 'stretch' },
-		    margin: '0 0 0 5',
-		    split: true,
-		    width: 200,
-		    items: [ selview, rtree ],
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewWidth = me.getSize().width;
-			    if (width > viewWidth - 100) {
-				panel.setWidth(viewWidth - 100);
-			    }
-			}
-		    }
-		},
-		{
-		    xtype: 'pveStatusPanel',
-		    stateful: true,
-		    stateId: 'pvesouth',
-		    itemId: 'south',
-		    region: 'south',
-		    margin:'0 5 5 5',
-		    title: gettext('Logs'),
-		    collapsible: true,
-		    header: false,
-		    height: 200,
-		    split:true,
-		    listeners: {
-			resize: function(panel, width, height) {
-			    var viewHeight = me.getSize().height;
-			    if (height > (viewHeight - 150)) {
-				panel.setHeight(viewHeight - 150);
-			    }
-			}
-		    }
-		}
-	    ]
-	});
-
-	me.callParent();
-
-	me.updateUserInfo();
-
-	// on resize, center all modal windows
-	Ext.on('resize', function(){
-	    var wins = Ext.ComponentQuery.query('window[modal]');
-	    if (wins.length > 0) {
-		wins.forEach(function(win){
-		    win.alignTo(me, 'c-c');
-		});
-	    }
-	});
-    }
-});
-
diff --git a/serverside/jsmod/README.md b/serverside/jsmod/README.md
deleted file mode 100644
index e811fc70996e91107bc15c76dc16a19745bea7df..0000000000000000000000000000000000000000
--- a/serverside/jsmod/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# PVEDiscordDark Javascript Modifications
-
-As you might have noticed, the CSS edits on its own do not completely darken Proxmox's Web UI.  
-HOWEVER, I have found a way to change that - by modifying it's javascript files.  
-
-These modifications are server-side only and currently it is only working on PVE 5.4-3 as I dont have servers that run an older version. If you're running an older version you could send me the files needed so I could take a look at them but for now this is all I have.
-
-## Installation
-Download the bash file for your version and run it anywhere on your Proxmox **node**. If the changes arent appearing on your browser right away, please clear cache.
-
-Currently supported versions are 5.4-3, 6.0-4 and 6.1-3. 
-
-## Uninstallation
-The bash script backs up the files it replaces. Just remove the modified file and remove the '.bak' extension from the end of the backed up files.
-
-## Files modified
-The files modified are..  
-* `/usr/share/pve-manager/js/pvemanager.js`
-* `/usr/share/javascript/extjs/charts.js`
-* `/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js`
-
-For more on whats modified, check [here.](https://github.com/Weilbyte/PVEDiscordDark/blob/master/serverside/jsmod/changes.md)
diff --git a/serverside/jsmod/changes.md b/serverside/jsmod/changes.md
deleted file mode 100644
index db9fc0ce284991e7af64160a8918831ffa0e213e..0000000000000000000000000000000000000000
--- a/serverside/jsmod/changes.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Changes
-Here you will find exactly what I have modified from the original Proxmox files
-
-## 5-4.3
-* **pvemanager.js**   
-Dark color for node summary background to dark  (`line 17026`)   
-Dark color for background of the TFA QR Code (`line 34513`)   
-Dark color for the S.M.A.R.T disk report (`line 15744`)   
-Dark color for the system report in subscription tab (`line 17210`)  
-* **charts.js**   
-Dark chart background color (`line 8874`)   
-White chart label color (`+line 8888`)   
-White chart title color (`+line 8895`)   
-Light dark color for the chart grid (`line 8901`)   
-White gauge text (`line 8935`)    
-* **proxmoxlib.js**   
-Blurple color for gauge filled meter (`line 4462`)   
-Dark color for gauge meter background (`line 4463`)
-
-## 6.0-4
-* **pvemanagerlib.js**
-`background-color` to `#23272a` for node summary background (`line 18019`)
-`background-color` to `#23272a` for TFA QR code background (`line 35826`)
-`background-color` to `#23272a` for S.M.A.R.T disk report (`line 16729`)
-`background-color` to `#23272a` for system report (`line 18203`)
-* **charts.js**
-Remains roughly the same as 5-4.3
-* **proxmoxlib.js**
-`defaultColor` to `#7289DA` (`line 5084`)
-`backgroundColor` to `#2C2F33` (`line 5085`)
-
diff --git a/serverside/style.css b/serverside/style.css
deleted file mode 100644
index 1355fe1545c96ccd824875162e559f86c0408a01..0000000000000000000000000000000000000000
--- a/serverside/style.css
+++ /dev/null
@@ -1,834 +0,0 @@
-/* PVEDiscordDark Theme by Weilbyte - https://github.com/Weilbyte/PVEDiscordDark */
-.x-box-inner {
-overflow:hidden;
-position:relative;
-left:0;
-top:0;
-background:#23272a;
-}
-
-.x-body {
-color:#fff;
-font-size:13px;
-line-height:17px;
-font-weight:300;
-font-family:helvetica, arial, verdana, sans-serif;
-background:#fff;
-}
-
-.x-form-item-body.x-form-item-body-default.x-form-display-field-body.x-form-display-field-body-default {
-        border-radius: 6px;
-        padding: 2px;
-}
-
-.x-field.x-form-item.x-form-item-default.x-form-readonly.x-form-type-text {
-        border-radius: 6px;
-}
-
-.x-viewport {
-background:#23272a;
-}
-
-.x-viewport > .x-body {
-background:#23272a;
-}
-
-.x-form-text-default {
-color:#818082;
-background-color:#4a4d53;
-font:300 13px/17px helvetica, arial, verdana, sans-serif;
-min-height:22px;
-padding:0 6px 2px;
-}
-
-.x-form-trigger-wrap-default {
-border-color:#cfcfcf;
-border-style:solid;
-border-width:0;
-}
-
-.x-form-trigger-default {
-width:22px;
-background:0 center #72767d url(/pve2/images/dd_trigger.png) no-repeat;
-}
-
-.x-panel-body-default {
-background:#2c2f33;
-color:#fff;
-font-size:13px;
-font-weight:300;
-font-family:helvetica, arial, verdana, sans-serif;
-border-color:#fff;
-border-style:solid;
-border-width:0;
-}
-
-.x-grid-cell-inner {
-background: transparent;
-color:#fff;
-}
-
-.x-grid-cell-rowbody {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-toolbar-default {
-background-color:#2c2f33;
-border-width:0;
-}
-
-.x-toolbar {
-background:#2c2f33;
-}
-
-#toolbar-1069-innerCt {
-background:#2c2f33;
-}
-
-.x-autocontainer-innerCt {
-background:#2c2f33;
-}
-
-[id^="toolbar"] {
-background:#2c2f33;
-}
-
-[id^="legend"] {
-background:#23272a;
-border-color:red;
-}
-
-.x-legend-item {
-background:#2c2f33;
-color:#fff;
-border-width:0;
-}
-
-.x-legend-container {
-background:#2c2f33;
-border-radius:0;
-box-shadow:rgba(0,0,0,0) 0 0 0;
-border-width:0;
-}
-
-.x-legend.x-docked-top .x-legend-item {
-border-left:0;
-border-bottom:0;
-}
-
-.x-legend.x-docked-bottom .x-legend-item {
-border-left:0;
-border-bottom:0;
-}
-
-.x-legend-panel.x-docked-top .x-legend-item {
-border-left:0;
-border-bottom:0;
-}
-
-.x-legend-panel.x-docked-bottom .x-legend-item {
-border-left:0;
-border-bottom:0;
-}
-
-.x-treelist-item-leaf {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-container {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-row {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-row-with-icon {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-item-expandable {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-item-wrap {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-item-text {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-item-icon {
-background:#2c2f33;
-color:#fff;
-}
-
-.x-treelist-item-selected > .x-treelist-row {
-background-color:#23272a;
-}
-
-.x-treelist-row-over {
-color:#FF0;
-}
-
-.x-treelist-row-over > * > .x-treelist-item-text {
-color:#7289da;
-transition:color .5s;
-}
-
-.x-treelist-row-over > * > .x-treelist-item-icon {
-color:#7289da;
-transition:color .5s;
-}
-
-.fa-ceph:before {
-background-image:url(/pve2/images/dd_cephwhite.png);
-}
-
-.x-treelist-row-over > * > .fa-ceph:before {
-background-image:url(/pve2/images/dd_cephblurp.png);
-background-size:14px 14px;
-transition:background-image .5s;
-}
-
-.x-progress {
-background:#2c2f33;
-}
-
-.x-progress-bar {
-background-color:#7289da!important;
-}
-
-.x-progress-text.x-progress-text-back {
-color:#fff!important;
-}
-
-.x-progress-text {
-color:#fff!important;
-}
-
-.x-component.x-box-item.x-component-default {
-background:#23272a;
-}
-
-.x-panel-header {
-background:#23272a;
-border:0;
-}
-
-.x-title-text {
-color:#7289da;
-}
-
-.x-btn {
-background:#7289da;
-border-width:0;
-}
-
-.x-btn-inner {
-color:#fff;
-}
-
-.x-btn-inner.x-btn-inner-default-small {
-color:#fff;
-}
-
-#button-1030 { 
-        background:#23272a;
-        border: 1px solid #d23d3f;
-}
-
-#userinfo.x-btn {
-        background-color: transparent !important;
-        border: 1px solid #d23d3f !important;
-}
-
-#menuitem-1030-iconEl {
-        color: white;
-}
-
-#menuitem-1031-iconEl {
-        color: white;
-}
-
-#menuitem-1032-iconEl {
-        color: white;
-}
-
-#menuitem-1034-iconEl {
-        color: #c52d2f;
-}
-
-.x-btn.x-unselectable.x-box-item.x-toolbar-item.x-btn-default-toolbar-small.x-btn-over {
-background-color:#677bc4;
-}
-
-.x-btn.x-unselectable.x-box-item.x-btn-default-small.x-btn-over {
-background-color:#677bc4;
-}
-
-.x-menu-item-focus {
-background-color:#677bc4;
-}
-
-.x-btn.x-unselectable.x-box-item.x-toolbar-item.x-btn-default-toolbar-small.x-btn-menu-active {
-background-color:#677bc4;
-}
-
-.x-btn-disabled {
-background-image:none;
-background-color:#737fab!important;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-small.fa.fa-book.x-btn-icon-el-default-toolbar-small {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-undo {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-terminal {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-fw.fa-ellipsis-v {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.x-btn-icon-el-default-toolbar-small.fa.fa-question-circle {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-send-o {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-play {
-color:#43b581;
-}
-
-.x-btn-inner.x-btn-inner-default-toolbar-small {
-color:#fff;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-small.fa.black.fa-gear {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-send-o {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-clone {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-file-o {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-heartbeat {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-trash-o {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-desktop {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-cube {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-terminal {
-color:#fff;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-play {
-color:#43b581;
-}
-
-.x-btn-icon-el.x-btn-icon-el-default-toolbar-small.fa.fa-power-off {
-color:#d23d3f;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-stop {
-color:#d23d3f;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-stop {
-color:#d23d3f;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-power-off {
-color:#d23d3f;
-}
-
-.x-menu-item-icon-default.x-menu-item-icon.fa.fa-fw.fa-pause {
-color:#faa61a;
-}
-
-.x-menu-item {
-background:#7289da;
-border-style:none;
-border-width:0;
-}
-
-.x-menu-default {
-background:#7289da;
-border-style:none;
-border-width:0;
-}
-
-.x-menu-item-text {
-color:#fff;
-}
-
-.x-menu-item-default.x-menu-item-separator {
-height:0;
-border-top-width:0;
-margin:0;
-padding:0;
-}
-
-.x-menu-header {
-border-radius:1px;
-background:#23272a;
-border-width:0;
-}
-
-[id^="tooltip"] {
-background:#7289da;
-color:#fff;
-border-width:0;
-}
-
-[id^="ext-quicktips-tip-body"] {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0;
-}
-
-[id^="ext-quicktips-tip-innerCt"] {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0;
-}
-
-[id^="ext-quicktips-tip-ext-quicktips-tip-outerCt"] {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0;
-}
-
-[id^="ext-form-error"] {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0;
-}
-
-.x-tip-default {
-background-color:#7289da;
-color:#fff;
-border-radius:0;
-border-width:0;
-}
-
-.x-tool-img {
-background-image:url(/pve2/images/dd_tool-sprites.png);
-}
-
-.x-window-header.x-header.x-header-draggable.x-docked.x-unselectable.x-window-header-default.x-horizontal.x-window-header-horizontal.x-window-header-default-horizontal.x-top.x-window-header-top.x-window-header-default-top.x-box-layout-ct {
-background:#23272a;
-border-bottom-width:0;
-border-right-width:0;
-}
-
-.x-window-body {
-background:#23272a;
-border-bottom-width:0;
-border-right-width:0;
-}
-
-.x-window-default {
-border-radius:0;
-background-color:#23272a;
-box-shadow:none;
-border-color:#23272a;
-border-style:none;
-border-width:0;
-padding:0;
-}
-
-.x-window-default-mc {
-background-color:#23272a;
-}
-
-.x-window-body-default {
-color: white;
-border-width:0!important;
-}
-
-.x-window-header-default-top {
-border-top-left-radius:0!important;
-border-top-right-radius:0!important;
-border-bottom-right-radius:0!important;
-border-bottom-left-radius:0!important;
-background-color:#23272a;
-border-width:0!important;
-padding:9px;
-}
-
-.x-form-text {
-color:#fff;
-}
-
-.x-form-item-label-inner-default {
-color:#fff;
-}
-
-.x-window-text {
-color:#fff;
-}
-
-.x-form-display-field {
-color: #707C80;
-}
-
-.x-component {
-color:#fff;
-}
-
-.x-mask {
-background-color:rgba(26,26,29,0.27);
-}
-
-.x-splitter-collapsed .x-layout-split-bottom {
-background-image:url(/pve2/images/dd_mini-top.png);
-}
-
-.x-layout-split-bottom {
-background-image:url(/pve2/images/dd_mini-bottom.png);
-}
-
-.x-tab {
-background:#737fab;
-color:#fff;
-border-width:0;
-}
-
-.x-tab-inner {
-color:#fff;
-}
-
-.x-tab-active {
-background:#7289da!important;
-border-width:0!important;
-}
-
-.x-tab-over {
-background:#7289da!important;
-border-width:0!important;
-}
-
-.x-tab-default-focus {
-background:#7289da!important;
-border-width:0!important;
-}
-
-.x-tab-focus {
-background:#7289da!important;
-border-width:0!important;
-}
-
-.x-tab-bar-body {
-background:#23272a;
-}
-
-.x-tab-disabled {
-background:#737fab!important;
-}
-
-.x-column-header-inner {
-background:#2c2f33;
-border-width:0!important;
-}
-
-.x-column-header-default {
-background:#2c2f33;
-border-width:0!important;
-}
-
-.x-grid-item {
-background:#2c2f33;
-border-width:0!important;
-}
-
-.x-grid-item-alt {
-background:#23272a;
-border-width:0!important;
-}
-
-.x-grid-header-ct {
-background:#2c2f33;
-border-width:0!important;
-}
-
-.x-column-header-text-inner {
-color:#fff;
-}
-
-.x-column-header-trigger {
-border-color:#23272a;
-}
-
-.x-toolbar-text.x-box-item.x-toolbar-item.x-toolbar-text-default {
-color:#fff;
-}
-
-.x-grid-group-title {
-color:#fff;
-}
-
-[id^="pveNodeStatus"] {
-background:#23272a;
-}
-
-div[id^="pveNotesView-"][id$="-innerCt"] {
-background:#23272a;
-}
-
-img[src^="/pve2/images/proxmox_logo"] {
-background:#23272a;
-content:url(/pve2/images/dd_logo.png);
-}
-
-[id^="versioninfo"] {
-background:#23272a;
-}
-
-[id^="proxmoxGauge"] {
-background:#23272a;
-}
-
-div[id^="panel-"][id$="-body"] {
-background:#23272a;
-}
-
-.x-surface-canvas {
-border-radius:3px;
-}
-
-.x-component.x-fieldset-header-text.x-component-default {
-color:#fff;
-}
-
-.x-fieldset-default {
-border:1px solid #7289da;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-server {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-server {
-color:#7289da!important;
-}
-
-.fa-building.online {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-cube.running.ha-unmanaged {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-building {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-building {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-cube {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-desktop {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-leaf.fa.fa-database {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-cube {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-desktop {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent.fa.fa-database {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-database {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-desktop {
-color:#7289da!important;
-}
-
-.x-tree-icon.x-tree-icon-custom.x-tree-icon-parent-expanded.fa.fa-cube {
-color:#7289da!important;
-}
-
-.x-grid-group-hd.x-grid-group-hd-collapsible {
-background:#23272a;
-color:#fff;
-border-width:0;
-}
-
-.x-splitter {
-background:#23272a;
-}
-
-.x-box-scroller {
-background:#2c2f33!important;
-}
-
-.x-box-scroller-body-vertical {
-background:#2c2f33!important;
-}
-
-.x-vertical-scroller {
-background:#2c2f33!important;
-}
-
-.x-toolbar-vertical-scroller {
-background:#2c2f33!important;
-}
-
-.x-toolbar-default-vertical-scroller {
-background:#2c2f33!important;
-}
-
-.pve-itype-icon-processor {
-background-image:url(/pve2/images/dd_icon-cpu.png);
-}
-
-.pve-itype-icon-memory {
-background-image:url(/pve2/images/dd_icon-ram.png);
-}
-
-.pve-itype-icon-storage {
-background-image:url(/pve2/images/dd_icon-hdd.png);
-}
-
-.pve-itype-icon-swap {
-background-image:url(/pve2/images/dd_icon-swap.png);
-}
-
-.pve-itype-icon-display, .x-grid-row-console {
-background-image: url(/pve2/images/dd_icon-display.png);
-}
-
-.pve-itype-icon-cdrom  {
-background-image: url(/pve2/images/dd_icon-cd.png);
-}
-
-.pve-itype-icon-network {
-background-image: url(/pve2/images/dd_icon-network.png);
-}
-
-.pve-itype-icon-pci {
-background-image: url(/pve2/images/dd_icon-pci.png);
-}
-
-.pve-itype-icon-usb {
-background-image: url(/pve2/images/dd_icon-usb.png);
-}
-
-.pve-itype-icon-serial {
-background-image: url(/pve2/images/dd_icon-serial.png);
-}
-
-.pve-itype-icon-cloud {
-background-image: url(/pve2/images/dd_icon-cloud.png);
-}
-
-.fa-fw.x-grid-icon-custom.fa.fa-database {
-color:#7289da;
-}
-
-.fa-fw.x-grid-icon-custom.fa.fa-desktop {
-color:#7289da;
-}
-
-.fa-fw.x-grid-icon-custom.fa.fa-cube {
-color:#7289da;
-}
-
-html {
-overflow:scroll;
-overflow-x:hidden;
-}
-
-::-webkit-scrollbar {
-width:0;
-background:transparent;
-}
-
-.lxc:after {
-background:transparent!important;
-color:#7289da;
-text-shadow:0 0 0 #2c2f33!important;
-}
-
-.qemu:after {
-background:transparent!important;
-color:#7289da;
-text-shadow:0 0 0 #2c2f33!important;
-}
-
-.x-tree-icon-custom:after {
-text-shadow:0 0 0 #2c2f33;
-}
-
-.x-grid-icon-custom:after {
-text-shadow:0 0 0 #2c2f33;
-}
-
-* {
-        font-weight: 350;
-}
-
-.x-grid-row-loading {
-background-image: url(/pve2/images/dd_loading.svg);
-background-size: 32px;
-}
-
-.proxmox-invalid-row {
-background-color: #401314;
-}